xref: /reactos/dll/directx/wine/wined3d/query.c (revision 9987f029)
1 /*
2  * Copyright 2005 Oliver Stieber
3  * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
4  * Copyright 2009-2010 Henri Verbeet for CodeWeavers.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 
22 #include "config.h"
23 #include "wine/port.h"
24 #include "wined3d_private.h"
25 
26 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
27 
get_query_result64(GLuint id,const struct wined3d_gl_info * gl_info)28 static UINT64 get_query_result64(GLuint id, const struct wined3d_gl_info *gl_info)
29 {
30     if (gl_info->supported[ARB_TIMER_QUERY])
31     {
32         GLuint64 result;
33         GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, &result));
34         return result;
35     }
36     else
37     {
38         GLuint result;
39         GL_EXTCALL(glGetQueryObjectuiv(id, GL_QUERY_RESULT, &result));
40         return result;
41     }
42 }
43 
wined3d_query_init(struct wined3d_query * query,struct wined3d_device * device,enum wined3d_query_type type,const void * data,DWORD data_size,const struct wined3d_query_ops * query_ops,void * parent,const struct wined3d_parent_ops * parent_ops)44 static void wined3d_query_init(struct wined3d_query *query, struct wined3d_device *device,
45         enum wined3d_query_type type, const void *data, DWORD data_size,
46         const struct wined3d_query_ops *query_ops, void *parent, const struct wined3d_parent_ops *parent_ops)
47 {
48     query->ref = 1;
49     query->parent = parent;
50     query->parent_ops = parent_ops;
51     query->device = device;
52     query->state = QUERY_CREATED;
53     query->type = type;
54     query->data = data;
55     query->data_size = data_size;
56     query->query_ops = query_ops;
57     list_init(&query->poll_list_entry);
58 }
59 
wined3d_event_query_from_query(struct wined3d_query * query)60 static struct wined3d_event_query *wined3d_event_query_from_query(struct wined3d_query *query)
61 {
62     return CONTAINING_RECORD(query, struct wined3d_event_query, query);
63 }
64 
wined3d_occlusion_query_from_query(struct wined3d_query * query)65 static struct wined3d_occlusion_query *wined3d_occlusion_query_from_query(struct wined3d_query *query)
66 {
67     return CONTAINING_RECORD(query, struct wined3d_occlusion_query, query);
68 }
69 
wined3d_timestamp_query_from_query(struct wined3d_query * query)70 static struct wined3d_timestamp_query *wined3d_timestamp_query_from_query(struct wined3d_query *query)
71 {
72     return CONTAINING_RECORD(query, struct wined3d_timestamp_query, query);
73 }
74 
wined3d_so_statistics_query_from_query(struct wined3d_query * query)75 static struct wined3d_so_statistics_query *wined3d_so_statistics_query_from_query(struct wined3d_query *query)
76 {
77     return CONTAINING_RECORD(query, struct wined3d_so_statistics_query, query);
78 }
79 
wined3d_pipeline_statistics_query_from_query(struct wined3d_query * query)80 static struct wined3d_pipeline_statistics_query *wined3d_pipeline_statistics_query_from_query(
81         struct wined3d_query *query)
82 {
83     return CONTAINING_RECORD(query, struct wined3d_pipeline_statistics_query, query);
84 }
85 
wined3d_fence_supported(const struct wined3d_gl_info * gl_info)86 static BOOL wined3d_fence_supported(const struct wined3d_gl_info *gl_info)
87 {
88     return gl_info->supported[ARB_SYNC] || gl_info->supported[NV_FENCE] || gl_info->supported[APPLE_FENCE];
89 }
90 
wined3d_fence_test(const struct wined3d_fence * fence,const struct wined3d_device * device,DWORD flags)91 static enum wined3d_fence_result wined3d_fence_test(const struct wined3d_fence *fence,
92         const struct wined3d_device *device, DWORD flags)
93 {
94     const struct wined3d_gl_info *gl_info;
95     struct wined3d_context *context;
96     enum wined3d_fence_result ret;
97     BOOL fence_result;
98 
99     TRACE("fence %p, device %p, flags %#x.\n", fence, device, flags);
100 
101     if (!fence->context)
102     {
103         TRACE("Fence not issued.\n");
104         return WINED3D_FENCE_NOT_STARTED;
105     }
106 
107     if (!(context = context_reacquire(device, fence->context)))
108     {
109         if (!fence->context->gl_info->supported[ARB_SYNC])
110         {
111             WARN("Fence tested from wrong thread.\n");
112             return WINED3D_FENCE_WRONG_THREAD;
113         }
114         context = context_acquire(device, NULL, 0);
115     }
116     gl_info = context->gl_info;
117 
118     if (gl_info->supported[ARB_SYNC])
119     {
120         GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
121                 (flags & WINED3DGETDATA_FLUSH) ? GL_SYNC_FLUSH_COMMANDS_BIT : 0, 0));
122         checkGLcall("glClientWaitSync");
123 
124         switch (gl_ret)
125         {
126             case GL_ALREADY_SIGNALED:
127             case GL_CONDITION_SATISFIED:
128                 ret = WINED3D_FENCE_OK;
129                 break;
130 
131             case GL_TIMEOUT_EXPIRED:
132                 ret = WINED3D_FENCE_WAITING;
133                 break;
134 
135             case GL_WAIT_FAILED:
136             default:
137                 ERR("glClientWaitSync returned %#x.\n", gl_ret);
138                 ret = WINED3D_FENCE_ERROR;
139         }
140     }
141     else if (gl_info->supported[APPLE_FENCE])
142     {
143         fence_result = GL_EXTCALL(glTestFenceAPPLE(fence->object.id));
144         checkGLcall("glTestFenceAPPLE");
145         if (fence_result)
146             ret = WINED3D_FENCE_OK;
147         else
148             ret = WINED3D_FENCE_WAITING;
149     }
150     else if (gl_info->supported[NV_FENCE])
151     {
152         fence_result = GL_EXTCALL(glTestFenceNV(fence->object.id));
153         checkGLcall("glTestFenceNV");
154         if (fence_result)
155             ret = WINED3D_FENCE_OK;
156         else
157             ret = WINED3D_FENCE_WAITING;
158     }
159     else
160     {
161         ERR("Fence created despite lack of GL support.\n");
162         ret = WINED3D_FENCE_ERROR;
163     }
164 
165     context_release(context);
166     return ret;
167 }
168 
wined3d_fence_wait(const struct wined3d_fence * fence,const struct wined3d_device * device)169 enum wined3d_fence_result wined3d_fence_wait(const struct wined3d_fence *fence,
170         const struct wined3d_device *device)
171 {
172     const struct wined3d_gl_info *gl_info;
173     struct wined3d_context *context;
174     enum wined3d_fence_result ret;
175 
176     TRACE("fence %p, device %p.\n", fence, device);
177 
178     if (!fence->context)
179     {
180         TRACE("Fence not issued.\n");
181         return WINED3D_FENCE_NOT_STARTED;
182     }
183     gl_info = fence->context->gl_info;
184 
185     if (!(context = context_reacquire(device, fence->context)))
186     {
187         /* A glFinish does not reliably wait for draws in other contexts. The caller has
188          * to find its own way to cope with the thread switch
189          */
190         if (!gl_info->supported[ARB_SYNC])
191         {
192             WARN("Fence finished from wrong thread.\n");
193             return WINED3D_FENCE_WRONG_THREAD;
194         }
195         context = context_acquire(device, NULL, 0);
196     }
197     gl_info = context->gl_info;
198 
199     if (gl_info->supported[ARB_SYNC])
200     {
201         /* Timeouts near 0xffffffffffffffff may immediately return GL_TIMEOUT_EXPIRED,
202          * possibly because macOS internally adds some slop to the timer. To avoid this,
203          * we use a large number that isn't near the point of overflow (macOS 10.12.5).
204          */
205         GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
206                 GL_SYNC_FLUSH_COMMANDS_BIT, ~(GLuint64)0 >> 1));
207         checkGLcall("glClientWaitSync");
208 
209         switch (gl_ret)
210         {
211             case GL_ALREADY_SIGNALED:
212             case GL_CONDITION_SATISFIED:
213                 ret = WINED3D_FENCE_OK;
214                 break;
215 
216                 /* We don't expect a timeout for a ~292 year wait */
217             default:
218                 ERR("glClientWaitSync returned %#x.\n", gl_ret);
219                 ret = WINED3D_FENCE_ERROR;
220         }
221     }
222     else if (context->gl_info->supported[APPLE_FENCE])
223     {
224         GL_EXTCALL(glFinishFenceAPPLE(fence->object.id));
225         checkGLcall("glFinishFenceAPPLE");
226         ret = WINED3D_FENCE_OK;
227     }
228     else if (context->gl_info->supported[NV_FENCE])
229     {
230         GL_EXTCALL(glFinishFenceNV(fence->object.id));
231         checkGLcall("glFinishFenceNV");
232         ret = WINED3D_FENCE_OK;
233     }
234     else
235     {
236         ERR("Fence created without GL support.\n");
237         ret = WINED3D_FENCE_ERROR;
238     }
239 
240     context_release(context);
241     return ret;
242 }
243 
wined3d_fence_issue(struct wined3d_fence * fence,const struct wined3d_device * device)244 void wined3d_fence_issue(struct wined3d_fence *fence, const struct wined3d_device *device)
245 {
246     struct wined3d_context *context = NULL;
247     const struct wined3d_gl_info *gl_info;
248 
249     if (fence->context && !(context = context_reacquire(device, fence->context))
250             && !fence->context->gl_info->supported[ARB_SYNC])
251         context_free_fence(fence);
252     if (!context)
253         context = context_acquire(device, NULL, 0);
254     gl_info = context->gl_info;
255     if (!fence->context)
256         context_alloc_fence(context, fence);
257 
258     if (gl_info->supported[ARB_SYNC])
259     {
260         if (fence->object.sync)
261             GL_EXTCALL(glDeleteSync(fence->object.sync));
262         checkGLcall("glDeleteSync");
263         fence->object.sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
264         checkGLcall("glFenceSync");
265     }
266     else if (gl_info->supported[APPLE_FENCE])
267     {
268         GL_EXTCALL(glSetFenceAPPLE(fence->object.id));
269         checkGLcall("glSetFenceAPPLE");
270     }
271     else if (gl_info->supported[NV_FENCE])
272     {
273         GL_EXTCALL(glSetFenceNV(fence->object.id, GL_ALL_COMPLETED_NV));
274         checkGLcall("glSetFenceNV");
275     }
276 
277     context_release(context);
278 }
279 
wined3d_fence_free(struct wined3d_fence * fence)280 static void wined3d_fence_free(struct wined3d_fence *fence)
281 {
282     if (fence->context)
283         context_free_fence(fence);
284 }
285 
wined3d_fence_destroy(struct wined3d_fence * fence)286 void wined3d_fence_destroy(struct wined3d_fence *fence)
287 {
288     wined3d_fence_free(fence);
289     heap_free(fence);
290 }
291 
wined3d_fence_init(struct wined3d_fence * fence,const struct wined3d_gl_info * gl_info)292 static HRESULT wined3d_fence_init(struct wined3d_fence *fence, const struct wined3d_gl_info *gl_info)
293 {
294     if (!wined3d_fence_supported(gl_info))
295     {
296         WARN("Fences not supported.\n");
297         return WINED3DERR_NOTAVAILABLE;
298     }
299 
300     return WINED3D_OK;
301 }
302 
wined3d_fence_create(struct wined3d_device * device,struct wined3d_fence ** fence)303 HRESULT wined3d_fence_create(struct wined3d_device *device, struct wined3d_fence **fence)
304 {
305     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
306     struct wined3d_fence *object;
307     HRESULT hr;
308 
309     TRACE("device %p, fence %p.\n", device, fence);
310 
311     if (!(object = heap_alloc_zero(sizeof(*object))))
312         return E_OUTOFMEMORY;
313 
314     if (FAILED(hr = wined3d_fence_init(object, gl_info)))
315     {
316         heap_free(object);
317         return hr;
318     }
319 
320     TRACE("Created fence %p.\n", object);
321     *fence = object;
322 
323     return WINED3D_OK;
324 }
325 
wined3d_query_incref(struct wined3d_query * query)326 ULONG CDECL wined3d_query_incref(struct wined3d_query *query)
327 {
328     ULONG refcount = InterlockedIncrement(&query->ref);
329 
330     TRACE("%p increasing refcount to %u.\n", query, refcount);
331 
332     return refcount;
333 }
334 
wined3d_query_destroy_object(void * object)335 static void wined3d_query_destroy_object(void *object)
336 {
337     struct wined3d_query *query = object;
338 
339     if (!list_empty(&query->poll_list_entry))
340         list_remove(&query->poll_list_entry);
341 
342     /* Queries are specific to the GL context that created them. Not
343      * deleting the query will obviously leak it, but that's still better
344      * than potentially deleting a different query with the same id in this
345      * context, and (still) leaking the actual query. */
346     query->query_ops->query_destroy(query);
347 }
348 
wined3d_query_decref(struct wined3d_query * query)349 ULONG CDECL wined3d_query_decref(struct wined3d_query *query)
350 {
351     ULONG refcount = InterlockedDecrement(&query->ref);
352 
353     TRACE("%p decreasing refcount to %u.\n", query, refcount);
354 
355     if (!refcount)
356     {
357         query->parent_ops->wined3d_object_destroyed(query->parent);
358         wined3d_cs_destroy_object(query->device->cs, wined3d_query_destroy_object, query);
359     }
360 
361     return refcount;
362 }
363 
wined3d_query_get_data(struct wined3d_query * query,void * data,UINT data_size,DWORD flags)364 HRESULT CDECL wined3d_query_get_data(struct wined3d_query *query,
365         void *data, UINT data_size, DWORD flags)
366 {
367     TRACE("query %p, data %p, data_size %u, flags %#x.\n",
368             query, data, data_size, flags);
369 
370     if (flags)
371         WARN("Ignoring flags %#x.\n", flags);
372 
373     if (query->state == QUERY_BUILDING)
374     {
375         WARN("Query is building, returning S_FALSE.\n");
376         return S_FALSE;
377     }
378 
379     if (query->state == QUERY_CREATED)
380     {
381         WARN("Query wasn't started yet.\n");
382         return WINED3DERR_INVALIDCALL;
383     }
384 
385     if (!query->device->cs->thread)
386     {
387         if (!query->query_ops->query_poll(query, flags))
388             return S_FALSE;
389     }
390     else if (query->counter_main != query->counter_retrieved)
391     {
392         if (flags & WINED3DGETDATA_FLUSH && !query->device->cs->queries_flushed)
393             wined3d_cs_emit_flush(query->device->cs);
394         return S_FALSE;
395     }
396 
397     if (data)
398         memcpy(data, query->data, min(data_size, query->data_size));
399 
400     return S_OK;
401 }
402 
wined3d_query_get_data_size(const struct wined3d_query * query)403 UINT CDECL wined3d_query_get_data_size(const struct wined3d_query *query)
404 {
405     TRACE("query %p.\n", query);
406 
407     return query->data_size;
408 }
409 
wined3d_query_issue(struct wined3d_query * query,DWORD flags)410 HRESULT CDECL wined3d_query_issue(struct wined3d_query *query, DWORD flags)
411 {
412     TRACE("query %p, flags %#x.\n", query, flags);
413 
414     if (flags & WINED3DISSUE_END)
415         ++query->counter_main;
416 
417     wined3d_cs_emit_query_issue(query->device->cs, query, flags);
418 
419     if (flags & WINED3DISSUE_BEGIN)
420         query->state = QUERY_BUILDING;
421     else
422         query->state = QUERY_SIGNALLED;
423 
424     return WINED3D_OK;
425 }
426 
wined3d_occlusion_query_ops_poll(struct wined3d_query * query,DWORD flags)427 static BOOL wined3d_occlusion_query_ops_poll(struct wined3d_query *query, DWORD flags)
428 {
429     struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
430     struct wined3d_device *device = query->device;
431     const struct wined3d_gl_info *gl_info;
432     struct wined3d_context *context;
433     GLuint available;
434 
435     TRACE("query %p, flags %#x.\n", query, flags);
436 
437     if (!(context = context_reacquire(device, oq->context)))
438     {
439         FIXME("%p Wrong thread, returning 1.\n", query);
440         oq->samples = 1;
441         return TRUE;
442     }
443     gl_info = context->gl_info;
444 
445     GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT_AVAILABLE, &available));
446     TRACE("Available %#x.\n", available);
447 
448     if (available)
449     {
450         oq->samples = get_query_result64(oq->id, gl_info);
451         TRACE("Returning 0x%s samples.\n", wine_dbgstr_longlong(oq->samples));
452     }
453 
454     checkGLcall("poll occlusion query");
455     context_release(context);
456 
457     return available;
458 }
459 
wined3d_event_query_ops_poll(struct wined3d_query * query,DWORD flags)460 static BOOL wined3d_event_query_ops_poll(struct wined3d_query *query, DWORD flags)
461 {
462     struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
463     enum wined3d_fence_result ret;
464 
465     TRACE("query %p, flags %#x.\n", query, flags);
466 
467     ret = wined3d_fence_test(&event_query->fence, query->device, flags);
468     switch (ret)
469     {
470         case WINED3D_FENCE_OK:
471         case WINED3D_FENCE_NOT_STARTED:
472             return event_query->signalled = TRUE;
473 
474         case WINED3D_FENCE_WAITING:
475             return event_query->signalled = FALSE;
476 
477         case WINED3D_FENCE_WRONG_THREAD:
478             FIXME("(%p) Wrong thread, reporting GPU idle.\n", query);
479             return event_query->signalled = TRUE;
480 
481         case WINED3D_FENCE_ERROR:
482             ERR("The GL event query failed.\n");
483             return event_query->signalled = TRUE;
484 
485         default:
486             ERR("Unexpected wined3d_event_query_test result %#x.\n", ret);
487             return event_query->signalled = TRUE;
488     }
489 }
490 
wined3d_query_get_parent(const struct wined3d_query * query)491 void * CDECL wined3d_query_get_parent(const struct wined3d_query *query)
492 {
493     TRACE("query %p.\n", query);
494 
495     return query->parent;
496 }
497 
wined3d_query_get_type(const struct wined3d_query * query)498 enum wined3d_query_type CDECL wined3d_query_get_type(const struct wined3d_query *query)
499 {
500     TRACE("query %p.\n", query);
501 
502     return query->type;
503 }
504 
wined3d_event_query_ops_issue(struct wined3d_query * query,DWORD flags)505 static BOOL wined3d_event_query_ops_issue(struct wined3d_query *query, DWORD flags)
506 {
507     TRACE("query %p, flags %#x.\n", query, flags);
508 
509     if (flags & WINED3DISSUE_END)
510     {
511         struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
512 
513         wined3d_fence_issue(&event_query->fence, query->device);
514         return TRUE;
515     }
516     else if (flags & WINED3DISSUE_BEGIN)
517     {
518         /* Started implicitly at query creation. */
519         ERR("Event query issued with START flag - what to do?\n");
520     }
521 
522     return FALSE;
523 }
524 
wined3d_occlusion_query_ops_issue(struct wined3d_query * query,DWORD flags)525 static BOOL wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DWORD flags)
526 {
527     struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
528     struct wined3d_device *device = query->device;
529     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
530     struct wined3d_context *context;
531     BOOL poll = FALSE;
532 
533     TRACE("query %p, flags %#x.\n", query, flags);
534 
535     /* This is allowed according to MSDN and our tests. Reset the query and
536      * restart. */
537     if (flags & WINED3DISSUE_BEGIN)
538     {
539         if (oq->started)
540         {
541             if ((context = context_reacquire(device, oq->context)))
542             {
543                 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
544                 checkGLcall("glEndQuery()");
545             }
546             else
547             {
548                 FIXME("Wrong thread, can't restart query.\n");
549                 context_free_occlusion_query(oq);
550                 context = context_acquire(device, NULL, 0);
551                 context_alloc_occlusion_query(context, oq);
552             }
553         }
554         else
555         {
556             if (oq->context)
557                 context_free_occlusion_query(oq);
558             context = context_acquire(device, NULL, 0);
559             context_alloc_occlusion_query(context, oq);
560         }
561 
562         GL_EXTCALL(glBeginQuery(GL_SAMPLES_PASSED, oq->id));
563         checkGLcall("glBeginQuery()");
564 
565         context_release(context);
566         oq->started = TRUE;
567     }
568     if (flags & WINED3DISSUE_END)
569     {
570         /* MSDN says END on a non-building occlusion query returns an error,
571          * but our tests show that it returns OK. But OpenGL doesn't like it,
572          * so avoid generating an error. */
573         if (oq->started)
574         {
575             if ((context = context_reacquire(device, oq->context)))
576             {
577                 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
578                 checkGLcall("glEndQuery()");
579 
580                 context_release(context);
581                 poll = TRUE;
582             }
583             else
584             {
585                 FIXME("Wrong thread, can't end query.\n");
586             }
587         }
588         oq->started = FALSE;
589     }
590 
591     return poll;
592 }
593 
wined3d_timestamp_query_ops_poll(struct wined3d_query * query,DWORD flags)594 static BOOL wined3d_timestamp_query_ops_poll(struct wined3d_query *query, DWORD flags)
595 {
596     struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
597     struct wined3d_device *device = query->device;
598     const struct wined3d_gl_info *gl_info;
599     struct wined3d_context *context;
600     GLuint64 timestamp;
601     GLuint available;
602 
603     TRACE("query %p, flags %#x.\n", query, flags);
604 
605     if (!(context = context_reacquire(device, tq->context)))
606     {
607         FIXME("%p Wrong thread, returning 1.\n", query);
608         tq->timestamp = 1;
609         return TRUE;
610     }
611     gl_info = context->gl_info;
612 
613     GL_EXTCALL(glGetQueryObjectuiv(tq->id, GL_QUERY_RESULT_AVAILABLE, &available));
614     checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
615     TRACE("available %#x.\n", available);
616 
617     if (available)
618     {
619         GL_EXTCALL(glGetQueryObjectui64v(tq->id, GL_QUERY_RESULT, &timestamp));
620         checkGLcall("glGetQueryObjectui64v(GL_QUERY_RESULT)");
621         TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp));
622         tq->timestamp = timestamp;
623     }
624 
625     context_release(context);
626 
627     return available;
628 }
629 
wined3d_timestamp_query_ops_issue(struct wined3d_query * query,DWORD flags)630 static BOOL wined3d_timestamp_query_ops_issue(struct wined3d_query *query, DWORD flags)
631 {
632     struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
633     const struct wined3d_gl_info *gl_info;
634     struct wined3d_context *context;
635 
636     TRACE("query %p, flags %#x.\n", query, flags);
637 
638     if (flags & WINED3DISSUE_BEGIN)
639     {
640         WARN("Ignoring WINED3DISSUE_BEGIN with a TIMESTAMP query.\n");
641     }
642     if (flags & WINED3DISSUE_END)
643     {
644         if (tq->context)
645             context_free_timestamp_query(tq);
646         context = context_acquire(query->device, NULL, 0);
647         gl_info = context->gl_info;
648         context_alloc_timestamp_query(context, tq);
649         GL_EXTCALL(glQueryCounter(tq->id, GL_TIMESTAMP));
650         checkGLcall("glQueryCounter()");
651         context_release(context);
652 
653         return TRUE;
654     }
655 
656     return FALSE;
657 }
658 
wined3d_timestamp_disjoint_query_ops_poll(struct wined3d_query * query,DWORD flags)659 static BOOL wined3d_timestamp_disjoint_query_ops_poll(struct wined3d_query *query, DWORD flags)
660 {
661     TRACE("query %p, flags %#x.\n", query, flags);
662 
663     return TRUE;
664 }
665 
wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query * query,DWORD flags)666 static BOOL wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query *query, DWORD flags)
667 {
668     TRACE("query %p, flags %#x.\n", query, flags);
669 
670     return FALSE;
671 }
672 
wined3d_so_statistics_query_ops_poll(struct wined3d_query * query,DWORD flags)673 static BOOL wined3d_so_statistics_query_ops_poll(struct wined3d_query *query, DWORD flags)
674 {
675     struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
676     struct wined3d_device *device = query->device;
677     GLuint written_available, generated_available;
678     const struct wined3d_gl_info *gl_info;
679     struct wined3d_context *context;
680 
681     TRACE("query %p, flags %#x.\n", query, flags);
682 
683     if (!(context = context_reacquire(device, pq->context)))
684     {
685         FIXME("%p Wrong thread, returning 0 primitives.\n", query);
686         memset(&pq->statistics, 0, sizeof(pq->statistics));
687         return TRUE;
688     }
689     gl_info = context->gl_info;
690 
691     GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.written,
692             GL_QUERY_RESULT_AVAILABLE, &written_available));
693     GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.generated,
694             GL_QUERY_RESULT_AVAILABLE, &generated_available));
695     TRACE("Available %#x, %#x.\n", written_available, generated_available);
696 
697     if (written_available && generated_available)
698     {
699         pq->statistics.primitives_written = get_query_result64(pq->u.query.written, gl_info);
700         pq->statistics.primitives_generated = get_query_result64(pq->u.query.generated, gl_info);
701         TRACE("Returning %s, %s primitives.\n",
702                 wine_dbgstr_longlong(pq->statistics.primitives_written),
703                 wine_dbgstr_longlong(pq->statistics.primitives_generated));
704     }
705 
706     checkGLcall("poll SO statistics query");
707     context_release(context);
708 
709     return written_available && generated_available;
710 }
711 
wined3d_so_statistics_query_ops_issue(struct wined3d_query * query,DWORD flags)712 static BOOL wined3d_so_statistics_query_ops_issue(struct wined3d_query *query, DWORD flags)
713 {
714     struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
715     struct wined3d_device *device = query->device;
716     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
717     struct wined3d_context *context;
718     BOOL poll = FALSE;
719 
720     TRACE("query %p, flags %#x.\n", query, flags);
721 
722     if (flags & WINED3DISSUE_BEGIN)
723     {
724         if (pq->started)
725         {
726             if ((context = context_reacquire(device, pq->context)))
727             {
728                 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, pq->stream_idx));
729                 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED, pq->stream_idx));
730             }
731             else
732             {
733                 FIXME("Wrong thread, can't restart query.\n");
734                 context_free_so_statistics_query(pq);
735                 context = context_acquire(device, NULL, 0);
736                 context_alloc_so_statistics_query(context, pq);
737             }
738         }
739         else
740         {
741             if (pq->context)
742                 context_free_so_statistics_query(pq);
743             context = context_acquire(device, NULL, 0);
744             context_alloc_so_statistics_query(context, pq);
745         }
746 
747         GL_EXTCALL(glBeginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
748                 pq->stream_idx, pq->u.query.written));
749         GL_EXTCALL(glBeginQueryIndexed(GL_PRIMITIVES_GENERATED,
750                 pq->stream_idx, pq->u.query.generated));
751         checkGLcall("begin query");
752 
753         context_release(context);
754         pq->started = TRUE;
755     }
756     if (flags & WINED3DISSUE_END)
757     {
758         if (pq->started)
759         {
760             if ((context = context_reacquire(device, pq->context)))
761             {
762                 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, pq->stream_idx));
763                 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED, pq->stream_idx));
764                 checkGLcall("end query");
765 
766                 context_release(context);
767                 poll = TRUE;
768             }
769             else
770             {
771                 FIXME("Wrong thread, can't end query.\n");
772             }
773         }
774         pq->started = FALSE;
775     }
776 
777     return poll;
778 }
779 
wined3d_pipeline_query_ops_poll(struct wined3d_query * query,DWORD flags)780 static BOOL wined3d_pipeline_query_ops_poll(struct wined3d_query *query, DWORD flags)
781 {
782     struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
783     struct wined3d_device *device = query->device;
784     const struct wined3d_gl_info *gl_info;
785     struct wined3d_context *context;
786     GLuint available;
787     int i;
788 
789     TRACE("query %p, flags %#x.\n", query, flags);
790 
791     if (!(context = context_reacquire(device, pq->context)))
792     {
793         FIXME("%p Wrong thread.\n", query);
794         memset(&pq->statistics, 0, sizeof(pq->statistics));
795         return TRUE;
796     }
797     gl_info = context->gl_info;
798 
799     for (i = 0; i < ARRAY_SIZE(pq->u.id); ++i)
800     {
801         GL_EXTCALL(glGetQueryObjectuiv(pq->u.id[i], GL_QUERY_RESULT_AVAILABLE, &available));
802         if (!available)
803             break;
804     }
805 
806     if (available)
807     {
808         pq->statistics.vertices_submitted = get_query_result64(pq->u.query.vertices, gl_info);
809         pq->statistics.primitives_submitted = get_query_result64(pq->u.query.primitives, gl_info);
810         pq->statistics.vs_invocations = get_query_result64(pq->u.query.vertex_shader, gl_info);
811         pq->statistics.hs_invocations = get_query_result64(pq->u.query.tess_control_shader, gl_info);
812         pq->statistics.ds_invocations = get_query_result64(pq->u.query.tess_eval_shader, gl_info);
813         pq->statistics.gs_invocations = get_query_result64(pq->u.query.geometry_shader, gl_info);
814         pq->statistics.gs_primitives = get_query_result64(pq->u.query.geometry_primitives, gl_info);
815         pq->statistics.ps_invocations = get_query_result64(pq->u.query.fragment_shader, gl_info);
816         pq->statistics.cs_invocations = get_query_result64(pq->u.query.compute_shader, gl_info);
817         pq->statistics.clipping_input_primitives = get_query_result64(pq->u.query.clipping_input, gl_info);
818         pq->statistics.clipping_output_primitives = get_query_result64(pq->u.query.clipping_output, gl_info);
819     }
820 
821     checkGLcall("poll pipeline statistics query");
822     context_release(context);
823     return available;
824 }
825 
wined3d_pipeline_statistics_query_end(struct wined3d_pipeline_statistics_query * query,struct wined3d_context * context)826 static void wined3d_pipeline_statistics_query_end(struct wined3d_pipeline_statistics_query *query,
827         struct wined3d_context *context)
828 {
829     const struct wined3d_gl_info *gl_info = context->gl_info;
830 
831     GL_EXTCALL(glEndQuery(GL_VERTICES_SUBMITTED_ARB));
832     GL_EXTCALL(glEndQuery(GL_PRIMITIVES_SUBMITTED_ARB));
833     GL_EXTCALL(glEndQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB));
834     GL_EXTCALL(glEndQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB));
835     GL_EXTCALL(glEndQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB));
836     GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_INVOCATIONS));
837     GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB));
838     GL_EXTCALL(glEndQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB));
839     GL_EXTCALL(glEndQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB));
840     GL_EXTCALL(glEndQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB));
841     GL_EXTCALL(glEndQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB));
842     checkGLcall("end query");
843 }
844 
wined3d_pipeline_query_ops_issue(struct wined3d_query * query,DWORD flags)845 static BOOL wined3d_pipeline_query_ops_issue(struct wined3d_query *query, DWORD flags)
846 {
847     struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
848     struct wined3d_device *device = query->device;
849     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
850     struct wined3d_context *context;
851     BOOL poll = FALSE;
852 
853     TRACE("query %p, flags %#x.\n", query, flags);
854 
855     if (flags & WINED3DISSUE_BEGIN)
856     {
857         if (pq->started)
858         {
859             if ((context = context_reacquire(device, pq->context)))
860             {
861                 wined3d_pipeline_statistics_query_end(pq, context);
862             }
863             else
864             {
865                 FIXME("Wrong thread, can't restart query.\n");
866                 context_free_pipeline_statistics_query(pq);
867                 context = context_acquire(device, NULL, 0);
868                 context_alloc_pipeline_statistics_query(context, pq);
869             }
870         }
871         else
872         {
873             if (pq->context)
874                 context_free_pipeline_statistics_query(pq);
875             context = context_acquire(device, NULL, 0);
876             context_alloc_pipeline_statistics_query(context, pq);
877         }
878 
879         GL_EXTCALL(glBeginQuery(GL_VERTICES_SUBMITTED_ARB, pq->u.query.vertices));
880         GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_SUBMITTED_ARB, pq->u.query.primitives));
881         GL_EXTCALL(glBeginQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB, pq->u.query.vertex_shader));
882         GL_EXTCALL(glBeginQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB, pq->u.query.tess_control_shader));
883         GL_EXTCALL(glBeginQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB, pq->u.query.tess_eval_shader));
884         GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_INVOCATIONS, pq->u.query.geometry_shader));
885         GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB, pq->u.query.geometry_primitives));
886         GL_EXTCALL(glBeginQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB, pq->u.query.fragment_shader));
887         GL_EXTCALL(glBeginQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB, pq->u.query.compute_shader));
888         GL_EXTCALL(glBeginQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB, pq->u.query.clipping_input));
889         GL_EXTCALL(glBeginQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB, pq->u.query.clipping_output));
890         checkGLcall("begin query");
891 
892         context_release(context);
893         pq->started = TRUE;
894     }
895     if (flags & WINED3DISSUE_END)
896     {
897         if (pq->started)
898         {
899             if ((context = context_reacquire(device, pq->context)))
900             {
901                 wined3d_pipeline_statistics_query_end(pq, context);
902                 context_release(context);
903                 poll = TRUE;
904             }
905             else
906             {
907                 FIXME("Wrong thread, can't end query.\n");
908             }
909         }
910         pq->started = FALSE;
911     }
912 
913     return poll;
914 }
915 
wined3d_statistics_query_ops_poll(struct wined3d_query * query,DWORD flags)916 static BOOL wined3d_statistics_query_ops_poll(struct wined3d_query *query, DWORD flags)
917 {
918     TRACE("query %p, flags %#x.\n", query, flags);
919 
920     return TRUE;
921 }
922 
wined3d_statistics_query_ops_issue(struct wined3d_query * query,DWORD flags)923 static BOOL wined3d_statistics_query_ops_issue(struct wined3d_query *query, DWORD flags)
924 {
925     FIXME("query %p, flags %#x.\n", query, flags);
926 
927     return FALSE;
928 }
929 
wined3d_overflow_query_ops_poll(struct wined3d_query * query,DWORD flags)930 static BOOL wined3d_overflow_query_ops_poll(struct wined3d_query *query, DWORD flags)
931 {
932     TRACE("query %p, flags %#x.\n", query, flags);
933 
934     return TRUE;
935 }
936 
wined3d_overflow_query_ops_issue(struct wined3d_query * query,DWORD flags)937 static BOOL wined3d_overflow_query_ops_issue(struct wined3d_query *query, DWORD flags)
938 {
939     FIXME("query %p, flags %#x.\n", query, flags);
940 
941     return FALSE;
942 }
943 
wined3d_event_query_ops_destroy(struct wined3d_query * query)944 static void wined3d_event_query_ops_destroy(struct wined3d_query *query)
945 {
946     struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
947 
948     wined3d_fence_free(&event_query->fence);
949     heap_free(event_query);
950 }
951 
952 static const struct wined3d_query_ops event_query_ops =
953 {
954     wined3d_event_query_ops_poll,
955     wined3d_event_query_ops_issue,
956     wined3d_event_query_ops_destroy,
957 };
958 
wined3d_event_query_create(struct wined3d_device * device,enum wined3d_query_type type,void * parent,const struct wined3d_parent_ops * parent_ops,struct wined3d_query ** query)959 static HRESULT wined3d_event_query_create(struct wined3d_device *device,
960         enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
961         struct wined3d_query **query)
962 {
963     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
964     struct wined3d_event_query *object;
965     HRESULT hr;
966 
967     TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
968             device, type, parent, parent_ops, query);
969 
970     if (!(object = heap_alloc_zero(sizeof(*object))))
971         return E_OUTOFMEMORY;
972 
973     if (FAILED(hr = wined3d_fence_init(&object->fence, gl_info)))
974     {
975         WARN("Event queries not supported.\n");
976         heap_free(object);
977         return hr;
978     }
979 
980     wined3d_query_init(&object->query, device, type, &object->signalled,
981             sizeof(object->signalled), &event_query_ops, parent, parent_ops);
982 
983     TRACE("Created query %p.\n", object);
984     *query = &object->query;
985 
986     return WINED3D_OK;
987 }
988 
wined3d_occlusion_query_ops_destroy(struct wined3d_query * query)989 static void wined3d_occlusion_query_ops_destroy(struct wined3d_query *query)
990 {
991     struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
992 
993     if (oq->context)
994         context_free_occlusion_query(oq);
995     heap_free(oq);
996 }
997 
998 static const struct wined3d_query_ops occlusion_query_ops =
999 {
1000     wined3d_occlusion_query_ops_poll,
1001     wined3d_occlusion_query_ops_issue,
1002     wined3d_occlusion_query_ops_destroy,
1003 };
1004 
wined3d_occlusion_query_create(struct wined3d_device * device,enum wined3d_query_type type,void * parent,const struct wined3d_parent_ops * parent_ops,struct wined3d_query ** query)1005 static HRESULT wined3d_occlusion_query_create(struct wined3d_device *device,
1006         enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1007         struct wined3d_query **query)
1008 {
1009     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1010     struct wined3d_occlusion_query *object;
1011 
1012     TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1013             device, type, parent, parent_ops, query);
1014 
1015     if (!gl_info->supported[ARB_OCCLUSION_QUERY])
1016     {
1017         WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
1018         return WINED3DERR_NOTAVAILABLE;
1019     }
1020 
1021     if (!(object = heap_alloc_zero(sizeof(*object))))
1022         return E_OUTOFMEMORY;
1023 
1024     wined3d_query_init(&object->query, device, type, &object->samples,
1025             sizeof(object->samples), &occlusion_query_ops, parent, parent_ops);
1026 
1027     TRACE("Created query %p.\n", object);
1028     *query = &object->query;
1029 
1030     return WINED3D_OK;
1031 }
1032 
wined3d_timestamp_query_ops_destroy(struct wined3d_query * query)1033 static void wined3d_timestamp_query_ops_destroy(struct wined3d_query *query)
1034 {
1035     struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
1036 
1037     if (tq->context)
1038         context_free_timestamp_query(tq);
1039     heap_free(tq);
1040 }
1041 
1042 static const struct wined3d_query_ops timestamp_query_ops =
1043 {
1044     wined3d_timestamp_query_ops_poll,
1045     wined3d_timestamp_query_ops_issue,
1046     wined3d_timestamp_query_ops_destroy,
1047 };
1048 
wined3d_timestamp_query_create(struct wined3d_device * device,enum wined3d_query_type type,void * parent,const struct wined3d_parent_ops * parent_ops,struct wined3d_query ** query)1049 static HRESULT wined3d_timestamp_query_create(struct wined3d_device *device,
1050         enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1051         struct wined3d_query **query)
1052 {
1053     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1054     struct wined3d_timestamp_query *object;
1055 
1056     TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1057             device, type, parent, parent_ops, query);
1058 
1059     if (!gl_info->supported[ARB_TIMER_QUERY])
1060     {
1061         WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1062         return WINED3DERR_NOTAVAILABLE;
1063     }
1064 
1065     if (!(object = heap_alloc_zero(sizeof(*object))))
1066         return E_OUTOFMEMORY;
1067 
1068     wined3d_query_init(&object->query, device, type, &object->timestamp,
1069             sizeof(object->timestamp), &timestamp_query_ops, parent, parent_ops);
1070 
1071     TRACE("Created query %p.\n", object);
1072     *query = &object->query;
1073 
1074     return WINED3D_OK;
1075 }
1076 
wined3d_timestamp_disjoint_query_ops_destroy(struct wined3d_query * query)1077 static void wined3d_timestamp_disjoint_query_ops_destroy(struct wined3d_query *query)
1078 {
1079     heap_free(query);
1080 }
1081 
1082 static const struct wined3d_query_ops timestamp_disjoint_query_ops =
1083 {
1084     wined3d_timestamp_disjoint_query_ops_poll,
1085     wined3d_timestamp_disjoint_query_ops_issue,
1086     wined3d_timestamp_disjoint_query_ops_destroy,
1087 };
1088 
wined3d_timestamp_disjoint_query_create(struct wined3d_device * device,enum wined3d_query_type type,void * parent,const struct wined3d_parent_ops * parent_ops,struct wined3d_query ** query)1089 static HRESULT wined3d_timestamp_disjoint_query_create(struct wined3d_device *device,
1090         enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1091         struct wined3d_query **query)
1092 {
1093     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1094     struct wined3d_query *object;
1095 
1096     TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1097             device, type, parent, parent_ops, query);
1098 
1099     if (!gl_info->supported[ARB_TIMER_QUERY])
1100     {
1101         WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1102         return WINED3DERR_NOTAVAILABLE;
1103     }
1104 
1105     if (!(object = heap_alloc_zero(sizeof(*object))))
1106         return E_OUTOFMEMORY;
1107 
1108     if (type == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT)
1109     {
1110         static const struct wined3d_query_data_timestamp_disjoint disjoint_data = {1000 * 1000 * 1000, FALSE};
1111 
1112         wined3d_query_init(object, device, type, &disjoint_data,
1113                 sizeof(disjoint_data), &timestamp_disjoint_query_ops, parent, parent_ops);
1114     }
1115     else
1116     {
1117         static const UINT64 freq = 1000 * 1000 * 1000;
1118 
1119         wined3d_query_init(object, device, type, &freq,
1120                 sizeof(freq), &timestamp_disjoint_query_ops, parent, parent_ops);
1121     }
1122 
1123     TRACE("Created query %p.\n", object);
1124     *query = object;
1125 
1126     return WINED3D_OK;
1127 }
1128 
wined3d_so_statistics_query_ops_destroy(struct wined3d_query * query)1129 static void wined3d_so_statistics_query_ops_destroy(struct wined3d_query *query)
1130 {
1131     struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
1132 
1133     if (pq->context)
1134         context_free_so_statistics_query(pq);
1135     heap_free(pq);
1136 }
1137 
1138 static const struct wined3d_query_ops so_statistics_query_ops =
1139 {
1140     wined3d_so_statistics_query_ops_poll,
1141     wined3d_so_statistics_query_ops_issue,
1142     wined3d_so_statistics_query_ops_destroy,
1143 };
1144 
wined3d_so_statistics_query_create(struct wined3d_device * device,enum wined3d_query_type type,void * parent,const struct wined3d_parent_ops * parent_ops,struct wined3d_query ** query)1145 static HRESULT wined3d_so_statistics_query_create(struct wined3d_device *device,
1146         enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1147         struct wined3d_query **query)
1148 {
1149     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1150     struct wined3d_so_statistics_query *object;
1151     unsigned int stream_idx;
1152 
1153     if (WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0 <= type && type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1154         stream_idx = type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0;
1155     else
1156         return WINED3DERR_NOTAVAILABLE;
1157 
1158     TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1159             device, type, parent, parent_ops, query);
1160 
1161     if (!gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY])
1162     {
1163         WARN("OpenGL implementation does not support primitive queries.\n");
1164         return WINED3DERR_NOTAVAILABLE;
1165     }
1166     if (!gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
1167     {
1168         WARN("OpenGL implementation does not support indexed queries.\n");
1169         return WINED3DERR_NOTAVAILABLE;
1170     }
1171 
1172     if (!(object = heap_alloc_zero(sizeof(*object))))
1173         return E_OUTOFMEMORY;
1174 
1175     wined3d_query_init(&object->query, device, type, &object->statistics,
1176             sizeof(object->statistics), &so_statistics_query_ops, parent, parent_ops);
1177     object->stream_idx = stream_idx;
1178 
1179     TRACE("Created query %p.\n", object);
1180     *query = &object->query;
1181 
1182     return WINED3D_OK;
1183 }
1184 
wined3d_pipeline_query_ops_destroy(struct wined3d_query * query)1185 static void wined3d_pipeline_query_ops_destroy(struct wined3d_query *query)
1186 {
1187     struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
1188     if (pq->context)
1189         context_free_pipeline_statistics_query(pq);
1190     heap_free(pq);
1191 }
1192 
1193 static const struct wined3d_query_ops pipeline_query_ops =
1194 {
1195     wined3d_pipeline_query_ops_poll,
1196     wined3d_pipeline_query_ops_issue,
1197     wined3d_pipeline_query_ops_destroy,
1198 };
1199 
wined3d_pipeline_query_create(struct wined3d_device * device,enum wined3d_query_type type,void * parent,const struct wined3d_parent_ops * parent_ops,struct wined3d_query ** query)1200 static HRESULT wined3d_pipeline_query_create(struct wined3d_device *device,
1201         enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1202         struct wined3d_query **query)
1203 {
1204     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1205     struct wined3d_pipeline_statistics_query *object;
1206 
1207     TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1208             device, type, parent, parent_ops, query);
1209 
1210     if (!gl_info->supported[ARB_PIPELINE_STATISTICS_QUERY])
1211     {
1212         WARN("OpenGL implementation does not support pipeline statistics queries.\n");
1213         return WINED3DERR_NOTAVAILABLE;
1214     }
1215 
1216     if (!(object = heap_alloc_zero(sizeof(*object))))
1217         return E_OUTOFMEMORY;
1218 
1219     wined3d_query_init(&object->query, device, type, &object->statistics,
1220             sizeof(object->statistics), &pipeline_query_ops, parent, parent_ops);
1221 
1222     TRACE("Created query %p.\n", object);
1223     *query = &object->query;
1224 
1225     return WINED3D_OK;
1226 }
1227 
wined3d_statistics_query_ops_destroy(struct wined3d_query * query)1228 static void wined3d_statistics_query_ops_destroy(struct wined3d_query *query)
1229 {
1230     HeapFree(GetProcessHeap(), 0, query);
1231 }
1232 
1233 static const struct wined3d_query_ops statistics_query_ops =
1234 {
1235     wined3d_statistics_query_ops_poll,
1236     wined3d_statistics_query_ops_issue,
1237     wined3d_statistics_query_ops_destroy,
1238 };
1239 
wined3d_statistics_query_create(struct wined3d_device * device,enum wined3d_query_type type,void * parent,const struct wined3d_parent_ops * parent_ops,struct wined3d_query ** query)1240 static HRESULT wined3d_statistics_query_create(struct wined3d_device *device,
1241         enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1242         struct wined3d_query **query)
1243 {
1244     static const struct wined3d_query_data_so_statistics statistics = { 1, 1 };
1245     struct wined3d_query *object;
1246 
1247     FIXME("device %p, type %#x, parent %p, query %p.\n", device, type, parent, query);
1248 
1249     if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
1250         return E_OUTOFMEMORY;
1251 
1252     wined3d_query_init(object, device, type, &statistics,
1253             sizeof(statistics), &statistics_query_ops, parent, parent_ops);
1254 
1255     TRACE("Created query %p.\n", object);
1256     *query = object;
1257 
1258     return WINED3D_OK;
1259 }
1260 
wined3d_overflow_query_ops_destroy(struct wined3d_query * query)1261 static void wined3d_overflow_query_ops_destroy(struct wined3d_query *query)
1262 {
1263     HeapFree(GetProcessHeap(), 0, query);
1264 }
1265 
1266 static const struct wined3d_query_ops overflow_query_ops =
1267 {
1268     wined3d_overflow_query_ops_poll,
1269     wined3d_overflow_query_ops_issue,
1270     wined3d_overflow_query_ops_destroy,
1271 };
1272 
wined3d_overflow_query_create(struct wined3d_device * device,enum wined3d_query_type type,void * parent,const struct wined3d_parent_ops * parent_ops,struct wined3d_query ** query)1273 static HRESULT wined3d_overflow_query_create(struct wined3d_device *device,
1274         enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1275         struct wined3d_query **query)
1276 {
1277     static const BOOL overflow = FALSE;
1278     struct wined3d_query *object;
1279 
1280     FIXME("device %p, type %#x, parent %p, query %p.\n", device, type, parent, query);
1281 
1282     if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
1283         return E_OUTOFMEMORY;
1284 
1285     wined3d_query_init(object, device, type, &overflow,
1286             sizeof(overflow), &overflow_query_ops, parent, parent_ops);
1287 
1288     TRACE("Created query %p.\n", object);
1289     *query = object;
1290 
1291     return WINED3D_OK;
1292 }
1293 
wined3d_query_create(struct wined3d_device * device,enum wined3d_query_type type,void * parent,const struct wined3d_parent_ops * parent_ops,struct wined3d_query ** query)1294 HRESULT CDECL wined3d_query_create(struct wined3d_device *device, enum wined3d_query_type type,
1295         void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1296 {
1297     TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1298             device, type, parent, parent_ops, query);
1299 
1300     switch (type)
1301     {
1302         case WINED3D_QUERY_TYPE_EVENT:
1303             return wined3d_event_query_create(device, type, parent, parent_ops, query);
1304 
1305         case WINED3D_QUERY_TYPE_OCCLUSION:
1306             return wined3d_occlusion_query_create(device, type, parent, parent_ops, query);
1307 
1308         case WINED3D_QUERY_TYPE_TIMESTAMP:
1309             return wined3d_timestamp_query_create(device, type, parent, parent_ops, query);
1310 
1311         case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1312         case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ:
1313             return wined3d_timestamp_disjoint_query_create(device, type, parent, parent_ops, query);
1314 
1315         case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1316         case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1317         case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1318         case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1319             return wined3d_so_statistics_query_create(device, type, parent, parent_ops, query);
1320 
1321         case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1322             return wined3d_pipeline_query_create(device, type, parent, parent_ops, query);
1323 
1324         case WINED3D_QUERY_TYPE_SO_STATISTICS:
1325             return wined3d_statistics_query_create(device, type, parent, parent_ops, query);
1326 
1327         case WINED3D_QUERY_TYPE_SO_OVERFLOW:
1328             return wined3d_overflow_query_create(device, type, parent, parent_ops, query);
1329 
1330         default:
1331             FIXME("Unhandled query type %#x.\n", type);
1332             return WINED3DERR_NOTAVAILABLE;
1333     }
1334 }
1335