kernelbase: Check pointer validity in unsafe_ptr_from_HLOCAL.
[wine.git] / dlls / wined3d / query.c
blob4b94cb8daeac6c3f2fb8a2838cd0822873a02ee6
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
21 #include "wined3d_private.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
25 static void wined3d_query_buffer_invalidate(struct wined3d_query *query)
27 /* map[0] != map[1]: exact values do not have any significance. */
28 query->map_ptr[0] = 0;
29 query->map_ptr[1] = ~(UINT64)0;
32 static BOOL wined3d_query_buffer_is_valid(struct wined3d_query *query)
34 return query->map_ptr[0] == query->map_ptr[1];
37 static void wined3d_query_create_buffer_object(struct wined3d_context_gl *context_gl, struct wined3d_query *query)
39 const GLuint map_flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
40 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
41 GLuint buffer_object;
43 GL_EXTCALL(glGenBuffers(1, &buffer_object));
44 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, buffer_object));
45 GL_EXTCALL(glBufferStorage(GL_QUERY_BUFFER, sizeof(query->map_ptr[0]) * 2, NULL, map_flags));
46 query->map_ptr = GL_EXTCALL(glMapBufferRange(GL_QUERY_BUFFER, 0, sizeof(query->map_ptr[0]) * 2, map_flags));
47 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, 0));
48 checkGLcall("query buffer object creation");
50 wined3d_query_buffer_invalidate(query);
51 query->buffer_object = buffer_object;
54 void wined3d_query_gl_destroy_buffer_object(struct wined3d_context_gl *context_gl, struct wined3d_query *query)
56 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
58 GL_EXTCALL(glDeleteBuffers(1, &query->buffer_object));
59 checkGLcall("query buffer object destruction");
61 query->buffer_object = 0;
62 query->map_ptr = NULL;
65 /* From ARB_occlusion_query: "Querying the state for a given occlusion query
66 * forces that occlusion query to complete within a finite amount of time."
67 * In practice, that means drivers flush when retrieving
68 * GL_QUERY_RESULT_AVAILABLE, which can be undesirable when applications use a
69 * significant number of queries. Using a persistently mapped query buffer
70 * object allows us to avoid these implicit flushes. An additional benefit is
71 * that it allows us to poll the query status from the application-thread
72 * instead of from the csmt-thread. */
73 static BOOL wined3d_query_buffer_queue_result(struct wined3d_context_gl *context_gl,
74 struct wined3d_query *query, GLuint id)
76 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
77 GLsync tmp_sync;
79 if (!gl_info->supported[ARB_QUERY_BUFFER_OBJECT] || !gl_info->supported[ARB_BUFFER_STORAGE])
80 return FALSE;
81 /* Don't use query buffers without CSMT, mainly for simplicity. */
82 if (!context_gl->c.device->cs->thread)
83 return FALSE;
85 if (query->buffer_object)
87 /* If there's still a query result in-flight for the existing buffer
88 * object (i.e., the query was restarted before we received its
89 * result), we can't reuse the existing buffer object. */
90 if (wined3d_query_buffer_is_valid(query))
91 wined3d_query_buffer_invalidate(query);
92 else
93 wined3d_query_gl_destroy_buffer_object(context_gl, query);
96 if (!query->buffer_object)
97 wined3d_query_create_buffer_object(context_gl, query);
99 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, query->buffer_object));
100 /* Read the same value twice. We know we have the result if map_ptr[0] == map_ptr[1]. */
101 GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, (void *)0));
102 GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, (void *)sizeof(query->map_ptr[0])));
103 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, 0));
104 checkGLcall("queue query result");
106 /* ARB_buffer_storage requires the client to call FenceSync with
107 * SYNC_GPU_COMMANDS_COMPLETE after the server does a write. This behavior
108 * is not enforced by Mesa.
110 tmp_sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
111 GL_EXTCALL(glDeleteSync(tmp_sync));
112 checkGLcall("query buffer sync");
114 return TRUE;
117 static UINT64 get_query_result64(GLuint id, const struct wined3d_gl_info *gl_info)
119 if (gl_info->supported[ARB_TIMER_QUERY])
121 GLuint64 result;
122 GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, &result));
123 return result;
125 else
127 GLuint result;
128 GL_EXTCALL(glGetQueryObjectuiv(id, GL_QUERY_RESULT, &result));
129 return result;
133 static void wined3d_query_init(struct wined3d_query *query, struct wined3d_device *device,
134 enum wined3d_query_type type, const void *data, DWORD data_size,
135 const struct wined3d_query_ops *query_ops, void *parent, const struct wined3d_parent_ops *parent_ops)
137 query->ref = 1;
138 query->parent = parent;
139 query->parent_ops = parent_ops;
140 query->device = device;
141 query->state = QUERY_CREATED;
142 query->type = type;
143 query->data = data;
144 query->data_size = data_size;
145 query->query_ops = query_ops;
146 query->poll_in_cs = !!device->cs->thread;
147 list_init(&query->poll_list_entry);
150 static struct wined3d_event_query *wined3d_event_query_from_query(struct wined3d_query *query)
152 return CONTAINING_RECORD(query, struct wined3d_event_query, query);
155 static struct wined3d_occlusion_query *wined3d_occlusion_query_from_query(struct wined3d_query *query)
157 return CONTAINING_RECORD(query, struct wined3d_occlusion_query, query);
160 static struct wined3d_timestamp_query *wined3d_timestamp_query_from_query(struct wined3d_query *query)
162 return CONTAINING_RECORD(query, struct wined3d_timestamp_query, query);
165 static struct wined3d_so_statistics_query *wined3d_so_statistics_query_from_query(struct wined3d_query *query)
167 return CONTAINING_RECORD(query, struct wined3d_so_statistics_query, query);
170 static struct wined3d_pipeline_statistics_query *wined3d_pipeline_statistics_query_from_query(
171 struct wined3d_query *query)
173 return CONTAINING_RECORD(query, struct wined3d_pipeline_statistics_query, query);
176 static BOOL wined3d_fence_supported(const struct wined3d_gl_info *gl_info)
178 return gl_info->supported[ARB_SYNC] || gl_info->supported[NV_FENCE] || gl_info->supported[APPLE_FENCE];
181 enum wined3d_fence_result wined3d_fence_test(const struct wined3d_fence *fence,
182 struct wined3d_device *device, DWORD flags)
184 const struct wined3d_gl_info *gl_info;
185 struct wined3d_context_gl *context_gl;
186 enum wined3d_fence_result ret;
187 BOOL fence_result;
189 TRACE("fence %p, device %p, flags %#x.\n", fence, device, flags);
191 if (!fence->context_gl)
193 TRACE("Fence not issued.\n");
194 return WINED3D_FENCE_NOT_STARTED;
197 if (!(context_gl = wined3d_context_gl_reacquire(fence->context_gl)))
199 if (!fence->context_gl->gl_info->supported[ARB_SYNC])
201 WARN("Fence tested from wrong thread.\n");
202 return WINED3D_FENCE_WRONG_THREAD;
204 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
206 gl_info = context_gl->gl_info;
208 if (gl_info->supported[ARB_SYNC])
210 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
211 (flags & WINED3DGETDATA_FLUSH) ? GL_SYNC_FLUSH_COMMANDS_BIT : 0, 0));
212 checkGLcall("glClientWaitSync");
214 switch (gl_ret)
216 case GL_ALREADY_SIGNALED:
217 case GL_CONDITION_SATISFIED:
218 ret = WINED3D_FENCE_OK;
219 break;
221 case GL_TIMEOUT_EXPIRED:
222 ret = WINED3D_FENCE_WAITING;
223 break;
225 case GL_WAIT_FAILED:
226 default:
227 ERR("glClientWaitSync returned %#x.\n", gl_ret);
228 ret = WINED3D_FENCE_ERROR;
231 else if (gl_info->supported[APPLE_FENCE])
233 fence_result = GL_EXTCALL(glTestFenceAPPLE(fence->object.id));
234 checkGLcall("glTestFenceAPPLE");
235 if (fence_result)
236 ret = WINED3D_FENCE_OK;
237 else
238 ret = WINED3D_FENCE_WAITING;
240 else if (gl_info->supported[NV_FENCE])
242 fence_result = GL_EXTCALL(glTestFenceNV(fence->object.id));
243 checkGLcall("glTestFenceNV");
244 if (fence_result)
245 ret = WINED3D_FENCE_OK;
246 else
247 ret = WINED3D_FENCE_WAITING;
249 else
251 ERR("Fence created despite lack of GL support.\n");
252 ret = WINED3D_FENCE_ERROR;
255 context_release(&context_gl->c);
256 return ret;
259 enum wined3d_fence_result wined3d_fence_wait(const struct wined3d_fence *fence,
260 struct wined3d_device *device)
262 const struct wined3d_gl_info *gl_info;
263 struct wined3d_context_gl *context_gl;
264 enum wined3d_fence_result ret;
266 TRACE("fence %p, device %p.\n", fence, device);
268 if (!fence->context_gl)
270 TRACE("Fence not issued.\n");
271 return WINED3D_FENCE_NOT_STARTED;
273 gl_info = fence->context_gl->gl_info;
275 if (!(context_gl = wined3d_context_gl_reacquire(fence->context_gl)))
277 /* A glFinish does not reliably wait for draws in other contexts. The caller has
278 * to find its own way to cope with the thread switch
280 if (!gl_info->supported[ARB_SYNC])
282 WARN("Fence finished from wrong thread.\n");
283 return WINED3D_FENCE_WRONG_THREAD;
285 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
287 gl_info = context_gl->gl_info;
289 if (gl_info->supported[ARB_SYNC])
291 /* Timeouts near 0xffffffffffffffff may immediately return GL_TIMEOUT_EXPIRED,
292 * possibly because macOS internally adds some slop to the timer. To avoid this,
293 * we use a large number that isn't near the point of overflow (macOS 10.12.5).
295 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
296 GL_SYNC_FLUSH_COMMANDS_BIT, ~(GLuint64)0 >> 1));
297 checkGLcall("glClientWaitSync");
299 switch (gl_ret)
301 case GL_ALREADY_SIGNALED:
302 case GL_CONDITION_SATISFIED:
303 ret = WINED3D_FENCE_OK;
304 break;
306 /* We don't expect a timeout for a ~292 year wait */
307 default:
308 ERR("glClientWaitSync returned %#x.\n", gl_ret);
309 ret = WINED3D_FENCE_ERROR;
312 else if (gl_info->supported[APPLE_FENCE])
314 GL_EXTCALL(glFinishFenceAPPLE(fence->object.id));
315 checkGLcall("glFinishFenceAPPLE");
316 ret = WINED3D_FENCE_OK;
318 else if (gl_info->supported[NV_FENCE])
320 GL_EXTCALL(glFinishFenceNV(fence->object.id));
321 checkGLcall("glFinishFenceNV");
322 ret = WINED3D_FENCE_OK;
324 else
326 ERR("Fence created without GL support.\n");
327 ret = WINED3D_FENCE_ERROR;
330 context_release(&context_gl->c);
331 return ret;
334 void wined3d_fence_issue(struct wined3d_fence *fence, struct wined3d_device *device)
336 struct wined3d_context_gl *context_gl = NULL;
337 const struct wined3d_gl_info *gl_info;
339 if (fence->context_gl && !(context_gl = wined3d_context_gl_reacquire(fence->context_gl))
340 && !fence->context_gl->gl_info->supported[ARB_SYNC])
341 wined3d_context_gl_free_fence(fence);
342 if (!context_gl)
343 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
344 gl_info = context_gl->gl_info;
345 if (!fence->context_gl)
346 wined3d_context_gl_alloc_fence(context_gl, fence);
348 if (gl_info->supported[ARB_SYNC])
350 if (fence->object.sync)
351 GL_EXTCALL(glDeleteSync(fence->object.sync));
352 checkGLcall("glDeleteSync");
353 fence->object.sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
354 checkGLcall("glFenceSync");
356 else if (gl_info->supported[APPLE_FENCE])
358 GL_EXTCALL(glSetFenceAPPLE(fence->object.id));
359 checkGLcall("glSetFenceAPPLE");
361 else if (gl_info->supported[NV_FENCE])
363 GL_EXTCALL(glSetFenceNV(fence->object.id, GL_ALL_COMPLETED_NV));
364 checkGLcall("glSetFenceNV");
367 context_release(&context_gl->c);
370 static void wined3d_fence_free(struct wined3d_fence *fence)
372 if (fence->context_gl)
373 wined3d_context_gl_free_fence(fence);
376 void wined3d_fence_destroy(struct wined3d_fence *fence)
378 wined3d_fence_free(fence);
379 heap_free(fence);
382 static HRESULT wined3d_fence_init(struct wined3d_fence *fence, const struct wined3d_gl_info *gl_info)
384 if (!wined3d_fence_supported(gl_info))
386 WARN("Fences not supported.\n");
387 return WINED3DERR_NOTAVAILABLE;
390 return WINED3D_OK;
393 HRESULT wined3d_fence_create(struct wined3d_device *device, struct wined3d_fence **fence)
395 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
396 struct wined3d_fence *object;
397 HRESULT hr;
399 TRACE("device %p, fence %p.\n", device, fence);
401 if (!(object = heap_alloc_zero(sizeof(*object))))
402 return E_OUTOFMEMORY;
404 if (FAILED(hr = wined3d_fence_init(object, gl_info)))
406 heap_free(object);
407 return hr;
410 TRACE("Created fence %p.\n", object);
411 *fence = object;
413 return WINED3D_OK;
416 ULONG CDECL wined3d_query_incref(struct wined3d_query *query)
418 ULONG refcount = InterlockedIncrement(&query->ref);
420 TRACE("%p increasing refcount to %u.\n", query, refcount);
422 return refcount;
425 static void wined3d_query_destroy_object(void *object)
427 struct wined3d_query *query = object;
429 TRACE("query %p.\n", query);
431 if (!list_empty(&query->poll_list_entry))
432 list_remove(&query->poll_list_entry);
435 ULONG CDECL wined3d_query_decref(struct wined3d_query *query)
437 ULONG refcount = InterlockedDecrement(&query->ref);
439 TRACE("%p decreasing refcount to %u.\n", query, refcount);
441 if (!refcount)
443 struct wined3d_device *device = query->device;
445 wined3d_mutex_lock();
446 query->parent_ops->wined3d_object_destroyed(query->parent);
447 wined3d_cs_destroy_object(device->cs, wined3d_query_destroy_object, query);
448 device->adapter->adapter_ops->adapter_destroy_query(query);
449 wined3d_mutex_unlock();
452 return refcount;
455 HRESULT CDECL wined3d_query_get_data(struct wined3d_query *query,
456 void *data, UINT data_size, DWORD flags)
458 TRACE("query %p, data %p, data_size %u, flags %#x.\n",
459 query, data, data_size, flags);
461 if (query->state == QUERY_BUILDING)
463 WARN("Query is building, returning S_FALSE.\n");
464 return S_FALSE;
467 if (query->state == QUERY_CREATED)
469 WARN("Query wasn't started yet.\n");
470 return WINED3DERR_INVALIDCALL;
473 if (query->counter_main != query->counter_retrieved
474 || (query->buffer_object && !wined3d_query_buffer_is_valid(query)))
476 if (flags & WINED3DGETDATA_FLUSH && !query->device->cs->queries_flushed)
477 query->device->cs->c.ops->flush(&query->device->cs->c);
478 return S_FALSE;
480 else if (!query->poll_in_cs && !query->query_ops->query_poll(query, flags))
482 return S_FALSE;
485 if (query->buffer_object)
486 query->data = query->map_ptr;
488 if (data)
489 memcpy(data, query->data, min(data_size, query->data_size));
491 return S_OK;
494 UINT CDECL wined3d_query_get_data_size(const struct wined3d_query *query)
496 TRACE("query %p.\n", query);
498 return query->data_size;
501 HRESULT CDECL wined3d_query_issue(struct wined3d_query *query, DWORD flags)
503 TRACE("query %p, flags %#x.\n", query, flags);
505 wined3d_device_context_issue_query(&query->device->cs->c, query, flags);
507 return WINED3D_OK;
510 static BOOL wined3d_occlusion_query_ops_poll(struct wined3d_query *query, DWORD flags)
512 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
513 const struct wined3d_gl_info *gl_info;
514 struct wined3d_context_gl *context_gl;
515 GLuint available;
517 TRACE("query %p, flags %#x.\n", query, flags);
519 if (!(context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
521 FIXME("%p Wrong thread, returning 1.\n", query);
522 oq->samples = 1;
523 return TRUE;
525 gl_info = context_gl->gl_info;
527 GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT_AVAILABLE, &available));
528 TRACE("Available %#x.\n", available);
530 if (available)
532 oq->samples = get_query_result64(oq->id, gl_info);
533 TRACE("Returning 0x%s samples.\n", wine_dbgstr_longlong(oq->samples));
536 checkGLcall("poll occlusion query");
537 context_release(&context_gl->c);
539 return available;
542 static BOOL wined3d_event_query_ops_poll(struct wined3d_query *query, DWORD flags)
544 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
545 enum wined3d_fence_result ret;
547 TRACE("query %p, flags %#x.\n", query, flags);
549 ret = wined3d_fence_test(&event_query->fence, query->device, flags);
550 switch (ret)
552 case WINED3D_FENCE_OK:
553 case WINED3D_FENCE_NOT_STARTED:
554 return event_query->signalled = TRUE;
556 case WINED3D_FENCE_WAITING:
557 return event_query->signalled = FALSE;
559 case WINED3D_FENCE_WRONG_THREAD:
560 FIXME("(%p) Wrong thread, reporting GPU idle.\n", query);
561 return event_query->signalled = TRUE;
563 case WINED3D_FENCE_ERROR:
564 ERR("The GL event query failed.\n");
565 return event_query->signalled = TRUE;
567 default:
568 ERR("Unexpected wined3d_event_query_test result %#x.\n", ret);
569 return event_query->signalled = TRUE;
573 void * CDECL wined3d_query_get_parent(const struct wined3d_query *query)
575 TRACE("query %p.\n", query);
577 return query->parent;
580 enum wined3d_query_type CDECL wined3d_query_get_type(const struct wined3d_query *query)
582 TRACE("query %p.\n", query);
584 return query->type;
587 static BOOL wined3d_event_query_ops_issue(struct wined3d_query *query, DWORD flags)
589 TRACE("query %p, flags %#x.\n", query, flags);
591 if (flags & WINED3DISSUE_END)
593 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
595 wined3d_fence_issue(&event_query->fence, query->device);
596 return TRUE;
598 else if (flags & WINED3DISSUE_BEGIN)
600 /* Started implicitly at query creation. */
601 ERR("Event query issued with START flag - what to do?\n");
604 return FALSE;
607 static BOOL wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DWORD flags)
609 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
610 struct wined3d_device *device = query->device;
611 const struct wined3d_gl_info *gl_info;
612 struct wined3d_context_gl *context_gl;
613 BOOL poll = FALSE;
615 TRACE("query %p, flags %#x.\n", query, flags);
617 /* This is allowed according to MSDN and our tests. Reset the query and
618 * restart. */
619 if (flags & WINED3DISSUE_BEGIN)
621 if (oq->started)
623 if ((context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
625 gl_info = context_gl->gl_info;
626 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
627 checkGLcall("glEndQuery()");
629 else
631 FIXME("Wrong thread, can't restart query.\n");
632 wined3d_context_gl_free_occlusion_query(oq);
633 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
634 wined3d_context_gl_alloc_occlusion_query(context_gl, oq);
637 else
639 if (oq->context_gl)
640 wined3d_context_gl_free_occlusion_query(oq);
641 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
642 wined3d_context_gl_alloc_occlusion_query(context_gl, oq);
644 gl_info = context_gl->gl_info;
646 GL_EXTCALL(glBeginQuery(GL_SAMPLES_PASSED, oq->id));
647 checkGLcall("glBeginQuery()");
649 context_release(&context_gl->c);
650 oq->started = TRUE;
652 if (flags & WINED3DISSUE_END)
654 /* MSDN says END on a non-building occlusion query returns an error,
655 * but our tests show that it returns OK. But OpenGL doesn't like it,
656 * so avoid generating an error. */
657 if (oq->started)
659 if ((context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
661 gl_info = context_gl->gl_info;
662 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
663 checkGLcall("glEndQuery()");
664 wined3d_query_buffer_queue_result(context_gl, query, oq->id);
666 context_release(&context_gl->c);
667 poll = TRUE;
669 else
671 FIXME("Wrong thread, can't end query.\n");
674 oq->started = FALSE;
677 return poll;
680 static BOOL wined3d_timestamp_query_ops_poll(struct wined3d_query *query, DWORD flags)
682 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
683 const struct wined3d_gl_info *gl_info;
684 struct wined3d_context_gl *context_gl;
685 GLuint64 timestamp;
686 GLuint available;
688 TRACE("query %p, flags %#x.\n", query, flags);
690 if (!(context_gl = wined3d_context_gl_reacquire(tq->context_gl)))
692 FIXME("%p Wrong thread, returning 1.\n", query);
693 tq->timestamp = 1;
694 return TRUE;
696 gl_info = context_gl->gl_info;
698 GL_EXTCALL(glGetQueryObjectuiv(tq->id, GL_QUERY_RESULT_AVAILABLE, &available));
699 checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
700 TRACE("available %#x.\n", available);
702 if (available)
704 GL_EXTCALL(glGetQueryObjectui64v(tq->id, GL_QUERY_RESULT, &timestamp));
705 checkGLcall("glGetQueryObjectui64v(GL_QUERY_RESULT)");
706 TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp));
707 tq->timestamp = timestamp;
710 context_release(&context_gl->c);
712 return available;
715 static BOOL wined3d_timestamp_query_ops_issue(struct wined3d_query *query, DWORD flags)
717 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
718 const struct wined3d_gl_info *gl_info;
719 struct wined3d_context_gl *context_gl;
721 TRACE("query %p, flags %#x.\n", query, flags);
723 if (flags & WINED3DISSUE_BEGIN)
725 WARN("Ignoring WINED3DISSUE_BEGIN with a TIMESTAMP query.\n");
727 if (flags & WINED3DISSUE_END)
729 if (tq->context_gl)
730 wined3d_context_gl_free_timestamp_query(tq);
731 context_gl = wined3d_context_gl(context_acquire(query->device, NULL, 0));
732 gl_info = context_gl->gl_info;
733 wined3d_context_gl_alloc_timestamp_query(context_gl, tq);
734 GL_EXTCALL(glQueryCounter(tq->id, GL_TIMESTAMP));
735 checkGLcall("glQueryCounter()");
736 context_release(&context_gl->c);
738 return TRUE;
741 return FALSE;
744 static BOOL wined3d_timestamp_disjoint_query_ops_poll(struct wined3d_query *query, DWORD flags)
746 TRACE("query %p, flags %#x.\n", query, flags);
748 return TRUE;
751 static BOOL wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query *query, DWORD flags)
753 TRACE("query %p, flags %#x.\n", query, flags);
755 return FALSE;
758 static BOOL wined3d_so_statistics_query_ops_poll(struct wined3d_query *query, DWORD flags)
760 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
761 GLuint written_available, generated_available;
762 const struct wined3d_gl_info *gl_info;
763 struct wined3d_context_gl *context_gl;
765 TRACE("query %p, flags %#x.\n", query, flags);
767 if (!(context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
769 FIXME("%p Wrong thread, returning 0 primitives.\n", query);
770 memset(&pq->statistics, 0, sizeof(pq->statistics));
771 return TRUE;
773 gl_info = context_gl->gl_info;
775 GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.written,
776 GL_QUERY_RESULT_AVAILABLE, &written_available));
777 GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.generated,
778 GL_QUERY_RESULT_AVAILABLE, &generated_available));
779 TRACE("Available %#x, %#x.\n", written_available, generated_available);
781 if (written_available && generated_available)
783 pq->statistics.primitives_written = get_query_result64(pq->u.query.written, gl_info);
784 pq->statistics.primitives_generated = get_query_result64(pq->u.query.generated, gl_info);
785 TRACE("Returning %s, %s primitives.\n",
786 wine_dbgstr_longlong(pq->statistics.primitives_written),
787 wine_dbgstr_longlong(pq->statistics.primitives_generated));
790 checkGLcall("poll SO statistics query");
791 context_release(&context_gl->c);
793 return written_available && generated_available;
796 static void wined3d_so_statistics_query_end(struct wined3d_so_statistics_query *query,
797 struct wined3d_context_gl *context_gl)
799 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
801 if (gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
803 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query->stream_idx));
804 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED, query->stream_idx));
806 else
808 GL_EXTCALL(glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN));
809 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_GENERATED));
811 checkGLcall("end query");
814 static BOOL wined3d_so_statistics_query_ops_issue(struct wined3d_query *query, DWORD flags)
816 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
817 struct wined3d_device *device = query->device;
818 const struct wined3d_gl_info *gl_info;
819 struct wined3d_context_gl *context_gl;
820 BOOL poll = FALSE;
822 TRACE("query %p, flags %#x.\n", query, flags);
824 if (flags & WINED3DISSUE_BEGIN)
826 if (pq->started)
828 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
830 wined3d_so_statistics_query_end(pq, context_gl);
832 else
834 FIXME("Wrong thread, can't restart query.\n");
835 wined3d_context_gl_free_so_statistics_query(pq);
836 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
837 wined3d_context_gl_alloc_so_statistics_query(context_gl, pq);
840 else
842 if (pq->context_gl)
843 wined3d_context_gl_free_so_statistics_query(pq);
844 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
845 wined3d_context_gl_alloc_so_statistics_query(context_gl, pq);
847 gl_info = context_gl->gl_info;
849 if (gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
851 GL_EXTCALL(glBeginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
852 pq->stream_idx, pq->u.query.written));
853 GL_EXTCALL(glBeginQueryIndexed(GL_PRIMITIVES_GENERATED,
854 pq->stream_idx, pq->u.query.generated));
856 else
858 GL_EXTCALL(glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
859 pq->u.query.written));
860 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_GENERATED,
861 pq->u.query.generated));
863 checkGLcall("begin query");
865 context_release(&context_gl->c);
866 pq->started = TRUE;
868 if (flags & WINED3DISSUE_END)
870 if (pq->started)
872 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
874 wined3d_so_statistics_query_end(pq, context_gl);
876 context_release(&context_gl->c);
877 poll = TRUE;
879 else
881 FIXME("Wrong thread, can't end query.\n");
884 pq->started = FALSE;
887 return poll;
890 static BOOL wined3d_pipeline_query_ops_poll(struct wined3d_query *query, DWORD flags)
892 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
893 const struct wined3d_gl_info *gl_info;
894 struct wined3d_context_gl *context_gl;
895 GLuint available;
896 int i;
898 TRACE("query %p, flags %#x.\n", query, flags);
900 if (!(context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
902 FIXME("%p Wrong thread.\n", query);
903 memset(&pq->statistics, 0, sizeof(pq->statistics));
904 return TRUE;
906 gl_info = context_gl->gl_info;
908 for (i = 0; i < ARRAY_SIZE(pq->u.id); ++i)
910 GL_EXTCALL(glGetQueryObjectuiv(pq->u.id[i], GL_QUERY_RESULT_AVAILABLE, &available));
911 if (!available)
912 break;
915 if (available)
917 pq->statistics.vertices_submitted = get_query_result64(pq->u.query.vertices, gl_info);
918 pq->statistics.primitives_submitted = get_query_result64(pq->u.query.primitives, gl_info);
919 pq->statistics.vs_invocations = get_query_result64(pq->u.query.vertex_shader, gl_info);
920 pq->statistics.hs_invocations = get_query_result64(pq->u.query.tess_control_shader, gl_info);
921 pq->statistics.ds_invocations = get_query_result64(pq->u.query.tess_eval_shader, gl_info);
922 pq->statistics.gs_invocations = get_query_result64(pq->u.query.geometry_shader, gl_info);
923 pq->statistics.gs_primitives = get_query_result64(pq->u.query.geometry_primitives, gl_info);
924 pq->statistics.ps_invocations = get_query_result64(pq->u.query.fragment_shader, gl_info);
925 pq->statistics.cs_invocations = get_query_result64(pq->u.query.compute_shader, gl_info);
926 pq->statistics.clipping_input_primitives = get_query_result64(pq->u.query.clipping_input, gl_info);
927 pq->statistics.clipping_output_primitives = get_query_result64(pq->u.query.clipping_output, gl_info);
930 checkGLcall("poll pipeline statistics query");
931 context_release(&context_gl->c);
932 return available;
935 static void wined3d_pipeline_statistics_query_end(struct wined3d_pipeline_statistics_query *query,
936 struct wined3d_context_gl *context_gl)
938 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
940 GL_EXTCALL(glEndQuery(GL_VERTICES_SUBMITTED_ARB));
941 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_SUBMITTED_ARB));
942 GL_EXTCALL(glEndQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB));
943 GL_EXTCALL(glEndQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB));
944 GL_EXTCALL(glEndQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB));
945 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_INVOCATIONS));
946 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB));
947 GL_EXTCALL(glEndQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB));
948 GL_EXTCALL(glEndQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB));
949 GL_EXTCALL(glEndQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB));
950 GL_EXTCALL(glEndQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB));
951 checkGLcall("end query");
954 static BOOL wined3d_pipeline_query_ops_issue(struct wined3d_query *query, DWORD flags)
956 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
957 struct wined3d_device *device = query->device;
958 const struct wined3d_gl_info *gl_info;
959 struct wined3d_context_gl *context_gl;
960 BOOL poll = FALSE;
962 TRACE("query %p, flags %#x.\n", query, flags);
964 if (flags & WINED3DISSUE_BEGIN)
966 if (pq->started)
968 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
970 wined3d_pipeline_statistics_query_end(pq, context_gl);
972 else
974 FIXME("Wrong thread, can't restart query.\n");
975 wined3d_context_gl_free_pipeline_statistics_query(pq);
976 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
977 wined3d_context_gl_alloc_pipeline_statistics_query(context_gl, pq);
980 else
982 if (pq->context_gl)
983 wined3d_context_gl_free_pipeline_statistics_query(pq);
984 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
985 wined3d_context_gl_alloc_pipeline_statistics_query(context_gl, pq);
987 gl_info = context_gl->gl_info;
989 GL_EXTCALL(glBeginQuery(GL_VERTICES_SUBMITTED_ARB, pq->u.query.vertices));
990 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_SUBMITTED_ARB, pq->u.query.primitives));
991 GL_EXTCALL(glBeginQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB, pq->u.query.vertex_shader));
992 GL_EXTCALL(glBeginQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB, pq->u.query.tess_control_shader));
993 GL_EXTCALL(glBeginQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB, pq->u.query.tess_eval_shader));
994 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_INVOCATIONS, pq->u.query.geometry_shader));
995 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB, pq->u.query.geometry_primitives));
996 GL_EXTCALL(glBeginQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB, pq->u.query.fragment_shader));
997 GL_EXTCALL(glBeginQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB, pq->u.query.compute_shader));
998 GL_EXTCALL(glBeginQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB, pq->u.query.clipping_input));
999 GL_EXTCALL(glBeginQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB, pq->u.query.clipping_output));
1000 checkGLcall("begin query");
1002 context_release(&context_gl->c);
1003 pq->started = TRUE;
1005 if (flags & WINED3DISSUE_END)
1007 if (pq->started)
1009 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
1011 wined3d_pipeline_statistics_query_end(pq, context_gl);
1012 context_release(&context_gl->c);
1013 poll = TRUE;
1015 else
1017 FIXME("Wrong thread, can't end query.\n");
1020 pq->started = FALSE;
1023 return poll;
1026 static void wined3d_event_query_ops_destroy(struct wined3d_query *query)
1028 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
1030 wined3d_fence_free(&event_query->fence);
1031 heap_free(event_query);
1034 static const struct wined3d_query_ops event_query_ops =
1036 wined3d_event_query_ops_poll,
1037 wined3d_event_query_ops_issue,
1038 wined3d_event_query_ops_destroy,
1041 static HRESULT wined3d_event_query_create(struct wined3d_device *device,
1042 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1043 struct wined3d_query **query)
1045 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1046 struct wined3d_event_query *object;
1047 HRESULT hr;
1049 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1050 device, type, parent, parent_ops, query);
1052 if (!(object = heap_alloc_zero(sizeof(*object))))
1053 return E_OUTOFMEMORY;
1055 if (FAILED(hr = wined3d_fence_init(&object->fence, gl_info)))
1057 WARN("Event queries not supported.\n");
1058 heap_free(object);
1059 return hr;
1062 wined3d_query_init(&object->query, device, type, &object->signalled,
1063 sizeof(object->signalled), &event_query_ops, parent, parent_ops);
1065 TRACE("Created query %p.\n", object);
1066 *query = &object->query;
1068 return WINED3D_OK;
1071 static void wined3d_occlusion_query_ops_destroy(struct wined3d_query *query)
1073 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
1075 if (oq->context_gl)
1076 wined3d_context_gl_free_occlusion_query(oq);
1077 heap_free(oq);
1080 static const struct wined3d_query_ops occlusion_query_ops =
1082 wined3d_occlusion_query_ops_poll,
1083 wined3d_occlusion_query_ops_issue,
1084 wined3d_occlusion_query_ops_destroy,
1087 static HRESULT wined3d_occlusion_query_create(struct wined3d_device *device,
1088 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1089 struct wined3d_query **query)
1091 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1092 struct wined3d_occlusion_query *object;
1094 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1095 device, type, parent, parent_ops, query);
1097 if (!gl_info->supported[ARB_OCCLUSION_QUERY])
1099 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
1100 return WINED3DERR_NOTAVAILABLE;
1103 if (!(object = heap_alloc_zero(sizeof(*object))))
1104 return E_OUTOFMEMORY;
1106 wined3d_query_init(&object->query, device, type, &object->samples,
1107 sizeof(object->samples), &occlusion_query_ops, parent, parent_ops);
1109 TRACE("Created query %p.\n", object);
1110 *query = &object->query;
1112 return WINED3D_OK;
1115 static void wined3d_timestamp_query_ops_destroy(struct wined3d_query *query)
1117 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
1119 if (tq->context_gl)
1120 wined3d_context_gl_free_timestamp_query(tq);
1121 heap_free(tq);
1124 static const struct wined3d_query_ops timestamp_query_ops =
1126 wined3d_timestamp_query_ops_poll,
1127 wined3d_timestamp_query_ops_issue,
1128 wined3d_timestamp_query_ops_destroy,
1131 static HRESULT wined3d_timestamp_query_create(struct wined3d_device *device,
1132 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1133 struct wined3d_query **query)
1135 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1136 struct wined3d_timestamp_query *object;
1138 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1139 device, type, parent, parent_ops, query);
1141 if (!gl_info->supported[ARB_TIMER_QUERY])
1143 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1144 return WINED3DERR_NOTAVAILABLE;
1147 if (!(object = heap_alloc_zero(sizeof(*object))))
1148 return E_OUTOFMEMORY;
1150 wined3d_query_init(&object->query, device, type, &object->timestamp,
1151 sizeof(object->timestamp), &timestamp_query_ops, parent, parent_ops);
1153 TRACE("Created query %p.\n", object);
1154 *query = &object->query;
1156 return WINED3D_OK;
1159 static void wined3d_timestamp_disjoint_query_ops_destroy(struct wined3d_query *query)
1161 heap_free(query);
1164 static const struct wined3d_query_ops timestamp_disjoint_query_ops =
1166 wined3d_timestamp_disjoint_query_ops_poll,
1167 wined3d_timestamp_disjoint_query_ops_issue,
1168 wined3d_timestamp_disjoint_query_ops_destroy,
1171 static HRESULT wined3d_timestamp_disjoint_query_create(struct wined3d_device *device,
1172 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1173 struct wined3d_query **query)
1175 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1176 struct wined3d_query *object;
1178 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1179 device, type, parent, parent_ops, query);
1181 if (!gl_info->supported[ARB_TIMER_QUERY])
1183 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1184 return WINED3DERR_NOTAVAILABLE;
1187 if (!(object = heap_alloc_zero(sizeof(*object))))
1188 return E_OUTOFMEMORY;
1190 if (type == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT)
1192 static const struct wined3d_query_data_timestamp_disjoint disjoint_data = {1000 * 1000 * 1000, FALSE};
1194 wined3d_query_init(object, device, type, &disjoint_data,
1195 sizeof(disjoint_data), &timestamp_disjoint_query_ops, parent, parent_ops);
1197 else
1199 static const UINT64 freq = 1000 * 1000 * 1000;
1201 wined3d_query_init(object, device, type, &freq,
1202 sizeof(freq), &timestamp_disjoint_query_ops, parent, parent_ops);
1205 TRACE("Created query %p.\n", object);
1206 *query = object;
1208 return WINED3D_OK;
1211 static void wined3d_so_statistics_query_ops_destroy(struct wined3d_query *query)
1213 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
1215 if (pq->context_gl)
1216 wined3d_context_gl_free_so_statistics_query(pq);
1217 heap_free(pq);
1220 static const struct wined3d_query_ops so_statistics_query_ops =
1222 wined3d_so_statistics_query_ops_poll,
1223 wined3d_so_statistics_query_ops_issue,
1224 wined3d_so_statistics_query_ops_destroy,
1227 static HRESULT wined3d_so_statistics_query_create(struct wined3d_device *device,
1228 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1229 struct wined3d_query **query)
1231 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1232 struct wined3d_so_statistics_query *object;
1233 unsigned int stream_idx;
1235 if (WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0 <= type && type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1236 stream_idx = type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0;
1237 else if (type == WINED3D_QUERY_TYPE_SO_STATISTICS)
1238 stream_idx = 0;
1239 else
1240 return WINED3DERR_NOTAVAILABLE;
1242 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1243 device, type, parent, parent_ops, query);
1245 if (!gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY])
1247 WARN("OpenGL implementation does not support primitive queries.\n");
1248 return WINED3DERR_NOTAVAILABLE;
1250 if (stream_idx && !gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
1252 WARN("OpenGL implementation does not support indexed queries.\n");
1253 return WINED3DERR_NOTAVAILABLE;
1256 if (!(object = heap_alloc_zero(sizeof(*object))))
1257 return E_OUTOFMEMORY;
1259 wined3d_query_init(&object->query, device, type, &object->statistics,
1260 sizeof(object->statistics), &so_statistics_query_ops, parent, parent_ops);
1261 object->stream_idx = stream_idx;
1263 TRACE("Created query %p.\n", object);
1264 *query = &object->query;
1266 return WINED3D_OK;
1269 static void wined3d_pipeline_query_ops_destroy(struct wined3d_query *query)
1271 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
1272 if (pq->context_gl)
1273 wined3d_context_gl_free_pipeline_statistics_query(pq);
1274 heap_free(pq);
1277 static const struct wined3d_query_ops pipeline_query_ops =
1279 wined3d_pipeline_query_ops_poll,
1280 wined3d_pipeline_query_ops_issue,
1281 wined3d_pipeline_query_ops_destroy,
1284 static HRESULT wined3d_pipeline_query_create(struct wined3d_device *device,
1285 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1286 struct wined3d_query **query)
1288 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1289 struct wined3d_pipeline_statistics_query *object;
1291 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1292 device, type, parent, parent_ops, query);
1294 if (!gl_info->supported[ARB_PIPELINE_STATISTICS_QUERY])
1296 WARN("OpenGL implementation does not support pipeline statistics queries.\n");
1297 return WINED3DERR_NOTAVAILABLE;
1300 if (!(object = heap_alloc_zero(sizeof(*object))))
1301 return E_OUTOFMEMORY;
1303 wined3d_query_init(&object->query, device, type, &object->statistics,
1304 sizeof(object->statistics), &pipeline_query_ops, parent, parent_ops);
1306 TRACE("Created query %p.\n", object);
1307 *query = &object->query;
1309 return WINED3D_OK;
1312 HRESULT wined3d_query_gl_create(struct wined3d_device *device, enum wined3d_query_type type,
1313 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1315 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1316 device, type, parent, parent_ops, query);
1318 switch (type)
1320 case WINED3D_QUERY_TYPE_EVENT:
1321 return wined3d_event_query_create(device, type, parent, parent_ops, query);
1323 case WINED3D_QUERY_TYPE_OCCLUSION:
1324 return wined3d_occlusion_query_create(device, type, parent, parent_ops, query);
1326 case WINED3D_QUERY_TYPE_TIMESTAMP:
1327 return wined3d_timestamp_query_create(device, type, parent, parent_ops, query);
1329 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1330 case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ:
1331 return wined3d_timestamp_disjoint_query_create(device, type, parent, parent_ops, query);
1333 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1334 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1335 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1336 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1337 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1338 return wined3d_so_statistics_query_create(device, type, parent, parent_ops, query);
1340 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1341 return wined3d_pipeline_query_create(device, type, parent, parent_ops, query);
1343 default:
1344 FIXME("Unhandled query type %#x.\n", type);
1345 return WINED3DERR_NOTAVAILABLE;
1349 static void wined3d_query_pool_vk_mark_complete(struct wined3d_query_pool_vk *pool_vk, size_t idx,
1350 struct wined3d_context_vk *context_vk)
1352 /* Don't reset completed queries right away, as vkCmdResetQueryPool() needs to happen
1353 * outside of a render pass. Queue the query to be reset at the very end of the current
1354 * command buffer instead. */
1355 wined3d_bitmap_set(pool_vk->completed, idx);
1356 if (list_empty(&pool_vk->completed_entry))
1357 list_add_tail(&context_vk->completed_query_pools, &pool_vk->completed_entry);
1360 bool wined3d_query_pool_vk_allocate_query(struct wined3d_query_pool_vk *pool_vk, size_t *idx)
1362 if ((*idx = wined3d_bitmap_ffz(pool_vk->allocated, WINED3D_QUERY_POOL_SIZE, 0)) > WINED3D_QUERY_POOL_SIZE)
1363 return false;
1364 wined3d_bitmap_set(pool_vk->allocated, *idx);
1366 return true;
1369 void wined3d_query_pool_vk_mark_free(struct wined3d_context_vk *context_vk, struct wined3d_query_pool_vk *pool_vk,
1370 uint32_t start, uint32_t count)
1372 unsigned int idx, end = start + count;
1374 for (idx = start; idx < end; ++idx)
1375 wined3d_bitmap_clear(pool_vk->allocated, idx);
1377 if (list_empty(&pool_vk->entry))
1378 list_add_tail(pool_vk->free_list, &pool_vk->entry);
1381 void wined3d_query_pool_vk_cleanup(struct wined3d_query_pool_vk *pool_vk, struct wined3d_context_vk *context_vk)
1383 struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
1384 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1386 VK_CALL(vkDestroyQueryPool(device_vk->vk_device, pool_vk->vk_query_pool, NULL));
1387 if (pool_vk->vk_event)
1388 VK_CALL(vkDestroyEvent(device_vk->vk_device, pool_vk->vk_event, NULL));
1389 list_remove(&pool_vk->entry);
1390 list_remove(&pool_vk->completed_entry);
1393 bool wined3d_query_pool_vk_init(struct wined3d_query_pool_vk *pool_vk,
1394 struct wined3d_context_vk *context_vk, enum wined3d_query_type type, struct list *free_pools)
1396 struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
1397 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1398 VkQueryPoolCreateInfo pool_info;
1399 VkResult vr;
1401 list_init(&pool_vk->entry);
1402 list_init(&pool_vk->completed_entry);
1403 pool_vk->free_list = free_pools;
1405 pool_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1406 pool_info.pNext = NULL;
1407 pool_info.flags = 0;
1408 pool_info.queryCount = WINED3D_QUERY_POOL_SIZE;
1410 switch (type)
1412 case WINED3D_QUERY_TYPE_OCCLUSION:
1413 pool_info.queryType = VK_QUERY_TYPE_OCCLUSION;
1414 pool_info.pipelineStatistics = 0;
1415 break;
1417 case WINED3D_QUERY_TYPE_TIMESTAMP:
1418 pool_info.queryType = VK_QUERY_TYPE_TIMESTAMP;
1419 pool_info.pipelineStatistics = 0;
1420 break;
1422 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1423 pool_info.queryType = VK_QUERY_TYPE_PIPELINE_STATISTICS;
1424 pool_info.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT
1425 | VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT
1426 | VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT
1427 | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT
1428 | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT
1429 | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT
1430 | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT
1431 | VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT
1432 | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT
1433 | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT
1434 | VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT;
1435 break;
1437 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1438 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1439 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1440 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1441 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1442 pool_info.queryType = VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT;
1443 pool_info.pipelineStatistics = 0;
1444 break;
1446 default:
1447 FIXME("Unhandled query type %#x.\n", type);
1448 return false;
1451 if ((vr = VK_CALL(vkCreateQueryPool(device_vk->vk_device, &pool_info, NULL, &pool_vk->vk_query_pool))) < 0)
1453 ERR("Failed to create Vulkan query pool, vr %s.\n", wined3d_debug_vkresult(vr));
1454 return false;
1457 list_add_head(free_pools, &pool_vk->entry);
1459 return true;
1462 bool wined3d_query_vk_accumulate_data(struct wined3d_query_vk *query_vk,
1463 struct wined3d_device_vk *device_vk, const struct wined3d_query_pool_idx_vk *pool_idx)
1465 const struct wined3d_query_data_pipeline_statistics *ps_tmp;
1466 const struct wined3d_vk_info *vk_info = &device_vk->vk_info;
1467 struct wined3d_query_data_pipeline_statistics *ps_result;
1468 VkResult vr;
1469 union
1471 uint64_t occlusion;
1472 uint64_t timestamp;
1473 struct wined3d_query_data_pipeline_statistics pipeline_statistics;
1474 struct wined3d_query_data_so_statistics so_statistics;
1475 } tmp, *result;
1477 if (pool_idx->pool_vk->vk_event)
1479 /* Check if the pool's initial reset command executed. */
1480 vr = VK_CALL(vkGetEventStatus(device_vk->vk_device,
1481 pool_idx->pool_vk->vk_event));
1482 if (vr == VK_EVENT_RESET)
1483 return false;
1484 else if (vr != VK_EVENT_SET)
1486 ERR("Failed to get event status, vr %s\n", wined3d_debug_vkresult(vr));
1487 return false;
1491 if ((vr = VK_CALL(vkGetQueryPoolResults(device_vk->vk_device, pool_idx->pool_vk->vk_query_pool,
1492 pool_idx->idx, 1, sizeof(tmp), &tmp, sizeof(tmp), VK_QUERY_RESULT_64_BIT))) < 0)
1494 ERR("Failed to get query results, vr %s.\n", wined3d_debug_vkresult(vr));
1495 return false;
1498 if (vr == VK_NOT_READY)
1499 return false;
1501 result = (void *)query_vk->q.data;
1502 switch (query_vk->q.type)
1504 case WINED3D_QUERY_TYPE_OCCLUSION:
1505 result->occlusion += tmp.occlusion;
1506 break;
1508 case WINED3D_QUERY_TYPE_TIMESTAMP:
1509 result->timestamp = tmp.timestamp;
1510 break;
1512 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1513 ps_result = &result->pipeline_statistics;
1514 ps_tmp = &tmp.pipeline_statistics;
1515 ps_result->vertices_submitted += ps_tmp->vertices_submitted;
1516 ps_result->primitives_submitted += ps_tmp->primitives_submitted;
1517 ps_result->vs_invocations += ps_tmp->vs_invocations;
1518 ps_result->gs_invocations += ps_tmp->gs_invocations;
1519 ps_result->gs_primitives += ps_tmp->gs_primitives;
1520 ps_result->clipping_input_primitives += ps_tmp->clipping_input_primitives;
1521 ps_result->clipping_output_primitives += ps_tmp->clipping_output_primitives;
1522 ps_result->ps_invocations += ps_tmp->ps_invocations;
1523 ps_result->hs_invocations += ps_tmp->hs_invocations;
1524 ps_result->ds_invocations += ps_tmp->ds_invocations;
1525 ps_result->cs_invocations += ps_tmp->cs_invocations;
1526 break;
1528 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1529 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1530 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1531 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1532 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1533 result->so_statistics.primitives_written += tmp.so_statistics.primitives_written;
1534 result->so_statistics.primitives_generated += tmp.so_statistics.primitives_generated;
1535 break;
1537 default:
1538 FIXME("Unhandled query type %#x.\n", query_vk->q.type);
1539 return false;
1542 return true;
1545 static void wined3d_query_vk_begin(struct wined3d_query_vk *query_vk,
1546 struct wined3d_context_vk *context_vk, VkCommandBuffer vk_command_buffer)
1548 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1549 struct wined3d_query_pool_vk *pool_vk;
1550 size_t idx;
1552 pool_vk = query_vk->pool_idx.pool_vk;
1553 idx = query_vk->pool_idx.idx;
1555 if (query_vk->q.type >= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
1556 && query_vk->q.type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1557 VK_CALL(vkCmdBeginQueryIndexedEXT(vk_command_buffer, pool_vk->vk_query_pool, idx,
1558 query_vk->control_flags, query_vk->q.type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0));
1559 else
1560 VK_CALL(vkCmdBeginQuery(vk_command_buffer, pool_vk->vk_query_pool, idx, query_vk->control_flags));
1561 wined3d_context_vk_reference_query(context_vk, query_vk);
1564 static void wined3d_query_vk_end(struct wined3d_query_vk *query_vk,
1565 struct wined3d_context_vk *context_vk, VkCommandBuffer vk_command_buffer)
1567 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1568 struct wined3d_query_pool_vk *pool_vk;
1569 size_t idx;
1571 pool_vk = query_vk->pool_idx.pool_vk;
1572 idx = query_vk->pool_idx.idx;
1574 if (query_vk->q.type >= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
1575 && query_vk->q.type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1576 VK_CALL(vkCmdEndQueryIndexedEXT(vk_command_buffer, pool_vk->vk_query_pool,
1577 idx, query_vk->q.type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0));
1578 else
1579 VK_CALL(vkCmdEndQuery(vk_command_buffer, pool_vk->vk_query_pool, idx));
1582 void wined3d_query_vk_resume(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk)
1584 VkCommandBuffer vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer;
1586 wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
1587 query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE;
1590 void wined3d_query_vk_suspend(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk)
1592 VkCommandBuffer vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer;
1594 wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
1596 if (!wined3d_array_reserve((void **)&query_vk->pending, &query_vk->pending_size,
1597 query_vk->pending_count + 1, sizeof(*query_vk->pending)))
1599 ERR("Failed to allocate entry.\n");
1600 return;
1603 query_vk->pending[query_vk->pending_count++] = query_vk->pool_idx;
1604 query_vk->pool_idx.pool_vk = NULL;
1605 query_vk->flags &= ~WINED3D_QUERY_VK_FLAG_ACTIVE;
1608 static BOOL wined3d_query_vk_poll(struct wined3d_query *query, uint32_t flags)
1610 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1611 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1612 unsigned int i;
1614 memset((void *)query->data, 0, query->data_size);
1616 if (query_vk->pool_idx.pool_vk && !wined3d_query_vk_accumulate_data(query_vk, device_vk, &query_vk->pool_idx))
1617 goto unavailable;
1619 for (i = 0; i < query_vk->pending_count; ++i)
1621 if (!wined3d_query_vk_accumulate_data(query_vk, device_vk, &query_vk->pending[i]))
1622 goto unavailable;
1625 return TRUE;
1627 unavailable:
1628 if ((flags & WINED3DGETDATA_FLUSH) && !query->device->cs->queries_flushed)
1629 query->device->cs->c.ops->flush(&query->device->cs->c);
1631 return FALSE;
1634 static void wined3d_query_vk_remove_pending_queries(struct wined3d_context_vk *context_vk,
1635 struct wined3d_query_vk *query_vk)
1637 size_t i;
1639 for (i = 0; i < query_vk->pending_count; ++i)
1640 wined3d_query_pool_vk_mark_complete(query_vk->pending[i].pool_vk, query_vk->pending[i].idx, context_vk);
1642 query_vk->pending_count = 0;
1645 static BOOL wined3d_query_vk_issue(struct wined3d_query *query, uint32_t flags)
1647 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1648 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1649 struct wined3d_context_vk *context_vk;
1650 VkCommandBuffer vk_command_buffer;
1651 bool poll = false;
1653 TRACE("query %p, flags %#x.\n", query, flags);
1655 if (flags & WINED3DISSUE_BEGIN)
1657 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1659 if (query_vk->pending_count)
1660 wined3d_query_vk_remove_pending_queries(context_vk, query_vk);
1661 vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
1662 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED)
1664 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_ACTIVE)
1665 wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
1666 list_remove(&query_vk->entry);
1668 if (query_vk->pool_idx.pool_vk)
1669 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk,
1670 query_vk->pool_idx.idx, context_vk);
1672 if (!wined3d_context_vk_allocate_query(context_vk, query_vk->q.type, &query_vk->pool_idx))
1674 ERR("Failed to allocate new query.\n");
1675 return false;
1678 /* A query needs to either begin and end inside a single render pass
1679 * or begin and end outside of a render pass. Occlusion queries, if
1680 * issued outside of a render pass, are queued up and only begun when
1681 * a render pass is started, to avoid interrupting the render pass
1682 * when the query ends. */
1683 if (context_vk->vk_render_pass)
1685 wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
1686 list_add_head(&context_vk->render_pass_queries, &query_vk->entry);
1687 query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE | WINED3D_QUERY_VK_FLAG_RENDER_PASS;
1689 else if (query->type == WINED3D_QUERY_TYPE_OCCLUSION)
1691 list_add_head(&context_vk->render_pass_queries, &query_vk->entry);
1692 query_vk->flags |= WINED3D_QUERY_VK_FLAG_RENDER_PASS;
1694 else
1696 wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
1697 list_add_head(&context_vk->active_queries, &query_vk->entry);
1698 query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE;
1701 query_vk->flags |= WINED3D_QUERY_VK_FLAG_STARTED;
1702 context_release(&context_vk->c);
1704 if (flags & WINED3DISSUE_END && query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED)
1706 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1708 /* If the query was already ended because the command buffer was
1709 * flushed or the render pass ended, we don't need to end it here. */
1710 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_ACTIVE)
1712 vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
1713 if (!(query_vk->flags & WINED3D_QUERY_VK_FLAG_RENDER_PASS))
1714 wined3d_context_vk_end_current_render_pass(context_vk);
1715 wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
1717 else if (query_vk->pool_idx.pool_vk)
1719 /* It was queued, but never activated. */
1720 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk,
1721 query_vk->pool_idx.idx, context_vk);
1722 query_vk->pool_idx.pool_vk = NULL;
1724 list_remove(&query_vk->entry);
1725 query_vk->flags = 0;
1726 poll = true;
1728 context_release(&context_vk->c);
1731 return poll;
1734 static void wined3d_query_vk_destroy(struct wined3d_query *query)
1736 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1737 struct wined3d_context_vk *context_vk;
1739 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED)
1740 list_remove(&query_vk->entry);
1741 context_vk = wined3d_context_vk(context_acquire(query_vk->q.device, NULL, 0));
1742 wined3d_query_vk_remove_pending_queries(context_vk, query_vk);
1743 if (query_vk->pool_idx.pool_vk)
1744 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk, query_vk->pool_idx.idx, context_vk);
1745 if (query_vk->vk_event)
1746 wined3d_context_vk_destroy_vk_event(context_vk, query_vk->vk_event, query_vk->command_buffer_id);
1747 context_release(&context_vk->c);
1748 heap_free(query_vk->pending);
1749 heap_free(query_vk);
1752 static const struct wined3d_query_ops wined3d_query_vk_ops =
1754 .query_poll = wined3d_query_vk_poll,
1755 .query_issue = wined3d_query_vk_issue,
1756 .query_destroy = wined3d_query_vk_destroy,
1759 static BOOL wined3d_query_event_vk_poll(struct wined3d_query *query, uint32_t flags)
1761 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1762 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1763 const struct wined3d_vk_info *vk_info = &device_vk->vk_info;
1764 BOOL signalled;
1766 signalled = VK_CALL(vkGetEventStatus(device_vk->vk_device, query_vk->vk_event))
1767 == VK_EVENT_SET;
1768 if (!signalled && (flags & WINED3DGETDATA_FLUSH) && !query->device->cs->queries_flushed)
1769 query->device->cs->c.ops->flush(&query->device->cs->c);
1770 return *(BOOL *)query->data = signalled;
1773 static BOOL wined3d_query_event_vk_issue(struct wined3d_query *query, uint32_t flags)
1775 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1776 const struct wined3d_vk_info *vk_info = &device_vk->vk_info;
1777 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1778 struct wined3d_context_vk *context_vk;
1779 VkEventCreateInfo create_info;
1780 VkResult vr;
1782 TRACE("query %p, flags %#x.\n", query, flags);
1784 if (flags & WINED3DISSUE_END)
1786 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1787 wined3d_context_vk_end_current_render_pass(context_vk);
1789 if (query_vk->vk_event)
1791 if (query_vk->command_buffer_id > context_vk->completed_command_buffer_id)
1793 /* Cannot reuse this event, as it may still get signalled by previous usage. */
1794 /* Throw it away and create a new one, but if that happens a lot we may want to pool instead. */
1795 wined3d_context_vk_destroy_vk_event(context_vk, query_vk->vk_event, query_vk->command_buffer_id);
1796 query_vk->vk_event = VK_NULL_HANDLE;
1798 else
1800 VK_CALL(vkResetEvent(device_vk->vk_device, query_vk->vk_event));
1804 if (!query_vk->vk_event)
1806 create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
1807 create_info.pNext = NULL;
1808 create_info.flags = 0;
1810 vr = VK_CALL(vkCreateEvent(device_vk->vk_device, &create_info, NULL, &query_vk->vk_event));
1811 if (vr != VK_SUCCESS)
1813 ERR("Failed to create Vulkan event, vr %s\n", wined3d_debug_vkresult(vr));
1814 context_release(&context_vk->c);
1815 return FALSE;
1819 wined3d_context_vk_reference_query(context_vk, query_vk);
1820 VK_CALL(vkCmdSetEvent(wined3d_context_vk_get_command_buffer(context_vk), query_vk->vk_event,
1821 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT));
1822 context_release(&context_vk->c);
1824 return TRUE;
1827 return FALSE;
1830 static const struct wined3d_query_ops wined3d_query_event_vk_ops =
1832 .query_poll = wined3d_query_event_vk_poll,
1833 .query_issue = wined3d_query_event_vk_issue,
1834 .query_destroy = wined3d_query_vk_destroy,
1837 static BOOL wined3d_query_timestamp_vk_issue(struct wined3d_query *query, uint32_t flags)
1839 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1840 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1841 const struct wined3d_vk_info *vk_info;
1842 struct wined3d_context_vk *context_vk;
1843 VkCommandBuffer command_buffer;
1845 TRACE("query %p, flags %#x.\n", query, flags);
1847 if (flags & WINED3DISSUE_BEGIN)
1848 TRACE("Ignoring WINED3DISSUE_BEGIN.\n");
1850 if (flags & WINED3DISSUE_END)
1852 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1853 vk_info = context_vk->vk_info;
1855 command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
1856 if (query_vk->pool_idx.pool_vk)
1857 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk, query_vk->pool_idx.idx, context_vk);
1858 if (!wined3d_context_vk_allocate_query(context_vk, query_vk->q.type, &query_vk->pool_idx))
1860 ERR("Failed to allocate new query.\n");
1861 return FALSE;
1863 VK_CALL(vkCmdWriteTimestamp(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1864 query_vk->pool_idx.pool_vk->vk_query_pool, query_vk->pool_idx.idx));
1865 wined3d_context_vk_reference_query(context_vk, query_vk);
1867 context_release(&context_vk->c);
1869 return TRUE;
1872 return FALSE;
1875 static const struct wined3d_query_ops wined3d_query_timestamp_vk_ops =
1877 .query_poll = wined3d_query_vk_poll,
1878 .query_issue = wined3d_query_timestamp_vk_issue,
1879 .query_destroy = wined3d_query_vk_destroy,
1882 static const struct wined3d_query_ops wined3d_query_timestamp_disjoint_vk_ops =
1884 .query_poll = wined3d_timestamp_disjoint_query_ops_poll,
1885 .query_issue = wined3d_timestamp_disjoint_query_ops_issue,
1886 .query_destroy = wined3d_query_vk_destroy,
1889 HRESULT wined3d_query_vk_create(struct wined3d_device *device, enum wined3d_query_type type,
1890 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1892 struct wined3d_query_data_timestamp_disjoint *disjoint_data;
1893 const struct wined3d_query_ops *ops = &wined3d_query_vk_ops;
1894 struct wined3d_query_vk *query_vk;
1895 unsigned int data_size;
1896 void *data;
1898 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1899 device, type, parent, parent_ops, query);
1901 switch (type)
1903 case WINED3D_QUERY_TYPE_EVENT:
1904 ops = &wined3d_query_event_vk_ops;
1905 data_size = sizeof(BOOL);
1906 break;
1908 case WINED3D_QUERY_TYPE_OCCLUSION:
1909 data_size = sizeof(uint64_t);
1910 break;
1912 case WINED3D_QUERY_TYPE_TIMESTAMP:
1913 if (!wined3d_device_vk(device)->timestamp_bits)
1915 WARN("Timestamp queries not supported.\n");
1916 return WINED3DERR_NOTAVAILABLE;
1918 ops = &wined3d_query_timestamp_vk_ops;
1919 data_size = sizeof(uint64_t);
1920 break;
1922 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1923 if (!wined3d_device_vk(device)->timestamp_bits)
1925 WARN("Timestamp queries not supported.\n");
1926 return WINED3DERR_NOTAVAILABLE;
1928 ops = &wined3d_query_timestamp_disjoint_vk_ops;
1929 data_size = sizeof(struct wined3d_query_data_timestamp_disjoint);
1930 break;
1932 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1933 data_size = sizeof(struct wined3d_query_data_pipeline_statistics);
1934 break;
1936 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1937 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1938 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1939 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1940 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1941 if (!wined3d_adapter_vk(device->adapter)->vk_info.supported[WINED3D_VK_EXT_TRANSFORM_FEEDBACK])
1943 WARN("Stream output queries not supported.\n");
1944 return WINED3DERR_NOTAVAILABLE;
1946 data_size = sizeof(struct wined3d_query_data_so_statistics);
1947 break;
1949 default:
1950 FIXME("Unhandled query type %#x.\n", type);
1951 return WINED3DERR_NOTAVAILABLE;
1954 if (!(query_vk = heap_alloc_zero(sizeof(*query_vk) + data_size)))
1955 return E_OUTOFMEMORY;
1956 data = query_vk + 1;
1958 wined3d_query_init(&query_vk->q, device, type, data, data_size, ops, parent, parent_ops);
1959 query_vk->q.poll_in_cs = false;
1961 switch (type)
1963 case WINED3D_QUERY_TYPE_OCCLUSION:
1964 query_vk->control_flags = VK_QUERY_CONTROL_PRECISE_BIT;
1965 break;
1967 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1968 disjoint_data = data;
1969 disjoint_data->frequency = 1000000000 / wined3d_adapter_vk(device->adapter)->device_limits.timestampPeriod;
1970 disjoint_data->disjoint = FALSE;
1971 break;
1973 default:
1974 break;
1977 TRACE("Created query %p.\n", query_vk);
1978 *query = &query_vk->q;
1980 return WINED3D_OK;
1983 HRESULT CDECL wined3d_query_create(struct wined3d_device *device, enum wined3d_query_type type,
1984 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1986 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1987 device, type, parent, parent_ops, query);
1989 return device->adapter->adapter_ops->adapter_create_query(device, type, parent, parent_ops, query);