urlmon: Correctly handle BINDF_NEEDFILE flag in http protocol.
[wine/wine64.git] / dlls / wined3d / query.c
blob3f029012de62d6cd24bb588d2d495467e1875758
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 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/advancedtopics/Queries.asp
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
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->wineD3DDevice->adapter->gl_info
38 /* *******************************************
39 IWineD3DQuery IUnknown parts follow
40 ******************************************* */
41 static HRESULT WINAPI IWineD3DQueryImpl_QueryInterface(IWineD3DQuery *iface, REFIID riid, LPVOID *ppobj)
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;
52 *ppobj = NULL;
53 return E_NOINTERFACE;
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);
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");
76 } else if(This->type == WINED3DQUERYTYPE_OCCLUSION && GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
77 GL_EXTCALL(glDeleteQueriesARB(1, &((WineQueryOcclusionData *)(This->extendedData))->queryId));
78 checkGLcall("glDeleteQueriesARB");
81 HeapFree(GetProcessHeap(), 0, This->extendedData);
82 HeapFree(GetProcessHeap(), 0, This);
84 return ref;
87 /* *******************************************
88 IWineD3DQuery IWineD3DQuery parts follow
89 ******************************************* */
90 static HRESULT WINAPI IWineD3DQueryImpl_GetParent(IWineD3DQuery *iface, IUnknown** parent){
91 IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
93 *parent= (IUnknown*) parent;
94 IUnknown_AddRef(*parent);
95 TRACE("(%p) : returning %p\n", This, *parent);
96 return WINED3D_OK;
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;
108 static HRESULT WINAPI IWineD3DQueryImpl_GetData(IWineD3DQuery* iface, void* pData, DWORD dwSize, DWORD dwGetDataFlags){
109 IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
110 HRESULT res = S_OK;
112 TRACE("(%p) : type %#x, pData %p, dwSize %#x, dwGetDataFlags %#x\n", This, This->type, pData, dwSize, dwGetDataFlags);
114 switch (This->type){
116 case WINED3DQUERYTYPE_VCACHE:
119 WINED3DDEVINFO_VCACHE *data = (WINED3DDEVINFO_VCACHE *)pData;
120 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VCACHE\n", This);
121 if(pData == NULL || dwSize == 0) break;
122 data->Pattern = WINEMAKEFOURCC('C','A','C','H');
123 data->OptMethod = 0; /*0 get longest strips, 1 optimize vertex cache*/
124 data->CacheSize = 0; /*cache size, only required if OptMethod == 1*/
125 data->MagicNumber = 0; /*only required if OptMethod == 1 (used internally)*/
128 break;
129 case WINED3DQUERYTYPE_RESOURCEMANAGER:
131 WINED3DDEVINFO_RESOURCEMANAGER *data = (WINED3DDEVINFO_RESOURCEMANAGER *)pData;
132 int i;
133 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_RESOURCEMANAGER\n", This);
134 if(pData == NULL || dwSize == 0) break;
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 information */
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;
152 break;
153 case WINED3DQUERYTYPE_VERTEXSTATS:
155 WINED3DDEVINFO_VERTEXSTATS *data = (WINED3DDEVINFO_VERTEXSTATS *)pData;
156 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXSTATS\n", This);
157 if(pData == NULL || dwSize == 0) break;
158 data->NumRenderedTriangles = 1;
159 data->NumExtraClippingTriangles = 1;
162 break;
163 case WINED3DQUERYTYPE_EVENT:
165 BOOL* data = pData;
166 WineD3DContext *ctx = ((WineQueryEventData *)This->extendedData)->ctx;
167 if(pData == NULL || dwSize == 0) {
168 break;
169 } if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) {
170 /* See comment in IWineD3DQuery::Issue, event query codeblock */
171 WARN("Query context not active, reporting GPU idle\n");
172 *data = TRUE;
173 } else if(GL_SUPPORT(APPLE_FENCE)) {
174 *data = GL_EXTCALL(glTestFenceAPPLE(((WineQueryEventData *)This->extendedData)->fenceId));
175 checkGLcall("glTestFenceAPPLE");
176 } else if(GL_SUPPORT(NV_FENCE)) {
177 *data = GL_EXTCALL(glTestFenceNV(((WineQueryEventData *)This->extendedData)->fenceId));
178 checkGLcall("glTestFenceNV");
179 } else {
180 WARN("(%p): reporting GPU idle\n", This);
181 *data = TRUE;
184 break;
185 case WINED3DQUERYTYPE_OCCLUSION:
187 DWORD* data = pData;
189 if(This->state == QUERY_CREATED) {
190 /* D3D allows GetData on a new query, OpenGL doesn't. So just invent the data ourselves */
191 TRACE("Query wasn't yet started, returning S_OK\n");
192 res = S_OK;
193 if(data) *data = 0;
194 } else if(This->state == QUERY_BUILDING) {
195 /* Msdn says this returns an error, but our tests show that S_FALSE is returned */
196 TRACE("Query is building, returning S_FALSE\n");
197 res = S_FALSE;
198 } else if (GL_SUPPORT(ARB_OCCLUSION_QUERY) &&
199 ((WineQueryOcclusionData *)This->extendedData)->ctx == This->wineD3DDevice->activeContext &&
200 This->wineD3DDevice->activeContext->tid == GetCurrentThreadId()) {
201 GLuint available;
202 GLuint samples;
203 GLuint queryId = ((WineQueryOcclusionData *)This->extendedData)->queryId;
205 GL_EXTCALL(glGetQueryObjectuivARB(queryId, GL_QUERY_RESULT_AVAILABLE_ARB, &available));
206 checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT_AVAILABLE)\n");
207 TRACE("(%p) : available %d.\n", This, available);
209 if (available) {
210 if(data) {
211 GL_EXTCALL(glGetQueryObjectuivARB(queryId, GL_QUERY_RESULT_ARB, &samples));
212 checkGLcall("glGetQueryObjectuivARB(GL_QUERY_RESULT)\n");
213 TRACE("(%p) : Returning %d samples.\n", This, samples);
214 *data = samples;
216 res = S_OK;
217 } else {
218 res = S_FALSE;
220 } else {
221 WARN("(%p) : Occlusion queries not supported, or wrong context. Returning 1.\n", This);
222 *data = 1;
223 res = S_OK;
226 break;
227 case WINED3DQUERYTYPE_TIMESTAMP:
229 UINT64* data = pData;
230 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMP\n", This);
231 if(pData == NULL || dwSize == 0) break;
232 *data = 1; /*Don't know what this is supposed to be*/
234 break;
235 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
237 BOOL* data = pData;
238 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPDISJOINT\n", This);
239 if(pData == NULL || dwSize == 0) break;
240 *data = FALSE; /*Don't know what this is supposed to be*/
242 break;
243 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
245 UINT64* data = pData;
246 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_TIMESTAMPFREQ\n", This);
247 if(pData == NULL || dwSize == 0) break;
248 *data = 1; /*Don't know what this is supposed to be*/
250 break;
251 case WINED3DQUERYTYPE_PIPELINETIMINGS:
253 WINED3DDEVINFO_PIPELINETIMINGS *data = (WINED3DDEVINFO_PIPELINETIMINGS *)pData;
254 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIPELINETIMINGS\n", This);
255 if(pData == NULL || dwSize == 0) break;
257 data->VertexProcessingTimePercent = 1.0f;
258 data->PixelProcessingTimePercent = 1.0f;
259 data->OtherGPUProcessingTimePercent = 97.0f;
260 data->GPUIdleTimePercent = 1.0f;
262 break;
263 case WINED3DQUERYTYPE_INTERFACETIMINGS:
265 WINED3DDEVINFO_INTERFACETIMINGS *data = (WINED3DDEVINFO_INTERFACETIMINGS *)pData;
266 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_INTERFACETIMINGS\n", This);
268 if(pData == NULL || dwSize == 0) break;
269 data->WaitingForGPUToUseApplicationResourceTimePercent = 1.0f;
270 data->WaitingForGPUToAcceptMoreCommandsTimePercent = 1.0f;
271 data->WaitingForGPUToStayWithinLatencyTimePercent = 1.0f;
272 data->WaitingForGPUExclusiveResourceTimePercent = 1.0f;
273 data->WaitingForGPUOtherTimePercent = 96.0f;
276 break;
277 case WINED3DQUERYTYPE_VERTEXTIMINGS:
279 WINED3DDEVINFO_STAGETIMINGS *data = (WINED3DDEVINFO_STAGETIMINGS *)pData;
280 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_VERTEXTIMINGS\n", This);
282 if(pData == NULL || dwSize == 0) break;
283 data->MemoryProcessingPercent = 50.0f;
284 data->ComputationProcessingPercent = 50.0f;
287 break;
288 case WINED3DQUERYTYPE_PIXELTIMINGS:
290 WINED3DDEVINFO_STAGETIMINGS *data = (WINED3DDEVINFO_STAGETIMINGS *)pData;
291 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_PIXELTIMINGS\n", This);
293 if(pData == NULL || dwSize == 0) break;
294 data->MemoryProcessingPercent = 50.0f;
295 data->ComputationProcessingPercent = 50.0f;
297 break;
298 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
300 WINED3DDEVINFO_BANDWIDTHTIMINGS *data = (WINED3DDEVINFO_BANDWIDTHTIMINGS *)pData;
301 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_BANDWIDTHTIMINGS\n", This);
303 if(pData == NULL || dwSize == 0) break;
304 data->MaxBandwidthUtilized = 1.0f;
305 data->FrontEndUploadMemoryUtilizedPercent = 1.0f;
306 data->VertexRateUtilizedPercent = 1.0f;
307 data->TriangleSetupRateUtilizedPercent = 1.0f;
308 data->FillRateUtilizedPercent = 97.0f;
310 break;
311 case WINED3DQUERYTYPE_CACHEUTILIZATION:
313 WINED3DDEVINFO_CACHEUTILIZATION *data = (WINED3DDEVINFO_CACHEUTILIZATION *)pData;
314 FIXME("(%p): Unimplemented query WINED3DQUERYTYPE_CACHEUTILIZATION\n", This);
316 if(pData == NULL || dwSize == 0) break;
317 data->TextureCacheHitRate = 1.0f;
318 data->PostTransformVertexCacheHitRate = 1.0f;
322 break;
323 default:
324 FIXME("(%p) Unhandled query type %d\n",This , This->type);
328 /*dwGetDataFlags = 0 || D3DGETDATA_FLUSH
329 D3DGETDATA_FLUSH may return WINED3DERR_DEVICELOST if the device is lost
331 return res; /* S_OK if the query data is available*/
335 static DWORD WINAPI IWineD3DQueryImpl_GetDataSize(IWineD3DQuery* iface){
336 IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
337 int dataSize = 0;
338 TRACE("(%p) : type %#x\n", This, This->type);
339 switch(This->type){
340 case WINED3DQUERYTYPE_VCACHE:
341 dataSize = sizeof(WINED3DDEVINFO_VCACHE);
342 break;
343 case WINED3DQUERYTYPE_RESOURCEMANAGER:
344 dataSize = sizeof(WINED3DDEVINFO_RESOURCEMANAGER);
345 break;
346 case WINED3DQUERYTYPE_VERTEXSTATS:
347 dataSize = sizeof(WINED3DDEVINFO_VERTEXSTATS);
348 break;
349 case WINED3DQUERYTYPE_EVENT:
350 dataSize = sizeof(BOOL);
351 break;
352 case WINED3DQUERYTYPE_OCCLUSION:
353 dataSize = sizeof(DWORD);
354 break;
355 case WINED3DQUERYTYPE_TIMESTAMP:
356 dataSize = sizeof(UINT64);
357 break;
358 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
359 dataSize = sizeof(BOOL);
360 break;
361 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
362 dataSize = sizeof(UINT64);
363 break;
364 case WINED3DQUERYTYPE_PIPELINETIMINGS:
365 dataSize = sizeof(WINED3DDEVINFO_PIPELINETIMINGS);
366 break;
367 case WINED3DQUERYTYPE_INTERFACETIMINGS:
368 dataSize = sizeof(WINED3DDEVINFO_INTERFACETIMINGS);
369 break;
370 case WINED3DQUERYTYPE_VERTEXTIMINGS:
371 dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS);
372 break;
373 case WINED3DQUERYTYPE_PIXELTIMINGS:
374 dataSize = sizeof(WINED3DDEVINFO_STAGETIMINGS);
375 break;
376 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
377 dataSize = sizeof(WINED3DQUERYTYPE_BANDWIDTHTIMINGS);
378 break;
379 case WINED3DQUERYTYPE_CACHEUTILIZATION:
380 dataSize = sizeof(WINED3DDEVINFO_CACHEUTILIZATION);
381 break;
382 default:
383 FIXME("(%p) Unhandled query type %d\n",This , This->type);
384 dataSize = 0;
386 return dataSize;
390 static WINED3DQUERYTYPE WINAPI IWineD3DQueryImpl_GetType(IWineD3DQuery* iface){
391 IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
392 return This->type;
396 static HRESULT WINAPI IWineD3DQueryImpl_Issue(IWineD3DQuery* iface, DWORD dwIssueFlags){
397 IWineD3DQueryImpl *This = (IWineD3DQueryImpl *)iface;
399 TRACE("(%p) : dwIssueFlags %#x, type %#x\n", This, dwIssueFlags, This->type);
401 switch (This->type) {
402 case WINED3DQUERYTYPE_OCCLUSION:
403 if (GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
404 WineD3DContext *ctx = ((WineQueryOcclusionData *)This->extendedData)->ctx;
406 if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) {
407 WARN("Not the owning context, can't start query\n");
408 } else {
409 /* This is allowed according to msdn and our tests. Reset the query and restart */
410 if (dwIssueFlags & WINED3DISSUE_BEGIN) {
411 if(This->state == QUERY_BUILDING) {
412 GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
413 checkGLcall("glEndQuery()");
416 GL_EXTCALL(glBeginQueryARB(GL_SAMPLES_PASSED_ARB, ((WineQueryOcclusionData *)This->extendedData)->queryId));
417 checkGLcall("glBeginQuery()");
419 if (dwIssueFlags & WINED3DISSUE_END) {
420 /* Msdn says _END on a non-building occlusion query returns an error, but
421 * our tests show that it returns OK. But OpenGL doesn't like it, so avoid
422 * generating an error
424 if(This->state == QUERY_BUILDING) {
425 GL_EXTCALL(glEndQueryARB(GL_SAMPLES_PASSED_ARB));
426 checkGLcall("glEndQuery()");
430 } else {
431 FIXME("(%p) : Occlusion queries not supported\n", This);
433 break;
435 case WINED3DQUERYTYPE_EVENT: {
436 if (dwIssueFlags & WINED3DISSUE_END) {
437 WineD3DContext *ctx = ((WineQueryEventData *)This->extendedData)->ctx;
438 if(ctx != This->wineD3DDevice->activeContext || ctx->tid != GetCurrentThreadId()) {
439 /* GL fences can be used only from the context that created them,
440 * so if a different context is active, don't bother setting the query. The penalty
441 * of a context switch is most likely higher than the gain of a correct query result
443 * If the query is used from a different thread, don't bother creating a multithread
444 * context - there's no point in doing that as the query would be unusable anyway
446 WARN("Query context not active\n");
447 } else if(GL_SUPPORT(APPLE_FENCE)) {
448 GL_EXTCALL(glSetFenceAPPLE(((WineQueryEventData *)This->extendedData)->fenceId));
449 checkGLcall("glSetFenceAPPLE");
450 } else if (GL_SUPPORT(NV_FENCE)) {
451 GL_EXTCALL(glSetFenceNV(((WineQueryEventData *)This->extendedData)->fenceId, GL_ALL_COMPLETED_NV));
452 checkGLcall("glSetFenceNV");
454 } else if(dwIssueFlags & WINED3DISSUE_BEGIN) {
455 /* Started implicitly at device creation */
456 ERR("Event query issued with START flag - what to do?\n");
460 default:
461 /* The fixme is printed when the app asks for the resulting data */
462 WARN("(%p) : Unhandled query type %#x\n", This, This->type);
463 break;
466 if(dwIssueFlags & WINED3DISSUE_BEGIN) {
467 This->state = QUERY_BUILDING;
468 } else {
469 This->state = QUERY_SIGNALLED;
472 return WINED3D_OK; /* can be WINED3DERR_INVALIDCALL. */
476 /**********************************************************
477 * IWineD3DQuery VTbl follows
478 **********************************************************/
480 const IWineD3DQueryVtbl IWineD3DQuery_Vtbl =
482 /*** IUnknown methods ***/
483 IWineD3DQueryImpl_QueryInterface,
484 IWineD3DQueryImpl_AddRef,
485 IWineD3DQueryImpl_Release,
486 /*** IWineD3Dquery methods ***/
487 IWineD3DQueryImpl_GetParent,
488 IWineD3DQueryImpl_GetDevice,
489 IWineD3DQueryImpl_GetData,
490 IWineD3DQueryImpl_GetDataSize,
491 IWineD3DQueryImpl_GetType,
492 IWineD3DQueryImpl_Issue