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