dsound: Add support for 24/32 bits input sound buffers.
[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 This->wineD3DDevice->adapter->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     = WINEMAKEFOURCC('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         WineD3DContext *ctx = ((WineQueryEventData *)This->extendedData)->ctx;
171         if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) {
172             /* See comment in IWineD3DQuery::Issue, event query codeblock */
173             WARN("Query context not active, reporting GPU idle\n");
174             *data = TRUE;
175         } else if(GL_SUPPORT(APPLE_FENCE)) {
176             *data = GL_EXTCALL(glTestFenceAPPLE(((WineQueryEventData *)This->extendedData)->fenceId));
177             checkGLcall("glTestFenceAPPLE");
178         } else if(GL_SUPPORT(NV_FENCE)) {
179             *data = GL_EXTCALL(glTestFenceNV(((WineQueryEventData *)This->extendedData)->fenceId));
180             checkGLcall("glTestFenceNV");
181         } else {
182             WARN("(%p): reporting GPU idle\n", This);
183             *data = TRUE;
184         }
185     }
186     break;
187     case WINED3DQUERYTYPE_OCCLUSION:
188     {
189         DWORD* data = pData;
190         if (GL_SUPPORT(ARB_OCCLUSION_QUERY) &&
191             ((WineQueryOcclusionData *)This->extendedData)->ctx == This->wineD3DDevice->activeContext &&
192             This->wineD3DDevice->activeContext->tid == GetCurrentThreadId()) {
193             GLuint available;
194             GLuint samples;
195             GLuint queryId = ((WineQueryOcclusionData *)This->extendedData)->queryId;
196
197             GL_EXTCALL(glGetQueryObjectuivARB(queryId, GL_QUERY_RESULT_AVAILABLE_ARB, &available));
198             checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)\n");
199             TRACE("(%p) : available %d.\n", This, available);
200
201             if (available) {
202                 GL_EXTCALL(glGetQueryObjectuivARB(queryId, GL_QUERY_RESULT_ARB, &samples));
203                 checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)\n");
204                 TRACE("(%p) : Returning %d samples.\n", This, samples);
205                 *data = samples;
206                 res = S_OK;
207             } else {
208                 res = S_FALSE;
209             }
210         } else {
211             WARN("(%p) : Occlusion queries not supported, or wrong context. Returning 1.\n", This);
212             *data = 1;
213             res = S_OK;
214         }
215     }
216     break;
217     case WINED3DQUERYTYPE_TIMESTAMP:
218     {
219         UINT64* data = pData;
220         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMP\n", This);
221         *data = 1; /*Don't know what this is supposed to be*/
222     }
223     break;
224     case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
225     {
226         BOOL* data = pData;
227         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPDISJOINT\n", This);
228         *data = FALSE; /*Don't know what this is supposed to be*/
229     }
230     break;
231     case WINED3DQUERYTYPE_TIMESTAMPFREQ:
232     {
233         UINT64* data = pData;
234         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPFREQ\n", This);
235         *data = 1; /*Don't know what this is supposed to be*/
236     }
237     break;
238     case WINED3DQUERYTYPE_PIPELINETIMINGS:
239     {
240         WINED3DDEVINFO_PIPELINETIMINGS *data = (WINED3DDEVINFO_PIPELINETIMINGS *)pData;
241         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIPELINETIMINGS\n", This);
242
243         data->VertexProcessingTimePercent    =   1.0f;
244         data->PixelProcessingTimePercent     =   1.0f;
245         data->OtherGPUProcessingTimePercent  =  97.0f;
246         data->GPUIdleTimePercent             =   1.0f;
247     }
248     break;
249     case WINED3DQUERYTYPE_INTERFACETIMINGS:
250     {
251         WINED3DDEVINFO_INTERFACETIMINGS *data = (WINED3DDEVINFO_INTERFACETIMINGS *)pData;
252         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_INTERFACETIMINGS\n", This);
253
254         data->WaitingForGPUToUseApplicationResourceTimePercent =   1.0f;
255         data->WaitingForGPUToAcceptMoreCommandsTimePercent     =   1.0f;
256         data->WaitingForGPUToStayWithinLatencyTimePercent      =   1.0f;
257         data->WaitingForGPUExclusiveResourceTimePercent        =   1.0f;
258         data->WaitingForGPUOtherTimePercent                    =  96.0f;
259     }
260
261     break;
262     case WINED3DQUERYTYPE_VERTEXTIMINGS:
263     {
264         WINED3DDEVINFO_STAGETIMINGS *data = (WINED3DDEVINFO_STAGETIMINGS *)pData;
265         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXTIMINGS\n", This);
266
267         data->MemoryProcessingPercent      = 50.0f;
268         data->ComputationProcessingPercent = 50.0f;
269
270     }
271     break;
272     case WINED3DQUERYTYPE_PIXELTIMINGS:
273     {
274         WINED3DDEVINFO_STAGETIMINGS *data = (WINED3DDEVINFO_STAGETIMINGS *)pData;
275         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIXELTIMINGS\n", This);
276
277         data->MemoryProcessingPercent      = 50.0f;
278         data->ComputationProcessingPercent = 50.0f;
279     }
280     break;
281     case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
282     {
283         WINED3DDEVINFO_BANDWIDTHTIMINGS *data = (WINED3DDEVINFO_BANDWIDTHTIMINGS *)pData;
284         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_BANDWIDTHTIMINGS\n", This);
285
286         data->MaxBandwidthUtilized                =  1.0f;
287         data->FrontEndUploadMemoryUtilizedPercent =  1.0f;
288         data->VertexRateUtilizedPercent           =  1.0f;
289         data->TriangleSetupRateUtilizedPercent    =  1.0f;
290         data->FillRateUtilizedPercent             = 97.0f;
291     }
292     break;
293     case WINED3DQUERYTYPE_CACHEUTILIZATION:
294     {
295         WINED3DDEVINFO_CACHEUTILIZATION *data = (WINED3DDEVINFO_CACHEUTILIZATION *)pData;
296         FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_CACHEUTILIZATION\n", This);
297
298         data->TextureCacheHitRate             = 1.0f;
299         data->PostTransformVertexCacheHitRate = 1.0f;
300     }
301
302
303     break;
304     default:
305         FIXME("(%p) Unhandled query type %d\n",This , This->type);
306
307     };
308
309     /*dwGetDataFlags = 0 || D3DGETDATA_FLUSH
310     D3DGETDATA_FLUSH may return WINED3DERR_DEVICELOST if the device is lost
311     */
312     return res; /* S_OK if the query data is available*/
313 }
314
315
316 static DWORD  WINAPI IWineD3DQueryImpl_GetDataSize(IWineD3DQuery* iface){
317     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
318     int dataSize = 0;
319     TRACE("(%p) : type %#x\n", This, This->type);
320     switch(This->type){
321     case WINED3DQUERYTYPE_VCACHE:
322         dataSize = sizeof(WINED3DDEVINFO_VCACHE);
323         break;
324     case WINED3DQUERYTYPE_RESOURCEMANAGER:
325         dataSize = sizeof(WINED3DDEVINFO_RESOURCEMANAGER);
326         break;
327     case WINED3DQUERYTYPE_VERTEXSTATS:
328         dataSize = sizeof(WINED3DDEVINFO_VERTEXSTATS);
329         break;
330     case WINED3DQUERYTYPE_EVENT:
331         dataSize = sizeof(BOOL);
332         break;
333     case WINED3DQUERYTYPE_OCCLUSION:
334         dataSize = sizeof(DWORD);
335         break;
336     case WINED3DQUERYTYPE_TIMESTAMP:
337         dataSize = sizeof(UINT64);
338         break;
339     case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
340         dataSize = sizeof(BOOL);
341         break;
342     case WINED3DQUERYTYPE_TIMESTAMPFREQ:
343         dataSize = sizeof(UINT64);
344         break;
345     case WINED3DQUERYTYPE_PIPELINETIMINGS:
346         dataSize = sizeof(WINED3DDEVINFO_PIPELINETIMINGS);
347         break;
348     case WINED3DQUERYTYPE_INTERFACETIMINGS:
349         dataSize = sizeof(WINED3DDEVINFO_INTERFACETIMINGS);
350         break;
351     case WINED3DQUERYTYPE_VERTEXTIMINGS:
352         dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS);
353         break;
354     case WINED3DQUERYTYPE_PIXELTIMINGS:
355         dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS);
356         break;
357     case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
358         dataSize = sizeof(WINED3DQUERYTYPE_BANDWIDTHTIMINGS);
359         break;
360     case WINED3DQUERYTYPE_CACHEUTILIZATION:
361         dataSize = sizeof(WINED3DDEVINFO_CACHEUTILIZATION);
362         break;
363     default:
364        FIXME("(%p) Unhandled query type %d\n",This , This->type);
365        dataSize = 0;
366     }
367     return dataSize;
368 }
369
370
371 static WINED3DQUERYTYPE  WINAPI IWineD3DQueryImpl_GetType(IWineD3DQuery* iface){
372     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
373     return This->type;
374 }
375
376
377 static HRESULT  WINAPI IWineD3DQueryImpl_Issue(IWineD3DQuery* iface,  DWORD dwIssueFlags){
378     IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
379
380     TRACE("(%p) : dwIssueFlags %#x, type %#x\n", This, dwIssueFlags, This->type);
381
382     switch (This->type) {
383         case WINED3DQUERYTYPE_OCCLUSION:
384             if (GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
385                 WineD3DContext *ctx = ((WineQueryOcclusionData *)This->extendedData)->ctx;
386
387                 if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) {
388                     WARN("Not the owning context, can't start query\n");
389                 } else {
390                     if (dwIssueFlags & WINED3DISSUE_BEGIN) {
391                         GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, ((WineQueryOcclusionData *)This->extendedData)->queryId));
392                         checkGLcall("glBeginQuery()");
393                     }
394                     if (dwIssueFlags & WINED3DISSUE_END) {
395                         GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
396                         checkGLcall("glEndQuery()");
397                     }
398                 }
399             } else {
400                 FIXME("(%p) : Occlusion queries not supported\n", This);
401             }
402             break;
403
404         case WINED3DQUERYTYPE_EVENT: {
405             if (dwIssueFlags & WINED3DISSUE_END) {
406                 WineD3DContext *ctx = ((WineQueryEventData *)This->extendedData)->ctx;
407                 if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) {
408                     /* GL fences can be used only from the context that created them,
409                      * so if a different context is active, don't bother setting the query. The penalty
410                      * of a context switch is most likely higher than the gain of a correct query result
411                      *
412                      * If the query is used from a different thread, don't bother creating a multithread
413                      * context - there's no point in doing that as the query would be unusable anyway
414                      */
415                     WARN("Query context not active\n");
416                 } else if(GL_SUPPORT(APPLE_FENCE)) {
417                     GL_EXTCALL(glSetFenceAPPLE(((WineQueryEventData *)This->extendedData)->fenceId));
418                     checkGLcall("glSetFenceAPPLE");
419                 } else if (GL_SUPPORT(NV_FENCE)) {
420                     GL_EXTCALL(glSetFenceNV(((WineQueryEventData *)This->extendedData)->fenceId, GL_ALL_COMPLETED_NV));
421                     checkGLcall("glSetFenceNV");
422                 }
423             } else if(dwIssueFlags & WINED3DISSUE_BEGIN) {
424                 /* Started implicitly at device creation */
425                 ERR("Event query issued with START flag - what to do?\n");
426             }
427         }
428
429         default:
430             /* The fixme is printed when the app asks for the resulting data */
431             WARN("(%p) : Unhandled query type %#x\n", This, This->type);
432             break;
433     }
434
435     return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL.    */
436 }
437
438
439 /**********************************************************
440  * IWineD3DQuery VTbl follows
441  **********************************************************/
442
443 const IWineD3DQueryVtbl IWineD3DQuery_Vtbl =
444 {
445     /*** IUnknown methods ***/
446     IWineD3DQueryImpl_QueryInterface,
447     IWineD3DQueryImpl_AddRef,
448     IWineD3DQueryImpl_Release,
449      /*** IWineD3Dquery methods ***/
450     IWineD3DQueryImpl_GetParent,
451     IWineD3DQueryImpl_GetDevice,
452     IWineD3DQueryImpl_GetData,
453     IWineD3DQueryImpl_GetDataSize,
454     IWineD3DQueryImpl_GetType,
455     IWineD3DQueryImpl_Issue
456 };