wined3d: Handle FBO attachments slightly more efficiently.
[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) {
69             if(GL_SUPPORT(APPLE_FENCE)) {
70                 GL_EXTCALL(glDeleteFencesAPPLE(1, &((WineQueryEventData *)(This->extendedData))->fenceId));
71                 checkGLcall("glDeleteFencesAPPLE");
72             } else if(GL_SUPPORT(NV_FENCE)) {
73                 GL_EXTCALL(glDeleteFencesNV(1, &((WineQueryEventData *)(This->extendedData))->fenceId));
74                 checkGLcall("glDeleteFencesNV");
75             }
76         } else if(This->type == WINED3DQUERYTYPE_OCCLUSION && GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
77             GL_EXTCALL(glDeleteQueriesARB(1, &((WineQueryOcclusionData *)(This->extendedData))->queryId));
78             checkGLcall("glDeleteQueriesARB");
79         }
80
81         HeapFree(GetProcessHeap(), 0, This->extendedData);
82         HeapFree(GetProcessHeap(), 0, This);
83     }
84     return ref;
85 }
86
87 /* *******************************************
88    IWineD3DQuery IWineD3DQuery parts follow
89    ******************************************* */
90 static HRESULT  WINAPI IWineD3DQueryImpl_GetParent(IWineD3DQuery *iface, IUnknown** parent){
91     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
92
93     *parent= (IUnknown*) parent;
94     IUnknown_AddRef(*parent);
95     TRACE("(%p) : returning %p\n", This, *parent);
96     return WINED3D_OK;
97 }
98
99 static HRESULT  WINAPI IWineD3DQueryImpl_GetDevice(IWineD3DQuery* iface, IWineD3DDevice **pDevice){
100     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
101     IWineD3DDevice_AddRef((IWineD3DDevice *)This->wineD3DDevice);
102     *pDevice = (IWineD3DDevice *)This->wineD3DDevice;
103     TRACE("(%p) returning %p\n", This, *pDevice);
104     return WINED3D_OK;
105 }
106
107
108 static HRESULT  WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags){
109     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
110     HRESULT res = S_OK;
111
112     TRACE("(%p) : type %#x, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, This->type, pData, dwSize, dwGetDataFlags);
113
114     if(dwSize == 0){
115         /*you can use this method to poll the resource for the query status*/
116         /*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*/
117         return S_OK;
118     }else{
119     }
120
121     switch (This->type){
122
123     case WINED3DQUERYTYPE_VCACHE:
124     {
125
126         WINED3DDEVINFO_VCACHE *data = (WINED3DDEVINFO_VCACHE *)pData;
127         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VCACHE\n", This);
128         data->Pattern     = MAKEFOURCC('C','A','C','H');
129         data->OptMethod   = 0; /*0 get longest strips, 1 optimize vertex cache*/
130         data->CacheSize   = 0; /*cache size, only required if OptMethod == 1*/
131         data->MagicNumber = 0; /*only required if OptMethod == 1 (used internally)*/
132
133     }
134     break;
135     case WINED3DQUERYTYPE_RESOURCEMANAGER:
136     {
137         WINED3DDEVINFO_RESOURCEMANAGER *data = (WINED3DDEVINFO_RESOURCEMANAGER *)pData;
138         int i;
139         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_RESOURCEMANAGER\n", This);
140         for(i = 0; i < WINED3DRTYPECOUNT; i++){
141             /*I'm setting the default values to 1 so as to reduce the risk of a div/0 in the caller*/
142             /*  isTextureResident could be used to get some of this infomration  */
143             data->stats[i].bThrashing            = FALSE;
144             data->stats[i].ApproxBytesDownloaded = 1;
145             data->stats[i].NumEvicts             = 1;
146             data->stats[i].NumVidCreates         = 1;
147             data->stats[i].LastPri               = 1;
148             data->stats[i].NumUsed               = 1;
149             data->stats[i].NumUsedInVidMem       = 1;
150             data->stats[i].WorkingSet            = 1;
151             data->stats[i].WorkingSetBytes       = 1;
152             data->stats[i].TotalManaged          = 1;
153             data->stats[i].TotalBytes            = 1;
154         }
155
156     }
157     break;
158     case WINED3DQUERYTYPE_VERTEXSTATS:
159     {
160         WINED3DDEVINFO_VERTEXSTATS *data = (WINED3DDEVINFO_VERTEXSTATS *)pData;
161         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXSTATS\n", This);
162         data->NumRenderedTriangles      = 1;
163         data->NumExtraClippingTriangles = 1;
164
165     }
166     break;
167     case WINED3DQUERYTYPE_EVENT:
168     {
169         BOOL* data = pData;
170         if(GL_SUPPORT(APPLE_FENCE)) {
171             *data = GL_EXTCALL(glTestFenceAPPLE(((WineQueryEventData *)This->extendedData)->fenceId));
172             checkGLcall("glTestFenceAPPLE");
173         } else if(GL_SUPPORT(NV_FENCE)) {
174             *data = GL_EXTCALL(glTestFenceNV(((WineQueryEventData *)This->extendedData)->fenceId));
175             checkGLcall("glTestFenceNV");
176         } else {
177             WARN("(%p): reporting GPU idle\n", This);
178             *data = TRUE;
179         }
180     }
181     break;
182     case WINED3DQUERYTYPE_OCCLUSION:
183     {
184         DWORD* data = pData;
185         if (GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
186             GLuint available;
187             GLuint samples;
188             GLuint queryId = ((WineQueryOcclusionData *)This->extendedData)->queryId;
189
190             GL_EXTCALL(glGetQueryObjectuivARB(queryId, GL_QUERY_RESULT_AVAILABLE_ARB, &available));
191             checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)\n");
192             TRACE("(%p) : available %d.\n", This, available);
193
194             if (available) {
195                 GL_EXTCALL(glGetQueryObjectuivARB(queryId, GL_QUERY_RESULT_ARB, &samples));
196                 checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)\n");
197                 TRACE("(%p) : Returning %d samples.\n", This, samples);
198                 *data = samples;
199                 res = S_OK;
200             } else {
201                 res = S_FALSE;
202             }
203         } else {
204             FIXME("(%p) : Occlusion queries not supported. Returning 1.\n", This);
205             *data = 1;
206             res = S_OK;
207         }
208     }
209     break;
210     case WINED3DQUERYTYPE_TIMESTAMP:
211     {
212         UINT64* data = pData;
213         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMP\n", This);
214         *data = 1; /*Don't know what this is supposed to be*/
215     }
216     break;
217     case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
218     {
219         BOOL* data = pData;
220         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPDISJOINT\n", This);
221         *data = FALSE; /*Don't know what this is supposed to be*/
222     }
223     break;
224     case WINED3DQUERYTYPE_TIMESTAMPFREQ:
225     {
226         UINT64* data = pData;
227         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPFREQ\n", This);
228         *data = 1; /*Don't know what this is supposed to be*/
229     }
230     break;
231     case WINED3DQUERYTYPE_PIPELINETIMINGS:
232     {
233         WINED3DDEVINFO_PIPELINETIMINGS *data = (WINED3DDEVINFO_PIPELINETIMINGS *)pData;
234         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIPELINETIMINGS\n", This);
235
236         data->VertexProcessingTimePercent    =   1.0f;
237         data->PixelProcessingTimePercent     =   1.0f;
238         data->OtherGPUProcessingTimePercent  =  97.0f;
239         data->GPUIdleTimePercent             =   1.0f;
240     }
241     break;
242     case WINED3DQUERYTYPE_INTERFACETIMINGS:
243     {
244         WINED3DDEVINFO_INTERFACETIMINGS *data = (WINED3DDEVINFO_INTERFACETIMINGS *)pData;
245         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_INTERFACETIMINGS\n", This);
246
247         data->WaitingForGPUToUseApplicationResourceTimePercent =   1.0f;
248         data->WaitingForGPUToAcceptMoreCommandsTimePercent     =   1.0f;
249         data->WaitingForGPUToStayWithinLatencyTimePercent      =   1.0f;
250         data->WaitingForGPUExclusiveResourceTimePercent        =   1.0f;
251         data->WaitingForGPUOtherTimePercent                    =  96.0f;
252     }
253
254     break;
255     case WINED3DQUERYTYPE_VERTEXTIMINGS:
256     {
257         WINED3DDEVINFO_STAGETIMINGS *data = (WINED3DDEVINFO_STAGETIMINGS *)pData;
258         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXTIMINGS\n", This);
259
260         data->MemoryProcessingPercent      = 50.0f;
261         data->ComputationProcessingPercent = 50.0f;
262
263     }
264     break;
265     case WINED3DQUERYTYPE_PIXELTIMINGS:
266     {
267         WINED3DDEVINFO_STAGETIMINGS *data = (WINED3DDEVINFO_STAGETIMINGS *)pData;
268         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIXELTIMINGS\n", This);
269
270         data->MemoryProcessingPercent      = 50.0f;
271         data->ComputationProcessingPercent = 50.0f;
272     }
273     break;
274     case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
275     {
276         WINED3DDEVINFO_BANDWIDTHTIMINGS *data = (WINED3DDEVINFO_BANDWIDTHTIMINGS *)pData;
277         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_BANDWIDTHTIMINGS\n", This);
278
279         data->MaxBandwidthUtilized                =  1.0f;
280         data->FrontEndUploadMemoryUtilizedPercent =  1.0f;
281         data->VertexRateUtilizedPercent           =  1.0f;
282         data->TriangleSetupRateUtilizedPercent    =  1.0f;
283         data->FillRateUtilizedPercent             = 97.0f;
284     }
285     break;
286     case WINED3DQUERYTYPE_CACHEUTILIZATION:
287     {
288         WINED3DDEVINFO_CACHEUTILIZATION *data = (WINED3DDEVINFO_CACHEUTILIZATION *)pData;
289         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_CACHEUTILIZATION\n", This);
290
291         data->TextureCacheHitRate             = 1.0f;
292         data->PostTransformVertexCacheHitRate = 1.0f;
293     }
294
295
296     break;
297     default:
298         FIXME("(%p) Unhandled query type %d\n",This , This->type);
299
300     };
301
302     /*dwGetDataFlags = 0 || D3DGETDATA_FLUSH
303     D3DGETDATA_FLUSH may return WINED3DERR_DEVICELOST if the device is lost
304     */
305     return res; /* S_OK if the query data is available*/
306 }
307
308
309 static DWORD  WINAPI IWineD3DQueryImpl_GetDataSize(IWineD3DQuery* iface){
310     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
311     int dataSize = 0;
312     TRACE("(%p) : type %#x\n", This, This->type);
313     switch(This->type){
314     case WINED3DQUERYTYPE_VCACHE:
315         dataSize = sizeof(WINED3DDEVINFO_VCACHE);
316         break;
317     case WINED3DQUERYTYPE_RESOURCEMANAGER:
318         dataSize = sizeof(WINED3DDEVINFO_RESOURCEMANAGER);
319         break;
320     case WINED3DQUERYTYPE_VERTEXSTATS:
321         dataSize = sizeof(WINED3DDEVINFO_VERTEXSTATS);
322         break;
323     case WINED3DQUERYTYPE_EVENT:
324         dataSize = sizeof(BOOL);
325         break;
326     case WINED3DQUERYTYPE_OCCLUSION:
327         dataSize = sizeof(DWORD);
328         break;
329     case WINED3DQUERYTYPE_TIMESTAMP:
330         dataSize = sizeof(UINT64);
331         break;
332     case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
333         dataSize = sizeof(BOOL);
334         break;
335     case WINED3DQUERYTYPE_TIMESTAMPFREQ:
336         dataSize = sizeof(UINT64);
337         break;
338     case WINED3DQUERYTYPE_PIPELINETIMINGS:
339         dataSize = sizeof(WINED3DDEVINFO_PIPELINETIMINGS);
340         break;
341     case WINED3DQUERYTYPE_INTERFACETIMINGS:
342         dataSize = sizeof(WINED3DDEVINFO_INTERFACETIMINGS);
343         break;
344     case WINED3DQUERYTYPE_VERTEXTIMINGS:
345         dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS);
346         break;
347     case WINED3DQUERYTYPE_PIXELTIMINGS:
348         dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS);
349         break;
350     case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
351         dataSize = sizeof(WINED3DQUERYTYPE_BANDWIDTHTIMINGS);
352         break;
353     case WINED3DQUERYTYPE_CACHEUTILIZATION:
354         dataSize = sizeof(WINED3DDEVINFO_CACHEUTILIZATION);
355         break;
356     default:
357        FIXME("(%p) Unhandled query type %d\n",This , This->type);
358        dataSize = 0;
359     }
360     return dataSize;
361 }
362
363
364 static WINED3DQUERYTYPE  WINAPI IWineD3DQueryImpl_GetType(IWineD3DQuery* iface){
365     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
366     return This->type;
367 }
368
369
370 static HRESULT  WINAPI IWineD3DQueryImpl_Issue(IWineD3DQuery* iface,  DWORD dwIssueFlags){
371     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
372
373     TRACE("(%p) : dwIssueFlags %#x, type %#x\n", This, dwIssueFlags, This->type);
374
375     switch (This->type) {
376         case WINED3DQUERYTYPE_OCCLUSION:
377             if (GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
378                 if (dwIssueFlags & WINED3DISSUE_BEGIN) {
379                     GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, ((WineQueryOcclusionData *)This->extendedData)->queryId));
380                     checkGLcall("glBeginQuery()");
381                 }
382                 if (dwIssueFlags & WINED3DISSUE_END) {
383                     GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
384                     checkGLcall("glEndQuery()");
385                 }
386             } else {
387                 FIXME("(%p) : Occlusion queries not supported\n", This);
388             }
389             break;
390
391         case WINED3DQUERYTYPE_EVENT: {
392             if (dwIssueFlags & WINED3DISSUE_END) {
393                 if(GL_SUPPORT(APPLE_FENCE)) {
394                     GL_EXTCALL(glSetFenceAPPLE(((WineQueryEventData *)This->extendedData)->fenceId));
395                     checkGLcall("glSetFenceAPPLE");
396                 } else if (GL_SUPPORT(NV_FENCE)) {
397                     GL_EXTCALL(glSetFenceNV(((WineQueryEventData *)This->extendedData)->fenceId, GL_ALL_COMPLETED_NV));
398                     checkGLcall("glSetFenceNV");
399                 }
400             } else if(dwIssueFlags & WINED3DISSUE_BEGIN) {
401                 /* Started implicitly at device creation */
402                 ERR("Event query issued with START flag - what to do?\n");
403             }
404         }
405
406         default:
407             /* The fixme is printed when the app asks for the resulting data */
408             WARN("(%p) : Unhandled query type %#x\n", This, This->type);
409             break;
410     }
411
412     return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL.    */
413 }
414
415
416 /**********************************************************
417  * IWineD3DQuery VTbl follows
418  **********************************************************/
419
420 const IWineD3DQueryVtbl IWineD3DQuery_Vtbl =
421 {
422     /*** IUnknown methods ***/
423     IWineD3DQueryImpl_QueryInterface,
424     IWineD3DQueryImpl_AddRef,
425     IWineD3DQueryImpl_Release,
426      /*** IWineD3Dquery methods ***/
427     IWineD3DQueryImpl_GetParent,
428     IWineD3DQueryImpl_GetDevice,
429     IWineD3DQueryImpl_GetData,
430     IWineD3DQueryImpl_GetDataSize,
431     IWineD3DQueryImpl_GetType,
432     IWineD3DQueryImpl_Issue
433 };