include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / wined3d / query.c
bloba58ffbcf3d077b057db4890e5ac23ff347b63cbb
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"
22 #include "wined3d_gl.h"
23 #include "wined3d_vk.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
27 static void wined3d_query_buffer_invalidate(struct wined3d_query *query)
29 /* map[0] != map[1]: exact values do not have any significance. */
30 query->map_ptr[0] = 0;
31 query->map_ptr[1] = ~(UINT64)0;
34 static BOOL wined3d_query_buffer_is_valid(struct wined3d_query *query)
36 return query->map_ptr[0] == query->map_ptr[1];
39 static void wined3d_query_create_buffer_object(struct wined3d_context_gl *context_gl, struct wined3d_query *query)
41 const GLuint map_flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
42 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
43 GLuint buffer_object;
45 GL_EXTCALL(glGenBuffers(1, &buffer_object));
46 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, buffer_object));
47 GL_EXTCALL(glBufferStorage(GL_QUERY_BUFFER, sizeof(query->map_ptr[0]) * 2, NULL, map_flags));
48 query->map_ptr = GL_EXTCALL(glMapBufferRange(GL_QUERY_BUFFER, 0, sizeof(query->map_ptr[0]) * 2, map_flags));
49 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, 0));
50 checkGLcall("query buffer object creation");
52 wined3d_query_buffer_invalidate(query);
53 query->buffer_object = buffer_object;
56 void wined3d_query_gl_destroy_buffer_object(struct wined3d_context_gl *context_gl, struct wined3d_query *query)
58 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
60 GL_EXTCALL(glDeleteBuffers(1, &query->buffer_object));
61 checkGLcall("query buffer object destruction");
63 query->buffer_object = 0;
64 query->map_ptr = NULL;
67 /* From ARB_occlusion_query: "Querying the state for a given occlusion query
68 * forces that occlusion query to complete within a finite amount of time."
69 * In practice, that means drivers flush when retrieving
70 * GL_QUERY_RESULT_AVAILABLE, which can be undesirable when applications use a
71 * significant number of queries. Using a persistently mapped query buffer
72 * object allows us to avoid these implicit flushes. An additional benefit is
73 * that it allows us to poll the query status from the application-thread
74 * instead of from the csmt-thread. */
75 static BOOL wined3d_query_buffer_queue_result(struct wined3d_context_gl *context_gl,
76 struct wined3d_query *query, GLuint id)
78 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
79 GLsync tmp_sync;
81 if (!gl_info->supported[ARB_QUERY_BUFFER_OBJECT] || !gl_info->supported[ARB_BUFFER_STORAGE])
82 return FALSE;
83 /* Don't use query buffers without CSMT, mainly for simplicity. */
84 if (!context_gl->c.device->cs->thread)
85 return FALSE;
87 if (query->buffer_object)
89 /* If there's still a query result in-flight for the existing buffer
90 * object (i.e., the query was restarted before we received its
91 * result), we can't reuse the existing buffer object. */
92 if (wined3d_query_buffer_is_valid(query))
93 wined3d_query_buffer_invalidate(query);
94 else
95 wined3d_query_gl_destroy_buffer_object(context_gl, query);
98 if (!query->buffer_object)
99 wined3d_query_create_buffer_object(context_gl, query);
101 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, query->buffer_object));
102 /* Read the same value twice. We know we have the result if map_ptr[0] == map_ptr[1]. */
103 GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, (void *)0));
104 GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, (void *)sizeof(query->map_ptr[0])));
105 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, 0));
106 checkGLcall("queue query result");
108 /* ARB_buffer_storage requires the client to call FenceSync with
109 * SYNC_GPU_COMMANDS_COMPLETE after the server does a write. This behavior
110 * is not enforced by Mesa.
112 tmp_sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
113 GL_EXTCALL(glDeleteSync(tmp_sync));
114 checkGLcall("query buffer sync");
116 return TRUE;
119 static UINT64 get_query_result64(GLuint id, const struct wined3d_gl_info *gl_info)
121 if (gl_info->supported[ARB_TIMER_QUERY])
123 GLuint64 result;
124 GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, &result));
125 return result;
127 else
129 GLuint result;
130 GL_EXTCALL(glGetQueryObjectuiv(id, GL_QUERY_RESULT, &result));
131 return result;
135 static void wined3d_query_init(struct wined3d_query *query, struct wined3d_device *device,
136 enum wined3d_query_type type, const void *data, DWORD data_size,
137 const struct wined3d_query_ops *query_ops, void *parent, const struct wined3d_parent_ops *parent_ops)
139 query->ref = 1;
140 query->parent = parent;
141 query->parent_ops = parent_ops;
142 query->device = device;
143 query->state = QUERY_CREATED;
144 query->type = type;
145 query->data = data;
146 query->data_size = data_size;
147 query->query_ops = query_ops;
148 query->poll_in_cs = !!device->cs->thread;
149 list_init(&query->poll_list_entry);
152 static struct wined3d_event_query *wined3d_event_query_from_query(struct wined3d_query *query)
154 return CONTAINING_RECORD(query, struct wined3d_event_query, query);
157 static struct wined3d_occlusion_query *wined3d_occlusion_query_from_query(struct wined3d_query *query)
159 return CONTAINING_RECORD(query, struct wined3d_occlusion_query, query);
162 static struct wined3d_timestamp_query *wined3d_timestamp_query_from_query(struct wined3d_query *query)
164 return CONTAINING_RECORD(query, struct wined3d_timestamp_query, query);
167 static struct wined3d_so_statistics_query *wined3d_so_statistics_query_from_query(struct wined3d_query *query)
169 return CONTAINING_RECORD(query, struct wined3d_so_statistics_query, query);
172 static struct wined3d_pipeline_statistics_query *wined3d_pipeline_statistics_query_from_query(
173 struct wined3d_query *query)
175 return CONTAINING_RECORD(query, struct wined3d_pipeline_statistics_query, query);
178 enum wined3d_fence_result wined3d_fence_test(const struct wined3d_fence *fence,
179 struct wined3d_device *device, uint32_t flags)
181 const struct wined3d_gl_info *gl_info;
182 struct wined3d_context_gl *context_gl;
183 enum wined3d_fence_result ret;
184 BOOL fence_result;
186 TRACE("fence %p, device %p, flags %#x.\n", fence, device, flags);
188 if (!fence->context_gl)
190 TRACE("Fence not issued.\n");
191 return WINED3D_FENCE_NOT_STARTED;
194 if (!(context_gl = wined3d_context_gl_reacquire(fence->context_gl)))
196 if (!fence->context_gl->gl_info->supported[ARB_SYNC])
198 WARN("Fence tested from wrong thread.\n");
199 return WINED3D_FENCE_WRONG_THREAD;
201 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
203 gl_info = context_gl->gl_info;
205 if (gl_info->supported[ARB_SYNC])
207 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
208 (flags & WINED3DGETDATA_FLUSH) ? GL_SYNC_FLUSH_COMMANDS_BIT : 0, 0));
209 checkGLcall("glClientWaitSync");
211 switch (gl_ret)
213 case GL_ALREADY_SIGNALED:
214 case GL_CONDITION_SATISFIED:
215 ret = WINED3D_FENCE_OK;
216 break;
218 case GL_TIMEOUT_EXPIRED:
219 ret = WINED3D_FENCE_WAITING;
220 break;
222 case GL_WAIT_FAILED:
223 default:
224 ERR("glClientWaitSync returned %#x.\n", gl_ret);
225 ret = WINED3D_FENCE_ERROR;
228 else if (gl_info->supported[APPLE_FENCE])
230 fence_result = GL_EXTCALL(glTestFenceAPPLE(fence->object.id));
231 checkGLcall("glTestFenceAPPLE");
232 if (fence_result)
233 ret = WINED3D_FENCE_OK;
234 else
235 ret = WINED3D_FENCE_WAITING;
237 else if (gl_info->supported[NV_FENCE])
239 fence_result = GL_EXTCALL(glTestFenceNV(fence->object.id));
240 checkGLcall("glTestFenceNV");
241 if (fence_result)
242 ret = WINED3D_FENCE_OK;
243 else
244 ret = WINED3D_FENCE_WAITING;
246 else
248 ERR("Fence created despite lack of GL support.\n");
249 ret = WINED3D_FENCE_ERROR;
252 context_release(&context_gl->c);
253 return ret;
256 enum wined3d_fence_result wined3d_fence_wait(const struct wined3d_fence *fence,
257 struct wined3d_device *device)
259 const struct wined3d_gl_info *gl_info;
260 struct wined3d_context_gl *context_gl;
261 enum wined3d_fence_result ret;
263 TRACE("fence %p, device %p.\n", fence, device);
265 if (!fence->context_gl)
267 TRACE("Fence not issued.\n");
268 return WINED3D_FENCE_NOT_STARTED;
270 gl_info = fence->context_gl->gl_info;
272 if (!(context_gl = wined3d_context_gl_reacquire(fence->context_gl)))
274 /* A glFinish does not reliably wait for draws in other contexts. The caller has
275 * to find its own way to cope with the thread switch
277 if (!gl_info->supported[ARB_SYNC])
279 WARN("Fence finished from wrong thread.\n");
280 return WINED3D_FENCE_WRONG_THREAD;
282 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
284 gl_info = context_gl->gl_info;
286 if (gl_info->supported[ARB_SYNC])
288 /* Timeouts near 0xffffffffffffffff may immediately return GL_TIMEOUT_EXPIRED,
289 * possibly because macOS internally adds some slop to the timer. To avoid this,
290 * we use a large number that isn't near the point of overflow (macOS 10.12.5).
292 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
293 GL_SYNC_FLUSH_COMMANDS_BIT, ~(GLuint64)0 >> 1));
294 checkGLcall("glClientWaitSync");
296 switch (gl_ret)
298 case GL_ALREADY_SIGNALED:
299 case GL_CONDITION_SATISFIED:
300 ret = WINED3D_FENCE_OK;
301 break;
303 /* We don't expect a timeout for a ~292 year wait */
304 default:
305 ERR("glClientWaitSync returned %#x.\n", gl_ret);
306 ret = WINED3D_FENCE_ERROR;
309 else if (gl_info->supported[APPLE_FENCE])
311 GL_EXTCALL(glFinishFenceAPPLE(fence->object.id));
312 checkGLcall("glFinishFenceAPPLE");
313 ret = WINED3D_FENCE_OK;
315 else if (gl_info->supported[NV_FENCE])
317 GL_EXTCALL(glFinishFenceNV(fence->object.id));
318 checkGLcall("glFinishFenceNV");
319 ret = WINED3D_FENCE_OK;
321 else
323 ERR("Fence created without GL support.\n");
324 ret = WINED3D_FENCE_ERROR;
327 context_release(&context_gl->c);
328 return ret;
331 void wined3d_fence_issue(struct wined3d_fence *fence, struct wined3d_device *device)
333 struct wined3d_context_gl *context_gl = NULL;
334 const struct wined3d_gl_info *gl_info;
336 if (fence->context_gl && !(context_gl = wined3d_context_gl_reacquire(fence->context_gl))
337 && !fence->context_gl->gl_info->supported[ARB_SYNC])
338 wined3d_context_gl_free_fence(fence);
339 if (!context_gl)
340 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
341 gl_info = context_gl->gl_info;
342 if (!fence->context_gl)
343 wined3d_context_gl_alloc_fence(context_gl, fence);
345 if (gl_info->supported[ARB_SYNC])
347 if (fence->object.sync)
348 GL_EXTCALL(glDeleteSync(fence->object.sync));
349 checkGLcall("glDeleteSync");
350 fence->object.sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
351 checkGLcall("glFenceSync");
353 else if (gl_info->supported[APPLE_FENCE])
355 GL_EXTCALL(glSetFenceAPPLE(fence->object.id));
356 checkGLcall("glSetFenceAPPLE");
358 else if (gl_info->supported[NV_FENCE])
360 GL_EXTCALL(glSetFenceNV(fence->object.id, GL_ALL_COMPLETED_NV));
361 checkGLcall("glSetFenceNV");
364 context_release(&context_gl->c);
367 static void wined3d_fence_free(struct wined3d_fence *fence)
369 if (fence->context_gl)
370 wined3d_context_gl_free_fence(fence);
373 void wined3d_fence_destroy(struct wined3d_fence *fence)
375 wined3d_fence_free(fence);
376 free(fence);
379 static HRESULT wined3d_fence_init(struct wined3d_fence *fence, const struct wined3d_gl_info *gl_info)
381 if (!wined3d_fence_supported(gl_info))
383 WARN("Fences not supported.\n");
384 return WINED3DERR_NOTAVAILABLE;
387 return WINED3D_OK;
390 HRESULT wined3d_fence_create(struct wined3d_device *device, struct wined3d_fence **fence)
392 const struct wined3d_gl_info *gl_info = &wined3d_adapter_gl(device->adapter)->gl_info;
393 struct wined3d_fence *object;
394 HRESULT hr;
396 TRACE("device %p, fence %p.\n", device, fence);
398 if (!(object = calloc(1, sizeof(*object))))
399 return E_OUTOFMEMORY;
401 if (FAILED(hr = wined3d_fence_init(object, gl_info)))
403 free(object);
404 return hr;
407 TRACE("Created fence %p.\n", object);
408 *fence = object;
410 return WINED3D_OK;
413 ULONG CDECL wined3d_query_incref(struct wined3d_query *query)
415 unsigned int refcount = InterlockedIncrement(&query->ref);
417 TRACE("%p increasing refcount to %u.\n", query, refcount);
419 return refcount;
422 static void wined3d_query_destroy_object(void *object)
424 struct wined3d_query *query = object;
426 TRACE("query %p.\n", query);
428 if (!list_empty(&query->poll_list_entry))
429 list_remove(&query->poll_list_entry);
432 ULONG CDECL wined3d_query_decref(struct wined3d_query *query)
434 unsigned int refcount = InterlockedDecrement(&query->ref);
436 TRACE("%p decreasing refcount to %u.\n", query, refcount);
438 if (!refcount)
440 struct wined3d_device *device = query->device;
442 wined3d_mutex_lock();
443 query->parent_ops->wined3d_object_destroyed(query->parent);
444 wined3d_cs_destroy_object(device->cs, wined3d_query_destroy_object, query);
445 device->adapter->adapter_ops->adapter_destroy_query(query);
446 wined3d_mutex_unlock();
449 return refcount;
452 HRESULT CDECL wined3d_query_get_data(struct wined3d_query *query,
453 void *data, UINT data_size, uint32_t flags)
455 TRACE("query %p, data %p, data_size %u, flags %#x.\n",
456 query, data, data_size, flags);
458 if (query->state == QUERY_BUILDING)
460 WARN("Query is building, returning S_FALSE.\n");
461 return S_FALSE;
464 if (query->state == QUERY_CREATED)
466 WARN("Query wasn't started yet.\n");
467 return WINED3DERR_INVALIDCALL;
470 if (query->counter_main != query->counter_retrieved
471 || (query->buffer_object && !wined3d_query_buffer_is_valid(query)))
473 if (flags & WINED3DGETDATA_FLUSH && !query->device->cs->queries_flushed)
474 query->device->cs->c.ops->flush(&query->device->cs->c);
475 return S_FALSE;
477 else if (!query->poll_in_cs && !query->query_ops->query_poll(query, flags))
479 return S_FALSE;
482 if (query->buffer_object)
483 query->data = query->map_ptr;
485 if (data)
486 memcpy(data, query->data, min(data_size, query->data_size));
488 return S_OK;
491 UINT CDECL wined3d_query_get_data_size(const struct wined3d_query *query)
493 TRACE("query %p.\n", query);
495 return query->data_size;
498 HRESULT CDECL wined3d_query_issue(struct wined3d_query *query, uint32_t flags)
500 TRACE("query %p, flags %#x.\n", query, flags);
502 wined3d_device_context_issue_query(&query->device->cs->c, query, flags);
504 return WINED3D_OK;
507 static BOOL wined3d_occlusion_query_ops_poll(struct wined3d_query *query, uint32_t flags)
509 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
510 const struct wined3d_gl_info *gl_info;
511 struct wined3d_context_gl *context_gl;
512 GLuint available;
514 TRACE("query %p, flags %#x.\n", query, flags);
516 if (!(context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
518 FIXME("%p Wrong thread, returning 1.\n", query);
519 oq->samples = 1;
520 return TRUE;
522 gl_info = context_gl->gl_info;
524 GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT_AVAILABLE, &available));
525 TRACE("Available %#x.\n", available);
527 if (available)
529 oq->samples = get_query_result64(oq->id, gl_info);
530 TRACE("Returning 0x%s samples.\n", wine_dbgstr_longlong(oq->samples));
533 checkGLcall("poll occlusion query");
534 context_release(&context_gl->c);
536 return available;
539 static BOOL wined3d_event_query_ops_poll(struct wined3d_query *query, uint32_t flags)
541 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
542 enum wined3d_fence_result ret;
544 TRACE("query %p, flags %#x.\n", query, flags);
546 ret = wined3d_fence_test(&event_query->fence, query->device, flags);
547 switch (ret)
549 case WINED3D_FENCE_OK:
550 case WINED3D_FENCE_NOT_STARTED:
551 return event_query->signalled = TRUE;
553 case WINED3D_FENCE_WAITING:
554 return event_query->signalled = FALSE;
556 case WINED3D_FENCE_WRONG_THREAD:
557 FIXME("(%p) Wrong thread, reporting GPU idle.\n", query);
558 return event_query->signalled = TRUE;
560 case WINED3D_FENCE_ERROR:
561 ERR("The GL event query failed.\n");
562 return event_query->signalled = TRUE;
564 default:
565 ERR("Unexpected wined3d_event_query_test result %#x.\n", ret);
566 return event_query->signalled = TRUE;
570 void * CDECL wined3d_query_get_parent(const struct wined3d_query *query)
572 TRACE("query %p.\n", query);
574 return query->parent;
577 enum wined3d_query_type CDECL wined3d_query_get_type(const struct wined3d_query *query)
579 TRACE("query %p.\n", query);
581 return query->type;
584 static BOOL wined3d_event_query_ops_issue(struct wined3d_query *query, uint32_t flags)
586 TRACE("query %p, flags %#x.\n", query, flags);
588 if (flags & WINED3DISSUE_END)
590 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
592 wined3d_fence_issue(&event_query->fence, query->device);
593 return TRUE;
595 else if (flags & WINED3DISSUE_BEGIN)
597 /* Started implicitly at query creation. */
598 ERR("Event query issued with START flag - what to do?\n");
601 return FALSE;
604 static BOOL wined3d_occlusion_query_ops_issue(struct wined3d_query *query, uint32_t flags)
606 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
607 struct wined3d_device *device = query->device;
608 const struct wined3d_gl_info *gl_info;
609 struct wined3d_context_gl *context_gl;
610 BOOL poll = FALSE;
612 TRACE("query %p, flags %#x.\n", query, flags);
614 /* This is allowed according to MSDN and our tests. Reset the query and
615 * restart. */
616 if (flags & WINED3DISSUE_BEGIN)
618 if (oq->started)
620 if ((context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
622 gl_info = context_gl->gl_info;
623 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
624 checkGLcall("glEndQuery()");
626 else
628 FIXME("Wrong thread, can't restart query.\n");
629 wined3d_context_gl_free_occlusion_query(oq);
630 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
631 wined3d_context_gl_alloc_occlusion_query(context_gl, oq);
634 else
636 if (oq->context_gl)
637 wined3d_context_gl_free_occlusion_query(oq);
638 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
639 wined3d_context_gl_alloc_occlusion_query(context_gl, oq);
641 gl_info = context_gl->gl_info;
643 GL_EXTCALL(glBeginQuery(GL_SAMPLES_PASSED, oq->id));
644 checkGLcall("glBeginQuery()");
646 context_release(&context_gl->c);
647 oq->started = TRUE;
649 if (flags & WINED3DISSUE_END)
651 /* MSDN says END on a non-building occlusion query returns an error,
652 * but our tests show that it returns OK. But OpenGL doesn't like it,
653 * so avoid generating an error. */
654 if (oq->started)
656 if ((context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
658 gl_info = context_gl->gl_info;
659 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
660 checkGLcall("glEndQuery()");
661 wined3d_query_buffer_queue_result(context_gl, query, oq->id);
663 context_release(&context_gl->c);
664 poll = TRUE;
666 else
668 FIXME("Wrong thread, can't end query.\n");
671 oq->started = FALSE;
674 return poll;
677 static BOOL wined3d_timestamp_query_ops_poll(struct wined3d_query *query, uint32_t flags)
679 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
680 const struct wined3d_gl_info *gl_info;
681 struct wined3d_context_gl *context_gl;
682 GLuint64 timestamp;
683 GLuint available;
685 TRACE("query %p, flags %#x.\n", query, flags);
687 if (!(context_gl = wined3d_context_gl_reacquire(tq->context_gl)))
689 FIXME("%p Wrong thread, returning 1.\n", query);
690 tq->timestamp = 1;
691 return TRUE;
693 gl_info = context_gl->gl_info;
695 GL_EXTCALL(glGetQueryObjectuiv(tq->id, GL_QUERY_RESULT_AVAILABLE, &available));
696 checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
697 TRACE("available %#x.\n", available);
699 if (available)
701 GL_EXTCALL(glGetQueryObjectui64v(tq->id, GL_QUERY_RESULT, &timestamp));
702 checkGLcall("glGetQueryObjectui64v(GL_QUERY_RESULT)");
703 TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp));
704 tq->timestamp = timestamp;
707 context_release(&context_gl->c);
709 return available;
712 static BOOL wined3d_timestamp_query_ops_issue(struct wined3d_query *query, uint32_t flags)
714 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
715 const struct wined3d_gl_info *gl_info;
716 struct wined3d_context_gl *context_gl;
718 TRACE("query %p, flags %#x.\n", query, flags);
720 if (flags & WINED3DISSUE_BEGIN)
722 WARN("Ignoring WINED3DISSUE_BEGIN with a TIMESTAMP query.\n");
724 if (flags & WINED3DISSUE_END)
726 if (tq->context_gl)
727 wined3d_context_gl_free_timestamp_query(tq);
728 context_gl = wined3d_context_gl(context_acquire(query->device, NULL, 0));
729 gl_info = context_gl->gl_info;
730 wined3d_context_gl_alloc_timestamp_query(context_gl, tq);
731 GL_EXTCALL(glQueryCounter(tq->id, GL_TIMESTAMP));
732 checkGLcall("glQueryCounter()");
733 context_release(&context_gl->c);
735 return TRUE;
738 return FALSE;
741 static BOOL wined3d_timestamp_disjoint_query_ops_poll(struct wined3d_query *query, uint32_t flags)
743 TRACE("query %p, flags %#x.\n", query, flags);
745 return TRUE;
748 static BOOL wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query *query, uint32_t flags)
750 TRACE("query %p, flags %#x.\n", query, flags);
752 return FALSE;
755 static BOOL wined3d_so_statistics_query_ops_poll(struct wined3d_query *query, uint32_t flags)
757 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
758 GLuint written_available, generated_available;
759 const struct wined3d_gl_info *gl_info;
760 struct wined3d_context_gl *context_gl;
762 TRACE("query %p, flags %#x.\n", query, flags);
764 if (!(context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
766 FIXME("%p Wrong thread, returning 0 primitives.\n", query);
767 memset(&pq->statistics, 0, sizeof(pq->statistics));
768 return TRUE;
770 gl_info = context_gl->gl_info;
772 GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.written,
773 GL_QUERY_RESULT_AVAILABLE, &written_available));
774 GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.generated,
775 GL_QUERY_RESULT_AVAILABLE, &generated_available));
776 TRACE("Available %#x, %#x.\n", written_available, generated_available);
778 if (written_available && generated_available)
780 pq->statistics.primitives_written = get_query_result64(pq->u.query.written, gl_info);
781 pq->statistics.primitives_generated = get_query_result64(pq->u.query.generated, gl_info);
782 TRACE("Returning %s, %s primitives.\n",
783 wine_dbgstr_longlong(pq->statistics.primitives_written),
784 wine_dbgstr_longlong(pq->statistics.primitives_generated));
787 checkGLcall("poll SO statistics query");
788 context_release(&context_gl->c);
790 return written_available && generated_available;
793 static void wined3d_so_statistics_query_end(struct wined3d_so_statistics_query *query,
794 struct wined3d_context_gl *context_gl)
796 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
798 if (gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
800 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query->stream_idx));
801 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED, query->stream_idx));
803 else
805 GL_EXTCALL(glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN));
806 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_GENERATED));
808 checkGLcall("end query");
811 static BOOL wined3d_so_statistics_query_ops_issue(struct wined3d_query *query, uint32_t flags)
813 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
814 struct wined3d_device *device = query->device;
815 const struct wined3d_gl_info *gl_info;
816 struct wined3d_context_gl *context_gl;
817 BOOL poll = FALSE;
819 TRACE("query %p, flags %#x.\n", query, flags);
821 if (flags & WINED3DISSUE_BEGIN)
823 if (pq->started)
825 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
827 wined3d_so_statistics_query_end(pq, context_gl);
829 else
831 FIXME("Wrong thread, can't restart query.\n");
832 wined3d_context_gl_free_so_statistics_query(pq);
833 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
834 wined3d_context_gl_alloc_so_statistics_query(context_gl, pq);
837 else
839 if (pq->context_gl)
840 wined3d_context_gl_free_so_statistics_query(pq);
841 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
842 wined3d_context_gl_alloc_so_statistics_query(context_gl, pq);
844 gl_info = context_gl->gl_info;
846 if (gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
848 GL_EXTCALL(glBeginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
849 pq->stream_idx, pq->u.query.written));
850 GL_EXTCALL(glBeginQueryIndexed(GL_PRIMITIVES_GENERATED,
851 pq->stream_idx, pq->u.query.generated));
853 else
855 GL_EXTCALL(glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
856 pq->u.query.written));
857 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_GENERATED,
858 pq->u.query.generated));
860 checkGLcall("begin query");
862 context_release(&context_gl->c);
863 pq->started = TRUE;
865 if (flags & WINED3DISSUE_END)
867 if (pq->started)
869 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
871 wined3d_so_statistics_query_end(pq, context_gl);
873 context_release(&context_gl->c);
874 poll = TRUE;
876 else
878 FIXME("Wrong thread, can't end query.\n");
881 pq->started = FALSE;
884 return poll;
887 static BOOL wined3d_pipeline_query_ops_poll(struct wined3d_query *query, uint32_t flags)
889 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
890 const struct wined3d_gl_info *gl_info;
891 struct wined3d_context_gl *context_gl;
892 GLuint available;
893 int i;
895 TRACE("query %p, flags %#x.\n", query, flags);
897 if (!(context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
899 FIXME("%p Wrong thread.\n", query);
900 memset(&pq->statistics, 0, sizeof(pq->statistics));
901 return TRUE;
903 gl_info = context_gl->gl_info;
905 for (i = 0; i < ARRAY_SIZE(pq->u.id); ++i)
907 GL_EXTCALL(glGetQueryObjectuiv(pq->u.id[i], GL_QUERY_RESULT_AVAILABLE, &available));
908 if (!available)
909 break;
912 if (available)
914 pq->statistics.vertices_submitted = get_query_result64(pq->u.query.vertices, gl_info);
915 pq->statistics.primitives_submitted = get_query_result64(pq->u.query.primitives, gl_info);
916 pq->statistics.vs_invocations = get_query_result64(pq->u.query.vertex_shader, gl_info);
917 pq->statistics.hs_invocations = get_query_result64(pq->u.query.tess_control_shader, gl_info);
918 pq->statistics.ds_invocations = get_query_result64(pq->u.query.tess_eval_shader, gl_info);
919 pq->statistics.gs_invocations = get_query_result64(pq->u.query.geometry_shader, gl_info);
920 pq->statistics.gs_primitives = get_query_result64(pq->u.query.geometry_primitives, gl_info);
921 pq->statistics.ps_invocations = get_query_result64(pq->u.query.fragment_shader, gl_info);
922 pq->statistics.cs_invocations = get_query_result64(pq->u.query.compute_shader, gl_info);
923 pq->statistics.clipping_input_primitives = get_query_result64(pq->u.query.clipping_input, gl_info);
924 pq->statistics.clipping_output_primitives = get_query_result64(pq->u.query.clipping_output, gl_info);
927 checkGLcall("poll pipeline statistics query");
928 context_release(&context_gl->c);
929 return available;
932 static void wined3d_pipeline_statistics_query_end(struct wined3d_pipeline_statistics_query *query,
933 struct wined3d_context_gl *context_gl)
935 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
937 GL_EXTCALL(glEndQuery(GL_VERTICES_SUBMITTED_ARB));
938 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_SUBMITTED_ARB));
939 GL_EXTCALL(glEndQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB));
940 GL_EXTCALL(glEndQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB));
941 GL_EXTCALL(glEndQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB));
942 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_INVOCATIONS));
943 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB));
944 GL_EXTCALL(glEndQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB));
945 GL_EXTCALL(glEndQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB));
946 GL_EXTCALL(glEndQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB));
947 GL_EXTCALL(glEndQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB));
948 checkGLcall("end query");
951 static BOOL wined3d_pipeline_query_ops_issue(struct wined3d_query *query, uint32_t flags)
953 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
954 struct wined3d_device *device = query->device;
955 const struct wined3d_gl_info *gl_info;
956 struct wined3d_context_gl *context_gl;
957 BOOL poll = FALSE;
959 TRACE("query %p, flags %#x.\n", query, flags);
961 if (flags & WINED3DISSUE_BEGIN)
963 if (pq->started)
965 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
967 wined3d_pipeline_statistics_query_end(pq, context_gl);
969 else
971 FIXME("Wrong thread, can't restart query.\n");
972 wined3d_context_gl_free_pipeline_statistics_query(pq);
973 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
974 wined3d_context_gl_alloc_pipeline_statistics_query(context_gl, pq);
977 else
979 if (pq->context_gl)
980 wined3d_context_gl_free_pipeline_statistics_query(pq);
981 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
982 wined3d_context_gl_alloc_pipeline_statistics_query(context_gl, pq);
984 gl_info = context_gl->gl_info;
986 GL_EXTCALL(glBeginQuery(GL_VERTICES_SUBMITTED_ARB, pq->u.query.vertices));
987 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_SUBMITTED_ARB, pq->u.query.primitives));
988 GL_EXTCALL(glBeginQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB, pq->u.query.vertex_shader));
989 GL_EXTCALL(glBeginQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB, pq->u.query.tess_control_shader));
990 GL_EXTCALL(glBeginQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB, pq->u.query.tess_eval_shader));
991 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_INVOCATIONS, pq->u.query.geometry_shader));
992 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB, pq->u.query.geometry_primitives));
993 GL_EXTCALL(glBeginQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB, pq->u.query.fragment_shader));
994 GL_EXTCALL(glBeginQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB, pq->u.query.compute_shader));
995 GL_EXTCALL(glBeginQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB, pq->u.query.clipping_input));
996 GL_EXTCALL(glBeginQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB, pq->u.query.clipping_output));
997 checkGLcall("begin query");
999 context_release(&context_gl->c);
1000 pq->started = TRUE;
1002 if (flags & WINED3DISSUE_END)
1004 if (pq->started)
1006 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
1008 wined3d_pipeline_statistics_query_end(pq, context_gl);
1009 context_release(&context_gl->c);
1010 poll = TRUE;
1012 else
1014 FIXME("Wrong thread, can't end query.\n");
1017 pq->started = FALSE;
1020 return poll;
1023 static void wined3d_event_query_ops_destroy(struct wined3d_query *query)
1025 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
1027 wined3d_fence_free(&event_query->fence);
1028 free(event_query);
1031 static const struct wined3d_query_ops event_query_ops =
1033 wined3d_event_query_ops_poll,
1034 wined3d_event_query_ops_issue,
1035 wined3d_event_query_ops_destroy,
1038 static HRESULT wined3d_event_query_create(struct wined3d_device *device,
1039 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1040 struct wined3d_query **query)
1042 const struct wined3d_gl_info *gl_info = &wined3d_adapter_gl(device->adapter)->gl_info;
1043 struct wined3d_event_query *object;
1044 HRESULT hr;
1046 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1047 device, type, parent, parent_ops, query);
1049 if (!(object = calloc(1, sizeof(*object))))
1050 return E_OUTOFMEMORY;
1052 if (FAILED(hr = wined3d_fence_init(&object->fence, gl_info)))
1054 WARN("Event queries not supported.\n");
1055 free(object);
1056 return hr;
1059 wined3d_query_init(&object->query, device, type, &object->signalled,
1060 sizeof(object->signalled), &event_query_ops, parent, parent_ops);
1062 TRACE("Created query %p.\n", object);
1063 *query = &object->query;
1065 return WINED3D_OK;
1068 static void wined3d_occlusion_query_ops_destroy(struct wined3d_query *query)
1070 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
1072 if (oq->context_gl)
1073 wined3d_context_gl_free_occlusion_query(oq);
1074 free(oq);
1077 static const struct wined3d_query_ops occlusion_query_ops =
1079 wined3d_occlusion_query_ops_poll,
1080 wined3d_occlusion_query_ops_issue,
1081 wined3d_occlusion_query_ops_destroy,
1084 static HRESULT wined3d_occlusion_query_create(struct wined3d_device *device,
1085 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1086 struct wined3d_query **query)
1088 const struct wined3d_gl_info *gl_info = &wined3d_adapter_gl(device->adapter)->gl_info;
1089 struct wined3d_occlusion_query *object;
1091 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1092 device, type, parent, parent_ops, query);
1094 if (!gl_info->supported[ARB_OCCLUSION_QUERY])
1096 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
1097 return WINED3DERR_NOTAVAILABLE;
1100 if (!(object = calloc(1, sizeof(*object))))
1101 return E_OUTOFMEMORY;
1103 wined3d_query_init(&object->query, device, type, &object->samples,
1104 sizeof(object->samples), &occlusion_query_ops, parent, parent_ops);
1106 TRACE("Created query %p.\n", object);
1107 *query = &object->query;
1109 return WINED3D_OK;
1112 static void wined3d_timestamp_query_ops_destroy(struct wined3d_query *query)
1114 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
1116 if (tq->context_gl)
1117 wined3d_context_gl_free_timestamp_query(tq);
1118 free(tq);
1121 static const struct wined3d_query_ops timestamp_query_ops =
1123 wined3d_timestamp_query_ops_poll,
1124 wined3d_timestamp_query_ops_issue,
1125 wined3d_timestamp_query_ops_destroy,
1128 static HRESULT wined3d_timestamp_query_create(struct wined3d_device *device,
1129 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1130 struct wined3d_query **query)
1132 const struct wined3d_gl_info *gl_info = &wined3d_adapter_gl(device->adapter)->gl_info;
1133 struct wined3d_timestamp_query *object;
1135 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1136 device, type, parent, parent_ops, query);
1138 if (!gl_info->supported[ARB_TIMER_QUERY])
1140 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1141 return WINED3DERR_NOTAVAILABLE;
1144 if (!(object = calloc(1, sizeof(*object))))
1145 return E_OUTOFMEMORY;
1147 wined3d_query_init(&object->query, device, type, &object->timestamp,
1148 sizeof(object->timestamp), &timestamp_query_ops, parent, parent_ops);
1150 TRACE("Created query %p.\n", object);
1151 *query = &object->query;
1153 return WINED3D_OK;
1156 static void wined3d_timestamp_disjoint_query_ops_destroy(struct wined3d_query *query)
1158 free(query);
1161 static const struct wined3d_query_ops timestamp_disjoint_query_ops =
1163 wined3d_timestamp_disjoint_query_ops_poll,
1164 wined3d_timestamp_disjoint_query_ops_issue,
1165 wined3d_timestamp_disjoint_query_ops_destroy,
1168 static HRESULT wined3d_timestamp_disjoint_query_create(struct wined3d_device *device,
1169 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1170 struct wined3d_query **query)
1172 const struct wined3d_gl_info *gl_info = &wined3d_adapter_gl(device->adapter)->gl_info;
1173 struct wined3d_query *object;
1175 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1176 device, type, parent, parent_ops, query);
1178 if (!gl_info->supported[ARB_TIMER_QUERY])
1180 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1181 return WINED3DERR_NOTAVAILABLE;
1184 if (!(object = calloc(1, sizeof(*object))))
1185 return E_OUTOFMEMORY;
1187 if (type == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT)
1189 static const struct wined3d_query_data_timestamp_disjoint disjoint_data = {1000 * 1000 * 1000, FALSE};
1191 wined3d_query_init(object, device, type, &disjoint_data,
1192 sizeof(disjoint_data), &timestamp_disjoint_query_ops, parent, parent_ops);
1194 else
1196 static const UINT64 freq = 1000 * 1000 * 1000;
1198 wined3d_query_init(object, device, type, &freq,
1199 sizeof(freq), &timestamp_disjoint_query_ops, parent, parent_ops);
1202 TRACE("Created query %p.\n", object);
1203 *query = object;
1205 return WINED3D_OK;
1208 static void wined3d_so_statistics_query_ops_destroy(struct wined3d_query *query)
1210 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
1212 if (pq->context_gl)
1213 wined3d_context_gl_free_so_statistics_query(pq);
1214 free(pq);
1217 static const struct wined3d_query_ops so_statistics_query_ops =
1219 wined3d_so_statistics_query_ops_poll,
1220 wined3d_so_statistics_query_ops_issue,
1221 wined3d_so_statistics_query_ops_destroy,
1224 static HRESULT wined3d_so_statistics_query_create(struct wined3d_device *device,
1225 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1226 struct wined3d_query **query)
1228 const struct wined3d_gl_info *gl_info = &wined3d_adapter_gl(device->adapter)->gl_info;
1229 struct wined3d_so_statistics_query *object;
1230 unsigned int stream_idx;
1232 if (WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0 <= type && type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1233 stream_idx = type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0;
1234 else if (type == WINED3D_QUERY_TYPE_SO_STATISTICS)
1235 stream_idx = 0;
1236 else
1237 return WINED3DERR_NOTAVAILABLE;
1239 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1240 device, type, parent, parent_ops, query);
1242 if (!gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY])
1244 WARN("OpenGL implementation does not support primitive queries.\n");
1245 return WINED3DERR_NOTAVAILABLE;
1247 if (stream_idx && !gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
1249 WARN("OpenGL implementation does not support indexed queries.\n");
1250 return WINED3DERR_NOTAVAILABLE;
1253 if (!(object = calloc(1, sizeof(*object))))
1254 return E_OUTOFMEMORY;
1256 wined3d_query_init(&object->query, device, type, &object->statistics,
1257 sizeof(object->statistics), &so_statistics_query_ops, parent, parent_ops);
1258 object->stream_idx = stream_idx;
1260 TRACE("Created query %p.\n", object);
1261 *query = &object->query;
1263 return WINED3D_OK;
1266 static void wined3d_pipeline_query_ops_destroy(struct wined3d_query *query)
1268 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
1269 if (pq->context_gl)
1270 wined3d_context_gl_free_pipeline_statistics_query(pq);
1271 free(pq);
1274 static const struct wined3d_query_ops pipeline_query_ops =
1276 wined3d_pipeline_query_ops_poll,
1277 wined3d_pipeline_query_ops_issue,
1278 wined3d_pipeline_query_ops_destroy,
1281 static HRESULT wined3d_pipeline_query_create(struct wined3d_device *device,
1282 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1283 struct wined3d_query **query)
1285 const struct wined3d_gl_info *gl_info = &wined3d_adapter_gl(device->adapter)->gl_info;
1286 struct wined3d_pipeline_statistics_query *object;
1288 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1289 device, type, parent, parent_ops, query);
1291 if (!gl_info->supported[ARB_PIPELINE_STATISTICS_QUERY])
1293 WARN("OpenGL implementation does not support pipeline statistics queries.\n");
1294 return WINED3DERR_NOTAVAILABLE;
1297 if (!(object = calloc(1, sizeof(*object))))
1298 return E_OUTOFMEMORY;
1300 wined3d_query_init(&object->query, device, type, &object->statistics,
1301 sizeof(object->statistics), &pipeline_query_ops, parent, parent_ops);
1303 TRACE("Created query %p.\n", object);
1304 *query = &object->query;
1306 return WINED3D_OK;
1309 HRESULT wined3d_query_gl_create(struct wined3d_device *device, enum wined3d_query_type type,
1310 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1312 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1313 device, type, parent, parent_ops, query);
1315 switch (type)
1317 case WINED3D_QUERY_TYPE_EVENT:
1318 return wined3d_event_query_create(device, type, parent, parent_ops, query);
1320 case WINED3D_QUERY_TYPE_OCCLUSION:
1321 return wined3d_occlusion_query_create(device, type, parent, parent_ops, query);
1323 case WINED3D_QUERY_TYPE_TIMESTAMP:
1324 return wined3d_timestamp_query_create(device, type, parent, parent_ops, query);
1326 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1327 case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ:
1328 return wined3d_timestamp_disjoint_query_create(device, type, parent, parent_ops, query);
1330 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1331 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1332 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1333 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1334 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1335 return wined3d_so_statistics_query_create(device, type, parent, parent_ops, query);
1337 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1338 return wined3d_pipeline_query_create(device, type, parent, parent_ops, query);
1340 default:
1341 FIXME("Unhandled query type %#x.\n", type);
1342 return WINED3DERR_NOTAVAILABLE;
1346 static void wined3d_query_pool_vk_mark_complete(struct wined3d_query_pool_vk *pool_vk, size_t idx,
1347 struct wined3d_context_vk *context_vk)
1349 /* Don't reset completed queries right away, as vkCmdResetQueryPool() needs to happen
1350 * outside of a render pass. Queue the query to be reset at the very end of the current
1351 * command buffer instead. */
1352 wined3d_bitmap_set(pool_vk->completed, idx);
1353 if (list_empty(&pool_vk->completed_entry))
1354 list_add_tail(&context_vk->completed_query_pools, &pool_vk->completed_entry);
1357 bool wined3d_query_pool_vk_allocate_query(struct wined3d_query_pool_vk *pool_vk, size_t *idx)
1359 if ((*idx = wined3d_bitmap_ffz(pool_vk->allocated, WINED3D_QUERY_POOL_SIZE, 0)) > WINED3D_QUERY_POOL_SIZE)
1360 return false;
1361 wined3d_bitmap_set(pool_vk->allocated, *idx);
1363 return true;
1366 void wined3d_query_pool_vk_mark_free(struct wined3d_context_vk *context_vk, struct wined3d_query_pool_vk *pool_vk,
1367 uint32_t start, uint32_t count)
1369 unsigned int idx, end = start + count;
1371 for (idx = start; idx < end; ++idx)
1372 wined3d_bitmap_clear(pool_vk->allocated, idx);
1374 if (list_empty(&pool_vk->entry))
1375 list_add_tail(pool_vk->free_list, &pool_vk->entry);
1378 void wined3d_query_pool_vk_cleanup(struct wined3d_query_pool_vk *pool_vk, struct wined3d_context_vk *context_vk)
1380 struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
1381 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1383 VK_CALL(vkDestroyQueryPool(device_vk->vk_device, pool_vk->vk_query_pool, NULL));
1384 if (pool_vk->vk_event)
1385 VK_CALL(vkDestroyEvent(device_vk->vk_device, pool_vk->vk_event, NULL));
1386 list_remove(&pool_vk->entry);
1387 list_remove(&pool_vk->completed_entry);
1390 bool wined3d_query_pool_vk_init(struct wined3d_query_pool_vk *pool_vk,
1391 struct wined3d_context_vk *context_vk, enum wined3d_query_type type, struct list *free_pools)
1393 struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
1394 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1395 VkQueryPoolCreateInfo pool_info;
1396 VkResult vr;
1398 list_init(&pool_vk->entry);
1399 list_init(&pool_vk->completed_entry);
1400 pool_vk->free_list = free_pools;
1402 pool_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1403 pool_info.pNext = NULL;
1404 pool_info.flags = 0;
1405 pool_info.queryCount = WINED3D_QUERY_POOL_SIZE;
1407 switch (type)
1409 case WINED3D_QUERY_TYPE_OCCLUSION:
1410 pool_info.queryType = VK_QUERY_TYPE_OCCLUSION;
1411 pool_info.pipelineStatistics = 0;
1412 break;
1414 case WINED3D_QUERY_TYPE_TIMESTAMP:
1415 pool_info.queryType = VK_QUERY_TYPE_TIMESTAMP;
1416 pool_info.pipelineStatistics = 0;
1417 break;
1419 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1420 pool_info.queryType = VK_QUERY_TYPE_PIPELINE_STATISTICS;
1421 pool_info.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT
1422 | VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT
1423 | VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT
1424 | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT
1425 | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT
1426 | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT
1427 | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT
1428 | VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT
1429 | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT
1430 | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT
1431 | VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT;
1432 break;
1434 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1435 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1436 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1437 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1438 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1439 pool_info.queryType = VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT;
1440 pool_info.pipelineStatistics = 0;
1441 break;
1443 default:
1444 FIXME("Unhandled query type %#x.\n", type);
1445 return false;
1448 if ((vr = VK_CALL(vkCreateQueryPool(device_vk->vk_device, &pool_info, NULL, &pool_vk->vk_query_pool))) < 0)
1450 ERR("Failed to create Vulkan query pool, vr %s.\n", wined3d_debug_vkresult(vr));
1451 return false;
1454 list_add_head(free_pools, &pool_vk->entry);
1456 return true;
1459 bool wined3d_query_vk_accumulate_data(struct wined3d_query_vk *query_vk,
1460 struct wined3d_device_vk *device_vk, const struct wined3d_query_pool_idx_vk *pool_idx)
1462 const struct wined3d_query_data_pipeline_statistics *ps_tmp;
1463 const struct wined3d_vk_info *vk_info = &device_vk->vk_info;
1464 struct wined3d_query_data_pipeline_statistics *ps_result;
1465 VkResult vr;
1466 union
1468 uint64_t occlusion;
1469 uint64_t timestamp;
1470 struct wined3d_query_data_pipeline_statistics pipeline_statistics;
1471 struct wined3d_query_data_so_statistics so_statistics;
1472 } tmp, *result;
1474 if (pool_idx->pool_vk->vk_event)
1476 /* Check if the pool's initial reset command executed. */
1477 vr = VK_CALL(vkGetEventStatus(device_vk->vk_device,
1478 pool_idx->pool_vk->vk_event));
1479 if (vr == VK_EVENT_RESET)
1480 return false;
1481 else if (vr != VK_EVENT_SET)
1483 ERR("Failed to get event status, vr %s\n", wined3d_debug_vkresult(vr));
1484 return false;
1488 if ((vr = VK_CALL(vkGetQueryPoolResults(device_vk->vk_device, pool_idx->pool_vk->vk_query_pool,
1489 pool_idx->idx, 1, sizeof(tmp), &tmp, sizeof(tmp), VK_QUERY_RESULT_64_BIT))) < 0)
1491 ERR("Failed to get query results, vr %s.\n", wined3d_debug_vkresult(vr));
1492 return false;
1495 if (vr == VK_NOT_READY)
1496 return false;
1498 result = (void *)query_vk->q.data;
1499 switch (query_vk->q.type)
1501 case WINED3D_QUERY_TYPE_OCCLUSION:
1502 result->occlusion += tmp.occlusion;
1503 break;
1505 case WINED3D_QUERY_TYPE_TIMESTAMP:
1506 result->timestamp = tmp.timestamp;
1507 break;
1509 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1510 ps_result = &result->pipeline_statistics;
1511 ps_tmp = &tmp.pipeline_statistics;
1512 ps_result->vertices_submitted += ps_tmp->vertices_submitted;
1513 ps_result->primitives_submitted += ps_tmp->primitives_submitted;
1514 ps_result->vs_invocations += ps_tmp->vs_invocations;
1515 ps_result->gs_invocations += ps_tmp->gs_invocations;
1516 ps_result->gs_primitives += ps_tmp->gs_primitives;
1517 ps_result->clipping_input_primitives += ps_tmp->clipping_input_primitives;
1518 ps_result->clipping_output_primitives += ps_tmp->clipping_output_primitives;
1519 ps_result->ps_invocations += ps_tmp->ps_invocations;
1520 ps_result->hs_invocations += ps_tmp->hs_invocations;
1521 ps_result->ds_invocations += ps_tmp->ds_invocations;
1522 ps_result->cs_invocations += ps_tmp->cs_invocations;
1523 break;
1525 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1526 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1527 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1528 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1529 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1530 result->so_statistics.primitives_written += tmp.so_statistics.primitives_written;
1531 result->so_statistics.primitives_generated += tmp.so_statistics.primitives_generated;
1532 break;
1534 default:
1535 FIXME("Unhandled query type %#x.\n", query_vk->q.type);
1536 return false;
1539 return true;
1542 static void wined3d_query_vk_begin(struct wined3d_query_vk *query_vk,
1543 struct wined3d_context_vk *context_vk, VkCommandBuffer vk_command_buffer)
1545 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1546 struct wined3d_query_pool_vk *pool_vk;
1547 size_t idx;
1549 pool_vk = query_vk->pool_idx.pool_vk;
1550 idx = query_vk->pool_idx.idx;
1552 if (query_vk->q.type >= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
1553 && query_vk->q.type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1554 VK_CALL(vkCmdBeginQueryIndexedEXT(vk_command_buffer, pool_vk->vk_query_pool, idx,
1555 query_vk->control_flags, query_vk->q.type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0));
1556 else
1557 VK_CALL(vkCmdBeginQuery(vk_command_buffer, pool_vk->vk_query_pool, idx, query_vk->control_flags));
1558 wined3d_context_vk_reference_query(context_vk, query_vk);
1561 static void wined3d_query_vk_end(struct wined3d_query_vk *query_vk,
1562 struct wined3d_context_vk *context_vk, VkCommandBuffer vk_command_buffer)
1564 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1565 struct wined3d_query_pool_vk *pool_vk;
1566 size_t idx;
1568 pool_vk = query_vk->pool_idx.pool_vk;
1569 idx = query_vk->pool_idx.idx;
1571 if (query_vk->q.type >= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
1572 && query_vk->q.type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1573 VK_CALL(vkCmdEndQueryIndexedEXT(vk_command_buffer, pool_vk->vk_query_pool,
1574 idx, query_vk->q.type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0));
1575 else
1576 VK_CALL(vkCmdEndQuery(vk_command_buffer, pool_vk->vk_query_pool, idx));
1579 void wined3d_query_vk_resume(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk)
1581 VkCommandBuffer vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer;
1583 wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
1584 query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE;
1587 void wined3d_query_vk_suspend(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk)
1589 VkCommandBuffer vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer;
1591 wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
1593 if (!wined3d_array_reserve((void **)&query_vk->pending, &query_vk->pending_size,
1594 query_vk->pending_count + 1, sizeof(*query_vk->pending)))
1596 ERR("Failed to allocate entry.\n");
1597 return;
1600 query_vk->pending[query_vk->pending_count++] = query_vk->pool_idx;
1601 query_vk->pool_idx.pool_vk = NULL;
1602 query_vk->flags &= ~WINED3D_QUERY_VK_FLAG_ACTIVE;
1605 static BOOL wined3d_query_vk_poll(struct wined3d_query *query, uint32_t flags)
1607 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1608 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1609 unsigned int i;
1611 memset((void *)query->data, 0, query->data_size);
1613 if (query_vk->pool_idx.pool_vk && !wined3d_query_vk_accumulate_data(query_vk, device_vk, &query_vk->pool_idx))
1614 goto unavailable;
1616 for (i = 0; i < query_vk->pending_count; ++i)
1618 if (!wined3d_query_vk_accumulate_data(query_vk, device_vk, &query_vk->pending[i]))
1619 goto unavailable;
1622 return TRUE;
1624 unavailable:
1625 if ((flags & WINED3DGETDATA_FLUSH) && !query->device->cs->queries_flushed)
1626 query->device->cs->c.ops->flush(&query->device->cs->c);
1628 return FALSE;
1631 static void wined3d_query_vk_remove_pending_queries(struct wined3d_context_vk *context_vk,
1632 struct wined3d_query_vk *query_vk)
1634 size_t i;
1636 for (i = 0; i < query_vk->pending_count; ++i)
1637 wined3d_query_pool_vk_mark_complete(query_vk->pending[i].pool_vk, query_vk->pending[i].idx, context_vk);
1639 query_vk->pending_count = 0;
1642 static BOOL wined3d_query_vk_issue(struct wined3d_query *query, uint32_t flags)
1644 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1645 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1646 struct wined3d_context_vk *context_vk;
1647 VkCommandBuffer vk_command_buffer;
1648 bool poll = false;
1650 TRACE("query %p, flags %#x.\n", query, flags);
1652 if (flags & WINED3DISSUE_BEGIN)
1654 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1656 if (query_vk->pending_count)
1657 wined3d_query_vk_remove_pending_queries(context_vk, query_vk);
1658 vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
1659 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED)
1661 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_ACTIVE)
1662 wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
1663 list_remove(&query_vk->entry);
1665 if (query_vk->pool_idx.pool_vk)
1666 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk,
1667 query_vk->pool_idx.idx, context_vk);
1669 if (!wined3d_context_vk_allocate_query(context_vk, query_vk->q.type, &query_vk->pool_idx))
1671 ERR("Failed to allocate new query.\n");
1672 return false;
1675 /* A query needs to either begin and end inside a single render pass
1676 * or begin and end outside of a render pass. Occlusion queries, if
1677 * issued outside of a render pass, are queued up and only begun when
1678 * a render pass is started, to avoid interrupting the render pass
1679 * when the query ends. */
1680 if (context_vk->vk_render_pass)
1682 wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
1683 list_add_head(&context_vk->render_pass_queries, &query_vk->entry);
1684 query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE | WINED3D_QUERY_VK_FLAG_RENDER_PASS;
1686 else if (query->type == WINED3D_QUERY_TYPE_OCCLUSION)
1688 list_add_head(&context_vk->render_pass_queries, &query_vk->entry);
1689 query_vk->flags |= WINED3D_QUERY_VK_FLAG_RENDER_PASS;
1691 else
1693 wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
1694 list_add_head(&context_vk->active_queries, &query_vk->entry);
1695 query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE;
1698 query_vk->flags |= WINED3D_QUERY_VK_FLAG_STARTED;
1699 context_release(&context_vk->c);
1701 if (flags & WINED3DISSUE_END && query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED)
1703 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1705 /* If the query was already ended because the command buffer was
1706 * flushed or the render pass ended, we don't need to end it here. */
1707 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_ACTIVE)
1708 vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
1710 /* wined3d_context_vk_get_command_buffer() might have triggered
1711 * submission of the previous command buffer (due to retired
1712 * resource accumulation or periodic submit).
1713 * This will have suspended the query, and if it's a render pass
1714 * query, it won't have been resumed and therefore shouldn't be ended
1715 * here. Therefore we need to check whether it's active again. */
1716 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_ACTIVE)
1718 if (!(query_vk->flags & WINED3D_QUERY_VK_FLAG_RENDER_PASS))
1719 wined3d_context_vk_end_current_render_pass(context_vk);
1720 wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
1722 else if (query_vk->pool_idx.pool_vk)
1724 /* It was queued, but never activated. */
1725 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk,
1726 query_vk->pool_idx.idx, context_vk);
1727 query_vk->pool_idx.pool_vk = NULL;
1729 list_remove(&query_vk->entry);
1730 query_vk->flags = 0;
1731 poll = true;
1733 context_release(&context_vk->c);
1736 return poll;
1739 static void wined3d_query_vk_destroy(struct wined3d_query *query)
1741 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1742 struct wined3d_context_vk *context_vk;
1744 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED)
1745 list_remove(&query_vk->entry);
1746 context_vk = wined3d_context_vk(context_acquire(query_vk->q.device, NULL, 0));
1747 wined3d_query_vk_remove_pending_queries(context_vk, query_vk);
1748 if (query_vk->pool_idx.pool_vk)
1749 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk, query_vk->pool_idx.idx, context_vk);
1750 if (query_vk->vk_event)
1751 wined3d_context_vk_destroy_vk_event(context_vk, query_vk->vk_event, query_vk->command_buffer_id);
1752 context_release(&context_vk->c);
1753 free(query_vk->pending);
1754 free(query_vk);
1757 static const struct wined3d_query_ops wined3d_query_vk_ops =
1759 .query_poll = wined3d_query_vk_poll,
1760 .query_issue = wined3d_query_vk_issue,
1761 .query_destroy = wined3d_query_vk_destroy,
1764 static BOOL wined3d_query_event_vk_poll(struct wined3d_query *query, uint32_t flags)
1766 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1767 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1768 const struct wined3d_vk_info *vk_info = &device_vk->vk_info;
1769 BOOL signalled;
1771 signalled = VK_CALL(vkGetEventStatus(device_vk->vk_device, query_vk->vk_event))
1772 == VK_EVENT_SET;
1773 if (!signalled && (flags & WINED3DGETDATA_FLUSH) && !query->device->cs->queries_flushed)
1774 query->device->cs->c.ops->flush(&query->device->cs->c);
1775 return *(BOOL *)query->data = signalled;
1778 static BOOL wined3d_query_event_vk_issue(struct wined3d_query *query, uint32_t flags)
1780 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1781 const struct wined3d_vk_info *vk_info = &device_vk->vk_info;
1782 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1783 struct wined3d_context_vk *context_vk;
1784 VkEventCreateInfo create_info;
1785 VkResult vr;
1787 TRACE("query %p, flags %#x.\n", query, flags);
1789 if (flags & WINED3DISSUE_END)
1791 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1792 wined3d_context_vk_end_current_render_pass(context_vk);
1794 if (query_vk->vk_event)
1796 if (query_vk->command_buffer_id > context_vk->completed_command_buffer_id)
1798 /* Cannot reuse this event, as it may still get signalled by previous usage. */
1799 /* Throw it away and create a new one, but if that happens a lot we may want to pool instead. */
1800 wined3d_context_vk_destroy_vk_event(context_vk, query_vk->vk_event, query_vk->command_buffer_id);
1801 query_vk->vk_event = VK_NULL_HANDLE;
1803 else
1805 VK_CALL(vkResetEvent(device_vk->vk_device, query_vk->vk_event));
1809 if (!query_vk->vk_event)
1811 create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
1812 create_info.pNext = NULL;
1813 create_info.flags = 0;
1815 vr = VK_CALL(vkCreateEvent(device_vk->vk_device, &create_info, NULL, &query_vk->vk_event));
1816 if (vr != VK_SUCCESS)
1818 ERR("Failed to create Vulkan event, vr %s\n", wined3d_debug_vkresult(vr));
1819 context_release(&context_vk->c);
1820 return FALSE;
1824 wined3d_context_vk_reference_query(context_vk, query_vk);
1825 VK_CALL(vkCmdSetEvent(wined3d_context_vk_get_command_buffer(context_vk), query_vk->vk_event,
1826 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT));
1827 context_release(&context_vk->c);
1829 return TRUE;
1832 return FALSE;
1835 static const struct wined3d_query_ops wined3d_query_event_vk_ops =
1837 .query_poll = wined3d_query_event_vk_poll,
1838 .query_issue = wined3d_query_event_vk_issue,
1839 .query_destroy = wined3d_query_vk_destroy,
1842 static BOOL wined3d_query_timestamp_vk_issue(struct wined3d_query *query, uint32_t flags)
1844 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1845 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1846 const struct wined3d_vk_info *vk_info;
1847 struct wined3d_context_vk *context_vk;
1848 VkCommandBuffer command_buffer;
1850 TRACE("query %p, flags %#x.\n", query, flags);
1852 if (flags & WINED3DISSUE_BEGIN)
1853 TRACE("Ignoring WINED3DISSUE_BEGIN.\n");
1855 if (flags & WINED3DISSUE_END)
1857 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1858 vk_info = context_vk->vk_info;
1860 command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
1861 if (query_vk->pool_idx.pool_vk)
1862 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk, query_vk->pool_idx.idx, context_vk);
1863 if (!wined3d_context_vk_allocate_query(context_vk, query_vk->q.type, &query_vk->pool_idx))
1865 ERR("Failed to allocate new query.\n");
1866 return FALSE;
1868 VK_CALL(vkCmdWriteTimestamp(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1869 query_vk->pool_idx.pool_vk->vk_query_pool, query_vk->pool_idx.idx));
1870 wined3d_context_vk_reference_query(context_vk, query_vk);
1872 context_release(&context_vk->c);
1874 return TRUE;
1877 return FALSE;
1880 static const struct wined3d_query_ops wined3d_query_timestamp_vk_ops =
1882 .query_poll = wined3d_query_vk_poll,
1883 .query_issue = wined3d_query_timestamp_vk_issue,
1884 .query_destroy = wined3d_query_vk_destroy,
1887 static const struct wined3d_query_ops wined3d_query_timestamp_disjoint_vk_ops =
1889 .query_poll = wined3d_timestamp_disjoint_query_ops_poll,
1890 .query_issue = wined3d_timestamp_disjoint_query_ops_issue,
1891 .query_destroy = wined3d_query_vk_destroy,
1894 HRESULT wined3d_query_vk_create(struct wined3d_device *device, enum wined3d_query_type type,
1895 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1897 struct wined3d_query_data_timestamp_disjoint *disjoint_data;
1898 const struct wined3d_query_ops *ops = &wined3d_query_vk_ops;
1899 struct wined3d_query_vk *query_vk;
1900 unsigned int data_size;
1901 void *data;
1903 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1904 device, type, parent, parent_ops, query);
1906 switch (type)
1908 case WINED3D_QUERY_TYPE_EVENT:
1909 ops = &wined3d_query_event_vk_ops;
1910 data_size = sizeof(BOOL);
1911 break;
1913 case WINED3D_QUERY_TYPE_OCCLUSION:
1914 data_size = sizeof(uint64_t);
1915 break;
1917 case WINED3D_QUERY_TYPE_TIMESTAMP:
1918 if (!wined3d_device_vk(device)->timestamp_bits)
1920 WARN("Timestamp queries not supported.\n");
1921 return WINED3DERR_NOTAVAILABLE;
1923 ops = &wined3d_query_timestamp_vk_ops;
1924 data_size = sizeof(uint64_t);
1925 break;
1927 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1928 if (!wined3d_device_vk(device)->timestamp_bits)
1930 WARN("Timestamp queries not supported.\n");
1931 return WINED3DERR_NOTAVAILABLE;
1933 ops = &wined3d_query_timestamp_disjoint_vk_ops;
1934 data_size = sizeof(struct wined3d_query_data_timestamp_disjoint);
1935 break;
1937 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1938 data_size = sizeof(struct wined3d_query_data_pipeline_statistics);
1939 break;
1941 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1942 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1943 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1944 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1945 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1946 if (!wined3d_adapter_vk(device->adapter)->vk_info.supported[WINED3D_VK_EXT_TRANSFORM_FEEDBACK])
1948 WARN("Stream output queries not supported.\n");
1949 return WINED3DERR_NOTAVAILABLE;
1951 data_size = sizeof(struct wined3d_query_data_so_statistics);
1952 break;
1954 default:
1955 FIXME("Unhandled query type %#x.\n", type);
1956 return WINED3DERR_NOTAVAILABLE;
1959 if (!(query_vk = calloc(1, sizeof(*query_vk) + data_size)))
1960 return E_OUTOFMEMORY;
1961 data = query_vk + 1;
1963 wined3d_query_init(&query_vk->q, device, type, data, data_size, ops, parent, parent_ops);
1964 query_vk->q.poll_in_cs = false;
1966 switch (type)
1968 case WINED3D_QUERY_TYPE_OCCLUSION:
1969 query_vk->control_flags = VK_QUERY_CONTROL_PRECISE_BIT;
1970 break;
1972 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1973 disjoint_data = data;
1974 disjoint_data->frequency = 1000000000 / wined3d_adapter_vk(device->adapter)->device_limits.timestampPeriod;
1975 disjoint_data->disjoint = FALSE;
1976 break;
1978 default:
1979 break;
1982 TRACE("Created query %p.\n", query_vk);
1983 *query = &query_vk->q;
1985 return WINED3D_OK;
1988 HRESULT CDECL wined3d_query_create(struct wined3d_device *device, enum wined3d_query_type type,
1989 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1991 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1992 device, type, parent, parent_ops, query);
1994 return device->adapter->adapter_ops->adapter_create_query(device, type, parent, parent_ops, query);