wined3d: Support event queries using GL_NV_fence.
[wine] / dlls / wined3d / query.c
1 /*
2  * IWineD3DQuery implementation
3  *
4  * Copyright 2005 Oliver Stieber
5  *
6  *
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  * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/Queries.asp
29  *
30  * Occlusion Queries:
31  * http://www.gris.uni-tuebingen.de/~bartz/Publications/paper/hww98.pdf
32  * http://oss.sgi.com/projects/ogl-sample/registry/ARB/occlusion_query.txt
33  */
34
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->wineD3DDevice)->wineD3D))->gl_info
37
38 /* *******************************************
39    IWineD3DQuery IUnknown parts follow
40    ******************************************* */
41 static HRESULT  WINAPI IWineD3DQueryImpl_QueryInterface(IWineD3DQuery *iface, REFIID riid, LPVOID *ppobj)
42 {
43     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
44     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
45     if (IsEqualGUID(riid, &IID_IUnknown)
46         || IsEqualGUID(riid, &IID_IWineD3DBase)
47         || IsEqualGUID(riid, &IID_IWineD3DQuery)) {
48         IUnknown_AddRef(iface);
49         *ppobj = This;
50         return S_OK;
51     }
52     *ppobj = NULL;
53     return E_NOINTERFACE;
54 }
55
56 static ULONG  WINAPI IWineD3DQueryImpl_AddRef(IWineD3DQuery *iface) {
57     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
58     TRACE("(%p) : AddRef increasing from %d\n", This, This->ref);
59     return InterlockedIncrement(&This->ref);
60 }
61
62 static ULONG  WINAPI IWineD3DQueryImpl_Release(IWineD3DQuery *iface) {
63     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
64     ULONG ref;
65     TRACE("(%p) : Releasing from %d\n", This, This->ref);
66     ref = InterlockedDecrement(&This->ref);
67     if (ref == 0) {
68         if(This->type == WINED3DQUERYTYPE_EVENT && GL_SUPPORT(NV_FENCE)) {
69             GL_EXTCALL(glDeleteFencesNV(1, &((WineQueryEventData *)(This->extendedData))->fenceId));
70             checkGLcall("glDeleteFencesNV");
71         } else if(This->type == WINED3DQUERYTYPE_OCCLUSION && GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
72             GL_EXTCALL(glDeleteQueriesARB(1, &((WineQueryOcclusionData *)(This->extendedData))->queryId));
73             checkGLcall("glDeleteQueriesARB");
74         }
75
76         HeapFree(GetProcessHeap(), 0, This->extendedData);
77         HeapFree(GetProcessHeap(), 0, This);
78     }
79     return ref;
80 }
81
82 /* *******************************************
83    IWineD3DQuery IWineD3DQuery parts follow
84    ******************************************* */
85 static HRESULT  WINAPI IWineD3DQueryImpl_GetParent(IWineD3DQuery *iface, IUnknown** parent){
86     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
87
88     *parent= (IUnknown*) parent;
89     IUnknown_AddRef(*parent);
90     TRACE("(%p) : returning %p\n", This, *parent);
91     return WINED3D_OK;
92 }
93
94 static HRESULT  WINAPI IWineD3DQueryImpl_GetDevice(IWineD3DQuery* iface, IWineD3DDevice **pDevice){
95     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
96     IWineD3DDevice_AddRef((IWineD3DDevice *)This->wineD3DDevice);
97     *pDevice = (IWineD3DDevice *)This->wineD3DDevice;
98     TRACE("(%p) returning %p\n", This, *pDevice);
99     return WINED3D_OK;
100 }
101
102
103 static HRESULT  WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags){
104     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
105     HRESULT res = S_OK;
106
107     TRACE("(%p) : type %#x, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, This->type, pData, dwSize, dwGetDataFlags);
108
109     if(dwSize == 0){
110         /*you can use this method to poll the resource for the query status*/
111         /*We return success(S_OK) if we support a feature, and faikure(S_FALSE) if we don't, just return success and fluff it for now*/
112         return S_OK;
113     }else{
114     }
115
116     switch (This->type){
117
118     case WINED3DQUERYTYPE_VCACHE:
119     {
120
121         WINED3DDEVINFO_VCACHE *data = (WINED3DDEVINFO_VCACHE *)pData;
122         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VCACHE\n", This);
123         data->Pattern     = MAKEFOURCC('C','A','C','H');
124         data->OptMethod   = 0; /*0 get longest strips, 1 optimize vertex cache*/
125         data->CacheSize   = 0; /*cache size, only required if OptMethod == 1*/
126         data->MagicNumber = 0; /*only required if OptMethod == 1 (used internally)*/
127
128     }
129     break;
130     case WINED3DQUERYTYPE_RESOURCEMANAGER:
131     {
132         WINED3DDEVINFO_RESOURCEMANAGER *data = (WINED3DDEVINFO_RESOURCEMANAGER *)pData;
133         int i;
134         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_RESOURCEMANAGER\n", This);
135         for(i = 0; i < WINED3DRTYPECOUNT; i++){
136             /*I'm setting the default values to 1 so as to reduce the risk of a div/0 in the caller*/
137             /*  isTextureResident could be used to get some of this infomration  */
138             data->stats[i].bThrashing            = FALSE;
139             data->stats[i].ApproxBytesDownloaded = 1;
140             data->stats[i].NumEvicts             = 1;
141             data->stats[i].NumVidCreates         = 1;
142             data->stats[i].LastPri               = 1;
143             data->stats[i].NumUsed               = 1;
144             data->stats[i].NumUsedInVidMem       = 1;
145             data->stats[i].WorkingSet            = 1;
146             data->stats[i].WorkingSetBytes       = 1;
147             data->stats[i].TotalManaged          = 1;
148             data->stats[i].TotalBytes            = 1;
149         }
150
151     }
152     break;
153     case WINED3DQUERYTYPE_VERTEXSTATS:
154     {
155         WINED3DDEVINFO_VERTEXSTATS *data = (WINED3DDEVINFO_VERTEXSTATS *)pData;
156         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXSTATS\n", This);
157         data->NumRenderedTriangles      = 1;
158         data->NumExtraClippingTriangles = 1;
159
160     }
161     break;
162     case WINED3DQUERYTYPE_EVENT:
163     {
164         BOOL* data = pData;
165         if(GL_SUPPORT(NV_FENCE)) {
166             *data = GL_EXTCALL(glTestFenceNV(((WineQueryEventData *)This->extendedData)->fenceId));
167             checkGLcall("glTestFenceNV");
168         } else {
169             WARN("(%p): reporting GPU idle\n", This);
170             *data = TRUE;
171         }
172     }
173     break;
174     case WINED3DQUERYTYPE_OCCLUSION:
175     {
176         DWORD* data = pData;
177         if (GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
178             GLuint available;
179             GLuint samples;
180             GLuint queryId = ((WineQueryOcclusionData *)This->extendedData)->queryId;
181
182             GL_EXTCALL(glGetQueryObjectuivARB(queryId, GL_QUERY_RESULT_AVAILABLE_ARB, &available));
183             checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)\n");
184             TRACE("(%p) : available %d.\n", This, available);
185
186             if (available) {
187                 GL_EXTCALL(glGetQueryObjectuivARB(queryId, GL_QUERY_RESULT_ARB, &samples));
188                 checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)\n");
189                 TRACE("(%p) : Returning %d samples.\n", This, samples);
190                 *data = samples;
191                 res = S_OK;
192             } else {
193                 res = S_FALSE;
194             }
195         } else {
196             FIXME("(%p) : Occlusion queries not supported. Returning 1.\n", This);
197             *data = 1;
198             res = S_OK;
199         }
200     }
201     break;
202     case WINED3DQUERYTYPE_TIMESTAMP:
203     {
204         UINT64* data = pData;
205         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMP\n", This);
206         *data = 1; /*Don't know what this is supposed to be*/
207     }
208     break;
209     case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
210     {
211         BOOL* data = pData;
212         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPDISJOINT\n", This);
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         *data = 1; /*Don't know what this is supposed to be*/
221     }
222     break;
223     case WINED3DQUERYTYPE_PIPELINETIMINGS:
224     {
225         WINED3DDEVINFO_PIPELINETIMINGS *data = (WINED3DDEVINFO_PIPELINETIMINGS *)pData;
226         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIPELINETIMINGS\n", This);
227
228         data->VertexProcessingTimePercent    =   1.0f;
229         data->PixelProcessingTimePercent     =   1.0f;
230         data->OtherGPUProcessingTimePercent  =  97.0f;
231         data->GPUIdleTimePercent             =   1.0f;
232     }
233     break;
234     case WINED3DQUERYTYPE_INTERFACETIMINGS:
235     {
236         WINED3DDEVINFO_INTERFACETIMINGS *data = (WINED3DDEVINFO_INTERFACETIMINGS *)pData;
237         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_INTERFACETIMINGS\n", This);
238
239         data->WaitingForGPUToUseApplicationResourceTimePercent =   1.0f;
240         data->WaitingForGPUToAcceptMoreCommandsTimePercent     =   1.0f;
241         data->WaitingForGPUToStayWithinLatencyTimePercent      =   1.0f;
242         data->WaitingForGPUExclusiveResourceTimePercent        =   1.0f;
243         data->WaitingForGPUOtherTimePercent                    =  96.0f;
244     }
245
246     break;
247     case WINED3DQUERYTYPE_VERTEXTIMINGS:
248     {
249         WINED3DDEVINFO_STAGETIMINGS *data = (WINED3DDEVINFO_STAGETIMINGS *)pData;
250         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXTIMINGS\n", This);
251
252         data->MemoryProcessingPercent      = 50.0f;
253         data->ComputationProcessingPercent = 50.0f;
254
255     }
256     break;
257     case WINED3DQUERYTYPE_PIXELTIMINGS:
258     {
259         WINED3DDEVINFO_STAGETIMINGS *data = (WINED3DDEVINFO_STAGETIMINGS *)pData;
260         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIXELTIMINGS\n", This);
261
262         data->MemoryProcessingPercent      = 50.0f;
263         data->ComputationProcessingPercent = 50.0f;
264     }
265     break;
266     case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
267     {
268         WINED3DDEVINFO_BANDWIDTHTIMINGS *data = (WINED3DDEVINFO_BANDWIDTHTIMINGS *)pData;
269         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_BANDWIDTHTIMINGS\n", This);
270
271         data->MaxBandwidthUtilized                =  1.0f;
272         data->FrontEndUploadMemoryUtilizedPercent =  1.0f;
273         data->VertexRateUtilizedPercent           =  1.0f;
274         data->TriangleSetupRateUtilizedPercent    =  1.0f;
275         data->FillRateUtilizedPercent             = 97.0f;
276     }
277     break;
278     case WINED3DQUERYTYPE_CACHEUTILIZATION:
279     {
280         WINED3DDEVINFO_CACHEUTILIZATION *data = (WINED3DDEVINFO_CACHEUTILIZATION *)pData;
281         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_CACHEUTILIZATION\n", This);
282
283         data->TextureCacheHitRate             = 1.0f;
284         data->PostTransformVertexCacheHitRate = 1.0f;
285     }
286
287
288     break;
289     default:
290         FIXME("(%p) Unhandled query type %d\n",This , This->type);
291
292     };
293
294     /*dwGetDataFlags = 0 || D3DGETDATA_FLUSH
295     D3DGETDATA_FLUSH may return WINED3DERR_DEVICELOST if the device is lost
296     */
297     return res; /* S_OK if the query data is available*/
298 }
299
300
301 static DWORD  WINAPI IWineD3DQueryImpl_GetDataSize(IWineD3DQuery* iface){
302     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
303     int dataSize = 0;
304     TRACE("(%p) : type %#x\n", This, This->type);
305     switch(This->type){
306     case WINED3DQUERYTYPE_VCACHE:
307         dataSize = sizeof(WINED3DDEVINFO_VCACHE);
308         break;
309     case WINED3DQUERYTYPE_RESOURCEMANAGER:
310         dataSize = sizeof(WINED3DDEVINFO_RESOURCEMANAGER);
311         break;
312     case WINED3DQUERYTYPE_VERTEXSTATS:
313         dataSize = sizeof(WINED3DDEVINFO_VERTEXSTATS);
314         break;
315     case WINED3DQUERYTYPE_EVENT:
316         dataSize = sizeof(BOOL);
317         break;
318     case WINED3DQUERYTYPE_OCCLUSION:
319         dataSize = sizeof(DWORD);
320         break;
321     case WINED3DQUERYTYPE_TIMESTAMP:
322         dataSize = sizeof(UINT64);
323         break;
324     case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
325         dataSize = sizeof(BOOL);
326         break;
327     case WINED3DQUERYTYPE_TIMESTAMPFREQ:
328         dataSize = sizeof(UINT64);
329         break;
330     case WINED3DQUERYTYPE_PIPELINETIMINGS:
331         dataSize = sizeof(WINED3DDEVINFO_PIPELINETIMINGS);
332         break;
333     case WINED3DQUERYTYPE_INTERFACETIMINGS:
334         dataSize = sizeof(WINED3DDEVINFO_INTERFACETIMINGS);
335         break;
336     case WINED3DQUERYTYPE_VERTEXTIMINGS:
337         dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS);
338         break;
339     case WINED3DQUERYTYPE_PIXELTIMINGS:
340         dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS);
341         break;
342     case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
343         dataSize = sizeof(WINED3DQUERYTYPE_BANDWIDTHTIMINGS);
344         break;
345     case WINED3DQUERYTYPE_CACHEUTILIZATION:
346         dataSize = sizeof(WINED3DDEVINFO_CACHEUTILIZATION);
347         break;
348     default:
349        FIXME("(%p) Unhandled query type %d\n",This , This->type);
350        dataSize = 0;
351     }
352     return dataSize;
353 }
354
355
356 static WINED3DQUERYTYPE  WINAPI IWineD3DQueryImpl_GetType(IWineD3DQuery* iface){
357     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
358     return This->type;
359 }
360
361
362 static HRESULT  WINAPI IWineD3DQueryImpl_Issue(IWineD3DQuery* iface,  DWORD dwIssueFlags){
363     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
364
365     TRACE("(%p) : dwIssueFlags %#x, type %#x\n", This, dwIssueFlags, This->type);
366
367     switch (This->type) {
368         case WINED3DQUERYTYPE_OCCLUSION:
369             if (GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
370                 if (dwIssueFlags & WINED3DISSUE_BEGIN) {
371                     GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, ((WineQueryOcclusionData *)This->extendedData)->queryId));
372                     checkGLcall("glBeginQuery()");
373                 }
374                 if (dwIssueFlags & WINED3DISSUE_END) {
375                     GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
376                     checkGLcall("glEndQuery()");
377                 }
378             } else {
379                 FIXME("(%p) : Occlusion queries not supported\n", This);
380             }
381             break;
382
383         case WINED3DQUERYTYPE_EVENT: {
384             if (GL_SUPPORT(GL_NV_fence)) {
385                 if (dwIssueFlags & WINED3DISSUE_END) {
386                     GL_EXTCALL(glSetFenceNV(((WineQueryEventData *)This->extendedData)->fenceId, GL_ALL_COMPLETED_NV));
387                 } else if(dwIssueFlags & WINED3DISSUE_BEGIN) {
388                     /* Started implicitly at device creation */
389                     ERR("Event query issued with START flag - what to do?\n");
390                 }
391             }
392         }
393
394         default:
395             /* The fixme is printed when the app asks for the resulting data */
396             WARN("(%p) : Unhandled query type %#x\n", This, This->type);
397             break;
398     }
399
400     return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL.    */
401 }
402
403
404 /**********************************************************
405  * IWineD3DQuery VTbl follows
406  **********************************************************/
407
408 const IWineD3DQueryVtbl IWineD3DQuery_Vtbl =
409 {
410     /*** IUnknown methods ***/
411     IWineD3DQueryImpl_QueryInterface,
412     IWineD3DQueryImpl_AddRef,
413     IWineD3DQueryImpl_Release,
414      /*** IWineD3Dquery methods ***/
415     IWineD3DQueryImpl_GetParent,
416     IWineD3DQueryImpl_GetDevice,
417     IWineD3DQueryImpl_GetData,
418     IWineD3DQueryImpl_GetDataSize,
419     IWineD3DQueryImpl_GetType,
420     IWineD3DQueryImpl_Issue
421 };