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