winevulkan: Convert all 32-bit structs containing pNext pointer.
[wine.git] / dlls / wined3d / query.c
blob34ee56d5d115ee435dd57bd4088ff431a7f69b90
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 enum wined3d_fence_result wined3d_fence_test(const struct wined3d_fence *fence,
177 struct wined3d_device *device, DWORD flags)
179 const struct wined3d_gl_info *gl_info;
180 struct wined3d_context_gl *context_gl;
181 enum wined3d_fence_result ret;
182 BOOL fence_result;
184 TRACE("fence %p, device %p, flags %#x.\n", fence, device, flags);
186 if (!fence->context_gl)
188 TRACE("Fence not issued.\n");
189 return WINED3D_FENCE_NOT_STARTED;
192 if (!(context_gl = wined3d_context_gl_reacquire(fence->context_gl)))
194 if (!fence->context_gl->gl_info->supported[ARB_SYNC])
196 WARN("Fence tested from wrong thread.\n");
197 return WINED3D_FENCE_WRONG_THREAD;
199 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
201 gl_info = context_gl->gl_info;
203 if (gl_info->supported[ARB_SYNC])
205 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
206 (flags & WINED3DGETDATA_FLUSH) ? GL_SYNC_FLUSH_COMMANDS_BIT : 0, 0));
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 case GL_TIMEOUT_EXPIRED:
217 ret = WINED3D_FENCE_WAITING;
218 break;
220 case GL_WAIT_FAILED:
221 default:
222 ERR("glClientWaitSync returned %#x.\n", gl_ret);
223 ret = WINED3D_FENCE_ERROR;
226 else if (gl_info->supported[APPLE_FENCE])
228 fence_result = GL_EXTCALL(glTestFenceAPPLE(fence->object.id));
229 checkGLcall("glTestFenceAPPLE");
230 if (fence_result)
231 ret = WINED3D_FENCE_OK;
232 else
233 ret = WINED3D_FENCE_WAITING;
235 else if (gl_info->supported[NV_FENCE])
237 fence_result = GL_EXTCALL(glTestFenceNV(fence->object.id));
238 checkGLcall("glTestFenceNV");
239 if (fence_result)
240 ret = WINED3D_FENCE_OK;
241 else
242 ret = WINED3D_FENCE_WAITING;
244 else
246 ERR("Fence created despite lack of GL support.\n");
247 ret = WINED3D_FENCE_ERROR;
250 context_release(&context_gl->c);
251 return ret;
254 enum wined3d_fence_result wined3d_fence_wait(const struct wined3d_fence *fence,
255 struct wined3d_device *device)
257 const struct wined3d_gl_info *gl_info;
258 struct wined3d_context_gl *context_gl;
259 enum wined3d_fence_result ret;
261 TRACE("fence %p, device %p.\n", fence, device);
263 if (!fence->context_gl)
265 TRACE("Fence not issued.\n");
266 return WINED3D_FENCE_NOT_STARTED;
268 gl_info = fence->context_gl->gl_info;
270 if (!(context_gl = wined3d_context_gl_reacquire(fence->context_gl)))
272 /* A glFinish does not reliably wait for draws in other contexts. The caller has
273 * to find its own way to cope with the thread switch
275 if (!gl_info->supported[ARB_SYNC])
277 WARN("Fence finished from wrong thread.\n");
278 return WINED3D_FENCE_WRONG_THREAD;
280 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
282 gl_info = context_gl->gl_info;
284 if (gl_info->supported[ARB_SYNC])
286 /* Timeouts near 0xffffffffffffffff may immediately return GL_TIMEOUT_EXPIRED,
287 * possibly because macOS internally adds some slop to the timer. To avoid this,
288 * we use a large number that isn't near the point of overflow (macOS 10.12.5).
290 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
291 GL_SYNC_FLUSH_COMMANDS_BIT, ~(GLuint64)0 >> 1));
292 checkGLcall("glClientWaitSync");
294 switch (gl_ret)
296 case GL_ALREADY_SIGNALED:
297 case GL_CONDITION_SATISFIED:
298 ret = WINED3D_FENCE_OK;
299 break;
301 /* We don't expect a timeout for a ~292 year wait */
302 default:
303 ERR("glClientWaitSync returned %#x.\n", gl_ret);
304 ret = WINED3D_FENCE_ERROR;
307 else if (gl_info->supported[APPLE_FENCE])
309 GL_EXTCALL(glFinishFenceAPPLE(fence->object.id));
310 checkGLcall("glFinishFenceAPPLE");
311 ret = WINED3D_FENCE_OK;
313 else if (gl_info->supported[NV_FENCE])
315 GL_EXTCALL(glFinishFenceNV(fence->object.id));
316 checkGLcall("glFinishFenceNV");
317 ret = WINED3D_FENCE_OK;
319 else
321 ERR("Fence created without GL support.\n");
322 ret = WINED3D_FENCE_ERROR;
325 context_release(&context_gl->c);
326 return ret;
329 void wined3d_fence_issue(struct wined3d_fence *fence, struct wined3d_device *device)
331 struct wined3d_context_gl *context_gl = NULL;
332 const struct wined3d_gl_info *gl_info;
334 if (fence->context_gl && !(context_gl = wined3d_context_gl_reacquire(fence->context_gl))
335 && !fence->context_gl->gl_info->supported[ARB_SYNC])
336 wined3d_context_gl_free_fence(fence);
337 if (!context_gl)
338 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
339 gl_info = context_gl->gl_info;
340 if (!fence->context_gl)
341 wined3d_context_gl_alloc_fence(context_gl, fence);
343 if (gl_info->supported[ARB_SYNC])
345 if (fence->object.sync)
346 GL_EXTCALL(glDeleteSync(fence->object.sync));
347 checkGLcall("glDeleteSync");
348 fence->object.sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
349 checkGLcall("glFenceSync");
351 else if (gl_info->supported[APPLE_FENCE])
353 GL_EXTCALL(glSetFenceAPPLE(fence->object.id));
354 checkGLcall("glSetFenceAPPLE");
356 else if (gl_info->supported[NV_FENCE])
358 GL_EXTCALL(glSetFenceNV(fence->object.id, GL_ALL_COMPLETED_NV));
359 checkGLcall("glSetFenceNV");
362 context_release(&context_gl->c);
365 static void wined3d_fence_free(struct wined3d_fence *fence)
367 if (fence->context_gl)
368 wined3d_context_gl_free_fence(fence);
371 void wined3d_fence_destroy(struct wined3d_fence *fence)
373 wined3d_fence_free(fence);
374 heap_free(fence);
377 static HRESULT wined3d_fence_init(struct wined3d_fence *fence, const struct wined3d_gl_info *gl_info)
379 if (!wined3d_fence_supported(gl_info))
381 WARN("Fences not supported.\n");
382 return WINED3DERR_NOTAVAILABLE;
385 return WINED3D_OK;
388 HRESULT wined3d_fence_create(struct wined3d_device *device, struct wined3d_fence **fence)
390 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
391 struct wined3d_fence *object;
392 HRESULT hr;
394 TRACE("device %p, fence %p.\n", device, fence);
396 if (!(object = heap_alloc_zero(sizeof(*object))))
397 return E_OUTOFMEMORY;
399 if (FAILED(hr = wined3d_fence_init(object, gl_info)))
401 heap_free(object);
402 return hr;
405 TRACE("Created fence %p.\n", object);
406 *fence = object;
408 return WINED3D_OK;
411 ULONG CDECL wined3d_query_incref(struct wined3d_query *query)
413 ULONG refcount = InterlockedIncrement(&query->ref);
415 TRACE("%p increasing refcount to %u.\n", query, refcount);
417 return refcount;
420 static void wined3d_query_destroy_object(void *object)
422 struct wined3d_query *query = object;
424 TRACE("query %p.\n", query);
426 if (!list_empty(&query->poll_list_entry))
427 list_remove(&query->poll_list_entry);
430 ULONG CDECL wined3d_query_decref(struct wined3d_query *query)
432 ULONG refcount = InterlockedDecrement(&query->ref);
434 TRACE("%p decreasing refcount to %u.\n", query, refcount);
436 if (!refcount)
438 struct wined3d_device *device = query->device;
440 wined3d_mutex_lock();
441 query->parent_ops->wined3d_object_destroyed(query->parent);
442 wined3d_cs_destroy_object(device->cs, wined3d_query_destroy_object, query);
443 device->adapter->adapter_ops->adapter_destroy_query(query);
444 wined3d_mutex_unlock();
447 return refcount;
450 HRESULT CDECL wined3d_query_get_data(struct wined3d_query *query,
451 void *data, UINT data_size, DWORD flags)
453 TRACE("query %p, data %p, data_size %u, flags %#x.\n",
454 query, data, data_size, flags);
456 if (query->state == QUERY_BUILDING)
458 WARN("Query is building, returning S_FALSE.\n");
459 return S_FALSE;
462 if (query->state == QUERY_CREATED)
464 WARN("Query wasn't started yet.\n");
465 return WINED3DERR_INVALIDCALL;
468 if (query->counter_main != query->counter_retrieved
469 || (query->buffer_object && !wined3d_query_buffer_is_valid(query)))
471 if (flags & WINED3DGETDATA_FLUSH && !query->device->cs->queries_flushed)
472 query->device->cs->c.ops->flush(&query->device->cs->c);
473 return S_FALSE;
475 else if (!query->poll_in_cs && !query->query_ops->query_poll(query, flags))
477 return S_FALSE;
480 if (query->buffer_object)
481 query->data = query->map_ptr;
483 if (data)
484 memcpy(data, query->data, min(data_size, query->data_size));
486 return S_OK;
489 UINT CDECL wined3d_query_get_data_size(const struct wined3d_query *query)
491 TRACE("query %p.\n", query);
493 return query->data_size;
496 HRESULT CDECL wined3d_query_issue(struct wined3d_query *query, DWORD flags)
498 TRACE("query %p, flags %#x.\n", query, flags);
500 wined3d_device_context_issue_query(&query->device->cs->c, query, flags);
502 return WINED3D_OK;
505 static BOOL wined3d_occlusion_query_ops_poll(struct wined3d_query *query, DWORD flags)
507 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
508 const struct wined3d_gl_info *gl_info;
509 struct wined3d_context_gl *context_gl;
510 GLuint available;
512 TRACE("query %p, flags %#x.\n", query, flags);
514 if (!(context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
516 FIXME("%p Wrong thread, returning 1.\n", query);
517 oq->samples = 1;
518 return TRUE;
520 gl_info = context_gl->gl_info;
522 GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT_AVAILABLE, &available));
523 TRACE("Available %#x.\n", available);
525 if (available)
527 oq->samples = get_query_result64(oq->id, gl_info);
528 TRACE("Returning 0x%s samples.\n", wine_dbgstr_longlong(oq->samples));
531 checkGLcall("poll occlusion query");
532 context_release(&context_gl->c);
534 return available;
537 static BOOL wined3d_event_query_ops_poll(struct wined3d_query *query, DWORD flags)
539 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
540 enum wined3d_fence_result ret;
542 TRACE("query %p, flags %#x.\n", query, flags);
544 ret = wined3d_fence_test(&event_query->fence, query->device, flags);
545 switch (ret)
547 case WINED3D_FENCE_OK:
548 case WINED3D_FENCE_NOT_STARTED:
549 return event_query->signalled = TRUE;
551 case WINED3D_FENCE_WAITING:
552 return event_query->signalled = FALSE;
554 case WINED3D_FENCE_WRONG_THREAD:
555 FIXME("(%p) Wrong thread, reporting GPU idle.\n", query);
556 return event_query->signalled = TRUE;
558 case WINED3D_FENCE_ERROR:
559 ERR("The GL event query failed.\n");
560 return event_query->signalled = TRUE;
562 default:
563 ERR("Unexpected wined3d_event_query_test result %#x.\n", ret);
564 return event_query->signalled = TRUE;
568 void * CDECL wined3d_query_get_parent(const struct wined3d_query *query)
570 TRACE("query %p.\n", query);
572 return query->parent;
575 enum wined3d_query_type CDECL wined3d_query_get_type(const struct wined3d_query *query)
577 TRACE("query %p.\n", query);
579 return query->type;
582 static BOOL wined3d_event_query_ops_issue(struct wined3d_query *query, DWORD flags)
584 TRACE("query %p, flags %#x.\n", query, flags);
586 if (flags & WINED3DISSUE_END)
588 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
590 wined3d_fence_issue(&event_query->fence, query->device);
591 return TRUE;
593 else if (flags & WINED3DISSUE_BEGIN)
595 /* Started implicitly at query creation. */
596 ERR("Event query issued with START flag - what to do?\n");
599 return FALSE;
602 static BOOL wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DWORD flags)
604 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
605 struct wined3d_device *device = query->device;
606 const struct wined3d_gl_info *gl_info;
607 struct wined3d_context_gl *context_gl;
608 BOOL poll = FALSE;
610 TRACE("query %p, flags %#x.\n", query, flags);
612 /* This is allowed according to MSDN and our tests. Reset the query and
613 * restart. */
614 if (flags & WINED3DISSUE_BEGIN)
616 if (oq->started)
618 if ((context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
620 gl_info = context_gl->gl_info;
621 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
622 checkGLcall("glEndQuery()");
624 else
626 FIXME("Wrong thread, can't restart query.\n");
627 wined3d_context_gl_free_occlusion_query(oq);
628 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
629 wined3d_context_gl_alloc_occlusion_query(context_gl, oq);
632 else
634 if (oq->context_gl)
635 wined3d_context_gl_free_occlusion_query(oq);
636 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
637 wined3d_context_gl_alloc_occlusion_query(context_gl, oq);
639 gl_info = context_gl->gl_info;
641 GL_EXTCALL(glBeginQuery(GL_SAMPLES_PASSED, oq->id));
642 checkGLcall("glBeginQuery()");
644 context_release(&context_gl->c);
645 oq->started = TRUE;
647 if (flags & WINED3DISSUE_END)
649 /* MSDN says END on a non-building occlusion query returns an error,
650 * but our tests show that it returns OK. But OpenGL doesn't like it,
651 * so avoid generating an error. */
652 if (oq->started)
654 if ((context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
656 gl_info = context_gl->gl_info;
657 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
658 checkGLcall("glEndQuery()");
659 wined3d_query_buffer_queue_result(context_gl, query, oq->id);
661 context_release(&context_gl->c);
662 poll = TRUE;
664 else
666 FIXME("Wrong thread, can't end query.\n");
669 oq->started = FALSE;
672 return poll;
675 static BOOL wined3d_timestamp_query_ops_poll(struct wined3d_query *query, DWORD flags)
677 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
678 const struct wined3d_gl_info *gl_info;
679 struct wined3d_context_gl *context_gl;
680 GLuint64 timestamp;
681 GLuint available;
683 TRACE("query %p, flags %#x.\n", query, flags);
685 if (!(context_gl = wined3d_context_gl_reacquire(tq->context_gl)))
687 FIXME("%p Wrong thread, returning 1.\n", query);
688 tq->timestamp = 1;
689 return TRUE;
691 gl_info = context_gl->gl_info;
693 GL_EXTCALL(glGetQueryObjectuiv(tq->id, GL_QUERY_RESULT_AVAILABLE, &available));
694 checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
695 TRACE("available %#x.\n", available);
697 if (available)
699 GL_EXTCALL(glGetQueryObjectui64v(tq->id, GL_QUERY_RESULT, &timestamp));
700 checkGLcall("glGetQueryObjectui64v(GL_QUERY_RESULT)");
701 TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp));
702 tq->timestamp = timestamp;
705 context_release(&context_gl->c);
707 return available;
710 static BOOL wined3d_timestamp_query_ops_issue(struct wined3d_query *query, DWORD flags)
712 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
713 const struct wined3d_gl_info *gl_info;
714 struct wined3d_context_gl *context_gl;
716 TRACE("query %p, flags %#x.\n", query, flags);
718 if (flags & WINED3DISSUE_BEGIN)
720 WARN("Ignoring WINED3DISSUE_BEGIN with a TIMESTAMP query.\n");
722 if (flags & WINED3DISSUE_END)
724 if (tq->context_gl)
725 wined3d_context_gl_free_timestamp_query(tq);
726 context_gl = wined3d_context_gl(context_acquire(query->device, NULL, 0));
727 gl_info = context_gl->gl_info;
728 wined3d_context_gl_alloc_timestamp_query(context_gl, tq);
729 GL_EXTCALL(glQueryCounter(tq->id, GL_TIMESTAMP));
730 checkGLcall("glQueryCounter()");
731 context_release(&context_gl->c);
733 return TRUE;
736 return FALSE;
739 static BOOL wined3d_timestamp_disjoint_query_ops_poll(struct wined3d_query *query, DWORD flags)
741 TRACE("query %p, flags %#x.\n", query, flags);
743 return TRUE;
746 static BOOL wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query *query, DWORD flags)
748 TRACE("query %p, flags %#x.\n", query, flags);
750 return FALSE;
753 static BOOL wined3d_so_statistics_query_ops_poll(struct wined3d_query *query, DWORD flags)
755 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
756 GLuint written_available, generated_available;
757 const struct wined3d_gl_info *gl_info;
758 struct wined3d_context_gl *context_gl;
760 TRACE("query %p, flags %#x.\n", query, flags);
762 if (!(context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
764 FIXME("%p Wrong thread, returning 0 primitives.\n", query);
765 memset(&pq->statistics, 0, sizeof(pq->statistics));
766 return TRUE;
768 gl_info = context_gl->gl_info;
770 GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.written,
771 GL_QUERY_RESULT_AVAILABLE, &written_available));
772 GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.generated,
773 GL_QUERY_RESULT_AVAILABLE, &generated_available));
774 TRACE("Available %#x, %#x.\n", written_available, generated_available);
776 if (written_available && generated_available)
778 pq->statistics.primitives_written = get_query_result64(pq->u.query.written, gl_info);
779 pq->statistics.primitives_generated = get_query_result64(pq->u.query.generated, gl_info);
780 TRACE("Returning %s, %s primitives.\n",
781 wine_dbgstr_longlong(pq->statistics.primitives_written),
782 wine_dbgstr_longlong(pq->statistics.primitives_generated));
785 checkGLcall("poll SO statistics query");
786 context_release(&context_gl->c);
788 return written_available && generated_available;
791 static void wined3d_so_statistics_query_end(struct wined3d_so_statistics_query *query,
792 struct wined3d_context_gl *context_gl)
794 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
796 if (gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
798 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query->stream_idx));
799 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED, query->stream_idx));
801 else
803 GL_EXTCALL(glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN));
804 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_GENERATED));
806 checkGLcall("end query");
809 static BOOL wined3d_so_statistics_query_ops_issue(struct wined3d_query *query, DWORD flags)
811 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
812 struct wined3d_device *device = query->device;
813 const struct wined3d_gl_info *gl_info;
814 struct wined3d_context_gl *context_gl;
815 BOOL poll = FALSE;
817 TRACE("query %p, flags %#x.\n", query, flags);
819 if (flags & WINED3DISSUE_BEGIN)
821 if (pq->started)
823 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
825 wined3d_so_statistics_query_end(pq, context_gl);
827 else
829 FIXME("Wrong thread, can't restart query.\n");
830 wined3d_context_gl_free_so_statistics_query(pq);
831 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
832 wined3d_context_gl_alloc_so_statistics_query(context_gl, pq);
835 else
837 if (pq->context_gl)
838 wined3d_context_gl_free_so_statistics_query(pq);
839 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
840 wined3d_context_gl_alloc_so_statistics_query(context_gl, pq);
842 gl_info = context_gl->gl_info;
844 if (gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
846 GL_EXTCALL(glBeginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
847 pq->stream_idx, pq->u.query.written));
848 GL_EXTCALL(glBeginQueryIndexed(GL_PRIMITIVES_GENERATED,
849 pq->stream_idx, pq->u.query.generated));
851 else
853 GL_EXTCALL(glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
854 pq->u.query.written));
855 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_GENERATED,
856 pq->u.query.generated));
858 checkGLcall("begin query");
860 context_release(&context_gl->c);
861 pq->started = TRUE;
863 if (flags & WINED3DISSUE_END)
865 if (pq->started)
867 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
869 wined3d_so_statistics_query_end(pq, context_gl);
871 context_release(&context_gl->c);
872 poll = TRUE;
874 else
876 FIXME("Wrong thread, can't end query.\n");
879 pq->started = FALSE;
882 return poll;
885 static BOOL wined3d_pipeline_query_ops_poll(struct wined3d_query *query, DWORD flags)
887 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
888 const struct wined3d_gl_info *gl_info;
889 struct wined3d_context_gl *context_gl;
890 GLuint available;
891 int i;
893 TRACE("query %p, flags %#x.\n", query, flags);
895 if (!(context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
897 FIXME("%p Wrong thread.\n", query);
898 memset(&pq->statistics, 0, sizeof(pq->statistics));
899 return TRUE;
901 gl_info = context_gl->gl_info;
903 for (i = 0; i < ARRAY_SIZE(pq->u.id); ++i)
905 GL_EXTCALL(glGetQueryObjectuiv(pq->u.id[i], GL_QUERY_RESULT_AVAILABLE, &available));
906 if (!available)
907 break;
910 if (available)
912 pq->statistics.vertices_submitted = get_query_result64(pq->u.query.vertices, gl_info);
913 pq->statistics.primitives_submitted = get_query_result64(pq->u.query.primitives, gl_info);
914 pq->statistics.vs_invocations = get_query_result64(pq->u.query.vertex_shader, gl_info);
915 pq->statistics.hs_invocations = get_query_result64(pq->u.query.tess_control_shader, gl_info);
916 pq->statistics.ds_invocations = get_query_result64(pq->u.query.tess_eval_shader, gl_info);
917 pq->statistics.gs_invocations = get_query_result64(pq->u.query.geometry_shader, gl_info);
918 pq->statistics.gs_primitives = get_query_result64(pq->u.query.geometry_primitives, gl_info);
919 pq->statistics.ps_invocations = get_query_result64(pq->u.query.fragment_shader, gl_info);
920 pq->statistics.cs_invocations = get_query_result64(pq->u.query.compute_shader, gl_info);
921 pq->statistics.clipping_input_primitives = get_query_result64(pq->u.query.clipping_input, gl_info);
922 pq->statistics.clipping_output_primitives = get_query_result64(pq->u.query.clipping_output, gl_info);
925 checkGLcall("poll pipeline statistics query");
926 context_release(&context_gl->c);
927 return available;
930 static void wined3d_pipeline_statistics_query_end(struct wined3d_pipeline_statistics_query *query,
931 struct wined3d_context_gl *context_gl)
933 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
935 GL_EXTCALL(glEndQuery(GL_VERTICES_SUBMITTED_ARB));
936 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_SUBMITTED_ARB));
937 GL_EXTCALL(glEndQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB));
938 GL_EXTCALL(glEndQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB));
939 GL_EXTCALL(glEndQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB));
940 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_INVOCATIONS));
941 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB));
942 GL_EXTCALL(glEndQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB));
943 GL_EXTCALL(glEndQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB));
944 GL_EXTCALL(glEndQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB));
945 GL_EXTCALL(glEndQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB));
946 checkGLcall("end query");
949 static BOOL wined3d_pipeline_query_ops_issue(struct wined3d_query *query, DWORD flags)
951 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
952 struct wined3d_device *device = query->device;
953 const struct wined3d_gl_info *gl_info;
954 struct wined3d_context_gl *context_gl;
955 BOOL poll = FALSE;
957 TRACE("query %p, flags %#x.\n", query, flags);
959 if (flags & WINED3DISSUE_BEGIN)
961 if (pq->started)
963 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
965 wined3d_pipeline_statistics_query_end(pq, context_gl);
967 else
969 FIXME("Wrong thread, can't restart query.\n");
970 wined3d_context_gl_free_pipeline_statistics_query(pq);
971 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
972 wined3d_context_gl_alloc_pipeline_statistics_query(context_gl, pq);
975 else
977 if (pq->context_gl)
978 wined3d_context_gl_free_pipeline_statistics_query(pq);
979 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
980 wined3d_context_gl_alloc_pipeline_statistics_query(context_gl, pq);
982 gl_info = context_gl->gl_info;
984 GL_EXTCALL(glBeginQuery(GL_VERTICES_SUBMITTED_ARB, pq->u.query.vertices));
985 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_SUBMITTED_ARB, pq->u.query.primitives));
986 GL_EXTCALL(glBeginQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB, pq->u.query.vertex_shader));
987 GL_EXTCALL(glBeginQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB, pq->u.query.tess_control_shader));
988 GL_EXTCALL(glBeginQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB, pq->u.query.tess_eval_shader));
989 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_INVOCATIONS, pq->u.query.geometry_shader));
990 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB, pq->u.query.geometry_primitives));
991 GL_EXTCALL(glBeginQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB, pq->u.query.fragment_shader));
992 GL_EXTCALL(glBeginQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB, pq->u.query.compute_shader));
993 GL_EXTCALL(glBeginQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB, pq->u.query.clipping_input));
994 GL_EXTCALL(glBeginQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB, pq->u.query.clipping_output));
995 checkGLcall("begin query");
997 context_release(&context_gl->c);
998 pq->started = TRUE;
1000 if (flags & WINED3DISSUE_END)
1002 if (pq->started)
1004 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
1006 wined3d_pipeline_statistics_query_end(pq, context_gl);
1007 context_release(&context_gl->c);
1008 poll = TRUE;
1010 else
1012 FIXME("Wrong thread, can't end query.\n");
1015 pq->started = FALSE;
1018 return poll;
1021 static void wined3d_event_query_ops_destroy(struct wined3d_query *query)
1023 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
1025 wined3d_fence_free(&event_query->fence);
1026 heap_free(event_query);
1029 static const struct wined3d_query_ops event_query_ops =
1031 wined3d_event_query_ops_poll,
1032 wined3d_event_query_ops_issue,
1033 wined3d_event_query_ops_destroy,
1036 static HRESULT wined3d_event_query_create(struct wined3d_device *device,
1037 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1038 struct wined3d_query **query)
1040 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1041 struct wined3d_event_query *object;
1042 HRESULT hr;
1044 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1045 device, type, parent, parent_ops, query);
1047 if (!(object = heap_alloc_zero(sizeof(*object))))
1048 return E_OUTOFMEMORY;
1050 if (FAILED(hr = wined3d_fence_init(&object->fence, gl_info)))
1052 WARN("Event queries not supported.\n");
1053 heap_free(object);
1054 return hr;
1057 wined3d_query_init(&object->query, device, type, &object->signalled,
1058 sizeof(object->signalled), &event_query_ops, parent, parent_ops);
1060 TRACE("Created query %p.\n", object);
1061 *query = &object->query;
1063 return WINED3D_OK;
1066 static void wined3d_occlusion_query_ops_destroy(struct wined3d_query *query)
1068 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
1070 if (oq->context_gl)
1071 wined3d_context_gl_free_occlusion_query(oq);
1072 heap_free(oq);
1075 static const struct wined3d_query_ops occlusion_query_ops =
1077 wined3d_occlusion_query_ops_poll,
1078 wined3d_occlusion_query_ops_issue,
1079 wined3d_occlusion_query_ops_destroy,
1082 static HRESULT wined3d_occlusion_query_create(struct wined3d_device *device,
1083 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1084 struct wined3d_query **query)
1086 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1087 struct wined3d_occlusion_query *object;
1089 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1090 device, type, parent, parent_ops, query);
1092 if (!gl_info->supported[ARB_OCCLUSION_QUERY])
1094 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
1095 return WINED3DERR_NOTAVAILABLE;
1098 if (!(object = heap_alloc_zero(sizeof(*object))))
1099 return E_OUTOFMEMORY;
1101 wined3d_query_init(&object->query, device, type, &object->samples,
1102 sizeof(object->samples), &occlusion_query_ops, parent, parent_ops);
1104 TRACE("Created query %p.\n", object);
1105 *query = &object->query;
1107 return WINED3D_OK;
1110 static void wined3d_timestamp_query_ops_destroy(struct wined3d_query *query)
1112 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
1114 if (tq->context_gl)
1115 wined3d_context_gl_free_timestamp_query(tq);
1116 heap_free(tq);
1119 static const struct wined3d_query_ops timestamp_query_ops =
1121 wined3d_timestamp_query_ops_poll,
1122 wined3d_timestamp_query_ops_issue,
1123 wined3d_timestamp_query_ops_destroy,
1126 static HRESULT wined3d_timestamp_query_create(struct wined3d_device *device,
1127 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1128 struct wined3d_query **query)
1130 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1131 struct wined3d_timestamp_query *object;
1133 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1134 device, type, parent, parent_ops, query);
1136 if (!gl_info->supported[ARB_TIMER_QUERY])
1138 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1139 return WINED3DERR_NOTAVAILABLE;
1142 if (!(object = heap_alloc_zero(sizeof(*object))))
1143 return E_OUTOFMEMORY;
1145 wined3d_query_init(&object->query, device, type, &object->timestamp,
1146 sizeof(object->timestamp), &timestamp_query_ops, parent, parent_ops);
1148 TRACE("Created query %p.\n", object);
1149 *query = &object->query;
1151 return WINED3D_OK;
1154 static void wined3d_timestamp_disjoint_query_ops_destroy(struct wined3d_query *query)
1156 heap_free(query);
1159 static const struct wined3d_query_ops timestamp_disjoint_query_ops =
1161 wined3d_timestamp_disjoint_query_ops_poll,
1162 wined3d_timestamp_disjoint_query_ops_issue,
1163 wined3d_timestamp_disjoint_query_ops_destroy,
1166 static HRESULT wined3d_timestamp_disjoint_query_create(struct wined3d_device *device,
1167 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1168 struct wined3d_query **query)
1170 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1171 struct wined3d_query *object;
1173 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1174 device, type, parent, parent_ops, query);
1176 if (!gl_info->supported[ARB_TIMER_QUERY])
1178 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1179 return WINED3DERR_NOTAVAILABLE;
1182 if (!(object = heap_alloc_zero(sizeof(*object))))
1183 return E_OUTOFMEMORY;
1185 if (type == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT)
1187 static const struct wined3d_query_data_timestamp_disjoint disjoint_data = {1000 * 1000 * 1000, FALSE};
1189 wined3d_query_init(object, device, type, &disjoint_data,
1190 sizeof(disjoint_data), &timestamp_disjoint_query_ops, parent, parent_ops);
1192 else
1194 static const UINT64 freq = 1000 * 1000 * 1000;
1196 wined3d_query_init(object, device, type, &freq,
1197 sizeof(freq), &timestamp_disjoint_query_ops, parent, parent_ops);
1200 TRACE("Created query %p.\n", object);
1201 *query = object;
1203 return WINED3D_OK;
1206 static void wined3d_so_statistics_query_ops_destroy(struct wined3d_query *query)
1208 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
1210 if (pq->context_gl)
1211 wined3d_context_gl_free_so_statistics_query(pq);
1212 heap_free(pq);
1215 static const struct wined3d_query_ops so_statistics_query_ops =
1217 wined3d_so_statistics_query_ops_poll,
1218 wined3d_so_statistics_query_ops_issue,
1219 wined3d_so_statistics_query_ops_destroy,
1222 static HRESULT wined3d_so_statistics_query_create(struct wined3d_device *device,
1223 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1224 struct wined3d_query **query)
1226 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1227 struct wined3d_so_statistics_query *object;
1228 unsigned int stream_idx;
1230 if (WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0 <= type && type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1231 stream_idx = type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0;
1232 else if (type == WINED3D_QUERY_TYPE_SO_STATISTICS)
1233 stream_idx = 0;
1234 else
1235 return WINED3DERR_NOTAVAILABLE;
1237 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1238 device, type, parent, parent_ops, query);
1240 if (!gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY])
1242 WARN("OpenGL implementation does not support primitive queries.\n");
1243 return WINED3DERR_NOTAVAILABLE;
1245 if (stream_idx && !gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
1247 WARN("OpenGL implementation does not support indexed queries.\n");
1248 return WINED3DERR_NOTAVAILABLE;
1251 if (!(object = heap_alloc_zero(sizeof(*object))))
1252 return E_OUTOFMEMORY;
1254 wined3d_query_init(&object->query, device, type, &object->statistics,
1255 sizeof(object->statistics), &so_statistics_query_ops, parent, parent_ops);
1256 object->stream_idx = stream_idx;
1258 TRACE("Created query %p.\n", object);
1259 *query = &object->query;
1261 return WINED3D_OK;
1264 static void wined3d_pipeline_query_ops_destroy(struct wined3d_query *query)
1266 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
1267 if (pq->context_gl)
1268 wined3d_context_gl_free_pipeline_statistics_query(pq);
1269 heap_free(pq);
1272 static const struct wined3d_query_ops pipeline_query_ops =
1274 wined3d_pipeline_query_ops_poll,
1275 wined3d_pipeline_query_ops_issue,
1276 wined3d_pipeline_query_ops_destroy,
1279 static HRESULT wined3d_pipeline_query_create(struct wined3d_device *device,
1280 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1281 struct wined3d_query **query)
1283 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1284 struct wined3d_pipeline_statistics_query *object;
1286 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1287 device, type, parent, parent_ops, query);
1289 if (!gl_info->supported[ARB_PIPELINE_STATISTICS_QUERY])
1291 WARN("OpenGL implementation does not support pipeline statistics queries.\n");
1292 return WINED3DERR_NOTAVAILABLE;
1295 if (!(object = heap_alloc_zero(sizeof(*object))))
1296 return E_OUTOFMEMORY;
1298 wined3d_query_init(&object->query, device, type, &object->statistics,
1299 sizeof(object->statistics), &pipeline_query_ops, parent, parent_ops);
1301 TRACE("Created query %p.\n", object);
1302 *query = &object->query;
1304 return WINED3D_OK;
1307 HRESULT wined3d_query_gl_create(struct wined3d_device *device, enum wined3d_query_type type,
1308 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1310 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1311 device, type, parent, parent_ops, query);
1313 switch (type)
1315 case WINED3D_QUERY_TYPE_EVENT:
1316 return wined3d_event_query_create(device, type, parent, parent_ops, query);
1318 case WINED3D_QUERY_TYPE_OCCLUSION:
1319 return wined3d_occlusion_query_create(device, type, parent, parent_ops, query);
1321 case WINED3D_QUERY_TYPE_TIMESTAMP:
1322 return wined3d_timestamp_query_create(device, type, parent, parent_ops, query);
1324 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1325 case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ:
1326 return wined3d_timestamp_disjoint_query_create(device, type, parent, parent_ops, query);
1328 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1329 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1330 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1331 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1332 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1333 return wined3d_so_statistics_query_create(device, type, parent, parent_ops, query);
1335 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1336 return wined3d_pipeline_query_create(device, type, parent, parent_ops, query);
1338 default:
1339 FIXME("Unhandled query type %#x.\n", type);
1340 return WINED3DERR_NOTAVAILABLE;
1344 static void wined3d_query_pool_vk_mark_complete(struct wined3d_query_pool_vk *pool_vk, size_t idx,
1345 struct wined3d_context_vk *context_vk)
1347 /* Don't reset completed queries right away, as vkCmdResetQueryPool() needs to happen
1348 * outside of a render pass. Queue the query to be reset at the very end of the current
1349 * command buffer instead. */
1350 wined3d_bitmap_set(pool_vk->completed, idx);
1351 if (list_empty(&pool_vk->completed_entry))
1352 list_add_tail(&context_vk->completed_query_pools, &pool_vk->completed_entry);
1355 bool wined3d_query_pool_vk_allocate_query(struct wined3d_query_pool_vk *pool_vk, size_t *idx)
1357 if ((*idx = wined3d_bitmap_ffz(pool_vk->allocated, WINED3D_QUERY_POOL_SIZE, 0)) > WINED3D_QUERY_POOL_SIZE)
1358 return false;
1359 wined3d_bitmap_set(pool_vk->allocated, *idx);
1361 return true;
1364 void wined3d_query_pool_vk_mark_free(struct wined3d_context_vk *context_vk, struct wined3d_query_pool_vk *pool_vk,
1365 uint32_t start, uint32_t count)
1367 unsigned int idx, end = start + count;
1369 for (idx = start; idx < end; ++idx)
1370 wined3d_bitmap_clear(pool_vk->allocated, idx);
1372 if (list_empty(&pool_vk->entry))
1373 list_add_tail(pool_vk->free_list, &pool_vk->entry);
1376 void wined3d_query_pool_vk_cleanup(struct wined3d_query_pool_vk *pool_vk, struct wined3d_context_vk *context_vk)
1378 struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
1379 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1381 VK_CALL(vkDestroyQueryPool(device_vk->vk_device, pool_vk->vk_query_pool, NULL));
1382 if (pool_vk->vk_event)
1383 VK_CALL(vkDestroyEvent(device_vk->vk_device, pool_vk->vk_event, NULL));
1384 list_remove(&pool_vk->entry);
1385 list_remove(&pool_vk->completed_entry);
1388 bool wined3d_query_pool_vk_init(struct wined3d_query_pool_vk *pool_vk,
1389 struct wined3d_context_vk *context_vk, enum wined3d_query_type type, struct list *free_pools)
1391 struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
1392 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1393 VkQueryPoolCreateInfo pool_info;
1394 VkResult vr;
1396 list_init(&pool_vk->entry);
1397 list_init(&pool_vk->completed_entry);
1398 pool_vk->free_list = free_pools;
1400 pool_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1401 pool_info.pNext = NULL;
1402 pool_info.flags = 0;
1403 pool_info.queryCount = WINED3D_QUERY_POOL_SIZE;
1405 switch (type)
1407 case WINED3D_QUERY_TYPE_OCCLUSION:
1408 pool_info.queryType = VK_QUERY_TYPE_OCCLUSION;
1409 pool_info.pipelineStatistics = 0;
1410 break;
1412 case WINED3D_QUERY_TYPE_TIMESTAMP:
1413 pool_info.queryType = VK_QUERY_TYPE_TIMESTAMP;
1414 pool_info.pipelineStatistics = 0;
1415 break;
1417 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1418 pool_info.queryType = VK_QUERY_TYPE_PIPELINE_STATISTICS;
1419 pool_info.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT
1420 | VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT
1421 | VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT
1422 | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT
1423 | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT
1424 | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT
1425 | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT
1426 | VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT
1427 | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT
1428 | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT
1429 | VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT;
1430 break;
1432 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1433 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1434 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1435 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1436 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1437 pool_info.queryType = VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT;
1438 pool_info.pipelineStatistics = 0;
1439 break;
1441 default:
1442 FIXME("Unhandled query type %#x.\n", type);
1443 return false;
1446 if ((vr = VK_CALL(vkCreateQueryPool(device_vk->vk_device, &pool_info, NULL, &pool_vk->vk_query_pool))) < 0)
1448 ERR("Failed to create Vulkan query pool, vr %s.\n", wined3d_debug_vkresult(vr));
1449 return false;
1452 list_add_head(free_pools, &pool_vk->entry);
1454 return true;
1457 bool wined3d_query_vk_accumulate_data(struct wined3d_query_vk *query_vk,
1458 struct wined3d_device_vk *device_vk, const struct wined3d_query_pool_idx_vk *pool_idx)
1460 const struct wined3d_query_data_pipeline_statistics *ps_tmp;
1461 const struct wined3d_vk_info *vk_info = &device_vk->vk_info;
1462 struct wined3d_query_data_pipeline_statistics *ps_result;
1463 VkResult vr;
1464 union
1466 uint64_t occlusion;
1467 uint64_t timestamp;
1468 struct wined3d_query_data_pipeline_statistics pipeline_statistics;
1469 struct wined3d_query_data_so_statistics so_statistics;
1470 } tmp, *result;
1472 if (pool_idx->pool_vk->vk_event)
1474 /* Check if the pool's initial reset command executed. */
1475 vr = VK_CALL(vkGetEventStatus(device_vk->vk_device,
1476 pool_idx->pool_vk->vk_event));
1477 if (vr == VK_EVENT_RESET)
1478 return false;
1479 else if (vr != VK_EVENT_SET)
1481 ERR("Failed to get event status, vr %s\n", wined3d_debug_vkresult(vr));
1482 return false;
1486 if ((vr = VK_CALL(vkGetQueryPoolResults(device_vk->vk_device, pool_idx->pool_vk->vk_query_pool,
1487 pool_idx->idx, 1, sizeof(tmp), &tmp, sizeof(tmp), VK_QUERY_RESULT_64_BIT))) < 0)
1489 ERR("Failed to get query results, vr %s.\n", wined3d_debug_vkresult(vr));
1490 return false;
1493 if (vr == VK_NOT_READY)
1494 return false;
1496 result = (void *)query_vk->q.data;
1497 switch (query_vk->q.type)
1499 case WINED3D_QUERY_TYPE_OCCLUSION:
1500 result->occlusion += tmp.occlusion;
1501 break;
1503 case WINED3D_QUERY_TYPE_TIMESTAMP:
1504 result->timestamp = tmp.timestamp;
1505 break;
1507 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1508 ps_result = &result->pipeline_statistics;
1509 ps_tmp = &tmp.pipeline_statistics;
1510 ps_result->vertices_submitted += ps_tmp->vertices_submitted;
1511 ps_result->primitives_submitted += ps_tmp->primitives_submitted;
1512 ps_result->vs_invocations += ps_tmp->vs_invocations;
1513 ps_result->gs_invocations += ps_tmp->gs_invocations;
1514 ps_result->gs_primitives += ps_tmp->gs_primitives;
1515 ps_result->clipping_input_primitives += ps_tmp->clipping_input_primitives;
1516 ps_result->clipping_output_primitives += ps_tmp->clipping_output_primitives;
1517 ps_result->ps_invocations += ps_tmp->ps_invocations;
1518 ps_result->hs_invocations += ps_tmp->hs_invocations;
1519 ps_result->ds_invocations += ps_tmp->ds_invocations;
1520 ps_result->cs_invocations += ps_tmp->cs_invocations;
1521 break;
1523 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1524 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1525 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1526 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1527 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1528 result->so_statistics.primitives_written += tmp.so_statistics.primitives_written;
1529 result->so_statistics.primitives_generated += tmp.so_statistics.primitives_generated;
1530 break;
1532 default:
1533 FIXME("Unhandled query type %#x.\n", query_vk->q.type);
1534 return false;
1537 return true;
1540 static void wined3d_query_vk_begin(struct wined3d_query_vk *query_vk,
1541 struct wined3d_context_vk *context_vk, VkCommandBuffer vk_command_buffer)
1543 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1544 struct wined3d_query_pool_vk *pool_vk;
1545 size_t idx;
1547 pool_vk = query_vk->pool_idx.pool_vk;
1548 idx = query_vk->pool_idx.idx;
1550 if (query_vk->q.type >= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
1551 && query_vk->q.type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1552 VK_CALL(vkCmdBeginQueryIndexedEXT(vk_command_buffer, pool_vk->vk_query_pool, idx,
1553 query_vk->control_flags, query_vk->q.type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0));
1554 else
1555 VK_CALL(vkCmdBeginQuery(vk_command_buffer, pool_vk->vk_query_pool, idx, query_vk->control_flags));
1556 wined3d_context_vk_reference_query(context_vk, query_vk);
1559 static void wined3d_query_vk_end(struct wined3d_query_vk *query_vk,
1560 struct wined3d_context_vk *context_vk, VkCommandBuffer vk_command_buffer)
1562 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1563 struct wined3d_query_pool_vk *pool_vk;
1564 size_t idx;
1566 pool_vk = query_vk->pool_idx.pool_vk;
1567 idx = query_vk->pool_idx.idx;
1569 if (query_vk->q.type >= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
1570 && query_vk->q.type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1571 VK_CALL(vkCmdEndQueryIndexedEXT(vk_command_buffer, pool_vk->vk_query_pool,
1572 idx, query_vk->q.type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0));
1573 else
1574 VK_CALL(vkCmdEndQuery(vk_command_buffer, pool_vk->vk_query_pool, idx));
1577 void wined3d_query_vk_resume(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk)
1579 VkCommandBuffer vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer;
1581 wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
1582 query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE;
1585 void wined3d_query_vk_suspend(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk)
1587 VkCommandBuffer vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer;
1589 wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
1591 if (!wined3d_array_reserve((void **)&query_vk->pending, &query_vk->pending_size,
1592 query_vk->pending_count + 1, sizeof(*query_vk->pending)))
1594 ERR("Failed to allocate entry.\n");
1595 return;
1598 query_vk->pending[query_vk->pending_count++] = query_vk->pool_idx;
1599 query_vk->pool_idx.pool_vk = NULL;
1600 query_vk->flags &= ~WINED3D_QUERY_VK_FLAG_ACTIVE;
1603 static BOOL wined3d_query_vk_poll(struct wined3d_query *query, uint32_t flags)
1605 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1606 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1607 unsigned int i;
1609 memset((void *)query->data, 0, query->data_size);
1611 if (query_vk->pool_idx.pool_vk && !wined3d_query_vk_accumulate_data(query_vk, device_vk, &query_vk->pool_idx))
1612 goto unavailable;
1614 for (i = 0; i < query_vk->pending_count; ++i)
1616 if (!wined3d_query_vk_accumulate_data(query_vk, device_vk, &query_vk->pending[i]))
1617 goto unavailable;
1620 return TRUE;
1622 unavailable:
1623 if ((flags & WINED3DGETDATA_FLUSH) && !query->device->cs->queries_flushed)
1624 query->device->cs->c.ops->flush(&query->device->cs->c);
1626 return FALSE;
1629 static void wined3d_query_vk_remove_pending_queries(struct wined3d_context_vk *context_vk,
1630 struct wined3d_query_vk *query_vk)
1632 size_t i;
1634 for (i = 0; i < query_vk->pending_count; ++i)
1635 wined3d_query_pool_vk_mark_complete(query_vk->pending[i].pool_vk, query_vk->pending[i].idx, context_vk);
1637 query_vk->pending_count = 0;
1640 static BOOL wined3d_query_vk_issue(struct wined3d_query *query, uint32_t flags)
1642 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1643 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1644 struct wined3d_context_vk *context_vk;
1645 VkCommandBuffer vk_command_buffer;
1646 bool poll = false;
1648 TRACE("query %p, flags %#x.\n", query, flags);
1650 if (flags & WINED3DISSUE_BEGIN)
1652 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1654 if (query_vk->pending_count)
1655 wined3d_query_vk_remove_pending_queries(context_vk, query_vk);
1656 vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
1657 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED)
1659 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_ACTIVE)
1660 wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
1661 list_remove(&query_vk->entry);
1663 if (query_vk->pool_idx.pool_vk)
1664 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk,
1665 query_vk->pool_idx.idx, context_vk);
1667 if (!wined3d_context_vk_allocate_query(context_vk, query_vk->q.type, &query_vk->pool_idx))
1669 ERR("Failed to allocate new query.\n");
1670 return false;
1673 /* A query needs to either begin and end inside a single render pass
1674 * or begin and end outside of a render pass. Occlusion queries, if
1675 * issued outside of a render pass, are queued up and only begun when
1676 * a render pass is started, to avoid interrupting the render pass
1677 * when the query ends. */
1678 if (context_vk->vk_render_pass)
1680 wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
1681 list_add_head(&context_vk->render_pass_queries, &query_vk->entry);
1682 query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE | WINED3D_QUERY_VK_FLAG_RENDER_PASS;
1684 else if (query->type == WINED3D_QUERY_TYPE_OCCLUSION)
1686 list_add_head(&context_vk->render_pass_queries, &query_vk->entry);
1687 query_vk->flags |= WINED3D_QUERY_VK_FLAG_RENDER_PASS;
1689 else
1691 wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
1692 list_add_head(&context_vk->active_queries, &query_vk->entry);
1693 query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE;
1696 query_vk->flags |= WINED3D_QUERY_VK_FLAG_STARTED;
1697 context_release(&context_vk->c);
1699 if (flags & WINED3DISSUE_END && query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED)
1701 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1703 /* If the query was already ended because the command buffer was
1704 * flushed or the render pass ended, we don't need to end it here. */
1705 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_ACTIVE)
1707 vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
1708 if (!(query_vk->flags & WINED3D_QUERY_VK_FLAG_RENDER_PASS))
1709 wined3d_context_vk_end_current_render_pass(context_vk);
1710 wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
1712 else if (query_vk->pool_idx.pool_vk)
1714 /* It was queued, but never activated. */
1715 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk,
1716 query_vk->pool_idx.idx, context_vk);
1717 query_vk->pool_idx.pool_vk = NULL;
1719 list_remove(&query_vk->entry);
1720 query_vk->flags = 0;
1721 poll = true;
1723 context_release(&context_vk->c);
1726 return poll;
1729 static void wined3d_query_vk_destroy(struct wined3d_query *query)
1731 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1732 struct wined3d_context_vk *context_vk;
1734 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED)
1735 list_remove(&query_vk->entry);
1736 context_vk = wined3d_context_vk(context_acquire(query_vk->q.device, NULL, 0));
1737 wined3d_query_vk_remove_pending_queries(context_vk, query_vk);
1738 if (query_vk->pool_idx.pool_vk)
1739 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk, query_vk->pool_idx.idx, context_vk);
1740 if (query_vk->vk_event)
1741 wined3d_context_vk_destroy_vk_event(context_vk, query_vk->vk_event, query_vk->command_buffer_id);
1742 context_release(&context_vk->c);
1743 heap_free(query_vk->pending);
1744 heap_free(query_vk);
1747 static const struct wined3d_query_ops wined3d_query_vk_ops =
1749 .query_poll = wined3d_query_vk_poll,
1750 .query_issue = wined3d_query_vk_issue,
1751 .query_destroy = wined3d_query_vk_destroy,
1754 static BOOL wined3d_query_event_vk_poll(struct wined3d_query *query, uint32_t flags)
1756 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1757 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1758 const struct wined3d_vk_info *vk_info = &device_vk->vk_info;
1759 BOOL signalled;
1761 signalled = VK_CALL(vkGetEventStatus(device_vk->vk_device, query_vk->vk_event))
1762 == VK_EVENT_SET;
1763 if (!signalled && (flags & WINED3DGETDATA_FLUSH) && !query->device->cs->queries_flushed)
1764 query->device->cs->c.ops->flush(&query->device->cs->c);
1765 return *(BOOL *)query->data = signalled;
1768 static BOOL wined3d_query_event_vk_issue(struct wined3d_query *query, uint32_t flags)
1770 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1771 const struct wined3d_vk_info *vk_info = &device_vk->vk_info;
1772 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1773 struct wined3d_context_vk *context_vk;
1774 VkEventCreateInfo create_info;
1775 VkResult vr;
1777 TRACE("query %p, flags %#x.\n", query, flags);
1779 if (flags & WINED3DISSUE_END)
1781 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1782 wined3d_context_vk_end_current_render_pass(context_vk);
1784 if (query_vk->vk_event)
1786 if (query_vk->command_buffer_id > context_vk->completed_command_buffer_id)
1788 /* Cannot reuse this event, as it may still get signalled by previous usage. */
1789 /* Throw it away and create a new one, but if that happens a lot we may want to pool instead. */
1790 wined3d_context_vk_destroy_vk_event(context_vk, query_vk->vk_event, query_vk->command_buffer_id);
1791 query_vk->vk_event = VK_NULL_HANDLE;
1793 else
1795 VK_CALL(vkResetEvent(device_vk->vk_device, query_vk->vk_event));
1799 if (!query_vk->vk_event)
1801 create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
1802 create_info.pNext = NULL;
1803 create_info.flags = 0;
1805 vr = VK_CALL(vkCreateEvent(device_vk->vk_device, &create_info, NULL, &query_vk->vk_event));
1806 if (vr != VK_SUCCESS)
1808 ERR("Failed to create Vulkan event, vr %s\n", wined3d_debug_vkresult(vr));
1809 context_release(&context_vk->c);
1810 return FALSE;
1814 wined3d_context_vk_reference_query(context_vk, query_vk);
1815 VK_CALL(vkCmdSetEvent(wined3d_context_vk_get_command_buffer(context_vk), query_vk->vk_event,
1816 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT));
1817 context_release(&context_vk->c);
1819 return TRUE;
1822 return FALSE;
1825 static const struct wined3d_query_ops wined3d_query_event_vk_ops =
1827 .query_poll = wined3d_query_event_vk_poll,
1828 .query_issue = wined3d_query_event_vk_issue,
1829 .query_destroy = wined3d_query_vk_destroy,
1832 static BOOL wined3d_query_timestamp_vk_issue(struct wined3d_query *query, uint32_t flags)
1834 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1835 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1836 const struct wined3d_vk_info *vk_info;
1837 struct wined3d_context_vk *context_vk;
1838 VkCommandBuffer command_buffer;
1840 TRACE("query %p, flags %#x.\n", query, flags);
1842 if (flags & WINED3DISSUE_BEGIN)
1843 TRACE("Ignoring WINED3DISSUE_BEGIN.\n");
1845 if (flags & WINED3DISSUE_END)
1847 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1848 vk_info = context_vk->vk_info;
1850 command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
1851 if (query_vk->pool_idx.pool_vk)
1852 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk, query_vk->pool_idx.idx, context_vk);
1853 if (!wined3d_context_vk_allocate_query(context_vk, query_vk->q.type, &query_vk->pool_idx))
1855 ERR("Failed to allocate new query.\n");
1856 return FALSE;
1858 VK_CALL(vkCmdWriteTimestamp(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1859 query_vk->pool_idx.pool_vk->vk_query_pool, query_vk->pool_idx.idx));
1860 wined3d_context_vk_reference_query(context_vk, query_vk);
1862 context_release(&context_vk->c);
1864 return TRUE;
1867 return FALSE;
1870 static const struct wined3d_query_ops wined3d_query_timestamp_vk_ops =
1872 .query_poll = wined3d_query_vk_poll,
1873 .query_issue = wined3d_query_timestamp_vk_issue,
1874 .query_destroy = wined3d_query_vk_destroy,
1877 static const struct wined3d_query_ops wined3d_query_timestamp_disjoint_vk_ops =
1879 .query_poll = wined3d_timestamp_disjoint_query_ops_poll,
1880 .query_issue = wined3d_timestamp_disjoint_query_ops_issue,
1881 .query_destroy = wined3d_query_vk_destroy,
1884 HRESULT wined3d_query_vk_create(struct wined3d_device *device, enum wined3d_query_type type,
1885 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1887 struct wined3d_query_data_timestamp_disjoint *disjoint_data;
1888 const struct wined3d_query_ops *ops = &wined3d_query_vk_ops;
1889 struct wined3d_query_vk *query_vk;
1890 unsigned int data_size;
1891 void *data;
1893 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1894 device, type, parent, parent_ops, query);
1896 switch (type)
1898 case WINED3D_QUERY_TYPE_EVENT:
1899 ops = &wined3d_query_event_vk_ops;
1900 data_size = sizeof(BOOL);
1901 break;
1903 case WINED3D_QUERY_TYPE_OCCLUSION:
1904 data_size = sizeof(uint64_t);
1905 break;
1907 case WINED3D_QUERY_TYPE_TIMESTAMP:
1908 if (!wined3d_device_vk(device)->timestamp_bits)
1910 WARN("Timestamp queries not supported.\n");
1911 return WINED3DERR_NOTAVAILABLE;
1913 ops = &wined3d_query_timestamp_vk_ops;
1914 data_size = sizeof(uint64_t);
1915 break;
1917 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1918 if (!wined3d_device_vk(device)->timestamp_bits)
1920 WARN("Timestamp queries not supported.\n");
1921 return WINED3DERR_NOTAVAILABLE;
1923 ops = &wined3d_query_timestamp_disjoint_vk_ops;
1924 data_size = sizeof(struct wined3d_query_data_timestamp_disjoint);
1925 break;
1927 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1928 data_size = sizeof(struct wined3d_query_data_pipeline_statistics);
1929 break;
1931 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1932 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1933 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1934 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1935 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1936 if (!wined3d_adapter_vk(device->adapter)->vk_info.supported[WINED3D_VK_EXT_TRANSFORM_FEEDBACK])
1938 WARN("Stream output queries not supported.\n");
1939 return WINED3DERR_NOTAVAILABLE;
1941 data_size = sizeof(struct wined3d_query_data_so_statistics);
1942 break;
1944 default:
1945 FIXME("Unhandled query type %#x.\n", type);
1946 return WINED3DERR_NOTAVAILABLE;
1949 if (!(query_vk = heap_alloc_zero(sizeof(*query_vk) + data_size)))
1950 return E_OUTOFMEMORY;
1951 data = query_vk + 1;
1953 wined3d_query_init(&query_vk->q, device, type, data, data_size, ops, parent, parent_ops);
1954 query_vk->q.poll_in_cs = false;
1956 switch (type)
1958 case WINED3D_QUERY_TYPE_OCCLUSION:
1959 query_vk->control_flags = VK_QUERY_CONTROL_PRECISE_BIT;
1960 break;
1962 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1963 disjoint_data = data;
1964 disjoint_data->frequency = 1000000000 / wined3d_adapter_vk(device->adapter)->device_limits.timestampPeriod;
1965 disjoint_data->disjoint = FALSE;
1966 break;
1968 default:
1969 break;
1972 TRACE("Created query %p.\n", query_vk);
1973 *query = &query_vk->q;
1975 return WINED3D_OK;
1978 HRESULT CDECL wined3d_query_create(struct wined3d_device *device, enum wined3d_query_type type,
1979 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1981 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1982 device, type, parent, parent_ops, query);
1984 return device->adapter->adapter_ops->adapter_create_query(device, type, parent, parent_ops, query);