wined3d: Don't delete queries from the wrong context.
[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  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22
23 #include "config.h"
24 #include "wined3d_private.h"
25
26 /*
27  * Occlusion Queries:
28  * http://www.gris.uni-tuebingen.de/~bartz/Publications/paper/hww98.pdf
29  * http://oss.sgi.com/projects/ogl-sample/registry/ARB/occlusion_query.txt
30  */
31
32 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
33 #define GLINFO_LOCATION This->wineD3DDevice->adapter->gl_info
34
35 /* *******************************************
36    IWineD3DQuery IUnknown parts follow
37    ******************************************* */
38 static HRESULT  WINAPI IWineD3DQueryImpl_QueryInterface(IWineD3DQuery *iface, REFIID riid, LPVOID *ppobj)
39 {
40     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
41     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
42     if (IsEqualGUID(riid, &IID_IUnknown)
43         || IsEqualGUID(riid, &IID_IWineD3DBase)
44         || IsEqualGUID(riid, &IID_IWineD3DQuery)) {
45         IUnknown_AddRef(iface);
46         *ppobj = This;
47         return S_OK;
48     }
49     *ppobj = NULL;
50     return E_NOINTERFACE;
51 }
52
53 static ULONG  WINAPI IWineD3DQueryImpl_AddRef(IWineD3DQuery *iface) {
54     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
55     TRACE("(%p) : AddRef increasing from %d\n", This, This->ref);
56     return InterlockedIncrement(&This->ref);
57 }
58
59 static ULONG  WINAPI IWineD3DQueryImpl_Release(IWineD3DQuery *iface) {
60     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
61     ULONG ref;
62     TRACE("(%p) : Releasing from %d\n", This, This->ref);
63     ref = InterlockedDecrement(&This->ref);
64     if (ref == 0) {
65         ENTER_GL();
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             if (((WineQueryEventData *)This->extendedData)->ctx != This->wineD3DDevice->activeContext
72                     || This->wineD3DDevice->activeContext->tid != GetCurrentThreadId())
73             {
74                 FIXME("Query was created in a different context, skipping deletion\n");
75             }
76             else if(GL_SUPPORT(APPLE_FENCE))
77             {
78                 GL_EXTCALL(glDeleteFencesAPPLE(1, &((WineQueryEventData *)(This->extendedData))->fenceId));
79                 checkGLcall("glDeleteFencesAPPLE");
80             } else if(GL_SUPPORT(NV_FENCE)) {
81                 GL_EXTCALL(glDeleteFencesNV(1, &((WineQueryEventData *)(This->extendedData))->fenceId));
82                 checkGLcall("glDeleteFencesNV");
83             }
84         } else if(This->type == WINED3DQUERYTYPE_OCCLUSION && GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
85             if (((WineQueryOcclusionData *)This->extendedData)->ctx != This->wineD3DDevice->activeContext
86                     || This->wineD3DDevice->activeContext->tid != GetCurrentThreadId())
87             {
88                 FIXME("Query was created in a different context, skipping deletion\n");
89             }
90             else
91             {
92                 GL_EXTCALL(glDeleteQueriesARB(1, &((WineQueryOcclusionData *)(This->extendedData))->queryId));
93                 checkGLcall("glDeleteQueriesARB");
94             }
95         }
96         LEAVE_GL();
97
98         HeapFree(GetProcessHeap(), 0, This->extendedData);
99         HeapFree(GetProcessHeap(), 0, This);
100     }
101     return ref;
102 }
103
104 /* *******************************************
105    IWineD3DQuery IWineD3DQuery parts follow
106    ******************************************* */
107 static HRESULT  WINAPI IWineD3DQueryImpl_GetParent(IWineD3DQuery *iface, IUnknown** parent){
108     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
109
110     *parent= (IUnknown*) parent;
111     IUnknown_AddRef(*parent);
112     TRACE("(%p) : returning %p\n", This, *parent);
113     return WINED3D_OK;
114 }
115
116 static HRESULT  WINAPI IWineD3DQueryImpl_GetDevice(IWineD3DQuery* iface, IWineD3DDevice **pDevice){
117     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
118     IWineD3DDevice_AddRef((IWineD3DDevice *)This->wineD3DDevice);
119     *pDevice = (IWineD3DDevice *)This->wineD3DDevice;
120     TRACE("(%p) returning %p\n", This, *pDevice);
121     return WINED3D_OK;
122 }
123
124
125 static HRESULT  WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags){
126     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
127     HRESULT res = S_OK;
128
129     TRACE("(%p) : type %#x, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, This->type, pData, dwSize, dwGetDataFlags);
130
131     switch (This->type){
132
133     case WINED3DQUERYTYPE_VCACHE:
134     {
135
136         WINED3DDEVINFO_VCACHE *data = (WINED3DDEVINFO_VCACHE *)pData;
137         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VCACHE\n", This);
138         if(pData == NULL || dwSize == 0) break;
139         data->Pattern     = WINEMAKEFOURCC('C','A','C','H');
140         data->OptMethod   = 0; /*0 get longest strips, 1 optimize vertex cache*/
141         data->CacheSize   = 0; /*cache size, only required if OptMethod == 1*/
142         data->MagicNumber = 0; /*only required if OptMethod == 1 (used internally)*/
143
144     }
145     break;
146     case WINED3DQUERYTYPE_RESOURCEMANAGER:
147     {
148         WINED3DDEVINFO_RESOURCEMANAGER *data = (WINED3DDEVINFO_RESOURCEMANAGER *)pData;
149         int i;
150         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_RESOURCEMANAGER\n", This);
151         if(pData == NULL || dwSize == 0) break;
152         for(i = 0; i < WINED3DRTYPECOUNT; i++){
153             /*I'm setting the default values to 1 so as to reduce the risk of a div/0 in the caller*/
154             /*  isTextureResident could be used to get some of this information  */
155             data->stats[i].bThrashing            = FALSE;
156             data->stats[i].ApproxBytesDownloaded = 1;
157             data->stats[i].NumEvicts             = 1;
158             data->stats[i].NumVidCreates         = 1;
159             data->stats[i].LastPri               = 1;
160             data->stats[i].NumUsed               = 1;
161             data->stats[i].NumUsedInVidMem       = 1;
162             data->stats[i].WorkingSet            = 1;
163             data->stats[i].WorkingSetBytes       = 1;
164             data->stats[i].TotalManaged          = 1;
165             data->stats[i].TotalBytes            = 1;
166         }
167
168     }
169     break;
170     case WINED3DQUERYTYPE_VERTEXSTATS:
171     {
172         WINED3DDEVINFO_VERTEXSTATS *data = (WINED3DDEVINFO_VERTEXSTATS *)pData;
173         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXSTATS\n", This);
174         if(pData == NULL || dwSize == 0) break;
175         data->NumRenderedTriangles      = 1;
176         data->NumExtraClippingTriangles = 1;
177
178     }
179     break;
180     case WINED3DQUERYTYPE_TIMESTAMP:
181     {
182         UINT64* data = pData;
183         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMP\n", This);
184         if(pData == NULL || dwSize == 0) break;
185         *data = 1; /*Don't know what this is supposed to be*/
186     }
187     break;
188     case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
189     {
190         BOOL* data = pData;
191         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPDISJOINT\n", This);
192         if(pData == NULL || dwSize == 0) break;
193         *data = FALSE; /*Don't know what this is supposed to be*/
194     }
195     break;
196     case WINED3DQUERYTYPE_TIMESTAMPFREQ:
197     {
198         UINT64* data = pData;
199         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPFREQ\n", This);
200         if(pData == NULL || dwSize == 0) break;
201         *data = 1; /*Don't know what this is supposed to be*/
202     }
203     break;
204     case WINED3DQUERYTYPE_PIPELINETIMINGS:
205     {
206         WINED3DDEVINFO_PIPELINETIMINGS *data = (WINED3DDEVINFO_PIPELINETIMINGS *)pData;
207         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIPELINETIMINGS\n", This);
208         if(pData == NULL || dwSize == 0) break;
209
210         data->VertexProcessingTimePercent    =   1.0f;
211         data->PixelProcessingTimePercent     =   1.0f;
212         data->OtherGPUProcessingTimePercent  =  97.0f;
213         data->GPUIdleTimePercent             =   1.0f;
214     }
215     break;
216     case WINED3DQUERYTYPE_INTERFACETIMINGS:
217     {
218         WINED3DDEVINFO_INTERFACETIMINGS *data = (WINED3DDEVINFO_INTERFACETIMINGS *)pData;
219         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_INTERFACETIMINGS\n", This);
220
221         if(pData == NULL || dwSize == 0) break;
222         data->WaitingForGPUToUseApplicationResourceTimePercent =   1.0f;
223         data->WaitingForGPUToAcceptMoreCommandsTimePercent     =   1.0f;
224         data->WaitingForGPUToStayWithinLatencyTimePercent      =   1.0f;
225         data->WaitingForGPUExclusiveResourceTimePercent        =   1.0f;
226         data->WaitingForGPUOtherTimePercent                    =  96.0f;
227     }
228
229     break;
230     case WINED3DQUERYTYPE_VERTEXTIMINGS:
231     {
232         WINED3DDEVINFO_STAGETIMINGS *data = (WINED3DDEVINFO_STAGETIMINGS *)pData;
233         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXTIMINGS\n", This);
234
235         if(pData == NULL || dwSize == 0) break;
236         data->MemoryProcessingPercent      = 50.0f;
237         data->ComputationProcessingPercent = 50.0f;
238
239     }
240     break;
241     case WINED3DQUERYTYPE_PIXELTIMINGS:
242     {
243         WINED3DDEVINFO_STAGETIMINGS *data = (WINED3DDEVINFO_STAGETIMINGS *)pData;
244         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIXELTIMINGS\n", This);
245
246         if(pData == NULL || dwSize == 0) break;
247         data->MemoryProcessingPercent      = 50.0f;
248         data->ComputationProcessingPercent = 50.0f;
249     }
250     break;
251     case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
252     {
253         WINED3DDEVINFO_BANDWIDTHTIMINGS *data = (WINED3DDEVINFO_BANDWIDTHTIMINGS *)pData;
254         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_BANDWIDTHTIMINGS\n", This);
255
256         if(pData == NULL || dwSize == 0) break;
257         data->MaxBandwidthUtilized                =  1.0f;
258         data->FrontEndUploadMemoryUtilizedPercent =  1.0f;
259         data->VertexRateUtilizedPercent           =  1.0f;
260         data->TriangleSetupRateUtilizedPercent    =  1.0f;
261         data->FillRateUtilizedPercent             = 97.0f;
262     }
263     break;
264     case WINED3DQUERYTYPE_CACHEUTILIZATION:
265     {
266         WINED3DDEVINFO_CACHEUTILIZATION *data = (WINED3DDEVINFO_CACHEUTILIZATION *)pData;
267         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_CACHEUTILIZATION\n", This);
268
269         if(pData == NULL || dwSize == 0) break;
270         data->TextureCacheHitRate             = 1.0f;
271         data->PostTransformVertexCacheHitRate = 1.0f;
272     }
273
274
275     break;
276     default:
277         FIXME("(%p) Unhandled query type %d\n",This , This->type);
278
279     };
280
281     /*dwGetDataFlags = 0 || D3DGETDATA_FLUSH
282     D3DGETDATA_FLUSH may return WINED3DERR_DEVICELOST if the device is lost
283     */
284     return res; /* S_OK if the query data is available*/
285 }
286
287 static HRESULT  WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
288     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *) iface;
289     GLuint queryId = ((WineQueryOcclusionData *)This->extendedData)->queryId;
290     DWORD* data = pData;
291     GLuint available;
292     GLuint samples;
293     HRESULT res;
294
295     TRACE("(%p) : type D3DQUERY_OCCLUSION, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, pData, dwSize, dwGetDataFlags);
296
297     if (This->state == QUERY_CREATED)
298     {
299         /* D3D allows GetData on a new query, OpenGL doesn't. So just invent the data ourselves */
300         TRACE("Query wasn't yet started, returning S_OK\n");
301         if(data) *data = 0;
302         return S_OK;
303     }
304
305     if (This->state == QUERY_BUILDING)
306     {
307         /* Msdn says this returns an error, but our tests show that S_FALSE is returned */
308         TRACE("Query is building, returning S_FALSE\n");
309         return S_FALSE;
310     }
311
312     if (!GL_SUPPORT(ARB_OCCLUSION_QUERY))
313     {
314         WARN("(%p) : Occlusion queries not supported. Returning 1.\n", This);
315         *data = 1;
316         return S_OK;
317     }
318
319     if (((WineQueryOcclusionData *)This->extendedData)->ctx != This->wineD3DDevice->activeContext
320             || This->wineD3DDevice->activeContext->tid != GetCurrentThreadId())
321     {
322         FIXME("%p Wrong context, returning 1.\n", This);
323         *data = 1;
324         return S_OK;
325     }
326
327     ENTER_GL();
328
329     GL_EXTCALL(glGetQueryObjectuivARB(queryId, GL_QUERY_RESULT_AVAILABLE_ARB, &available));
330     checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)\n");
331     TRACE("(%p) : available %d.\n", This, available);
332
333     if (available)
334     {
335         if (data)
336         {
337             GL_EXTCALL(glGetQueryObjectuivARB(queryId, GL_QUERY_RESULT_ARB, &samples));
338             checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)\n");
339             TRACE("(%p) : Returning %d samples.\n", This, samples);
340             *data = samples;
341         }
342         res = S_OK;
343     }
344     else
345     {
346         res = S_FALSE;
347     }
348
349     LEAVE_GL();
350
351     return res;
352 }
353
354 static HRESULT  WINAPI IWineD3DEventQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
355     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *) iface;
356     BOOL* data = pData;
357     WineD3DContext *ctx;
358     TRACE("(%p) : type D3DQUERY_EVENT, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, pData, dwSize, dwGetDataFlags);
359
360     ctx = ((WineQueryEventData *)This->extendedData)->ctx;
361     if(pData == NULL || dwSize == 0) {
362         return S_OK;
363     } if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) {
364         /* See comment in IWineD3DQuery::Issue, event query codeblock */
365         FIXME("Query context not active, reporting GPU idle\n");
366         *data = TRUE;
367     } else if(GL_SUPPORT(APPLE_FENCE)) {
368         ENTER_GL();
369         *data = GL_EXTCALL(glTestFenceAPPLE(((WineQueryEventData *)This->extendedData)->fenceId));
370         checkGLcall("glTestFenceAPPLE");
371         LEAVE_GL();
372     } else if(GL_SUPPORT(NV_FENCE)) {
373         ENTER_GL();
374         *data = GL_EXTCALL(glTestFenceNV(((WineQueryEventData *)This->extendedData)->fenceId));
375         checkGLcall("glTestFenceNV");
376         LEAVE_GL();
377     } else {
378         WARN("(%p): reporting GPU idle\n", This);
379         *data = TRUE;
380     }
381
382     return S_OK;
383 }
384
385 static DWORD  WINAPI IWineD3DQueryImpl_GetDataSize(IWineD3DQuery* iface){
386     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
387     int dataSize = 0;
388     TRACE("(%p) : type %#x\n", This, This->type);
389     switch(This->type){
390     case WINED3DQUERYTYPE_VCACHE:
391         dataSize = sizeof(WINED3DDEVINFO_VCACHE);
392         break;
393     case WINED3DQUERYTYPE_RESOURCEMANAGER:
394         dataSize = sizeof(WINED3DDEVINFO_RESOURCEMANAGER);
395         break;
396     case WINED3DQUERYTYPE_VERTEXSTATS:
397         dataSize = sizeof(WINED3DDEVINFO_VERTEXSTATS);
398         break;
399     case WINED3DQUERYTYPE_EVENT:
400         dataSize = sizeof(BOOL);
401         break;
402     case WINED3DQUERYTYPE_TIMESTAMP:
403         dataSize = sizeof(UINT64);
404         break;
405     case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
406         dataSize = sizeof(BOOL);
407         break;
408     case WINED3DQUERYTYPE_TIMESTAMPFREQ:
409         dataSize = sizeof(UINT64);
410         break;
411     case WINED3DQUERYTYPE_PIPELINETIMINGS:
412         dataSize = sizeof(WINED3DDEVINFO_PIPELINETIMINGS);
413         break;
414     case WINED3DQUERYTYPE_INTERFACETIMINGS:
415         dataSize = sizeof(WINED3DDEVINFO_INTERFACETIMINGS);
416         break;
417     case WINED3DQUERYTYPE_VERTEXTIMINGS:
418         dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS);
419         break;
420     case WINED3DQUERYTYPE_PIXELTIMINGS:
421         dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS);
422         break;
423     case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
424         dataSize = sizeof(WINED3DQUERYTYPE_BANDWIDTHTIMINGS);
425         break;
426     case WINED3DQUERYTYPE_CACHEUTILIZATION:
427         dataSize = sizeof(WINED3DDEVINFO_CACHEUTILIZATION);
428         break;
429     default:
430        FIXME("(%p) Unhandled query type %d\n",This , This->type);
431        dataSize = 0;
432     }
433     return dataSize;
434 }
435
436 static DWORD  WINAPI IWineD3DEventQueryImpl_GetDataSize(IWineD3DQuery* iface){
437     TRACE("(%p) : type D3DQUERY_EVENT\n", iface);
438
439     return sizeof(BOOL);
440 }
441
442 static DWORD  WINAPI IWineD3DOcclusionQueryImpl_GetDataSize(IWineD3DQuery* iface){
443     TRACE("(%p) : type D3DQUERY_OCCLUSION\n", iface);
444
445     return sizeof(DWORD);
446 }
447
448 static WINED3DQUERYTYPE  WINAPI IWineD3DQueryImpl_GetType(IWineD3DQuery* iface){
449     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
450     return This->type;
451 }
452
453
454 static HRESULT  WINAPI IWineD3DEventQueryImpl_Issue(IWineD3DQuery* iface,  DWORD dwIssueFlags) {
455     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
456
457     TRACE("(%p) : dwIssueFlags %#x, type D3DQUERY_EVENT\n", This, dwIssueFlags);
458     if (dwIssueFlags & WINED3DISSUE_END) {
459         WineD3DContext *ctx = ((WineQueryEventData *)This->extendedData)->ctx;
460         if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) {
461             /* GL fences can be used only from the context that created them,
462              * so if a different context is active, don't bother setting the query. The penalty
463              * of a context switch is most likely higher than the gain of a correct query result
464              *
465              * If the query is used from a different thread, don't bother creating a multithread
466              * context - there's no point in doing that as the query would be unusable anyway
467              */
468             WARN("Query context not active\n");
469         } else if(GL_SUPPORT(APPLE_FENCE)) {
470             ENTER_GL();
471             GL_EXTCALL(glSetFenceAPPLE(((WineQueryEventData *)This->extendedData)->fenceId));
472             checkGLcall("glSetFenceAPPLE");
473             LEAVE_GL();
474         } else if (GL_SUPPORT(NV_FENCE)) {
475             ENTER_GL();
476             GL_EXTCALL(glSetFenceNV(((WineQueryEventData *)This->extendedData)->fenceId, GL_ALL_COMPLETED_NV));
477             checkGLcall("glSetFenceNV");
478             LEAVE_GL();
479         }
480     } else if(dwIssueFlags & WINED3DISSUE_BEGIN) {
481         /* Started implicitly at device creation */
482         ERR("Event query issued with START flag - what to do?\n");
483     }
484
485     if(dwIssueFlags & WINED3DISSUE_BEGIN) {
486         This->state = QUERY_BUILDING;
487     } else {
488         This->state = QUERY_SIGNALLED;
489     }
490
491     return WINED3D_OK;
492 }
493
494 static HRESULT  WINAPI IWineD3DOcclusionQueryImpl_Issue(IWineD3DQuery* iface,  DWORD dwIssueFlags) {
495     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
496
497     if (GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
498         WineD3DContext *ctx = ((WineQueryOcclusionData *)This->extendedData)->ctx;
499
500         if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) {
501             FIXME("Not the owning context, can't start query\n");
502         } else {
503             ENTER_GL();
504             /* This is allowed according to msdn and our tests. Reset the query and restart */
505             if (dwIssueFlags & WINED3DISSUE_BEGIN) {
506                 if(This->state == QUERY_BUILDING) {
507                     GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
508                     checkGLcall("glEndQuery()");
509                 }
510
511                 GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, ((WineQueryOcclusionData *)This->extendedData)->queryId));
512                 checkGLcall("glBeginQuery()");
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                     GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
521                     checkGLcall("glEndQuery()");
522                 }
523             }
524             LEAVE_GL();
525         }
526     } else {
527         FIXME("(%p) : Occlusion queries not supported\n", This);
528     }
529
530     if(dwIssueFlags & WINED3DISSUE_BEGIN) {
531         This->state = QUERY_BUILDING;
532     } else {
533         This->state = QUERY_SIGNALLED;
534     }
535     return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL.    */
536 }
537
538 static HRESULT  WINAPI IWineD3DQueryImpl_Issue(IWineD3DQuery* iface,  DWORD dwIssueFlags){
539     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
540
541     TRACE("(%p) : dwIssueFlags %#x, type %#x\n", This, dwIssueFlags, This->type);
542
543     /* The fixme is printed when the app asks for the resulting data */
544     WARN("(%p) : Unhandled query type %#x\n", This, This->type);
545
546     if(dwIssueFlags & WINED3DISSUE_BEGIN) {
547         This->state = QUERY_BUILDING;
548     } else {
549         This->state = QUERY_SIGNALLED;
550     }
551
552     return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL.    */
553 }
554
555
556 /**********************************************************
557  * IWineD3DQuery VTbl follows
558  **********************************************************/
559
560 const IWineD3DQueryVtbl IWineD3DQuery_Vtbl =
561 {
562     /*** IUnknown methods ***/
563     IWineD3DQueryImpl_QueryInterface,
564     IWineD3DQueryImpl_AddRef,
565     IWineD3DQueryImpl_Release,
566      /*** IWineD3Dquery methods ***/
567     IWineD3DQueryImpl_GetParent,
568     IWineD3DQueryImpl_GetDevice,
569     IWineD3DQueryImpl_GetData,
570     IWineD3DQueryImpl_GetDataSize,
571     IWineD3DQueryImpl_GetType,
572     IWineD3DQueryImpl_Issue
573 };
574
575 const IWineD3DQueryVtbl IWineD3DEventQuery_Vtbl =
576 {
577     /*** IUnknown methods ***/
578     IWineD3DQueryImpl_QueryInterface,
579     IWineD3DQueryImpl_AddRef,
580     IWineD3DQueryImpl_Release,
581     /*** IWineD3Dquery methods ***/
582     IWineD3DQueryImpl_GetParent,
583     IWineD3DQueryImpl_GetDevice,
584     IWineD3DEventQueryImpl_GetData,
585     IWineD3DEventQueryImpl_GetDataSize,
586     IWineD3DQueryImpl_GetType,
587     IWineD3DEventQueryImpl_Issue
588 };
589
590 const IWineD3DQueryVtbl IWineD3DOcclusionQuery_Vtbl =
591 {
592     /*** IUnknown methods ***/
593     IWineD3DQueryImpl_QueryInterface,
594     IWineD3DQueryImpl_AddRef,
595     IWineD3DQueryImpl_Release,
596     /*** IWineD3Dquery methods ***/
597     IWineD3DQueryImpl_GetParent,
598     IWineD3DQueryImpl_GetDevice,
599     IWineD3DOcclusionQueryImpl_GetData,
600     IWineD3DOcclusionQueryImpl_GetDataSize,
601     IWineD3DQueryImpl_GetType,
602     IWineD3DOcclusionQueryImpl_Issue
603 };