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