wined3d: Add a separate function for query initialization.
[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 /*
28  * Occlusion Queries:
29  * http://www.gris.uni-tuebingen.de/~bartz/Publications/paper/hww98.pdf
30  * http://oss.sgi.com/projects/ogl-sample/registry/ARB/occlusion_query.txt
31  */
32
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
34 #define GLINFO_LOCATION This->device->adapter->gl_info
35
36 /* *******************************************
37    IWineD3DQuery IUnknown parts follow
38    ******************************************* */
39 static HRESULT  WINAPI IWineD3DQueryImpl_QueryInterface(IWineD3DQuery *iface, REFIID riid, LPVOID *ppobj)
40 {
41     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
42     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
43     if (IsEqualGUID(riid, &IID_IUnknown)
44         || IsEqualGUID(riid, &IID_IWineD3DBase)
45         || IsEqualGUID(riid, &IID_IWineD3DQuery)) {
46         IUnknown_AddRef(iface);
47         *ppobj = This;
48         return S_OK;
49     }
50     *ppobj = NULL;
51     return E_NOINTERFACE;
52 }
53
54 static ULONG  WINAPI IWineD3DQueryImpl_AddRef(IWineD3DQuery *iface) {
55     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
56     TRACE("(%p) : AddRef increasing from %d\n", This, This->ref);
57     return InterlockedIncrement(&This->ref);
58 }
59
60 static ULONG  WINAPI IWineD3DQueryImpl_Release(IWineD3DQuery *iface) {
61     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
62     ULONG ref;
63     TRACE("(%p) : Releasing from %d\n", This, This->ref);
64     ref = InterlockedDecrement(&This->ref);
65     if (ref == 0) {
66         /* Queries are specific to the GL context that created them. Not
67          * deleting the query will obviously leak it, but that's still better
68          * than potentially deleting a different query with the same id in this
69          * context, and (still) leaking the actual query. */
70         if (This->type == WINED3DQUERYTYPE_EVENT)
71         {
72             struct wined3d_event_query *query = This->extendedData;
73
74             if (query->context) context_free_event_query(query);
75         }
76         else if (This->type == WINED3DQUERYTYPE_OCCLUSION)
77         {
78             struct wined3d_occlusion_query *query = This->extendedData;
79
80             if (query->context) context_free_occlusion_query(query);
81         }
82
83         HeapFree(GetProcessHeap(), 0, This->extendedData);
84         HeapFree(GetProcessHeap(), 0, This);
85     }
86     return ref;
87 }
88
89 /* *******************************************
90    IWineD3DQuery IWineD3DQuery parts follow
91    ******************************************* */
92 static HRESULT WINAPI IWineD3DQueryImpl_GetParent(IWineD3DQuery *iface, IUnknown **parent)
93 {
94     TRACE("iface %p, parent %p.\n", iface, parent);
95
96     *parent = (IUnknown *)parent;
97     IUnknown_AddRef(*parent);
98
99     TRACE("Returning %p.\n", *parent);
100
101     return WINED3D_OK;
102 }
103
104 static HRESULT  WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags){
105     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
106     HRESULT res = S_OK;
107
108     TRACE("(%p) : type %#x, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, This->type, pData, dwSize, dwGetDataFlags);
109
110     switch (This->type){
111
112     case WINED3DQUERYTYPE_VCACHE:
113     {
114
115         WINED3DDEVINFO_VCACHE *data = pData;
116         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VCACHE\n", This);
117         if(pData == NULL || dwSize == 0) break;
118         data->Pattern     = WINEMAKEFOURCC('C','A','C','H');
119         data->OptMethod   = 0; /*0 get longest strips, 1 optimize vertex cache*/
120         data->CacheSize   = 0; /*cache size, only required if OptMethod == 1*/
121         data->MagicNumber = 0; /*only required if OptMethod == 1 (used internally)*/
122
123     }
124     break;
125     case WINED3DQUERYTYPE_RESOURCEMANAGER:
126     {
127         WINED3DDEVINFO_RESOURCEMANAGER *data = pData;
128         int i;
129         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_RESOURCEMANAGER\n", This);
130         if(pData == NULL || dwSize == 0) break;
131         for(i = 0; i < WINED3DRTYPECOUNT; i++){
132             /*I'm setting the default values to 1 so as to reduce the risk of a div/0 in the caller*/
133             /*  isTextureResident could be used to get some of this information  */
134             data->stats[i].bThrashing            = FALSE;
135             data->stats[i].ApproxBytesDownloaded = 1;
136             data->stats[i].NumEvicts             = 1;
137             data->stats[i].NumVidCreates         = 1;
138             data->stats[i].LastPri               = 1;
139             data->stats[i].NumUsed               = 1;
140             data->stats[i].NumUsedInVidMem       = 1;
141             data->stats[i].WorkingSet            = 1;
142             data->stats[i].WorkingSetBytes       = 1;
143             data->stats[i].TotalManaged          = 1;
144             data->stats[i].TotalBytes            = 1;
145         }
146
147     }
148     break;
149     case WINED3DQUERYTYPE_VERTEXSTATS:
150     {
151         WINED3DDEVINFO_VERTEXSTATS *data = pData;
152         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXSTATS\n", This);
153         if(pData == NULL || dwSize == 0) break;
154         data->NumRenderedTriangles      = 1;
155         data->NumExtraClippingTriangles = 1;
156
157     }
158     break;
159     case WINED3DQUERYTYPE_TIMESTAMP:
160     {
161         UINT64* data = pData;
162         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMP\n", This);
163         if(pData == NULL || dwSize == 0) break;
164         *data = 1; /*Don't know what this is supposed to be*/
165     }
166     break;
167     case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
168     {
169         BOOL* data = pData;
170         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPDISJOINT\n", This);
171         if(pData == NULL || dwSize == 0) break;
172         *data = FALSE; /*Don't know what this is supposed to be*/
173     }
174     break;
175     case WINED3DQUERYTYPE_TIMESTAMPFREQ:
176     {
177         UINT64* data = pData;
178         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPFREQ\n", This);
179         if(pData == NULL || dwSize == 0) break;
180         *data = 1; /*Don't know what this is supposed to be*/
181     }
182     break;
183     case WINED3DQUERYTYPE_PIPELINETIMINGS:
184     {
185         WINED3DDEVINFO_PIPELINETIMINGS *data = pData;
186         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIPELINETIMINGS\n", This);
187         if(pData == NULL || dwSize == 0) break;
188
189         data->VertexProcessingTimePercent    =   1.0f;
190         data->PixelProcessingTimePercent     =   1.0f;
191         data->OtherGPUProcessingTimePercent  =  97.0f;
192         data->GPUIdleTimePercent             =   1.0f;
193     }
194     break;
195     case WINED3DQUERYTYPE_INTERFACETIMINGS:
196     {
197         WINED3DDEVINFO_INTERFACETIMINGS *data = pData;
198         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_INTERFACETIMINGS\n", This);
199
200         if(pData == NULL || dwSize == 0) break;
201         data->WaitingForGPUToUseApplicationResourceTimePercent =   1.0f;
202         data->WaitingForGPUToAcceptMoreCommandsTimePercent     =   1.0f;
203         data->WaitingForGPUToStayWithinLatencyTimePercent      =   1.0f;
204         data->WaitingForGPUExclusiveResourceTimePercent        =   1.0f;
205         data->WaitingForGPUOtherTimePercent                    =  96.0f;
206     }
207
208     break;
209     case WINED3DQUERYTYPE_VERTEXTIMINGS:
210     {
211         WINED3DDEVINFO_STAGETIMINGS *data = pData;
212         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXTIMINGS\n", This);
213
214         if(pData == NULL || dwSize == 0) break;
215         data->MemoryProcessingPercent      = 50.0f;
216         data->ComputationProcessingPercent = 50.0f;
217
218     }
219     break;
220     case WINED3DQUERYTYPE_PIXELTIMINGS:
221     {
222         WINED3DDEVINFO_STAGETIMINGS *data = pData;
223         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIXELTIMINGS\n", This);
224
225         if(pData == NULL || dwSize == 0) break;
226         data->MemoryProcessingPercent      = 50.0f;
227         data->ComputationProcessingPercent = 50.0f;
228     }
229     break;
230     case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
231     {
232         WINED3DDEVINFO_BANDWIDTHTIMINGS *data = pData;
233         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_BANDWIDTHTIMINGS\n", This);
234
235         if(pData == NULL || dwSize == 0) break;
236         data->MaxBandwidthUtilized                =  1.0f;
237         data->FrontEndUploadMemoryUtilizedPercent =  1.0f;
238         data->VertexRateUtilizedPercent           =  1.0f;
239         data->TriangleSetupRateUtilizedPercent    =  1.0f;
240         data->FillRateUtilizedPercent             = 97.0f;
241     }
242     break;
243     case WINED3DQUERYTYPE_CACHEUTILIZATION:
244     {
245         WINED3DDEVINFO_CACHEUTILIZATION *data = pData;
246         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_CACHEUTILIZATION\n", This);
247
248         if(pData == NULL || dwSize == 0) break;
249         data->TextureCacheHitRate             = 1.0f;
250         data->PostTransformVertexCacheHitRate = 1.0f;
251     }
252
253
254     break;
255     default:
256         FIXME("(%p) Unhandled query type %d\n",This , This->type);
257
258     };
259
260     /*dwGetDataFlags = 0 || D3DGETDATA_FLUSH
261     D3DGETDATA_FLUSH may return WINED3DERR_DEVICELOST if the device is lost
262     */
263     return res; /* S_OK if the query data is available*/
264 }
265
266 static HRESULT  WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
267     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *) iface;
268     struct wined3d_occlusion_query *query = This->extendedData;
269     IWineD3DDeviceImpl *device = This->device;
270     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
271     struct wined3d_context *context;
272     DWORD* data = pData;
273     GLuint available;
274     GLuint samples;
275     HRESULT res;
276
277     TRACE("(%p) : type D3DQUERY_OCCLUSION, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, pData, dwSize, dwGetDataFlags);
278
279     if (!query->context) This->state = QUERY_CREATED;
280
281     if (This->state == QUERY_CREATED)
282     {
283         /* D3D allows GetData on a new query, OpenGL doesn't. So just invent the data ourselves */
284         TRACE("Query wasn't yet started, returning S_OK\n");
285         if(data) *data = 0;
286         return S_OK;
287     }
288
289     if (This->state == QUERY_BUILDING)
290     {
291         /* Msdn says this returns an error, but our tests show that S_FALSE is returned */
292         TRACE("Query is building, returning S_FALSE\n");
293         return S_FALSE;
294     }
295
296     if (!gl_info->supported[ARB_OCCLUSION_QUERY])
297     {
298         WARN("(%p) : Occlusion queries not supported. Returning 1.\n", This);
299         *data = 1;
300         return S_OK;
301     }
302
303     if (query->context->tid != GetCurrentThreadId())
304     {
305         FIXME("%p Wrong thread, returning 1.\n", This);
306         *data = 1;
307         return S_OK;
308     }
309
310     context = context_acquire(This->device, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
311
312     ENTER_GL();
313
314     GL_EXTCALL(glGetQueryObjectuivARB(query->id, GL_QUERY_RESULT_AVAILABLE_ARB, &available));
315     checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)");
316     TRACE("(%p) : available %d.\n", This, available);
317
318     if (available)
319     {
320         if (data)
321         {
322             GL_EXTCALL(glGetQueryObjectuivARB(query->id, GL_QUERY_RESULT_ARB, &samples));
323             checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)");
324             TRACE("(%p) : Returning %d samples.\n", This, samples);
325             *data = samples;
326         }
327         res = S_OK;
328     }
329     else
330     {
331         res = S_FALSE;
332     }
333
334     LEAVE_GL();
335
336     context_release(context);
337
338     return res;
339 }
340
341 static HRESULT  WINAPI IWineD3DEventQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
342     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *) iface;
343     struct wined3d_event_query *query = This->extendedData;
344     struct wined3d_context *context;
345     BOOL *data = pData;
346
347     TRACE("(%p) : type D3DQUERY_EVENT, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, pData, dwSize, dwGetDataFlags);
348
349     if (!pData || !dwSize) return S_OK;
350
351     if (!query->context)
352     {
353         TRACE("Query not started, returning TRUE.\n");
354         *data = TRUE;
355
356         return S_OK;
357     }
358
359     if (query->context->tid != GetCurrentThreadId())
360     {
361         /* See comment in IWineD3DQuery::Issue, event query codeblock */
362         FIXME("Wrong thread, reporting GPU idle.\n");
363         *data = TRUE;
364
365         return S_OK;
366     }
367
368     context = context_acquire(This->device, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
369
370     ENTER_GL();
371
372     if (context->gl_info->supported[APPLE_FENCE])
373     {
374         *data = GL_EXTCALL(glTestFenceAPPLE(query->id));
375         checkGLcall("glTestFenceAPPLE");
376     }
377     else if (context->gl_info->supported[NV_FENCE])
378     {
379         *data = GL_EXTCALL(glTestFenceNV(query->id));
380         checkGLcall("glTestFenceNV");
381     }
382     else
383     {
384         WARN("(%p): reporting GPU idle\n", This);
385         *data = TRUE;
386     }
387
388     LEAVE_GL();
389
390     context_release(context);
391
392     return S_OK;
393 }
394
395 static DWORD  WINAPI IWineD3DQueryImpl_GetDataSize(IWineD3DQuery* iface){
396     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
397     int dataSize = 0;
398     TRACE("(%p) : type %#x\n", This, This->type);
399     switch(This->type){
400     case WINED3DQUERYTYPE_VCACHE:
401         dataSize = sizeof(WINED3DDEVINFO_VCACHE);
402         break;
403     case WINED3DQUERYTYPE_RESOURCEMANAGER:
404         dataSize = sizeof(WINED3DDEVINFO_RESOURCEMANAGER);
405         break;
406     case WINED3DQUERYTYPE_VERTEXSTATS:
407         dataSize = sizeof(WINED3DDEVINFO_VERTEXSTATS);
408         break;
409     case WINED3DQUERYTYPE_EVENT:
410         dataSize = sizeof(BOOL);
411         break;
412     case WINED3DQUERYTYPE_TIMESTAMP:
413         dataSize = sizeof(UINT64);
414         break;
415     case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
416         dataSize = sizeof(BOOL);
417         break;
418     case WINED3DQUERYTYPE_TIMESTAMPFREQ:
419         dataSize = sizeof(UINT64);
420         break;
421     case WINED3DQUERYTYPE_PIPELINETIMINGS:
422         dataSize = sizeof(WINED3DDEVINFO_PIPELINETIMINGS);
423         break;
424     case WINED3DQUERYTYPE_INTERFACETIMINGS:
425         dataSize = sizeof(WINED3DDEVINFO_INTERFACETIMINGS);
426         break;
427     case WINED3DQUERYTYPE_VERTEXTIMINGS:
428         dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS);
429         break;
430     case WINED3DQUERYTYPE_PIXELTIMINGS:
431         dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS);
432         break;
433     case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
434         dataSize = sizeof(WINED3DQUERYTYPE_BANDWIDTHTIMINGS);
435         break;
436     case WINED3DQUERYTYPE_CACHEUTILIZATION:
437         dataSize = sizeof(WINED3DDEVINFO_CACHEUTILIZATION);
438         break;
439     default:
440        FIXME("(%p) Unhandled query type %d\n",This , This->type);
441        dataSize = 0;
442     }
443     return dataSize;
444 }
445
446 static DWORD  WINAPI IWineD3DEventQueryImpl_GetDataSize(IWineD3DQuery* iface){
447     TRACE("(%p) : type D3DQUERY_EVENT\n", iface);
448
449     return sizeof(BOOL);
450 }
451
452 static DWORD  WINAPI IWineD3DOcclusionQueryImpl_GetDataSize(IWineD3DQuery* iface){
453     TRACE("(%p) : type D3DQUERY_OCCLUSION\n", iface);
454
455     return sizeof(DWORD);
456 }
457
458 static WINED3DQUERYTYPE  WINAPI IWineD3DQueryImpl_GetType(IWineD3DQuery* iface){
459     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
460     return This->type;
461 }
462
463
464 static HRESULT  WINAPI IWineD3DEventQueryImpl_Issue(IWineD3DQuery* iface,  DWORD dwIssueFlags) {
465     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
466
467     TRACE("(%p) : dwIssueFlags %#x, type D3DQUERY_EVENT\n", This, dwIssueFlags);
468     if (dwIssueFlags & WINED3DISSUE_END)
469     {
470         struct wined3d_event_query *query = This->extendedData;
471         struct wined3d_context *context;
472
473         if (query->context)
474         {
475             if (query->context->tid != GetCurrentThreadId())
476             {
477                 context_free_event_query(query);
478                 context = context_acquire(This->device, NULL, CTXUSAGE_RESOURCELOAD);
479                 context_alloc_event_query(context, query);
480             }
481             else
482             {
483                 context = context_acquire(This->device, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
484             }
485         }
486         else
487         {
488             context = context_acquire(This->device, NULL, CTXUSAGE_RESOURCELOAD);
489             context_alloc_event_query(context, query);
490         }
491
492         ENTER_GL();
493
494         if (context->gl_info->supported[APPLE_FENCE])
495         {
496             GL_EXTCALL(glSetFenceAPPLE(query->id));
497             checkGLcall("glSetFenceAPPLE");
498         }
499         else if (context->gl_info->supported[NV_FENCE])
500         {
501             GL_EXTCALL(glSetFenceNV(query->id, GL_ALL_COMPLETED_NV));
502             checkGLcall("glSetFenceNV");
503         }
504
505         LEAVE_GL();
506
507         context_release(context);
508     }
509     else if(dwIssueFlags & WINED3DISSUE_BEGIN)
510     {
511         /* Started implicitly at device creation */
512         ERR("Event query issued with START flag - what to do?\n");
513     }
514
515     if(dwIssueFlags & WINED3DISSUE_BEGIN) {
516         This->state = QUERY_BUILDING;
517     } else {
518         This->state = QUERY_SIGNALLED;
519     }
520
521     return WINED3D_OK;
522 }
523
524 static HRESULT  WINAPI IWineD3DOcclusionQueryImpl_Issue(IWineD3DQuery* iface,  DWORD dwIssueFlags) {
525     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
526     IWineD3DDeviceImpl *device = This->device;
527     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
528
529     if (gl_info->supported[ARB_OCCLUSION_QUERY])
530     {
531         struct wined3d_occlusion_query *query = This->extendedData;
532         struct wined3d_context *context;
533
534         /* This is allowed according to msdn and our tests. Reset the query and restart */
535         if (dwIssueFlags & WINED3DISSUE_BEGIN)
536         {
537             if (This->state == QUERY_BUILDING)
538             {
539                 if (query->context->tid != GetCurrentThreadId())
540                 {
541                     FIXME("Wrong thread, can't restart query.\n");
542
543                     context_free_occlusion_query(query);
544                     context = context_acquire(This->device, NULL, CTXUSAGE_RESOURCELOAD);
545                     context_alloc_occlusion_query(context, query);
546                 }
547                 else
548                 {
549                     context = context_acquire(This->device, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
550
551                     ENTER_GL();
552                     GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
553                     checkGLcall("glEndQuery()");
554                     LEAVE_GL();
555                 }
556             }
557             else
558             {
559                 if (query->context) context_free_occlusion_query(query);
560                 context = context_acquire(This->device, NULL, CTXUSAGE_RESOURCELOAD);
561                 context_alloc_occlusion_query(context, query);
562             }
563
564             ENTER_GL();
565             GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, query->id));
566             checkGLcall("glBeginQuery()");
567             LEAVE_GL();
568
569             context_release(context);
570         }
571         if (dwIssueFlags & WINED3DISSUE_END) {
572             /* Msdn says _END on a non-building occlusion query returns an error, but
573              * our tests show that it returns OK. But OpenGL doesn't like it, so avoid
574              * generating an error
575              */
576             if (This->state == QUERY_BUILDING)
577             {
578                 if (query->context->tid != GetCurrentThreadId())
579                 {
580                     FIXME("Wrong thread, can't end query.\n");
581                 }
582                 else
583                 {
584                     context = context_acquire(This->device, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
585
586                     ENTER_GL();
587                     GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
588                     checkGLcall("glEndQuery()");
589                     LEAVE_GL();
590
591                     context_release(context);
592                 }
593             }
594         }
595     } else {
596         FIXME("(%p) : Occlusion queries not supported\n", This);
597     }
598
599     if(dwIssueFlags & WINED3DISSUE_BEGIN) {
600         This->state = QUERY_BUILDING;
601     } else {
602         This->state = QUERY_SIGNALLED;
603     }
604     return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL.    */
605 }
606
607 static HRESULT  WINAPI IWineD3DQueryImpl_Issue(IWineD3DQuery* iface,  DWORD dwIssueFlags){
608     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
609
610     TRACE("(%p) : dwIssueFlags %#x, type %#x\n", This, dwIssueFlags, This->type);
611
612     /* The fixme is printed when the app asks for the resulting data */
613     WARN("(%p) : Unhandled query type %#x\n", This, This->type);
614
615     if(dwIssueFlags & WINED3DISSUE_BEGIN) {
616         This->state = QUERY_BUILDING;
617     } else {
618         This->state = QUERY_SIGNALLED;
619     }
620
621     return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL.    */
622 }
623
624
625 /**********************************************************
626  * IWineD3DQuery VTbl follows
627  **********************************************************/
628
629 static const IWineD3DQueryVtbl IWineD3DQuery_Vtbl =
630 {
631     /*** IUnknown methods ***/
632     IWineD3DQueryImpl_QueryInterface,
633     IWineD3DQueryImpl_AddRef,
634     IWineD3DQueryImpl_Release,
635      /*** IWineD3Dquery methods ***/
636     IWineD3DQueryImpl_GetParent,
637     IWineD3DQueryImpl_GetData,
638     IWineD3DQueryImpl_GetDataSize,
639     IWineD3DQueryImpl_GetType,
640     IWineD3DQueryImpl_Issue
641 };
642
643 static const IWineD3DQueryVtbl IWineD3DEventQuery_Vtbl =
644 {
645     /*** IUnknown methods ***/
646     IWineD3DQueryImpl_QueryInterface,
647     IWineD3DQueryImpl_AddRef,
648     IWineD3DQueryImpl_Release,
649     /*** IWineD3Dquery methods ***/
650     IWineD3DQueryImpl_GetParent,
651     IWineD3DEventQueryImpl_GetData,
652     IWineD3DEventQueryImpl_GetDataSize,
653     IWineD3DQueryImpl_GetType,
654     IWineD3DEventQueryImpl_Issue
655 };
656
657 static const IWineD3DQueryVtbl IWineD3DOcclusionQuery_Vtbl =
658 {
659     /*** IUnknown methods ***/
660     IWineD3DQueryImpl_QueryInterface,
661     IWineD3DQueryImpl_AddRef,
662     IWineD3DQueryImpl_Release,
663     /*** IWineD3Dquery methods ***/
664     IWineD3DQueryImpl_GetParent,
665     IWineD3DOcclusionQueryImpl_GetData,
666     IWineD3DOcclusionQueryImpl_GetDataSize,
667     IWineD3DQueryImpl_GetType,
668     IWineD3DOcclusionQueryImpl_Issue
669 };
670
671 HRESULT query_init(IWineD3DQueryImpl *query, IWineD3DDeviceImpl *device,
672         WINED3DQUERYTYPE type, IUnknown *parent)
673 {
674     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
675
676     switch (type)
677     {
678         case WINED3DQUERYTYPE_OCCLUSION:
679             TRACE("Occlusion query.\n");
680             if (!gl_info->supported[ARB_OCCLUSION_QUERY])
681             {
682                 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
683                 return WINED3DERR_NOTAVAILABLE;
684             }
685             query->lpVtbl = &IWineD3DOcclusionQuery_Vtbl;
686             query->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_occlusion_query));
687             if (!query->extendedData)
688             {
689                 ERR("Failed to allocate occlusion query extended data.\n");
690                 return E_OUTOFMEMORY;
691             }
692             ((struct wined3d_occlusion_query *)query->extendedData)->context = NULL;
693             break;
694
695         case WINED3DQUERYTYPE_EVENT:
696             TRACE("Event query.\n");
697             if (!gl_info->supported[NV_FENCE] && !gl_info->supported[APPLE_FENCE])
698             {
699                 /* Half-Life 2 needs this query. It does not render the main
700                  * menu correctly otherwise. Pretend to support it, faking
701                  * this query does not do much harm except potentially
702                  * lowering performance. */
703                 FIXME("Event query: Unimplemented, but pretending to be supported.\n");
704             }
705             query->lpVtbl = &IWineD3DEventQuery_Vtbl;
706             query->extendedData = HeapAlloc(GetProcessHeap(), 0, sizeof(struct wined3d_event_query));
707             if (!query->extendedData)
708             {
709                 ERR("Failed to allocate event query extended data.\n");
710                 return E_OUTOFMEMORY;
711             }
712             ((struct wined3d_event_query *)query->extendedData)->context = NULL;
713             break;
714
715         case WINED3DQUERYTYPE_VCACHE:
716         case WINED3DQUERYTYPE_RESOURCEMANAGER:
717         case WINED3DQUERYTYPE_VERTEXSTATS:
718         case WINED3DQUERYTYPE_TIMESTAMP:
719         case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
720         case WINED3DQUERYTYPE_TIMESTAMPFREQ:
721         case WINED3DQUERYTYPE_PIPELINETIMINGS:
722         case WINED3DQUERYTYPE_INTERFACETIMINGS:
723         case WINED3DQUERYTYPE_VERTEXTIMINGS:
724         case WINED3DQUERYTYPE_PIXELTIMINGS:
725         case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
726         case WINED3DQUERYTYPE_CACHEUTILIZATION:
727         default:
728             /* Use the base query vtable until we have a special one for each query. */
729             query->lpVtbl = &IWineD3DQuery_Vtbl;
730             FIXME("Unhandled query type %#x.\n", type);
731             return WINED3DERR_NOTAVAILABLE;
732     }
733
734     query->type = type;
735     query->state = QUERY_CREATED;
736     query->device = device;
737     query->parent = parent;
738     query->ref = 1;
739
740     return WINED3D_OK;
741 }