mshtml: Test return value of OnStateChange.
[wine] / dlls / wined3d / query.c
1 /*
2  * IWineD3DQuery implementation
3  *
4  * Copyright 2005 Oliver Stieber
5  * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
6  * Copyright 2009 Henri Verbeet for CodeWeavers.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23
24 #include "config.h"
25 #include "wined3d_private.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
28 #define GLINFO_LOCATION (*gl_info)
29
30 BOOL wined3d_event_query_supported(const struct wined3d_gl_info *gl_info)
31 {
32     return gl_info->supported[ARB_SYNC] || gl_info->supported[NV_FENCE] || gl_info->supported[APPLE_FENCE];
33 }
34
35 void wined3d_event_query_destroy(struct wined3d_event_query *query)
36 {
37     if (query->context) context_free_event_query(query);
38     HeapFree(GetProcessHeap(), 0, query);
39 }
40
41 enum wined3d_event_query_result wined3d_event_query_test(struct wined3d_event_query *query, IWineD3DDeviceImpl *device)
42 {
43     struct wined3d_context *context;
44     const struct wined3d_gl_info *gl_info;
45     enum wined3d_event_query_result ret;
46     BOOL fence_result;
47
48     TRACE("(%p) : device %p\n", query, device);
49
50     if (query->context == NULL)
51     {
52         TRACE("Query not started\n");
53         return WINED3D_EVENT_QUERY_NOT_STARTED;
54     }
55
56     if (!query->context->gl_info->supported[ARB_SYNC] && query->context->tid != GetCurrentThreadId())
57     {
58         WARN("Event query tested from wrong thread\n");
59         return WINED3D_EVENT_QUERY_WRONG_THREAD;
60     }
61
62     context = context_acquire(device, query->context->current_rt);
63     gl_info = context->gl_info;
64
65     ENTER_GL();
66
67     if (gl_info->supported[ARB_SYNC])
68     {
69         GLenum gl_ret = GL_EXTCALL(glClientWaitSync(query->object.sync, 0, 0));
70         checkGLcall("glClientWaitSync");
71
72         switch (gl_ret)
73         {
74             case GL_ALREADY_SIGNALED:
75             case GL_CONDITION_SATISFIED:
76                 ret = WINED3D_EVENT_QUERY_OK;
77                 break;
78
79             case GL_TIMEOUT_EXPIRED:
80                 ret = WINED3D_EVENT_QUERY_WAITING;
81                 break;
82
83             case GL_WAIT_FAILED:
84             default:
85                 ERR("glClientWaitSync returned %#x.\n", gl_ret);
86                 ret = WINED3D_EVENT_QUERY_ERROR;
87         }
88     }
89     else if (gl_info->supported[APPLE_FENCE])
90     {
91         fence_result = GL_EXTCALL(glTestFenceAPPLE(query->object.id));
92         checkGLcall("glTestFenceAPPLE");
93         if (fence_result) ret = WINED3D_EVENT_QUERY_OK;
94         else ret = WINED3D_EVENT_QUERY_WAITING;
95     }
96     else if (gl_info->supported[NV_FENCE])
97     {
98         fence_result = GL_EXTCALL(glTestFenceNV(query->object.id));
99         checkGLcall("glTestFenceNV");
100         if (fence_result) ret = WINED3D_EVENT_QUERY_OK;
101         else ret = WINED3D_EVENT_QUERY_WAITING;
102     }
103     else
104     {
105         ERR("Event query created despite lack of GL support\n");
106         ret = WINED3D_EVENT_QUERY_ERROR;
107     }
108
109     LEAVE_GL();
110
111     context_release(context);
112     return ret;
113 }
114
115 enum wined3d_event_query_result wined3d_event_query_finish(struct wined3d_event_query *query, IWineD3DDeviceImpl *device)
116 {
117     struct wined3d_context *context;
118     const struct wined3d_gl_info *gl_info;
119     enum wined3d_event_query_result ret;
120
121     TRACE("(%p)\n", query);
122
123     if (!query->context)
124     {
125         TRACE("Query not started\n");
126         return WINED3D_EVENT_QUERY_NOT_STARTED;
127     }
128     gl_info = query->context->gl_info;
129
130     if (query->context->tid != GetCurrentThreadId() && !gl_info->supported[ARB_SYNC])
131     {
132         /* A glFinish does not reliably wait for draws in other contexts. The caller has
133          * to find its own way to cope with the thread switch
134          */
135         WARN("Event query finished from wrong thread\n");
136         return WINED3D_EVENT_QUERY_WRONG_THREAD;
137     }
138
139     context = context_acquire(device, query->context->current_rt);
140
141     ENTER_GL();
142     if (gl_info->supported[ARB_SYNC])
143     {
144         GLenum gl_ret = GL_EXTCALL(glClientWaitSync(query->object.sync, 0, ~(GLuint64)0));
145         checkGLcall("glClientWaitSync");
146
147         switch (gl_ret)
148         {
149             case GL_ALREADY_SIGNALED:
150             case GL_CONDITION_SATISFIED:
151                 ret = WINED3D_EVENT_QUERY_OK;
152                 break;
153
154                 /* We don't expect a timeout for a ~584 year wait */
155             default:
156                 ERR("glClientWaitSync returned %#x.\n", gl_ret);
157                 ret = WINED3D_EVENT_QUERY_ERROR;
158         }
159     }
160     else if (context->gl_info->supported[APPLE_FENCE])
161     {
162         GL_EXTCALL(glFinishFenceAPPLE(query->object.id));
163         checkGLcall("glFinishFenceAPPLE");
164         ret = WINED3D_EVENT_QUERY_OK;
165     }
166     else if (context->gl_info->supported[NV_FENCE])
167     {
168         GL_EXTCALL(glFinishFenceNV(query->object.id));
169         checkGLcall("glFinishFenceNV");
170         ret = WINED3D_EVENT_QUERY_OK;
171     }
172     else
173     {
174         ERR("Event query created without GL support\n");
175         ret = WINED3D_EVENT_QUERY_ERROR;
176     }
177     LEAVE_GL();
178
179     context_release(context);
180     return ret;
181 }
182
183 void wined3d_event_query_issue(struct wined3d_event_query *query, IWineD3DDeviceImpl *device)
184 {
185     const struct wined3d_gl_info *gl_info;
186     struct wined3d_context *context;
187
188     if (query->context)
189     {
190         if (!query->context->gl_info->supported[ARB_SYNC] && query->context->tid != GetCurrentThreadId())
191         {
192             context_free_event_query(query);
193             context = context_acquire(device, NULL);
194             context_alloc_event_query(context, query);
195         }
196         else
197         {
198             context = context_acquire(device, query->context->current_rt);
199         }
200     }
201     else
202     {
203         context = context_acquire(device, NULL);
204         context_alloc_event_query(context, query);
205     }
206
207     gl_info = context->gl_info;
208
209     ENTER_GL();
210
211     if (gl_info->supported[ARB_SYNC])
212     {
213         if (query->object.sync) GL_EXTCALL(glDeleteSync(query->object.sync));
214         checkGLcall("glDeleteSync");
215         query->object.sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
216         checkGLcall("glFenceSync");
217     }
218     else if (gl_info->supported[APPLE_FENCE])
219     {
220         GL_EXTCALL(glSetFenceAPPLE(query->object.id));
221         checkGLcall("glSetFenceAPPLE");
222     }
223     else if (gl_info->supported[NV_FENCE])
224     {
225         GL_EXTCALL(glSetFenceNV(query->object.id, GL_ALL_COMPLETED_NV));
226         checkGLcall("glSetFenceNV");
227     }
228
229     LEAVE_GL();
230
231     context_release(context);
232 }
233
234 /*
235  * Occlusion Queries:
236  * http://www.gris.uni-tuebingen.de/~bartz/Publications/paper/hww98.pdf
237  * http://oss.sgi.com/projects/ogl-sample/registry/ARB/occlusion_query.txt
238  */
239
240 /* *******************************************
241    IWineD3DQuery IUnknown parts follow
242    ******************************************* */
243 static HRESULT  WINAPI IWineD3DQueryImpl_QueryInterface(IWineD3DQuery *iface, REFIID riid, LPVOID *ppobj)
244 {
245     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
246     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
247     if (IsEqualGUID(riid, &IID_IUnknown)
248         || IsEqualGUID(riid, &IID_IWineD3DBase)
249         || IsEqualGUID(riid, &IID_IWineD3DQuery)) {
250         IUnknown_AddRef(iface);
251         *ppobj = This;
252         return S_OK;
253     }
254     *ppobj = NULL;
255     return E_NOINTERFACE;
256 }
257
258 static ULONG  WINAPI IWineD3DQueryImpl_AddRef(IWineD3DQuery *iface) {
259     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
260     TRACE("(%p) : AddRef increasing from %d\n", This, This->ref);
261     return InterlockedIncrement(&This->ref);
262 }
263
264 static ULONG  WINAPI IWineD3DQueryImpl_Release(IWineD3DQuery *iface) {
265     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
266     ULONG ref;
267     TRACE("(%p) : Releasing from %d\n", This, This->ref);
268     ref = InterlockedDecrement(&This->ref);
269     if (ref == 0) {
270         /* Queries are specific to the GL context that created them. Not
271          * deleting the query will obviously leak it, but that's still better
272          * than potentially deleting a different query with the same id in this
273          * context, and (still) leaking the actual query. */
274         if (This->type == WINED3DQUERYTYPE_EVENT)
275         {
276             struct wined3d_event_query *query = This->extendedData;
277             if (query) wined3d_event_query_destroy(query);
278         }
279         else if (This->type == WINED3DQUERYTYPE_OCCLUSION)
280         {
281             struct wined3d_occlusion_query *query = This->extendedData;
282
283             if (query->context) context_free_occlusion_query(query);
284             HeapFree(GetProcessHeap(), 0, This->extendedData);
285         }
286
287         HeapFree(GetProcessHeap(), 0, This);
288     }
289     return ref;
290 }
291
292 /* *******************************************
293    IWineD3DQuery IWineD3DQuery parts follow
294    ******************************************* */
295 static HRESULT WINAPI IWineD3DQueryImpl_GetParent(IWineD3DQuery *iface, IUnknown **parent)
296 {
297     TRACE("iface %p, parent %p.\n", iface, parent);
298
299     *parent = (IUnknown *)parent;
300     IUnknown_AddRef(*parent);
301
302     TRACE("Returning %p.\n", *parent);
303
304     return WINED3D_OK;
305 }
306
307 static HRESULT  WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
308     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *) iface;
309     struct wined3d_occlusion_query *query = This->extendedData;
310     IWineD3DDeviceImpl *device = This->device;
311     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
312     struct wined3d_context *context;
313     DWORD* data = pData;
314     GLuint available;
315     GLuint samples;
316     HRESULT res;
317
318     TRACE("(%p) : type D3DQUERY_OCCLUSION, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, pData, dwSize, dwGetDataFlags);
319
320     if (!query->context) This->state = QUERY_CREATED;
321
322     if (This->state == QUERY_CREATED)
323     {
324         /* D3D allows GetData on a new query, OpenGL doesn't. So just invent the data ourselves */
325         TRACE("Query wasn't yet started, returning S_OK\n");
326         if(data) *data = 0;
327         return S_OK;
328     }
329
330     if (This->state == QUERY_BUILDING)
331     {
332         /* Msdn says this returns an error, but our tests show that S_FALSE is returned */
333         TRACE("Query is building, returning S_FALSE\n");
334         return S_FALSE;
335     }
336
337     if (!gl_info->supported[ARB_OCCLUSION_QUERY])
338     {
339         WARN("(%p) : Occlusion queries not supported. Returning 1.\n", This);
340         *data = 1;
341         return S_OK;
342     }
343
344     if (query->context->tid != GetCurrentThreadId())
345     {
346         FIXME("%p Wrong thread, returning 1.\n", This);
347         *data = 1;
348         return S_OK;
349     }
350
351     context = context_acquire(This->device, query->context->current_rt);
352
353     ENTER_GL();
354
355     GL_EXTCALL(glGetQueryObjectuivARB(query->id, GL_QUERY_RESULT_AVAILABLE_ARB, &available));
356     checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)");
357     TRACE("(%p) : available %d.\n", This, available);
358
359     if (available)
360     {
361         if (data)
362         {
363             GL_EXTCALL(glGetQueryObjectuivARB(query->id, GL_QUERY_RESULT_ARB, &samples));
364             checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)");
365             TRACE("(%p) : Returning %d samples.\n", This, samples);
366             *data = samples;
367         }
368         res = S_OK;
369     }
370     else
371     {
372         res = S_FALSE;
373     }
374
375     LEAVE_GL();
376
377     context_release(context);
378
379     return res;
380 }
381
382 static HRESULT  WINAPI IWineD3DEventQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
383     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *) iface;
384     struct wined3d_event_query *query = This->extendedData;
385     BOOL *data = pData;
386     enum wined3d_event_query_result ret;
387
388     TRACE("(%p) : type D3DQUERY_EVENT, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, pData, dwSize, dwGetDataFlags);
389
390     if (!pData || !dwSize) return S_OK;
391     if (!query)
392     {
393         WARN("(%p): Event query not supported by GL, reporting GPU idle\n", This);
394         *data = TRUE;
395         return S_OK;
396     }
397
398     ret = wined3d_event_query_test(query, This->device);
399     switch(ret)
400     {
401         case WINED3D_EVENT_QUERY_OK:
402         case WINED3D_EVENT_QUERY_NOT_STARTED:
403             *data = TRUE;
404             break;
405
406         case WINED3D_EVENT_QUERY_WAITING:
407             *data = FALSE;
408             break;
409
410         case WINED3D_EVENT_QUERY_WRONG_THREAD:
411             FIXME("(%p) Wrong thread, reporting GPU idle.\n", This);
412             *data = TRUE;
413             break;
414
415         case WINED3D_EVENT_QUERY_ERROR:
416             ERR("The GL event query failed, returning D3DERR_INVALIDCALL\n");
417             return WINED3DERR_INVALIDCALL;
418     }
419
420     return S_OK;
421 }
422
423 static DWORD  WINAPI IWineD3DEventQueryImpl_GetDataSize(IWineD3DQuery* iface){
424     TRACE("(%p) : type D3DQUERY_EVENT\n", iface);
425
426     return sizeof(BOOL);
427 }
428
429 static DWORD  WINAPI IWineD3DOcclusionQueryImpl_GetDataSize(IWineD3DQuery* iface){
430     TRACE("(%p) : type D3DQUERY_OCCLUSION\n", iface);
431
432     return sizeof(DWORD);
433 }
434
435 static WINED3DQUERYTYPE  WINAPI IWineD3DQueryImpl_GetType(IWineD3DQuery* iface){
436     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
437     return This->type;
438 }
439
440 static HRESULT  WINAPI IWineD3DEventQueryImpl_Issue(IWineD3DQuery* iface,  DWORD dwIssueFlags) {
441     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
442
443     TRACE("(%p) : dwIssueFlags %#x, type D3DQUERY_EVENT\n", This, dwIssueFlags);
444     if (dwIssueFlags & WINED3DISSUE_END)
445     {
446         struct wined3d_event_query *query = This->extendedData;
447
448         /* Faked event query support */
449         if (!query) return WINED3D_OK;
450
451         wined3d_event_query_issue(query, This->device);
452     }
453     else if(dwIssueFlags & WINED3DISSUE_BEGIN)
454     {
455         /* Started implicitly at device creation */
456         ERR("Event query issued with START flag - what to do?\n");
457     }
458
459     if(dwIssueFlags & WINED3DISSUE_BEGIN) {
460         This->state = QUERY_BUILDING;
461     } else {
462         This->state = QUERY_SIGNALLED;
463     }
464
465     return WINED3D_OK;
466 }
467
468 static HRESULT  WINAPI IWineD3DOcclusionQueryImpl_Issue(IWineD3DQuery* iface,  DWORD dwIssueFlags) {
469     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
470     IWineD3DDeviceImpl *device = This->device;
471     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
472
473     if (gl_info->supported[ARB_OCCLUSION_QUERY])
474     {
475         struct wined3d_occlusion_query *query = This->extendedData;
476         struct wined3d_context *context;
477
478         /* This is allowed according to msdn and our tests. Reset the query and restart */
479         if (dwIssueFlags & WINED3DISSUE_BEGIN)
480         {
481             if (This->state == QUERY_BUILDING)
482             {
483                 if (query->context->tid != GetCurrentThreadId())
484                 {
485                     FIXME("Wrong thread, can't restart query.\n");
486
487                     context_free_occlusion_query(query);
488                     context = context_acquire(This->device, NULL);
489                     context_alloc_occlusion_query(context, query);
490                 }
491                 else
492                 {
493                     context = context_acquire(This->device, query->context->current_rt);
494
495                     ENTER_GL();
496                     GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
497                     checkGLcall("glEndQuery()");
498                     LEAVE_GL();
499                 }
500             }
501             else
502             {
503                 if (query->context) context_free_occlusion_query(query);
504                 context = context_acquire(This->device, NULL);
505                 context_alloc_occlusion_query(context, query);
506             }
507
508             ENTER_GL();
509             GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, query->id));
510             checkGLcall("glBeginQuery()");
511             LEAVE_GL();
512
513             context_release(context);
514         }
515         if (dwIssueFlags & WINED3DISSUE_END) {
516             /* Msdn says _END on a non-building occlusion query returns an error, but
517              * our tests show that it returns OK. But OpenGL doesn't like it, so avoid
518              * generating an error
519              */
520             if (This->state == QUERY_BUILDING)
521             {
522                 if (query->context->tid != GetCurrentThreadId())
523                 {
524                     FIXME("Wrong thread, can't end query.\n");
525                 }
526                 else
527                 {
528                     context = context_acquire(This->device, query->context->current_rt);
529
530                     ENTER_GL();
531                     GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
532                     checkGLcall("glEndQuery()");
533                     LEAVE_GL();
534
535                     context_release(context);
536                 }
537             }
538         }
539     } else {
540         FIXME("(%p) : Occlusion queries not supported\n", This);
541     }
542
543     if(dwIssueFlags & WINED3DISSUE_BEGIN) {
544         This->state = QUERY_BUILDING;
545     } else {
546         This->state = QUERY_SIGNALLED;
547     }
548     return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL.    */
549 }
550
551 static const IWineD3DQueryVtbl IWineD3DEventQuery_Vtbl =
552 {
553     /*** IUnknown methods ***/
554     IWineD3DQueryImpl_QueryInterface,
555     IWineD3DQueryImpl_AddRef,
556     IWineD3DQueryImpl_Release,
557     /*** IWineD3Dquery methods ***/
558     IWineD3DQueryImpl_GetParent,
559     IWineD3DEventQueryImpl_GetData,
560     IWineD3DEventQueryImpl_GetDataSize,
561     IWineD3DQueryImpl_GetType,
562     IWineD3DEventQueryImpl_Issue
563 };
564
565 static const IWineD3DQueryVtbl IWineD3DOcclusionQuery_Vtbl =
566 {
567     /*** IUnknown methods ***/
568     IWineD3DQueryImpl_QueryInterface,
569     IWineD3DQueryImpl_AddRef,
570     IWineD3DQueryImpl_Release,
571     /*** IWineD3Dquery methods ***/
572     IWineD3DQueryImpl_GetParent,
573     IWineD3DOcclusionQueryImpl_GetData,
574     IWineD3DOcclusionQueryImpl_GetDataSize,
575     IWineD3DQueryImpl_GetType,
576     IWineD3DOcclusionQueryImpl_Issue
577 };
578
579 HRESULT query_init(IWineD3DQueryImpl *query, IWineD3DDeviceImpl *device,
580         WINED3DQUERYTYPE type, IUnknown *parent)
581 {
582     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
583
584     switch (type)
585     {
586         case WINED3DQUERYTYPE_OCCLUSION:
587             TRACE("Occlusion query.\n");
588             if (!gl_info->supported[ARB_OCCLUSION_QUERY])
589             {
590                 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
591                 return WINED3DERR_NOTAVAILABLE;
592             }
593             query->lpVtbl = &IWineD3DOcclusionQuery_Vtbl;
594             query->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
595             if (!query->extendedData)
596             {
597                 ERR("Failed to allocate occlusion query extended data.\n");
598                 return E_OUTOFMEMORY;
599             }
600             ((struct wined3d_occlusion_query *)query->extendedData)->context = NULL;
601             break;
602
603         case WINED3DQUERYTYPE_EVENT:
604             TRACE("Event query.\n");
605             if (!wined3d_event_query_supported(gl_info))
606             {
607                 /* Half-Life 2 needs this query. It does not render the main
608                  * menu correctly otherwise. Pretend to support it, faking
609                  * this query does not do much harm except potentially
610                  * lowering performance. */
611                 FIXME("Event query: Unimplemented, but pretending to be supported.\n");
612             }
613             query->lpVtbl = &IWineD3DEventQuery_Vtbl;
614             query->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct wined3d_event_query));
615             if (!query->extendedData)
616             {
617                 ERR("Failed to allocate event query memory.\n");
618                 return E_OUTOFMEMORY;
619             }
620             break;
621
622         case WINED3DQUERYTYPE_VCACHE:
623         case WINED3DQUERYTYPE_RESOURCEMANAGER:
624         case WINED3DQUERYTYPE_VERTEXSTATS:
625         case WINED3DQUERYTYPE_TIMESTAMP:
626         case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
627         case WINED3DQUERYTYPE_TIMESTAMPFREQ:
628         case WINED3DQUERYTYPE_PIPELINETIMINGS:
629         case WINED3DQUERYTYPE_INTERFACETIMINGS:
630         case WINED3DQUERYTYPE_VERTEXTIMINGS:
631         case WINED3DQUERYTYPE_PIXELTIMINGS:
632         case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
633         case WINED3DQUERYTYPE_CACHEUTILIZATION:
634         default:
635             FIXME("Unhandled query type %#x.\n", type);
636             return WINED3DERR_NOTAVAILABLE;
637     }
638
639     query->type = type;
640     query->state = QUERY_CREATED;
641     query->device = device;
642     query->parent = parent;
643     query->ref = 1;
644
645     return WINED3D_OK;
646 }