server: Create the initial thread as a separate request.
[wine.git] / dlls / wined3d / query.c
blob01e6bcb9905c18533c36f15a389dcb6050f82b0d
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 heap_free(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 = heap_alloc_zero(sizeof(*object))))
312 return E_OUTOFMEMORY;
314 if (FAILED(hr = wined3d_fence_init(object, gl_info)))
316 heap_free(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;
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_info = context->gl_info;
544 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
545 checkGLcall("glEndQuery()");
547 else
549 FIXME("Wrong thread, can't restart query.\n");
550 context_free_occlusion_query(oq);
551 context = context_acquire(device, NULL, 0);
552 context_alloc_occlusion_query(context, oq);
555 else
557 if (oq->context)
558 context_free_occlusion_query(oq);
559 context = context_acquire(device, NULL, 0);
560 context_alloc_occlusion_query(context, oq);
562 gl_info = context->gl_info;
564 GL_EXTCALL(glBeginQuery(GL_SAMPLES_PASSED, oq->id));
565 checkGLcall("glBeginQuery()");
567 context_release(context);
568 oq->started = TRUE;
570 if (flags & WINED3DISSUE_END)
572 /* MSDN says END on a non-building occlusion query returns an error,
573 * but our tests show that it returns OK. But OpenGL doesn't like it,
574 * so avoid generating an error. */
575 if (oq->started)
577 if ((context = context_reacquire(device, oq->context)))
579 gl_info = context->gl_info;
580 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
581 checkGLcall("glEndQuery()");
583 context_release(context);
584 poll = TRUE;
586 else
588 FIXME("Wrong thread, can't end query.\n");
591 oq->started = FALSE;
594 return poll;
597 static BOOL wined3d_timestamp_query_ops_poll(struct wined3d_query *query, DWORD flags)
599 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
600 struct wined3d_device *device = query->device;
601 const struct wined3d_gl_info *gl_info;
602 struct wined3d_context *context;
603 GLuint64 timestamp;
604 GLuint available;
606 TRACE("query %p, flags %#x.\n", query, flags);
608 if (!(context = context_reacquire(device, tq->context)))
610 FIXME("%p Wrong thread, returning 1.\n", query);
611 tq->timestamp = 1;
612 return TRUE;
614 gl_info = context->gl_info;
616 GL_EXTCALL(glGetQueryObjectuiv(tq->id, GL_QUERY_RESULT_AVAILABLE, &available));
617 checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
618 TRACE("available %#x.\n", available);
620 if (available)
622 GL_EXTCALL(glGetQueryObjectui64v(tq->id, GL_QUERY_RESULT, &timestamp));
623 checkGLcall("glGetQueryObjectui64v(GL_QUERY_RESULT)");
624 TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp));
625 tq->timestamp = timestamp;
628 context_release(context);
630 return available;
633 static BOOL wined3d_timestamp_query_ops_issue(struct wined3d_query *query, DWORD flags)
635 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
636 const struct wined3d_gl_info *gl_info;
637 struct wined3d_context *context;
639 TRACE("query %p, flags %#x.\n", query, flags);
641 if (flags & WINED3DISSUE_BEGIN)
643 WARN("Ignoring WINED3DISSUE_BEGIN with a TIMESTAMP query.\n");
645 if (flags & WINED3DISSUE_END)
647 if (tq->context)
648 context_free_timestamp_query(tq);
649 context = context_acquire(query->device, NULL, 0);
650 gl_info = context->gl_info;
651 context_alloc_timestamp_query(context, tq);
652 GL_EXTCALL(glQueryCounter(tq->id, GL_TIMESTAMP));
653 checkGLcall("glQueryCounter()");
654 context_release(context);
656 return TRUE;
659 return FALSE;
662 static BOOL wined3d_timestamp_disjoint_query_ops_poll(struct wined3d_query *query, DWORD flags)
664 TRACE("query %p, flags %#x.\n", query, flags);
666 return TRUE;
669 static BOOL wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query *query, DWORD flags)
671 TRACE("query %p, flags %#x.\n", query, flags);
673 return FALSE;
676 static BOOL wined3d_so_statistics_query_ops_poll(struct wined3d_query *query, DWORD flags)
678 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
679 struct wined3d_device *device = query->device;
680 GLuint written_available, generated_available;
681 const struct wined3d_gl_info *gl_info;
682 struct wined3d_context *context;
684 TRACE("query %p, flags %#x.\n", query, flags);
686 if (!(context = context_reacquire(device, pq->context)))
688 FIXME("%p Wrong thread, returning 0 primitives.\n", query);
689 memset(&pq->statistics, 0, sizeof(pq->statistics));
690 return TRUE;
692 gl_info = context->gl_info;
694 GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.written,
695 GL_QUERY_RESULT_AVAILABLE, &written_available));
696 GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.generated,
697 GL_QUERY_RESULT_AVAILABLE, &generated_available));
698 TRACE("Available %#x, %#x.\n", written_available, generated_available);
700 if (written_available && generated_available)
702 pq->statistics.primitives_written = get_query_result64(pq->u.query.written, gl_info);
703 pq->statistics.primitives_generated = get_query_result64(pq->u.query.generated, gl_info);
704 TRACE("Returning %s, %s primitives.\n",
705 wine_dbgstr_longlong(pq->statistics.primitives_written),
706 wine_dbgstr_longlong(pq->statistics.primitives_generated));
709 checkGLcall("poll SO statistics query");
710 context_release(context);
712 return written_available && generated_available;
715 static BOOL wined3d_so_statistics_query_ops_issue(struct wined3d_query *query, DWORD flags)
717 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
718 struct wined3d_device *device = query->device;
719 const struct wined3d_gl_info *gl_info;
720 struct wined3d_context *context;
721 BOOL poll = FALSE;
723 TRACE("query %p, flags %#x.\n", query, flags);
725 if (flags & WINED3DISSUE_BEGIN)
727 if (pq->started)
729 if ((context = context_reacquire(device, pq->context)))
731 gl_info = context->gl_info;
732 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, pq->stream_idx));
733 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED, pq->stream_idx));
735 else
737 FIXME("Wrong thread, can't restart query.\n");
738 context_free_so_statistics_query(pq);
739 context = context_acquire(device, NULL, 0);
740 context_alloc_so_statistics_query(context, pq);
743 else
745 if (pq->context)
746 context_free_so_statistics_query(pq);
747 context = context_acquire(device, NULL, 0);
748 context_alloc_so_statistics_query(context, pq);
750 gl_info = context->gl_info;
752 GL_EXTCALL(glBeginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
753 pq->stream_idx, pq->u.query.written));
754 GL_EXTCALL(glBeginQueryIndexed(GL_PRIMITIVES_GENERATED,
755 pq->stream_idx, pq->u.query.generated));
756 checkGLcall("begin query");
758 context_release(context);
759 pq->started = TRUE;
761 if (flags & WINED3DISSUE_END)
763 if (pq->started)
765 if ((context = context_reacquire(device, pq->context)))
767 gl_info = context->gl_info;
768 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, pq->stream_idx));
769 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED, pq->stream_idx));
770 checkGLcall("end query");
772 context_release(context);
773 poll = TRUE;
775 else
777 FIXME("Wrong thread, can't end query.\n");
780 pq->started = FALSE;
783 return poll;
786 static BOOL wined3d_pipeline_query_ops_poll(struct wined3d_query *query, DWORD flags)
788 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
789 struct wined3d_device *device = query->device;
790 const struct wined3d_gl_info *gl_info;
791 struct wined3d_context *context;
792 GLuint available;
793 int i;
795 TRACE("query %p, flags %#x.\n", query, flags);
797 if (!(context = context_reacquire(device, pq->context)))
799 FIXME("%p Wrong thread.\n", query);
800 memset(&pq->statistics, 0, sizeof(pq->statistics));
801 return TRUE;
803 gl_info = context->gl_info;
805 for (i = 0; i < ARRAY_SIZE(pq->u.id); ++i)
807 GL_EXTCALL(glGetQueryObjectuiv(pq->u.id[i], GL_QUERY_RESULT_AVAILABLE, &available));
808 if (!available)
809 break;
812 if (available)
814 pq->statistics.vertices_submitted = get_query_result64(pq->u.query.vertices, gl_info);
815 pq->statistics.primitives_submitted = get_query_result64(pq->u.query.primitives, gl_info);
816 pq->statistics.vs_invocations = get_query_result64(pq->u.query.vertex_shader, gl_info);
817 pq->statistics.hs_invocations = get_query_result64(pq->u.query.tess_control_shader, gl_info);
818 pq->statistics.ds_invocations = get_query_result64(pq->u.query.tess_eval_shader, gl_info);
819 pq->statistics.gs_invocations = get_query_result64(pq->u.query.geometry_shader, gl_info);
820 pq->statistics.gs_primitives = get_query_result64(pq->u.query.geometry_primitives, gl_info);
821 pq->statistics.ps_invocations = get_query_result64(pq->u.query.fragment_shader, gl_info);
822 pq->statistics.cs_invocations = get_query_result64(pq->u.query.compute_shader, gl_info);
823 pq->statistics.clipping_input_primitives = get_query_result64(pq->u.query.clipping_input, gl_info);
824 pq->statistics.clipping_output_primitives = get_query_result64(pq->u.query.clipping_output, gl_info);
827 checkGLcall("poll pipeline statistics query");
828 context_release(context);
829 return available;
832 static void wined3d_pipeline_statistics_query_end(struct wined3d_pipeline_statistics_query *query,
833 struct wined3d_context *context)
835 const struct wined3d_gl_info *gl_info = context->gl_info;
837 GL_EXTCALL(glEndQuery(GL_VERTICES_SUBMITTED_ARB));
838 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_SUBMITTED_ARB));
839 GL_EXTCALL(glEndQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB));
840 GL_EXTCALL(glEndQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB));
841 GL_EXTCALL(glEndQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB));
842 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_INVOCATIONS));
843 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB));
844 GL_EXTCALL(glEndQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB));
845 GL_EXTCALL(glEndQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB));
846 GL_EXTCALL(glEndQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB));
847 GL_EXTCALL(glEndQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB));
848 checkGLcall("end query");
851 static BOOL wined3d_pipeline_query_ops_issue(struct wined3d_query *query, DWORD flags)
853 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
854 struct wined3d_device *device = query->device;
855 const struct wined3d_gl_info *gl_info;
856 struct wined3d_context *context;
857 BOOL poll = FALSE;
859 TRACE("query %p, flags %#x.\n", query, flags);
861 if (flags & WINED3DISSUE_BEGIN)
863 if (pq->started)
865 if ((context = context_reacquire(device, pq->context)))
867 wined3d_pipeline_statistics_query_end(pq, context);
869 else
871 FIXME("Wrong thread, can't restart query.\n");
872 context_free_pipeline_statistics_query(pq);
873 context = context_acquire(device, NULL, 0);
874 context_alloc_pipeline_statistics_query(context, pq);
877 else
879 if (pq->context)
880 context_free_pipeline_statistics_query(pq);
881 context = context_acquire(device, NULL, 0);
882 context_alloc_pipeline_statistics_query(context, pq);
884 gl_info = context->gl_info;
886 GL_EXTCALL(glBeginQuery(GL_VERTICES_SUBMITTED_ARB, pq->u.query.vertices));
887 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_SUBMITTED_ARB, pq->u.query.primitives));
888 GL_EXTCALL(glBeginQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB, pq->u.query.vertex_shader));
889 GL_EXTCALL(glBeginQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB, pq->u.query.tess_control_shader));
890 GL_EXTCALL(glBeginQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB, pq->u.query.tess_eval_shader));
891 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_INVOCATIONS, pq->u.query.geometry_shader));
892 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB, pq->u.query.geometry_primitives));
893 GL_EXTCALL(glBeginQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB, pq->u.query.fragment_shader));
894 GL_EXTCALL(glBeginQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB, pq->u.query.compute_shader));
895 GL_EXTCALL(glBeginQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB, pq->u.query.clipping_input));
896 GL_EXTCALL(glBeginQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB, pq->u.query.clipping_output));
897 checkGLcall("begin query");
899 context_release(context);
900 pq->started = TRUE;
902 if (flags & WINED3DISSUE_END)
904 if (pq->started)
906 if ((context = context_reacquire(device, pq->context)))
908 wined3d_pipeline_statistics_query_end(pq, context);
909 context_release(context);
910 poll = TRUE;
912 else
914 FIXME("Wrong thread, can't end query.\n");
917 pq->started = FALSE;
920 return poll;
923 static void wined3d_event_query_ops_destroy(struct wined3d_query *query)
925 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
927 wined3d_fence_free(&event_query->fence);
928 heap_free(event_query);
931 static const struct wined3d_query_ops event_query_ops =
933 wined3d_event_query_ops_poll,
934 wined3d_event_query_ops_issue,
935 wined3d_event_query_ops_destroy,
938 static HRESULT wined3d_event_query_create(struct wined3d_device *device,
939 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
940 struct wined3d_query **query)
942 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
943 struct wined3d_event_query *object;
944 HRESULT hr;
946 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
947 device, type, parent, parent_ops, query);
949 if (!(object = heap_alloc_zero(sizeof(*object))))
950 return E_OUTOFMEMORY;
952 if (FAILED(hr = wined3d_fence_init(&object->fence, gl_info)))
954 WARN("Event queries not supported.\n");
955 heap_free(object);
956 return hr;
959 wined3d_query_init(&object->query, device, type, &object->signalled,
960 sizeof(object->signalled), &event_query_ops, parent, parent_ops);
962 TRACE("Created query %p.\n", object);
963 *query = &object->query;
965 return WINED3D_OK;
968 static void wined3d_occlusion_query_ops_destroy(struct wined3d_query *query)
970 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
972 if (oq->context)
973 context_free_occlusion_query(oq);
974 heap_free(oq);
977 static const struct wined3d_query_ops occlusion_query_ops =
979 wined3d_occlusion_query_ops_poll,
980 wined3d_occlusion_query_ops_issue,
981 wined3d_occlusion_query_ops_destroy,
984 static HRESULT wined3d_occlusion_query_create(struct wined3d_device *device,
985 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
986 struct wined3d_query **query)
988 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
989 struct wined3d_occlusion_query *object;
991 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
992 device, type, parent, parent_ops, query);
994 if (!gl_info->supported[ARB_OCCLUSION_QUERY])
996 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
997 return WINED3DERR_NOTAVAILABLE;
1000 if (!(object = heap_alloc_zero(sizeof(*object))))
1001 return E_OUTOFMEMORY;
1003 wined3d_query_init(&object->query, device, type, &object->samples,
1004 sizeof(object->samples), &occlusion_query_ops, parent, parent_ops);
1006 TRACE("Created query %p.\n", object);
1007 *query = &object->query;
1009 return WINED3D_OK;
1012 static void wined3d_timestamp_query_ops_destroy(struct wined3d_query *query)
1014 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
1016 if (tq->context)
1017 context_free_timestamp_query(tq);
1018 heap_free(tq);
1021 static const struct wined3d_query_ops timestamp_query_ops =
1023 wined3d_timestamp_query_ops_poll,
1024 wined3d_timestamp_query_ops_issue,
1025 wined3d_timestamp_query_ops_destroy,
1028 static HRESULT wined3d_timestamp_query_create(struct wined3d_device *device,
1029 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1030 struct wined3d_query **query)
1032 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1033 struct wined3d_timestamp_query *object;
1035 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1036 device, type, parent, parent_ops, query);
1038 if (!gl_info->supported[ARB_TIMER_QUERY])
1040 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1041 return WINED3DERR_NOTAVAILABLE;
1044 if (!(object = heap_alloc_zero(sizeof(*object))))
1045 return E_OUTOFMEMORY;
1047 wined3d_query_init(&object->query, device, type, &object->timestamp,
1048 sizeof(object->timestamp), &timestamp_query_ops, parent, parent_ops);
1050 TRACE("Created query %p.\n", object);
1051 *query = &object->query;
1053 return WINED3D_OK;
1056 static void wined3d_timestamp_disjoint_query_ops_destroy(struct wined3d_query *query)
1058 heap_free(query);
1061 static const struct wined3d_query_ops timestamp_disjoint_query_ops =
1063 wined3d_timestamp_disjoint_query_ops_poll,
1064 wined3d_timestamp_disjoint_query_ops_issue,
1065 wined3d_timestamp_disjoint_query_ops_destroy,
1068 static HRESULT wined3d_timestamp_disjoint_query_create(struct wined3d_device *device,
1069 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1070 struct wined3d_query **query)
1072 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1073 struct wined3d_query *object;
1075 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1076 device, type, parent, parent_ops, query);
1078 if (!gl_info->supported[ARB_TIMER_QUERY])
1080 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1081 return WINED3DERR_NOTAVAILABLE;
1084 if (!(object = heap_alloc_zero(sizeof(*object))))
1085 return E_OUTOFMEMORY;
1087 if (type == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT)
1089 static const struct wined3d_query_data_timestamp_disjoint disjoint_data = {1000 * 1000 * 1000, FALSE};
1091 wined3d_query_init(object, device, type, &disjoint_data,
1092 sizeof(disjoint_data), &timestamp_disjoint_query_ops, parent, parent_ops);
1094 else
1096 static const UINT64 freq = 1000 * 1000 * 1000;
1098 wined3d_query_init(object, device, type, &freq,
1099 sizeof(freq), &timestamp_disjoint_query_ops, parent, parent_ops);
1102 TRACE("Created query %p.\n", object);
1103 *query = object;
1105 return WINED3D_OK;
1108 static void wined3d_so_statistics_query_ops_destroy(struct wined3d_query *query)
1110 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
1112 if (pq->context)
1113 context_free_so_statistics_query(pq);
1114 heap_free(pq);
1117 static const struct wined3d_query_ops so_statistics_query_ops =
1119 wined3d_so_statistics_query_ops_poll,
1120 wined3d_so_statistics_query_ops_issue,
1121 wined3d_so_statistics_query_ops_destroy,
1124 static HRESULT wined3d_so_statistics_query_create(struct wined3d_device *device,
1125 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1126 struct wined3d_query **query)
1128 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1129 struct wined3d_so_statistics_query *object;
1130 unsigned int stream_idx;
1132 if (WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0 <= type && type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1133 stream_idx = type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0;
1134 else
1135 return WINED3DERR_NOTAVAILABLE;
1137 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1138 device, type, parent, parent_ops, query);
1140 if (!gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY])
1142 WARN("OpenGL implementation does not support primitive queries.\n");
1143 return WINED3DERR_NOTAVAILABLE;
1145 if (!gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
1147 WARN("OpenGL implementation does not support indexed queries.\n");
1148 return WINED3DERR_NOTAVAILABLE;
1151 if (!(object = heap_alloc_zero(sizeof(*object))))
1152 return E_OUTOFMEMORY;
1154 wined3d_query_init(&object->query, device, type, &object->statistics,
1155 sizeof(object->statistics), &so_statistics_query_ops, parent, parent_ops);
1156 object->stream_idx = stream_idx;
1158 TRACE("Created query %p.\n", object);
1159 *query = &object->query;
1161 return WINED3D_OK;
1164 static void wined3d_pipeline_query_ops_destroy(struct wined3d_query *query)
1166 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
1167 if (pq->context)
1168 context_free_pipeline_statistics_query(pq);
1169 heap_free(pq);
1172 static const struct wined3d_query_ops pipeline_query_ops =
1174 wined3d_pipeline_query_ops_poll,
1175 wined3d_pipeline_query_ops_issue,
1176 wined3d_pipeline_query_ops_destroy,
1179 static HRESULT wined3d_pipeline_query_create(struct wined3d_device *device,
1180 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1181 struct wined3d_query **query)
1183 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1184 struct wined3d_pipeline_statistics_query *object;
1186 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1187 device, type, parent, parent_ops, query);
1189 if (!gl_info->supported[ARB_PIPELINE_STATISTICS_QUERY])
1191 WARN("OpenGL implementation does not support pipeline statistics queries.\n");
1192 return WINED3DERR_NOTAVAILABLE;
1195 if (!(object = heap_alloc_zero(sizeof(*object))))
1196 return E_OUTOFMEMORY;
1198 wined3d_query_init(&object->query, device, type, &object->statistics,
1199 sizeof(object->statistics), &pipeline_query_ops, parent, parent_ops);
1201 TRACE("Created query %p.\n", object);
1202 *query = &object->query;
1204 return WINED3D_OK;
1207 HRESULT CDECL wined3d_query_create(struct wined3d_device *device, enum wined3d_query_type type,
1208 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1210 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1211 device, type, parent, parent_ops, query);
1213 switch (type)
1215 case WINED3D_QUERY_TYPE_EVENT:
1216 return wined3d_event_query_create(device, type, parent, parent_ops, query);
1218 case WINED3D_QUERY_TYPE_OCCLUSION:
1219 return wined3d_occlusion_query_create(device, type, parent, parent_ops, query);
1221 case WINED3D_QUERY_TYPE_TIMESTAMP:
1222 return wined3d_timestamp_query_create(device, type, parent, parent_ops, query);
1224 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1225 case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ:
1226 return wined3d_timestamp_disjoint_query_create(device, type, parent, parent_ops, query);
1228 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1229 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1230 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1231 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1232 return wined3d_so_statistics_query_create(device, type, parent, parent_ops, query);
1234 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1235 return wined3d_pipeline_query_create(device, type, parent, parent_ops, query);
1237 default:
1238 FIXME("Unhandled query type %#x.\n", type);
1239 return WINED3DERR_NOTAVAILABLE;