janitorial: Remove links to any microsoft site.
[wine.git] / dlls / wined3d / query.c
blobb8b7a9511e3a29de740ad51c170e97a8a65d6a51
1 /*
2 * IWineD3DQuery implementation
4 * Copyright 2005 Oliver Stieber
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.
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.
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
24 #include "config.h"
25 #include "wined3d_private.h"
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
33 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
34 #define GLINFO_LOCATION This->wineD3DDevice->adapter->gl_info
36 /* *******************************************
37 IWineD3DQuery IUnknown parts follow
38 ******************************************* */
39 static HRESULT WINAPI IWineD3DQueryImpl_QueryInterface(IWineD3DQuery *iface, REFIID riid, LPVOID *ppobj)
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;
50 *ppobj = NULL;
51 return E_NOINTERFACE;
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);
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 if(This->type == WINED3DQUERYTYPE_EVENT) {
67 if(GL_SUPPORT(APPLE_FENCE)) {
68 GL_EXTCALL(glDeleteFencesAPPLE(1, &((WineQueryEventData *)(This->extendedData))->fenceId));
69 checkGLcall("glDeleteFencesAPPLE");
70 } else if(GL_SUPPORT(NV_FENCE)) {
71 GL_EXTCALL(glDeleteFencesNV(1, &((WineQueryEventData *)(This->extendedData))->fenceId));
72 checkGLcall("glDeleteFencesNV");
74 } else if(This->type == WINED3DQUERYTYPE_OCCLUSION && GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
75 GL_EXTCALL(glDeleteQueriesARB(1, &((WineQueryOcclusionData *)(This->extendedData))->queryId));
76 checkGLcall("glDeleteQueriesARB");
79 HeapFree(GetProcessHeap(), 0, This->extendedData);
80 HeapFree(GetProcessHeap(), 0, This);
82 return ref;
85 /* *******************************************
86 IWineD3DQuery IWineD3DQuery parts follow
87 ******************************************* */
88 static HRESULT WINAPI IWineD3DQueryImpl_GetParent(IWineD3DQuery *iface, IUnknown** parent){
89 IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
91 *parent= (IUnknown*) parent;
92 IUnknown_AddRef(*parent);
93 TRACE("(%p) : returning %p\n", This, *parent);
94 return WINED3D_OK;
97 static HRESULT WINAPI IWineD3DQueryImpl_GetDevice(IWineD3DQuery* iface, IWineD3DDevice **pDevice){
98 IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
99 IWineD3DDevice_AddRef((IWineD3DDevice *)This->wineD3DDevice);
100 *pDevice = (IWineD3DDevice *)This->wineD3DDevice;
101 TRACE("(%p) returning %p\n", This, *pDevice);
102 return WINED3D_OK;
106 static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags){
107 IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
108 HRESULT res = S_OK;
110 TRACE("(%p) : type %#x, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, This->type, pData, dwSize, dwGetDataFlags);
112 switch (This->type){
114 case WINED3DQUERYTYPE_VCACHE:
117 WINED3DDEVINFO_VCACHE *data = (WINED3DDEVINFO_VCACHE *)pData;
118 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VCACHE\n", This);
119 if(pData == NULL || dwSize == 0) break;
120 data->Pattern = WINEMAKEFOURCC('C','A','C','H');
121 data->OptMethod = 0; /*0 get longest strips, 1 optimize vertex cache*/
122 data->CacheSize = 0; /*cache size, only required if OptMethod == 1*/
123 data->MagicNumber = 0; /*only required if OptMethod == 1 (used internally)*/
126 break;
127 case WINED3DQUERYTYPE_RESOURCEMANAGER:
129 WINED3DDEVINFO_RESOURCEMANAGER *data = (WINED3DDEVINFO_RESOURCEMANAGER *)pData;
130 int i;
131 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_RESOURCEMANAGER\n", This);
132 if(pData == NULL || dwSize == 0) break;
133 for(i = 0; i < WINED3DRTYPECOUNT; i++){
134 /*I'm setting the default values to 1 so as to reduce the risk of a div/0 in the caller*/
135 /* isTextureResident could be used to get some of this information */
136 data->stats[i].bThrashing = FALSE;
137 data->stats[i].ApproxBytesDownloaded = 1;
138 data->stats[i].NumEvicts = 1;
139 data->stats[i].NumVidCreates = 1;
140 data->stats[i].LastPri = 1;
141 data->stats[i].NumUsed = 1;
142 data->stats[i].NumUsedInVidMem = 1;
143 data->stats[i].WorkingSet = 1;
144 data->stats[i].WorkingSetBytes = 1;
145 data->stats[i].TotalManaged = 1;
146 data->stats[i].TotalBytes = 1;
150 break;
151 case WINED3DQUERYTYPE_VERTEXSTATS:
153 WINED3DDEVINFO_VERTEXSTATS *data = (WINED3DDEVINFO_VERTEXSTATS *)pData;
154 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXSTATS\n", This);
155 if(pData == NULL || dwSize == 0) break;
156 data->NumRenderedTriangles = 1;
157 data->NumExtraClippingTriangles = 1;
160 break;
161 case WINED3DQUERYTYPE_EVENT:
163 BOOL* data = pData;
164 WineD3DContext *ctx = ((WineQueryEventData *)This->extendedData)->ctx;
165 if(pData == NULL || dwSize == 0) {
166 break;
167 } if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) {
168 /* See comment in IWineD3DQuery::Issue, event query codeblock */
169 WARN("Query context not active, reporting GPU idle\n");
170 *data = TRUE;
171 } else if(GL_SUPPORT(APPLE_FENCE)) {
172 *data = GL_EXTCALL(glTestFenceAPPLE(((WineQueryEventData *)This->extendedData)->fenceId));
173 checkGLcall("glTestFenceAPPLE");
174 } else if(GL_SUPPORT(NV_FENCE)) {
175 *data = GL_EXTCALL(glTestFenceNV(((WineQueryEventData *)This->extendedData)->fenceId));
176 checkGLcall("glTestFenceNV");
177 } else {
178 WARN("(%p): reporting GPU idle\n", This);
179 *data = TRUE;
182 break;
183 case WINED3DQUERYTYPE_OCCLUSION:
185 DWORD* data = pData;
187 if(This->state == QUERY_CREATED) {
188 /* D3D allows GetData on a new query, OpenGL doesn't. So just invent the data ourselves */
189 TRACE("Query wasn't yet started, returning S_OK\n");
190 res = S_OK;
191 if(data) *data = 0;
192 } else if(This->state == QUERY_BUILDING) {
193 /* Msdn says this returns an error, but our tests show that S_FALSE is returned */
194 TRACE("Query is building, returning S_FALSE\n");
195 res = S_FALSE;
196 } else if (GL_SUPPORT(ARB_OCCLUSION_QUERY) &&
197 ((WineQueryOcclusionData *)This->extendedData)->ctx == This->wineD3DDevice->activeContext &&
198 This->wineD3DDevice->activeContext->tid == GetCurrentThreadId()) {
199 GLuint available;
200 GLuint samples;
201 GLuint queryId = ((WineQueryOcclusionData *)This->extendedData)->queryId;
203 GL_EXTCALL(glGetQueryObjectuivARB(queryId, GL_QUERY_RESULT_AVAILABLE_ARB, &available));
204 checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)\n");
205 TRACE("(%p) : available %d.\n", This, available);
207 if (available) {
208 if(data) {
209 GL_EXTCALL(glGetQueryObjectuivARB(queryId, GL_QUERY_RESULT_ARB, &samples));
210 checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)\n");
211 TRACE("(%p) : Returning %d samples.\n", This, samples);
212 *data = samples;
214 res = S_OK;
215 } else {
216 res = S_FALSE;
218 } else {
219 WARN("(%p) : Occlusion queries not supported, or wrong context. Returning 1.\n", This);
220 *data = 1;
221 res = S_OK;
224 break;
225 case WINED3DQUERYTYPE_TIMESTAMP:
227 UINT64* data = pData;
228 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMP\n", This);
229 if(pData == NULL || dwSize == 0) break;
230 *data = 1; /*Don't know what this is supposed to be*/
232 break;
233 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
235 BOOL* data = pData;
236 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPDISJOINT\n", This);
237 if(pData == NULL || dwSize == 0) break;
238 *data = FALSE; /*Don't know what this is supposed to be*/
240 break;
241 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
243 UINT64* data = pData;
244 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPFREQ\n", This);
245 if(pData == NULL || dwSize == 0) break;
246 *data = 1; /*Don't know what this is supposed to be*/
248 break;
249 case WINED3DQUERYTYPE_PIPELINETIMINGS:
251 WINED3DDEVINFO_PIPELINETIMINGS *data = (WINED3DDEVINFO_PIPELINETIMINGS *)pData;
252 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIPELINETIMINGS\n", This);
253 if(pData == NULL || dwSize == 0) break;
255 data->VertexProcessingTimePercent = 1.0f;
256 data->PixelProcessingTimePercent = 1.0f;
257 data->OtherGPUProcessingTimePercent = 97.0f;
258 data->GPUIdleTimePercent = 1.0f;
260 break;
261 case WINED3DQUERYTYPE_INTERFACETIMINGS:
263 WINED3DDEVINFO_INTERFACETIMINGS *data = (WINED3DDEVINFO_INTERFACETIMINGS *)pData;
264 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_INTERFACETIMINGS\n", This);
266 if(pData == NULL || dwSize == 0) break;
267 data->WaitingForGPUToUseApplicationResourceTimePercent = 1.0f;
268 data->WaitingForGPUToAcceptMoreCommandsTimePercent = 1.0f;
269 data->WaitingForGPUToStayWithinLatencyTimePercent = 1.0f;
270 data->WaitingForGPUExclusiveResourceTimePercent = 1.0f;
271 data->WaitingForGPUOtherTimePercent = 96.0f;
274 break;
275 case WINED3DQUERYTYPE_VERTEXTIMINGS:
277 WINED3DDEVINFO_STAGETIMINGS *data = (WINED3DDEVINFO_STAGETIMINGS *)pData;
278 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXTIMINGS\n", This);
280 if(pData == NULL || dwSize == 0) break;
281 data->MemoryProcessingPercent = 50.0f;
282 data->ComputationProcessingPercent = 50.0f;
285 break;
286 case WINED3DQUERYTYPE_PIXELTIMINGS:
288 WINED3DDEVINFO_STAGETIMINGS *data = (WINED3DDEVINFO_STAGETIMINGS *)pData;
289 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIXELTIMINGS\n", This);
291 if(pData == NULL || dwSize == 0) break;
292 data->MemoryProcessingPercent = 50.0f;
293 data->ComputationProcessingPercent = 50.0f;
295 break;
296 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
298 WINED3DDEVINFO_BANDWIDTHTIMINGS *data = (WINED3DDEVINFO_BANDWIDTHTIMINGS *)pData;
299 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_BANDWIDTHTIMINGS\n", This);
301 if(pData == NULL || dwSize == 0) break;
302 data->MaxBandwidthUtilized = 1.0f;
303 data->FrontEndUploadMemoryUtilizedPercent = 1.0f;
304 data->VertexRateUtilizedPercent = 1.0f;
305 data->TriangleSetupRateUtilizedPercent = 1.0f;
306 data->FillRateUtilizedPercent = 97.0f;
308 break;
309 case WINED3DQUERYTYPE_CACHEUTILIZATION:
311 WINED3DDEVINFO_CACHEUTILIZATION *data = (WINED3DDEVINFO_CACHEUTILIZATION *)pData;
312 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_CACHEUTILIZATION\n", This);
314 if(pData == NULL || dwSize == 0) break;
315 data->TextureCacheHitRate = 1.0f;
316 data->PostTransformVertexCacheHitRate = 1.0f;
320 break;
321 default:
322 FIXME("(%p) Unhandled query type %d\n",This , This->type);
326 /*dwGetDataFlags = 0 || D3DGETDATA_FLUSH
327 D3DGETDATA_FLUSH may return WINED3DERR_DEVICELOST if the device is lost
329 return res; /* S_OK if the query data is available*/
333 static DWORD WINAPI IWineD3DQueryImpl_GetDataSize(IWineD3DQuery* iface){
334 IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
335 int dataSize = 0;
336 TRACE("(%p) : type %#x\n", This, This->type);
337 switch(This->type){
338 case WINED3DQUERYTYPE_VCACHE:
339 dataSize = sizeof(WINED3DDEVINFO_VCACHE);
340 break;
341 case WINED3DQUERYTYPE_RESOURCEMANAGER:
342 dataSize = sizeof(WINED3DDEVINFO_RESOURCEMANAGER);
343 break;
344 case WINED3DQUERYTYPE_VERTEXSTATS:
345 dataSize = sizeof(WINED3DDEVINFO_VERTEXSTATS);
346 break;
347 case WINED3DQUERYTYPE_EVENT:
348 dataSize = sizeof(BOOL);
349 break;
350 case WINED3DQUERYTYPE_OCCLUSION:
351 dataSize = sizeof(DWORD);
352 break;
353 case WINED3DQUERYTYPE_TIMESTAMP:
354 dataSize = sizeof(UINT64);
355 break;
356 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
357 dataSize = sizeof(BOOL);
358 break;
359 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
360 dataSize = sizeof(UINT64);
361 break;
362 case WINED3DQUERYTYPE_PIPELINETIMINGS:
363 dataSize = sizeof(WINED3DDEVINFO_PIPELINETIMINGS);
364 break;
365 case WINED3DQUERYTYPE_INTERFACETIMINGS:
366 dataSize = sizeof(WINED3DDEVINFO_INTERFACETIMINGS);
367 break;
368 case WINED3DQUERYTYPE_VERTEXTIMINGS:
369 dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS);
370 break;
371 case WINED3DQUERYTYPE_PIXELTIMINGS:
372 dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS);
373 break;
374 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
375 dataSize = sizeof(WINED3DQUERYTYPE_BANDWIDTHTIMINGS);
376 break;
377 case WINED3DQUERYTYPE_CACHEUTILIZATION:
378 dataSize = sizeof(WINED3DDEVINFO_CACHEUTILIZATION);
379 break;
380 default:
381 FIXME("(%p) Unhandled query type %d\n",This , This->type);
382 dataSize = 0;
384 return dataSize;
388 static WINED3DQUERYTYPE WINAPI IWineD3DQueryImpl_GetType(IWineD3DQuery* iface){
389 IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
390 return This->type;
394 static HRESULT WINAPI IWineD3DQueryImpl_Issue(IWineD3DQuery* iface, DWORD dwIssueFlags){
395 IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
397 TRACE("(%p) : dwIssueFlags %#x, type %#x\n", This, dwIssueFlags, This->type);
399 switch (This->type) {
400 case WINED3DQUERYTYPE_OCCLUSION:
401 if (GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
402 WineD3DContext *ctx = ((WineQueryOcclusionData *)This->extendedData)->ctx;
404 if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) {
405 WARN("Not the owning context, can't start query\n");
406 } else {
407 /* This is allowed according to msdn and our tests. Reset the query and restart */
408 if (dwIssueFlags & WINED3DISSUE_BEGIN) {
409 if(This->state == QUERY_BUILDING) {
410 GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
411 checkGLcall("glEndQuery()");
414 GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, ((WineQueryOcclusionData *)This->extendedData)->queryId));
415 checkGLcall("glBeginQuery()");
417 if (dwIssueFlags & WINED3DISSUE_END) {
418 /* Msdn says _END on a non-building occlusion query returns an error, but
419 * our tests show that it returns OK. But OpenGL doesn't like it, so avoid
420 * generating an error
422 if(This->state == QUERY_BUILDING) {
423 GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
424 checkGLcall("glEndQuery()");
428 } else {
429 FIXME("(%p) : Occlusion queries not supported\n", This);
431 break;
433 case WINED3DQUERYTYPE_EVENT: {
434 if (dwIssueFlags & WINED3DISSUE_END) {
435 WineD3DContext *ctx = ((WineQueryEventData *)This->extendedData)->ctx;
436 if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) {
437 /* GL fences can be used only from the context that created them,
438 * so if a different context is active, don't bother setting the query. The penalty
439 * of a context switch is most likely higher than the gain of a correct query result
441 * If the query is used from a different thread, don't bother creating a multithread
442 * context - there's no point in doing that as the query would be unusable anyway
444 WARN("Query context not active\n");
445 } else if(GL_SUPPORT(APPLE_FENCE)) {
446 GL_EXTCALL(glSetFenceAPPLE(((WineQueryEventData *)This->extendedData)->fenceId));
447 checkGLcall("glSetFenceAPPLE");
448 } else if (GL_SUPPORT(NV_FENCE)) {
449 GL_EXTCALL(glSetFenceNV(((WineQueryEventData *)This->extendedData)->fenceId, GL_ALL_COMPLETED_NV));
450 checkGLcall("glSetFenceNV");
452 } else if(dwIssueFlags & WINED3DISSUE_BEGIN) {
453 /* Started implicitly at device creation */
454 ERR("Event query issued with START flag - what to do?\n");
458 default:
459 /* The fixme is printed when the app asks for the resulting data */
460 WARN("(%p) : Unhandled query type %#x\n", This, This->type);
461 break;
464 if(dwIssueFlags & WINED3DISSUE_BEGIN) {
465 This->state = QUERY_BUILDING;
466 } else {
467 This->state = QUERY_SIGNALLED;
470 return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL. */
474 /**********************************************************
475 * IWineD3DQuery VTbl follows
476 **********************************************************/
478 const IWineD3DQueryVtbl IWineD3DQuery_Vtbl =
480 /*** IUnknown methods ***/
481 IWineD3DQueryImpl_QueryInterface,
482 IWineD3DQueryImpl_AddRef,
483 IWineD3DQueryImpl_Release,
484 /*** IWineD3Dquery methods ***/
485 IWineD3DQueryImpl_GetParent,
486 IWineD3DQueryImpl_GetDevice,
487 IWineD3DQueryImpl_GetData,
488 IWineD3DQueryImpl_GetDataSize,
489 IWineD3DQueryImpl_GetType,
490 IWineD3DQueryImpl_Issue