loader: We now have a preloader on ARM64.
[wine.git] / dlls / wined3d / query.c
blob1bdaaf0284f4908af8c23b9be538d164063d3d50
1 /*
2 * Copyright 2005 Oliver Stieber
3 * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
4 * Copyright 2009-2010 Henri Verbeet for CodeWeavers.
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.
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.
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
22 #include "config.h"
23 #include "wine/port.h"
24 #include "wined3d_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
28 static UINT64 get_query_result64(GLuint id, const struct wined3d_gl_info *gl_info)
30 if (gl_info->supported[ARB_TIMER_QUERY])
32 GLuint64 result;
33 GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, &result));
34 return result;
36 else
38 GLuint result;
39 GL_EXTCALL(glGetQueryObjectuiv(id, GL_QUERY_RESULT, &result));
40 return result;
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)
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);
60 static struct wined3d_event_query *wined3d_event_query_from_query(struct wined3d_query *query)
62 return CONTAINING_RECORD(query, struct wined3d_event_query, query);
65 static struct wined3d_occlusion_query *wined3d_occlusion_query_from_query(struct wined3d_query *query)
67 return CONTAINING_RECORD(query, struct wined3d_occlusion_query, query);
70 static struct wined3d_timestamp_query *wined3d_timestamp_query_from_query(struct wined3d_query *query)
72 return CONTAINING_RECORD(query, struct wined3d_timestamp_query, query);
75 static struct wined3d_so_statistics_query *wined3d_so_statistics_query_from_query(struct wined3d_query *query)
77 return CONTAINING_RECORD(query, struct wined3d_so_statistics_query, query);
80 static struct wined3d_pipeline_statistics_query *wined3d_pipeline_statistics_query_from_query(
81 struct wined3d_query *query)
83 return CONTAINING_RECORD(query, struct wined3d_pipeline_statistics_query, query);
86 static BOOL wined3d_fence_supported(const struct wined3d_gl_info *gl_info)
88 return gl_info->supported[ARB_SYNC] || gl_info->supported[NV_FENCE] || gl_info->supported[APPLE_FENCE];
91 static enum wined3d_fence_result wined3d_fence_test(const struct wined3d_fence *fence,
92 const struct wined3d_device *device, DWORD flags)
94 const struct wined3d_gl_info *gl_info;
95 struct wined3d_context *context;
96 enum wined3d_fence_result ret;
97 BOOL fence_result;
99 TRACE("fence %p, device %p, flags %#x.\n", fence, device, flags);
101 if (!fence->context)
103 TRACE("Fence not issued.\n");
104 return WINED3D_FENCE_NOT_STARTED;
107 if (!(context = context_reacquire(device, fence->context)))
109 if (!fence->context->gl_info->supported[ARB_SYNC])
111 WARN("Fence tested from wrong thread.\n");
112 return WINED3D_FENCE_WRONG_THREAD;
114 context = context_acquire(device, NULL, 0);
116 gl_info = context->gl_info;
118 if (gl_info->supported[ARB_SYNC])
120 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
121 (flags & WINED3DGETDATA_FLUSH) ? GL_SYNC_FLUSH_COMMANDS_BIT : 0, 0));
122 checkGLcall("glClientWaitSync");
124 switch (gl_ret)
126 case GL_ALREADY_SIGNALED:
127 case GL_CONDITION_SATISFIED:
128 ret = WINED3D_FENCE_OK;
129 break;
131 case GL_TIMEOUT_EXPIRED:
132 ret = WINED3D_FENCE_WAITING;
133 break;
135 case GL_WAIT_FAILED:
136 default:
137 ERR("glClientWaitSync returned %#x.\n", gl_ret);
138 ret = WINED3D_FENCE_ERROR;
141 else if (gl_info->supported[APPLE_FENCE])
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;
150 else if (gl_info->supported[NV_FENCE])
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;
159 else
161 ERR("Fence created despite lack of GL support.\n");
162 ret = WINED3D_FENCE_ERROR;
165 context_release(context);
166 return ret;
169 enum wined3d_fence_result wined3d_fence_wait(const struct wined3d_fence *fence,
170 const struct wined3d_device *device)
172 const struct wined3d_gl_info *gl_info;
173 struct wined3d_context *context;
174 enum wined3d_fence_result ret;
176 TRACE("fence %p, device %p.\n", fence, device);
178 if (!fence->context)
180 TRACE("Fence not issued.\n");
181 return WINED3D_FENCE_NOT_STARTED;
183 gl_info = fence->context->gl_info;
185 if (!(context = context_reacquire(device, fence->context)))
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
190 if (!gl_info->supported[ARB_SYNC])
192 WARN("Fence finished from wrong thread.\n");
193 return WINED3D_FENCE_WRONG_THREAD;
195 context = context_acquire(device, NULL, 0);
197 gl_info = context->gl_info;
199 if (gl_info->supported[ARB_SYNC])
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).
205 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
206 GL_SYNC_FLUSH_COMMANDS_BIT, ~(GLuint64)0 >> 1));
207 checkGLcall("glClientWaitSync");
209 switch (gl_ret)
211 case GL_ALREADY_SIGNALED:
212 case GL_CONDITION_SATISFIED:
213 ret = WINED3D_FENCE_OK;
214 break;
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;
222 else if (context->gl_info->supported[APPLE_FENCE])
224 GL_EXTCALL(glFinishFenceAPPLE(fence->object.id));
225 checkGLcall("glFinishFenceAPPLE");
226 ret = WINED3D_FENCE_OK;
228 else if (context->gl_info->supported[NV_FENCE])
230 GL_EXTCALL(glFinishFenceNV(fence->object.id));
231 checkGLcall("glFinishFenceNV");
232 ret = WINED3D_FENCE_OK;
234 else
236 ERR("Fence created without GL support.\n");
237 ret = WINED3D_FENCE_ERROR;
240 context_release(context);
241 return ret;
244 void wined3d_fence_issue(struct wined3d_fence *fence, const struct wined3d_device *device)
246 struct wined3d_context *context = NULL;
247 const struct wined3d_gl_info *gl_info;
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);
258 if (gl_info->supported[ARB_SYNC])
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");
266 else if (gl_info->supported[APPLE_FENCE])
268 GL_EXTCALL(glSetFenceAPPLE(fence->object.id));
269 checkGLcall("glSetFenceAPPLE");
271 else if (gl_info->supported[NV_FENCE])
273 GL_EXTCALL(glSetFenceNV(fence->object.id, GL_ALL_COMPLETED_NV));
274 checkGLcall("glSetFenceNV");
277 context_release(context);
280 static void wined3d_fence_free(struct wined3d_fence *fence)
282 if (fence->context)
283 context_free_fence(fence);
286 void wined3d_fence_destroy(struct wined3d_fence *fence)
288 wined3d_fence_free(fence);
289 HeapFree(GetProcessHeap(), 0, fence);
292 static HRESULT wined3d_fence_init(struct wined3d_fence *fence, const struct wined3d_gl_info *gl_info)
294 if (!wined3d_fence_supported(gl_info))
296 WARN("Fences not supported.\n");
297 return WINED3DERR_NOTAVAILABLE;
300 return WINED3D_OK;
303 HRESULT wined3d_fence_create(struct wined3d_device *device, struct wined3d_fence **fence)
305 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
306 struct wined3d_fence *object;
307 HRESULT hr;
309 TRACE("device %p, fence %p.\n", device, fence);
311 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
312 return E_OUTOFMEMORY;
314 if (FAILED(hr = wined3d_fence_init(object, gl_info)))
316 HeapFree(GetProcessHeap(), 0, object);
317 return hr;
320 TRACE("Created fence %p.\n", object);
321 *fence = object;
323 return WINED3D_OK;
326 ULONG CDECL wined3d_query_incref(struct wined3d_query *query)
328 ULONG refcount = InterlockedIncrement(&query->ref);
330 TRACE("%p increasing refcount to %u.\n", query, refcount);
332 return refcount;
335 static void wined3d_query_destroy_object(void *object)
337 struct wined3d_query *query = object;
339 if (!list_empty(&query->poll_list_entry))
340 list_remove(&query->poll_list_entry);
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);
349 ULONG CDECL wined3d_query_decref(struct wined3d_query *query)
351 ULONG refcount = InterlockedDecrement(&query->ref);
353 TRACE("%p decreasing refcount to %u.\n", query, refcount);
355 if (!refcount)
357 query->parent_ops->wined3d_object_destroyed(query->parent);
358 wined3d_cs_destroy_object(query->device->cs, wined3d_query_destroy_object, query);
361 return refcount;
364 HRESULT CDECL wined3d_query_get_data(struct wined3d_query *query,
365 void *data, UINT data_size, DWORD flags)
367 TRACE("query %p, data %p, data_size %u, flags %#x.\n",
368 query, data, data_size, flags);
370 if (flags)
371 WARN("Ignoring flags %#x.\n", flags);
373 if (query->state == QUERY_BUILDING)
375 WARN("Query is building, returning S_FALSE.\n");
376 return S_FALSE;
379 if (query->state == QUERY_CREATED)
381 WARN("Query wasn't started yet.\n");
382 return WINED3DERR_INVALIDCALL;
385 if (!query->device->cs->thread)
387 if (!query->query_ops->query_poll(query, flags))
388 return S_FALSE;
390 else if (query->counter_main != query->counter_retrieved)
392 if (flags & WINED3DGETDATA_FLUSH && !query->device->cs->queries_flushed)
393 wined3d_cs_emit_flush(query->device->cs);
394 return S_FALSE;
397 if (data)
398 memcpy(data, query->data, min(data_size, query->data_size));
400 return S_OK;
403 UINT CDECL wined3d_query_get_data_size(const struct wined3d_query *query)
405 TRACE("query %p.\n", query);
407 return query->data_size;
410 HRESULT CDECL wined3d_query_issue(struct wined3d_query *query, DWORD flags)
412 TRACE("query %p, flags %#x.\n", query, flags);
414 if (flags & WINED3DISSUE_END)
415 ++query->counter_main;
417 wined3d_cs_emit_query_issue(query->device->cs, query, flags);
419 if (flags & WINED3DISSUE_BEGIN)
420 query->state = QUERY_BUILDING;
421 else
422 query->state = QUERY_SIGNALLED;
424 return WINED3D_OK;
427 static BOOL wined3d_occlusion_query_ops_poll(struct wined3d_query *query, DWORD flags)
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;
435 TRACE("query %p, flags %#x.\n", query, flags);
437 if (!(context = context_reacquire(device, oq->context)))
439 FIXME("%p Wrong thread, returning 1.\n", query);
440 oq->samples = 1;
441 return TRUE;
443 gl_info = context->gl_info;
445 GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT_AVAILABLE, &available));
446 TRACE("Available %#x.\n", available);
448 if (available)
450 oq->samples = get_query_result64(oq->id, gl_info);
451 TRACE("Returning 0x%s samples.\n", wine_dbgstr_longlong(oq->samples));
454 checkGLcall("poll occlusion query");
455 context_release(context);
457 return available;
460 static BOOL wined3d_event_query_ops_poll(struct wined3d_query *query, DWORD flags)
462 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
463 enum wined3d_fence_result ret;
465 TRACE("query %p, flags %#x.\n", query, flags);
467 ret = wined3d_fence_test(&event_query->fence, query->device, flags);
468 switch (ret)
470 case WINED3D_FENCE_OK:
471 case WINED3D_FENCE_NOT_STARTED:
472 return event_query->signalled = TRUE;
474 case WINED3D_FENCE_WAITING:
475 return event_query->signalled = FALSE;
477 case WINED3D_FENCE_WRONG_THREAD:
478 FIXME("(%p) Wrong thread, reporting GPU idle.\n", query);
479 return event_query->signalled = TRUE;
481 case WINED3D_FENCE_ERROR:
482 ERR("The GL event query failed.\n");
483 return event_query->signalled = TRUE;
485 default:
486 ERR("Unexpected wined3d_event_query_test result %#x.\n", ret);
487 return event_query->signalled = TRUE;
491 void * CDECL wined3d_query_get_parent(const struct wined3d_query *query)
493 TRACE("query %p.\n", query);
495 return query->parent;
498 enum wined3d_query_type CDECL wined3d_query_get_type(const struct wined3d_query *query)
500 TRACE("query %p.\n", query);
502 return query->type;
505 static BOOL wined3d_event_query_ops_issue(struct wined3d_query *query, DWORD flags)
507 TRACE("query %p, flags %#x.\n", query, flags);
509 if (flags & WINED3DISSUE_END)
511 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
513 wined3d_fence_issue(&event_query->fence, query->device);
514 return TRUE;
516 else if (flags & WINED3DISSUE_BEGIN)
518 /* Started implicitly at query creation. */
519 ERR("Event query issued with START flag - what to do?\n");
522 return FALSE;
525 static BOOL wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DWORD flags)
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;
533 TRACE("query %p, flags %#x.\n", query, flags);
535 /* This is allowed according to MSDN and our tests. Reset the query and
536 * restart. */
537 if (flags & WINED3DISSUE_BEGIN)
539 if (oq->started)
541 if ((context = context_reacquire(device, oq->context)))
543 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
544 checkGLcall("glEndQuery()");
546 else
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);
554 else
556 if (oq->context)
557 context_free_occlusion_query(oq);
558 context = context_acquire(device, NULL, 0);
559 context_alloc_occlusion_query(context, oq);
562 GL_EXTCALL(glBeginQuery(GL_SAMPLES_PASSED, oq->id));
563 checkGLcall("glBeginQuery()");
565 context_release(context);
566 oq->started = TRUE;
568 if (flags & WINED3DISSUE_END)
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)
575 if ((context = context_reacquire(device, oq->context)))
577 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
578 checkGLcall("glEndQuery()");
580 context_release(context);
581 poll = TRUE;
583 else
585 FIXME("Wrong thread, can't end query.\n");
588 oq->started = FALSE;
591 return poll;
594 static BOOL wined3d_timestamp_query_ops_poll(struct wined3d_query *query, DWORD flags)
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;
603 TRACE("query %p, flags %#x.\n", query, flags);
605 if (!(context = context_reacquire(device, tq->context)))
607 FIXME("%p Wrong thread, returning 1.\n", query);
608 tq->timestamp = 1;
609 return TRUE;
611 gl_info = context->gl_info;
613 GL_EXTCALL(glGetQueryObjectuiv(tq->id, GL_QUERY_RESULT_AVAILABLE, &available));
614 checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
615 TRACE("available %#x.\n", available);
617 if (available)
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;
625 context_release(context);
627 return available;
630 static BOOL wined3d_timestamp_query_ops_issue(struct wined3d_query *query, DWORD flags)
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;
636 TRACE("query %p, flags %#x.\n", query, flags);
638 if (flags & WINED3DISSUE_BEGIN)
640 WARN("Ignoring WINED3DISSUE_BEGIN with a TIMESTAMP query.\n");
642 if (flags & WINED3DISSUE_END)
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);
653 return TRUE;
656 return FALSE;
659 static BOOL wined3d_timestamp_disjoint_query_ops_poll(struct wined3d_query *query, DWORD flags)
661 TRACE("query %p, flags %#x.\n", query, flags);
663 return TRUE;
666 static BOOL wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query *query, DWORD flags)
668 TRACE("query %p, flags %#x.\n", query, flags);
670 return FALSE;
673 static BOOL wined3d_so_statistics_query_ops_poll(struct wined3d_query *query, DWORD flags)
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;
681 TRACE("query %p, flags %#x.\n", query, flags);
683 if (!(context = context_reacquire(device, pq->context)))
685 FIXME("%p Wrong thread, returning 0 primitives.\n", query);
686 memset(&pq->statistics, 0, sizeof(pq->statistics));
687 return TRUE;
689 gl_info = context->gl_info;
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);
697 if (written_available && generated_available)
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));
706 checkGLcall("poll SO statistics query");
707 context_release(context);
709 return written_available && generated_available;
712 static BOOL wined3d_so_statistics_query_ops_issue(struct wined3d_query *query, DWORD flags)
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;
720 TRACE("query %p, flags %#x.\n", query, flags);
722 if (flags & WINED3DISSUE_BEGIN)
724 if (pq->started)
726 if ((context = context_reacquire(device, pq->context)))
728 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, pq->stream_idx));
729 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED, pq->stream_idx));
731 else
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);
739 else
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);
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");
753 context_release(context);
754 pq->started = TRUE;
756 if (flags & WINED3DISSUE_END)
758 if (pq->started)
760 if ((context = context_reacquire(device, pq->context)))
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");
766 context_release(context);
767 poll = TRUE;
769 else
771 FIXME("Wrong thread, can't end query.\n");
774 pq->started = FALSE;
777 return poll;
780 static BOOL wined3d_pipeline_query_ops_poll(struct wined3d_query *query, DWORD flags)
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;
789 TRACE("query %p, flags %#x.\n", query, flags);
791 if (!(context = context_reacquire(device, pq->context)))
793 FIXME("%p Wrong thread.\n", query);
794 memset(&pq->statistics, 0, sizeof(pq->statistics));
795 return TRUE;
797 gl_info = context->gl_info;
799 for (i = 0; i < ARRAY_SIZE(pq->u.id); ++i)
801 GL_EXTCALL(glGetQueryObjectuiv(pq->u.id[i], GL_QUERY_RESULT_AVAILABLE, &available));
802 if (!available)
803 break;
806 if (available)
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);
821 checkGLcall("poll pipeline statistics query");
822 context_release(context);
823 return available;
826 static void wined3d_pipeline_statistics_query_end(struct wined3d_pipeline_statistics_query *query,
827 struct wined3d_context *context)
829 const struct wined3d_gl_info *gl_info = context->gl_info;
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");
845 static BOOL wined3d_pipeline_query_ops_issue(struct wined3d_query *query, DWORD flags)
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;
853 TRACE("query %p, flags %#x.\n", query, flags);
855 if (flags & WINED3DISSUE_BEGIN)
857 if (pq->started)
859 if ((context = context_reacquire(device, pq->context)))
861 wined3d_pipeline_statistics_query_end(pq, context);
863 else
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);
871 else
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);
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");
892 context_release(context);
893 pq->started = TRUE;
895 if (flags & WINED3DISSUE_END)
897 if (pq->started)
899 if ((context = context_reacquire(device, pq->context)))
901 wined3d_pipeline_statistics_query_end(pq, context);
902 context_release(context);
903 poll = TRUE;
905 else
907 FIXME("Wrong thread, can't end query.\n");
910 pq->started = FALSE;
913 return poll;
916 static void wined3d_event_query_ops_destroy(struct wined3d_query *query)
918 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
920 wined3d_fence_free(&event_query->fence);
921 HeapFree(GetProcessHeap(), 0, event_query);
924 static const struct wined3d_query_ops event_query_ops =
926 wined3d_event_query_ops_poll,
927 wined3d_event_query_ops_issue,
928 wined3d_event_query_ops_destroy,
931 static HRESULT wined3d_event_query_create(struct wined3d_device *device,
932 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
933 struct wined3d_query **query)
935 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
936 struct wined3d_event_query *object;
937 HRESULT hr;
939 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
940 device, type, parent, parent_ops, query);
942 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
943 return E_OUTOFMEMORY;
945 if (FAILED(hr = wined3d_fence_init(&object->fence, gl_info)))
947 WARN("Event queries not supported.\n");
948 HeapFree(GetProcessHeap(), 0, object);
949 return hr;
952 wined3d_query_init(&object->query, device, type, &object->signalled,
953 sizeof(object->signalled), &event_query_ops, parent, parent_ops);
955 TRACE("Created query %p.\n", object);
956 *query = &object->query;
958 return WINED3D_OK;
961 static void wined3d_occlusion_query_ops_destroy(struct wined3d_query *query)
963 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
965 if (oq->context)
966 context_free_occlusion_query(oq);
967 HeapFree(GetProcessHeap(), 0, oq);
970 static const struct wined3d_query_ops occlusion_query_ops =
972 wined3d_occlusion_query_ops_poll,
973 wined3d_occlusion_query_ops_issue,
974 wined3d_occlusion_query_ops_destroy,
977 static HRESULT wined3d_occlusion_query_create(struct wined3d_device *device,
978 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
979 struct wined3d_query **query)
981 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
982 struct wined3d_occlusion_query *object;
984 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
985 device, type, parent, parent_ops, query);
987 if (!gl_info->supported[ARB_OCCLUSION_QUERY])
989 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
990 return WINED3DERR_NOTAVAILABLE;
993 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
994 return E_OUTOFMEMORY;
996 wined3d_query_init(&object->query, device, type, &object->samples,
997 sizeof(object->samples), &occlusion_query_ops, parent, parent_ops);
999 TRACE("Created query %p.\n", object);
1000 *query = &object->query;
1002 return WINED3D_OK;
1005 static void wined3d_timestamp_query_ops_destroy(struct wined3d_query *query)
1007 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
1009 if (tq->context)
1010 context_free_timestamp_query(tq);
1011 HeapFree(GetProcessHeap(), 0, tq);
1014 static const struct wined3d_query_ops timestamp_query_ops =
1016 wined3d_timestamp_query_ops_poll,
1017 wined3d_timestamp_query_ops_issue,
1018 wined3d_timestamp_query_ops_destroy,
1021 static HRESULT wined3d_timestamp_query_create(struct wined3d_device *device,
1022 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1023 struct wined3d_query **query)
1025 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1026 struct wined3d_timestamp_query *object;
1028 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1029 device, type, parent, parent_ops, query);
1031 if (!gl_info->supported[ARB_TIMER_QUERY])
1033 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1034 return WINED3DERR_NOTAVAILABLE;
1037 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
1038 return E_OUTOFMEMORY;
1040 wined3d_query_init(&object->query, device, type, &object->timestamp,
1041 sizeof(object->timestamp), &timestamp_query_ops, parent, parent_ops);
1043 TRACE("Created query %p.\n", object);
1044 *query = &object->query;
1046 return WINED3D_OK;
1049 static void wined3d_timestamp_disjoint_query_ops_destroy(struct wined3d_query *query)
1051 HeapFree(GetProcessHeap(), 0, query);
1054 static const struct wined3d_query_ops timestamp_disjoint_query_ops =
1056 wined3d_timestamp_disjoint_query_ops_poll,
1057 wined3d_timestamp_disjoint_query_ops_issue,
1058 wined3d_timestamp_disjoint_query_ops_destroy,
1061 static HRESULT wined3d_timestamp_disjoint_query_create(struct wined3d_device *device,
1062 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1063 struct wined3d_query **query)
1065 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1066 struct wined3d_query *object;
1068 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1069 device, type, parent, parent_ops, query);
1071 if (!gl_info->supported[ARB_TIMER_QUERY])
1073 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1074 return WINED3DERR_NOTAVAILABLE;
1077 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
1078 return E_OUTOFMEMORY;
1080 if (type == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT)
1082 static const struct wined3d_query_data_timestamp_disjoint disjoint_data = {1000 * 1000 * 1000, FALSE};
1084 wined3d_query_init(object, device, type, &disjoint_data,
1085 sizeof(disjoint_data), &timestamp_disjoint_query_ops, parent, parent_ops);
1087 else
1089 static const UINT64 freq = 1000 * 1000 * 1000;
1091 wined3d_query_init(object, device, type, &freq,
1092 sizeof(freq), &timestamp_disjoint_query_ops, parent, parent_ops);
1095 TRACE("Created query %p.\n", object);
1096 *query = object;
1098 return WINED3D_OK;
1101 static void wined3d_so_statistics_query_ops_destroy(struct wined3d_query *query)
1103 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
1105 if (pq->context)
1106 context_free_so_statistics_query(pq);
1107 HeapFree(GetProcessHeap(), 0, pq);
1110 static const struct wined3d_query_ops so_statistics_query_ops =
1112 wined3d_so_statistics_query_ops_poll,
1113 wined3d_so_statistics_query_ops_issue,
1114 wined3d_so_statistics_query_ops_destroy,
1117 static HRESULT wined3d_so_statistics_query_create(struct wined3d_device *device,
1118 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1119 struct wined3d_query **query)
1121 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1122 struct wined3d_so_statistics_query *object;
1123 unsigned int stream_idx;
1125 if (WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0 <= type && type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1126 stream_idx = type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0;
1127 else
1128 return WINED3DERR_NOTAVAILABLE;
1130 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1131 device, type, parent, parent_ops, query);
1133 if (!gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY])
1135 WARN("OpenGL implementation does not support primitive queries.\n");
1136 return WINED3DERR_NOTAVAILABLE;
1138 if (!gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
1140 WARN("OpenGL implementation does not support indexed queries.\n");
1141 return WINED3DERR_NOTAVAILABLE;
1144 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
1145 return E_OUTOFMEMORY;
1147 wined3d_query_init(&object->query, device, type, &object->statistics,
1148 sizeof(object->statistics), &so_statistics_query_ops, parent, parent_ops);
1149 object->stream_idx = stream_idx;
1151 TRACE("Created query %p.\n", object);
1152 *query = &object->query;
1154 return WINED3D_OK;
1157 static void wined3d_pipeline_query_ops_destroy(struct wined3d_query *query)
1159 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
1160 if (pq->context)
1161 context_free_pipeline_statistics_query(pq);
1162 HeapFree(GetProcessHeap(), 0, pq);
1165 static const struct wined3d_query_ops pipeline_query_ops =
1167 wined3d_pipeline_query_ops_poll,
1168 wined3d_pipeline_query_ops_issue,
1169 wined3d_pipeline_query_ops_destroy,
1172 static HRESULT wined3d_pipeline_query_create(struct wined3d_device *device,
1173 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1174 struct wined3d_query **query)
1176 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1177 struct wined3d_pipeline_statistics_query *object;
1179 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1180 device, type, parent, parent_ops, query);
1182 if (!gl_info->supported[ARB_PIPELINE_STATISTICS_QUERY])
1184 WARN("OpenGL implementation does not support pipeline statistics queries.\n");
1185 return WINED3DERR_NOTAVAILABLE;
1188 if (!(object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object))))
1189 return E_OUTOFMEMORY;
1191 wined3d_query_init(&object->query, device, type, &object->statistics,
1192 sizeof(object->statistics), &pipeline_query_ops, parent, parent_ops);
1194 TRACE("Created query %p.\n", object);
1195 *query = &object->query;
1197 return WINED3D_OK;
1200 HRESULT CDECL wined3d_query_create(struct wined3d_device *device, enum wined3d_query_type type,
1201 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1203 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1204 device, type, parent, parent_ops, query);
1206 switch (type)
1208 case WINED3D_QUERY_TYPE_EVENT:
1209 return wined3d_event_query_create(device, type, parent, parent_ops, query);
1211 case WINED3D_QUERY_TYPE_OCCLUSION:
1212 return wined3d_occlusion_query_create(device, type, parent, parent_ops, query);
1214 case WINED3D_QUERY_TYPE_TIMESTAMP:
1215 return wined3d_timestamp_query_create(device, type, parent, parent_ops, query);
1217 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1218 case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ:
1219 return wined3d_timestamp_disjoint_query_create(device, type, parent, parent_ops, query);
1221 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1222 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1223 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1224 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1225 return wined3d_so_statistics_query_create(device, type, parent, parent_ops, query);
1227 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1228 return wined3d_pipeline_query_create(device, type, parent, parent_ops, query);
1230 default:
1231 FIXME("Unhandled query type %#x.\n", type);
1232 return WINED3DERR_NOTAVAILABLE;