wined3d: Manage occlusion queries in the 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         /* Queries are specific to the GL context that created them. Not
66          * deleting the query will obviously leak it, but that's still better
67          * than potentially deleting a different query with the same id in this
68          * context, and (still) leaking the actual query. */
69         if (This->type == WINED3DQUERYTYPE_EVENT)
70         {
71             WineQueryEventData *query_data = (WineQueryEventData *)This->extendedData;
72
73             if (query_data->ctx->tid != GetCurrentThreadId())
74             {
75                 FIXME("Query was created in a different thread, skipping deletion.\n");
76             }
77             else
78             {
79                 ActivateContext(This->wineD3DDevice, query_data->ctx->surface, CTXUSAGE_RESOURCELOAD);
80
81                 ENTER_GL();
82
83                 if (GL_SUPPORT(APPLE_FENCE))
84                 {
85                     GL_EXTCALL(glDeleteFencesAPPLE(1, &query_data->fenceId));
86                     checkGLcall("glDeleteFencesAPPLE");
87                 }
88                 else if (GL_SUPPORT(NV_FENCE))
89                 {
90                     GL_EXTCALL(glDeleteFencesNV(1, &query_data->fenceId));
91                     checkGLcall("glDeleteFencesNV");
92                 }
93
94                 LEAVE_GL();
95             }
96         }
97         else if (This->type == WINED3DQUERYTYPE_OCCLUSION)
98         {
99             struct wined3d_occlusion_query *query = This->extendedData;
100
101             if (query->context) context_free_occlusion_query(query);
102         }
103
104         HeapFree(GetProcessHeap(), 0, This->extendedData);
105         HeapFree(GetProcessHeap(), 0, This);
106     }
107     return ref;
108 }
109
110 /* *******************************************
111    IWineD3DQuery IWineD3DQuery parts follow
112    ******************************************* */
113 static HRESULT  WINAPI IWineD3DQueryImpl_GetParent(IWineD3DQuery *iface, IUnknown** parent){
114     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
115
116     *parent= (IUnknown*) parent;
117     IUnknown_AddRef(*parent);
118     TRACE("(%p) : returning %p\n", This, *parent);
119     return WINED3D_OK;
120 }
121
122 static HRESULT  WINAPI IWineD3DQueryImpl_GetDevice(IWineD3DQuery* iface, IWineD3DDevice **pDevice){
123     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
124     IWineD3DDevice_AddRef((IWineD3DDevice *)This->wineD3DDevice);
125     *pDevice = (IWineD3DDevice *)This->wineD3DDevice;
126     TRACE("(%p) returning %p\n", This, *pDevice);
127     return WINED3D_OK;
128 }
129
130
131 static HRESULT  WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags){
132     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
133     HRESULT res = S_OK;
134
135     TRACE("(%p) : type %#x, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, This->type, pData, dwSize, dwGetDataFlags);
136
137     switch (This->type){
138
139     case WINED3DQUERYTYPE_VCACHE:
140     {
141
142         WINED3DDEVINFO_VCACHE *data = pData;
143         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VCACHE\n", This);
144         if(pData == NULL || dwSize == 0) break;
145         data->Pattern     = WINEMAKEFOURCC('C','A','C','H');
146         data->OptMethod   = 0; /*0 get longest strips, 1 optimize vertex cache*/
147         data->CacheSize   = 0; /*cache size, only required if OptMethod == 1*/
148         data->MagicNumber = 0; /*only required if OptMethod == 1 (used internally)*/
149
150     }
151     break;
152     case WINED3DQUERYTYPE_RESOURCEMANAGER:
153     {
154         WINED3DDEVINFO_RESOURCEMANAGER *data = pData;
155         int i;
156         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_RESOURCEMANAGER\n", This);
157         if(pData == NULL || dwSize == 0) break;
158         for(i = 0; i < WINED3DRTYPECOUNT; i++){
159             /*I'm setting the default values to 1 so as to reduce the risk of a div/0 in the caller*/
160             /*  isTextureResident could be used to get some of this information  */
161             data->stats[i].bThrashing            = FALSE;
162             data->stats[i].ApproxBytesDownloaded = 1;
163             data->stats[i].NumEvicts             = 1;
164             data->stats[i].NumVidCreates         = 1;
165             data->stats[i].LastPri               = 1;
166             data->stats[i].NumUsed               = 1;
167             data->stats[i].NumUsedInVidMem       = 1;
168             data->stats[i].WorkingSet            = 1;
169             data->stats[i].WorkingSetBytes       = 1;
170             data->stats[i].TotalManaged          = 1;
171             data->stats[i].TotalBytes            = 1;
172         }
173
174     }
175     break;
176     case WINED3DQUERYTYPE_VERTEXSTATS:
177     {
178         WINED3DDEVINFO_VERTEXSTATS *data = pData;
179         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXSTATS\n", This);
180         if(pData == NULL || dwSize == 0) break;
181         data->NumRenderedTriangles      = 1;
182         data->NumExtraClippingTriangles = 1;
183
184     }
185     break;
186     case WINED3DQUERYTYPE_TIMESTAMP:
187     {
188         UINT64* data = pData;
189         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMP\n", This);
190         if(pData == NULL || dwSize == 0) break;
191         *data = 1; /*Don't know what this is supposed to be*/
192     }
193     break;
194     case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
195     {
196         BOOL* data = pData;
197         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPDISJOINT\n", This);
198         if(pData == NULL || dwSize == 0) break;
199         *data = FALSE; /*Don't know what this is supposed to be*/
200     }
201     break;
202     case WINED3DQUERYTYPE_TIMESTAMPFREQ:
203     {
204         UINT64* data = pData;
205         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPFREQ\n", This);
206         if(pData == NULL || dwSize == 0) break;
207         *data = 1; /*Don't know what this is supposed to be*/
208     }
209     break;
210     case WINED3DQUERYTYPE_PIPELINETIMINGS:
211     {
212         WINED3DDEVINFO_PIPELINETIMINGS *data = pData;
213         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIPELINETIMINGS\n", This);
214         if(pData == NULL || dwSize == 0) break;
215
216         data->VertexProcessingTimePercent    =   1.0f;
217         data->PixelProcessingTimePercent     =   1.0f;
218         data->OtherGPUProcessingTimePercent  =  97.0f;
219         data->GPUIdleTimePercent             =   1.0f;
220     }
221     break;
222     case WINED3DQUERYTYPE_INTERFACETIMINGS:
223     {
224         WINED3DDEVINFO_INTERFACETIMINGS *data = pData;
225         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_INTERFACETIMINGS\n", This);
226
227         if(pData == NULL || dwSize == 0) break;
228         data->WaitingForGPUToUseApplicationResourceTimePercent =   1.0f;
229         data->WaitingForGPUToAcceptMoreCommandsTimePercent     =   1.0f;
230         data->WaitingForGPUToStayWithinLatencyTimePercent      =   1.0f;
231         data->WaitingForGPUExclusiveResourceTimePercent        =   1.0f;
232         data->WaitingForGPUOtherTimePercent                    =  96.0f;
233     }
234
235     break;
236     case WINED3DQUERYTYPE_VERTEXTIMINGS:
237     {
238         WINED3DDEVINFO_STAGETIMINGS *data = pData;
239         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXTIMINGS\n", This);
240
241         if(pData == NULL || dwSize == 0) break;
242         data->MemoryProcessingPercent      = 50.0f;
243         data->ComputationProcessingPercent = 50.0f;
244
245     }
246     break;
247     case WINED3DQUERYTYPE_PIXELTIMINGS:
248     {
249         WINED3DDEVINFO_STAGETIMINGS *data = pData;
250         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIXELTIMINGS\n", This);
251
252         if(pData == NULL || dwSize == 0) break;
253         data->MemoryProcessingPercent      = 50.0f;
254         data->ComputationProcessingPercent = 50.0f;
255     }
256     break;
257     case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
258     {
259         WINED3DDEVINFO_BANDWIDTHTIMINGS *data = pData;
260         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_BANDWIDTHTIMINGS\n", This);
261
262         if(pData == NULL || dwSize == 0) break;
263         data->MaxBandwidthUtilized                =  1.0f;
264         data->FrontEndUploadMemoryUtilizedPercent =  1.0f;
265         data->VertexRateUtilizedPercent           =  1.0f;
266         data->TriangleSetupRateUtilizedPercent    =  1.0f;
267         data->FillRateUtilizedPercent             = 97.0f;
268     }
269     break;
270     case WINED3DQUERYTYPE_CACHEUTILIZATION:
271     {
272         WINED3DDEVINFO_CACHEUTILIZATION *data = pData;
273         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_CACHEUTILIZATION\n", This);
274
275         if(pData == NULL || dwSize == 0) break;
276         data->TextureCacheHitRate             = 1.0f;
277         data->PostTransformVertexCacheHitRate = 1.0f;
278     }
279
280
281     break;
282     default:
283         FIXME("(%p) Unhandled query type %d\n",This , This->type);
284
285     };
286
287     /*dwGetDataFlags = 0 || D3DGETDATA_FLUSH
288     D3DGETDATA_FLUSH may return WINED3DERR_DEVICELOST if the device is lost
289     */
290     return res; /* S_OK if the query data is available*/
291 }
292
293 static HRESULT  WINAPI IWineD3DOcclusionQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
294     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *) iface;
295     struct wined3d_occlusion_query *query = This->extendedData;
296     DWORD* data = pData;
297     GLuint available;
298     GLuint samples;
299     HRESULT res;
300
301     TRACE("(%p) : type D3DQUERY_OCCLUSION, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, pData, dwSize, dwGetDataFlags);
302
303     if (!query->context) This->state = QUERY_CREATED;
304
305     if (This->state == QUERY_CREATED)
306     {
307         /* D3D allows GetData on a new query, OpenGL doesn't. So just invent the data ourselves */
308         TRACE("Query wasn't yet started, returning S_OK\n");
309         if(data) *data = 0;
310         return S_OK;
311     }
312
313     if (This->state == QUERY_BUILDING)
314     {
315         /* Msdn says this returns an error, but our tests show that S_FALSE is returned */
316         TRACE("Query is building, returning S_FALSE\n");
317         return S_FALSE;
318     }
319
320     if (!GL_SUPPORT(ARB_OCCLUSION_QUERY))
321     {
322         WARN("(%p) : Occlusion queries not supported. Returning 1.\n", This);
323         *data = 1;
324         return S_OK;
325     }
326
327     if (query->context->tid != GetCurrentThreadId())
328     {
329         FIXME("%p Wrong thread, returning 1.\n", This);
330         *data = 1;
331         return S_OK;
332     }
333
334     ActivateContext(This->wineD3DDevice, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
335
336     ENTER_GL();
337
338     GL_EXTCALL(glGetQueryObjectuivARB(query->id, GL_QUERY_RESULT_AVAILABLE_ARB, &available));
339     checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)");
340     TRACE("(%p) : available %d.\n", This, available);
341
342     if (available)
343     {
344         if (data)
345         {
346             GL_EXTCALL(glGetQueryObjectuivARB(query->id, GL_QUERY_RESULT_ARB, &samples));
347             checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)");
348             TRACE("(%p) : Returning %d samples.\n", This, samples);
349             *data = samples;
350         }
351         res = S_OK;
352     }
353     else
354     {
355         res = S_FALSE;
356     }
357
358     LEAVE_GL();
359
360     return res;
361 }
362
363 static HRESULT  WINAPI IWineD3DEventQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
364     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *) iface;
365     BOOL* data = pData;
366     WineQueryEventData *query_data = (WineQueryEventData *)This->extendedData;
367
368     TRACE("(%p) : type D3DQUERY_EVENT, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, pData, dwSize, dwGetDataFlags);
369
370     if (!pData || !dwSize) return S_OK;
371
372     if (query_data->ctx->tid != GetCurrentThreadId())
373     {
374         /* See comment in IWineD3DQuery::Issue, event query codeblock */
375         FIXME("Wrong thread, reporting GPU idle.\n");
376         *data = TRUE;
377
378         return S_OK;
379     }
380
381     ActivateContext(This->wineD3DDevice, query_data->ctx->surface, CTXUSAGE_RESOURCELOAD);
382
383     ENTER_GL();
384
385     if (GL_SUPPORT(APPLE_FENCE))
386     {
387         *data = GL_EXTCALL(glTestFenceAPPLE(query_data->fenceId));
388         checkGLcall("glTestFenceAPPLE");
389     }
390     else if (GL_SUPPORT(NV_FENCE))
391     {
392         *data = GL_EXTCALL(glTestFenceNV(query_data->fenceId));
393         checkGLcall("glTestFenceNV");
394     }
395     else
396     {
397         WARN("(%p): reporting GPU idle\n", This);
398         *data = TRUE;
399     }
400
401     LEAVE_GL();
402
403     return S_OK;
404 }
405
406 static DWORD  WINAPI IWineD3DQueryImpl_GetDataSize(IWineD3DQuery* iface){
407     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
408     int dataSize = 0;
409     TRACE("(%p) : type %#x\n", This, This->type);
410     switch(This->type){
411     case WINED3DQUERYTYPE_VCACHE:
412         dataSize = sizeof(WINED3DDEVINFO_VCACHE);
413         break;
414     case WINED3DQUERYTYPE_RESOURCEMANAGER:
415         dataSize = sizeof(WINED3DDEVINFO_RESOURCEMANAGER);
416         break;
417     case WINED3DQUERYTYPE_VERTEXSTATS:
418         dataSize = sizeof(WINED3DDEVINFO_VERTEXSTATS);
419         break;
420     case WINED3DQUERYTYPE_EVENT:
421         dataSize = sizeof(BOOL);
422         break;
423     case WINED3DQUERYTYPE_TIMESTAMP:
424         dataSize = sizeof(UINT64);
425         break;
426     case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
427         dataSize = sizeof(BOOL);
428         break;
429     case WINED3DQUERYTYPE_TIMESTAMPFREQ:
430         dataSize = sizeof(UINT64);
431         break;
432     case WINED3DQUERYTYPE_PIPELINETIMINGS:
433         dataSize = sizeof(WINED3DDEVINFO_PIPELINETIMINGS);
434         break;
435     case WINED3DQUERYTYPE_INTERFACETIMINGS:
436         dataSize = sizeof(WINED3DDEVINFO_INTERFACETIMINGS);
437         break;
438     case WINED3DQUERYTYPE_VERTEXTIMINGS:
439         dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS);
440         break;
441     case WINED3DQUERYTYPE_PIXELTIMINGS:
442         dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS);
443         break;
444     case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
445         dataSize = sizeof(WINED3DQUERYTYPE_BANDWIDTHTIMINGS);
446         break;
447     case WINED3DQUERYTYPE_CACHEUTILIZATION:
448         dataSize = sizeof(WINED3DDEVINFO_CACHEUTILIZATION);
449         break;
450     default:
451        FIXME("(%p) Unhandled query type %d\n",This , This->type);
452        dataSize = 0;
453     }
454     return dataSize;
455 }
456
457 static DWORD  WINAPI IWineD3DEventQueryImpl_GetDataSize(IWineD3DQuery* iface){
458     TRACE("(%p) : type D3DQUERY_EVENT\n", iface);
459
460     return sizeof(BOOL);
461 }
462
463 static DWORD  WINAPI IWineD3DOcclusionQueryImpl_GetDataSize(IWineD3DQuery* iface){
464     TRACE("(%p) : type D3DQUERY_OCCLUSION\n", iface);
465
466     return sizeof(DWORD);
467 }
468
469 static WINED3DQUERYTYPE  WINAPI IWineD3DQueryImpl_GetType(IWineD3DQuery* iface){
470     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
471     return This->type;
472 }
473
474
475 static HRESULT  WINAPI IWineD3DEventQueryImpl_Issue(IWineD3DQuery* iface,  DWORD dwIssueFlags) {
476     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
477
478     TRACE("(%p) : dwIssueFlags %#x, type D3DQUERY_EVENT\n", This, dwIssueFlags);
479     if (dwIssueFlags & WINED3DISSUE_END)
480     {
481         WineQueryEventData *query_data = (WineQueryEventData *)This->extendedData;
482
483         if (query_data->ctx->tid != GetCurrentThreadId())
484         {
485             /* GL fences can be used only from the context that created them,
486              * so if a different context is active, don't bother setting the query. The penalty
487              * of a context switch is most likely higher than the gain of a correct query result
488              *
489              * If the query is used from a different thread, don't bother creating a multithread
490              * context - there's no point in doing that as the query would be unusable anyway
491              */
492             WARN("Query context not active\n");
493         }
494         else
495         {
496             ActivateContext(This->wineD3DDevice, query_data->ctx->surface, CTXUSAGE_RESOURCELOAD);
497
498             ENTER_GL();
499
500             if (GL_SUPPORT(APPLE_FENCE))
501             {
502                 GL_EXTCALL(glSetFenceAPPLE(query_data->fenceId));
503                 checkGLcall("glSetFenceAPPLE");
504             }
505             else if (GL_SUPPORT(NV_FENCE))
506             {
507                 GL_EXTCALL(glSetFenceNV(query_data->fenceId, GL_ALL_COMPLETED_NV));
508                 checkGLcall("glSetFenceNV");
509             }
510
511             LEAVE_GL();
512         }
513     } else if(dwIssueFlags & WINED3DISSUE_BEGIN) {
514         /* Started implicitly at device creation */
515         ERR("Event query issued with START flag - what to do?\n");
516     }
517
518     if(dwIssueFlags & WINED3DISSUE_BEGIN) {
519         This->state = QUERY_BUILDING;
520     } else {
521         This->state = QUERY_SIGNALLED;
522     }
523
524     return WINED3D_OK;
525 }
526
527 static HRESULT  WINAPI IWineD3DOcclusionQueryImpl_Issue(IWineD3DQuery* iface,  DWORD dwIssueFlags) {
528     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
529
530     if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
531     {
532         struct wined3d_occlusion_query *query = This->extendedData;
533         struct WineD3DContext *context;
534
535         /* This is allowed according to msdn and our tests. Reset the query and restart */
536         if (dwIssueFlags & WINED3DISSUE_BEGIN)
537         {
538             if (This->state == QUERY_BUILDING)
539             {
540                 if (query->context->tid != GetCurrentThreadId())
541                 {
542                     FIXME("Wrong thread, can't restart query.\n");
543
544                     context_free_occlusion_query(query);
545                     context = ActivateContext(This->wineD3DDevice, NULL, CTXUSAGE_RESOURCELOAD);
546                     context_alloc_occlusion_query(context, query);
547                 }
548                 else
549                 {
550                     ActivateContext(This->wineD3DDevice, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
551
552                     ENTER_GL();
553                     GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
554                     checkGLcall("glEndQuery()");
555                     LEAVE_GL();
556                 }
557             }
558             else
559             {
560                 if (query->context) context_free_occlusion_query(query);
561                 context = ActivateContext(This->wineD3DDevice, NULL, CTXUSAGE_RESOURCELOAD);
562                 context_alloc_occlusion_query(context, query);
563             }
564
565             ENTER_GL();
566             GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, query->id));
567             checkGLcall("glBeginQuery()");
568             LEAVE_GL();
569         }
570         if (dwIssueFlags & WINED3DISSUE_END) {
571             /* Msdn says _END on a non-building occlusion query returns an error, but
572              * our tests show that it returns OK. But OpenGL doesn't like it, so avoid
573              * generating an error
574              */
575             if (This->state == QUERY_BUILDING)
576             {
577                 if (query->context->tid != GetCurrentThreadId())
578                 {
579                     FIXME("Wrong thread, can't end query.\n");
580                 }
581                 else
582                 {
583                     ActivateContext(This->wineD3DDevice, query->context->current_rt, CTXUSAGE_RESOURCELOAD);
584
585                     ENTER_GL();
586                     GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
587                     checkGLcall("glEndQuery()");
588                     LEAVE_GL();
589                 }
590             }
591         }
592     } else {
593         FIXME("(%p) : Occlusion queries not supported\n", This);
594     }
595
596     if(dwIssueFlags & WINED3DISSUE_BEGIN) {
597         This->state = QUERY_BUILDING;
598     } else {
599         This->state = QUERY_SIGNALLED;
600     }
601     return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL.    */
602 }
603
604 static HRESULT  WINAPI IWineD3DQueryImpl_Issue(IWineD3DQuery* iface,  DWORD dwIssueFlags){
605     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
606
607     TRACE("(%p) : dwIssueFlags %#x, type %#x\n", This, dwIssueFlags, This->type);
608
609     /* The fixme is printed when the app asks for the resulting data */
610     WARN("(%p) : Unhandled query type %#x\n", This, This->type);
611
612     if(dwIssueFlags & WINED3DISSUE_BEGIN) {
613         This->state = QUERY_BUILDING;
614     } else {
615         This->state = QUERY_SIGNALLED;
616     }
617
618     return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL.    */
619 }
620
621
622 /**********************************************************
623  * IWineD3DQuery VTbl follows
624  **********************************************************/
625
626 const IWineD3DQueryVtbl IWineD3DQuery_Vtbl =
627 {
628     /*** IUnknown methods ***/
629     IWineD3DQueryImpl_QueryInterface,
630     IWineD3DQueryImpl_AddRef,
631     IWineD3DQueryImpl_Release,
632      /*** IWineD3Dquery methods ***/
633     IWineD3DQueryImpl_GetParent,
634     IWineD3DQueryImpl_GetDevice,
635     IWineD3DQueryImpl_GetData,
636     IWineD3DQueryImpl_GetDataSize,
637     IWineD3DQueryImpl_GetType,
638     IWineD3DQueryImpl_Issue
639 };
640
641 const IWineD3DQueryVtbl IWineD3DEventQuery_Vtbl =
642 {
643     /*** IUnknown methods ***/
644     IWineD3DQueryImpl_QueryInterface,
645     IWineD3DQueryImpl_AddRef,
646     IWineD3DQueryImpl_Release,
647     /*** IWineD3Dquery methods ***/
648     IWineD3DQueryImpl_GetParent,
649     IWineD3DQueryImpl_GetDevice,
650     IWineD3DEventQueryImpl_GetData,
651     IWineD3DEventQueryImpl_GetDataSize,
652     IWineD3DQueryImpl_GetType,
653     IWineD3DEventQueryImpl_Issue
654 };
655
656 const IWineD3DQueryVtbl IWineD3DOcclusionQuery_Vtbl =
657 {
658     /*** IUnknown methods ***/
659     IWineD3DQueryImpl_QueryInterface,
660     IWineD3DQueryImpl_AddRef,
661     IWineD3DQueryImpl_Release,
662     /*** IWineD3Dquery methods ***/
663     IWineD3DQueryImpl_GetParent,
664     IWineD3DQueryImpl_GetDevice,
665     IWineD3DOcclusionQueryImpl_GetData,
666     IWineD3DOcclusionQueryImpl_GetDataSize,
667     IWineD3DQueryImpl_GetType,
668     IWineD3DOcclusionQueryImpl_Issue
669 };