wined3d: Move the wined3d_vk.h include to individual files.
[wine.git] / dlls / wined3d / query.c
blob8e5f60cc7fc625a363c93356d921f0edc70cf64f
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_vk.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
26 static void wined3d_query_buffer_invalidate(struct wined3d_query *query)
28 /* map[0] != map[1]: exact values do not have any significance. */
29 query->map_ptr[0] = 0;
30 query->map_ptr[1] = ~(UINT64)0;
33 static BOOL wined3d_query_buffer_is_valid(struct wined3d_query *query)
35 return query->map_ptr[0] == query->map_ptr[1];
38 static void wined3d_query_create_buffer_object(struct wined3d_context_gl *context_gl, struct wined3d_query *query)
40 const GLuint map_flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
41 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
42 GLuint buffer_object;
44 GL_EXTCALL(glGenBuffers(1, &buffer_object));
45 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, buffer_object));
46 GL_EXTCALL(glBufferStorage(GL_QUERY_BUFFER, sizeof(query->map_ptr[0]) * 2, NULL, map_flags));
47 query->map_ptr = GL_EXTCALL(glMapBufferRange(GL_QUERY_BUFFER, 0, sizeof(query->map_ptr[0]) * 2, map_flags));
48 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, 0));
49 checkGLcall("query buffer object creation");
51 wined3d_query_buffer_invalidate(query);
52 query->buffer_object = buffer_object;
55 void wined3d_query_gl_destroy_buffer_object(struct wined3d_context_gl *context_gl, struct wined3d_query *query)
57 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
59 GL_EXTCALL(glDeleteBuffers(1, &query->buffer_object));
60 checkGLcall("query buffer object destruction");
62 query->buffer_object = 0;
63 query->map_ptr = NULL;
66 /* From ARB_occlusion_query: "Querying the state for a given occlusion query
67 * forces that occlusion query to complete within a finite amount of time."
68 * In practice, that means drivers flush when retrieving
69 * GL_QUERY_RESULT_AVAILABLE, which can be undesirable when applications use a
70 * significant number of queries. Using a persistently mapped query buffer
71 * object allows us to avoid these implicit flushes. An additional benefit is
72 * that it allows us to poll the query status from the application-thread
73 * instead of from the csmt-thread. */
74 static BOOL wined3d_query_buffer_queue_result(struct wined3d_context_gl *context_gl,
75 struct wined3d_query *query, GLuint id)
77 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
78 GLsync tmp_sync;
80 if (!gl_info->supported[ARB_QUERY_BUFFER_OBJECT] || !gl_info->supported[ARB_BUFFER_STORAGE])
81 return FALSE;
82 /* Don't use query buffers without CSMT, mainly for simplicity. */
83 if (!context_gl->c.device->cs->thread)
84 return FALSE;
86 if (query->buffer_object)
88 /* If there's still a query result in-flight for the existing buffer
89 * object (i.e., the query was restarted before we received its
90 * result), we can't reuse the existing buffer object. */
91 if (wined3d_query_buffer_is_valid(query))
92 wined3d_query_buffer_invalidate(query);
93 else
94 wined3d_query_gl_destroy_buffer_object(context_gl, query);
97 if (!query->buffer_object)
98 wined3d_query_create_buffer_object(context_gl, query);
100 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, query->buffer_object));
101 /* Read the same value twice. We know we have the result if map_ptr[0] == map_ptr[1]. */
102 GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, (void *)0));
103 GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, (void *)sizeof(query->map_ptr[0])));
104 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, 0));
105 checkGLcall("queue query result");
107 /* ARB_buffer_storage requires the client to call FenceSync with
108 * SYNC_GPU_COMMANDS_COMPLETE after the server does a write. This behavior
109 * is not enforced by Mesa.
111 tmp_sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
112 GL_EXTCALL(glDeleteSync(tmp_sync));
113 checkGLcall("query buffer sync");
115 return TRUE;
118 static UINT64 get_query_result64(GLuint id, const struct wined3d_gl_info *gl_info)
120 if (gl_info->supported[ARB_TIMER_QUERY])
122 GLuint64 result;
123 GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, &result));
124 return result;
126 else
128 GLuint result;
129 GL_EXTCALL(glGetQueryObjectuiv(id, GL_QUERY_RESULT, &result));
130 return result;
134 static void wined3d_query_init(struct wined3d_query *query, struct wined3d_device *device,
135 enum wined3d_query_type type, const void *data, DWORD data_size,
136 const struct wined3d_query_ops *query_ops, void *parent, const struct wined3d_parent_ops *parent_ops)
138 query->ref = 1;
139 query->parent = parent;
140 query->parent_ops = parent_ops;
141 query->device = device;
142 query->state = QUERY_CREATED;
143 query->type = type;
144 query->data = data;
145 query->data_size = data_size;
146 query->query_ops = query_ops;
147 query->poll_in_cs = !!device->cs->thread;
148 list_init(&query->poll_list_entry);
151 static struct wined3d_event_query *wined3d_event_query_from_query(struct wined3d_query *query)
153 return CONTAINING_RECORD(query, struct wined3d_event_query, query);
156 static struct wined3d_occlusion_query *wined3d_occlusion_query_from_query(struct wined3d_query *query)
158 return CONTAINING_RECORD(query, struct wined3d_occlusion_query, query);
161 static struct wined3d_timestamp_query *wined3d_timestamp_query_from_query(struct wined3d_query *query)
163 return CONTAINING_RECORD(query, struct wined3d_timestamp_query, query);
166 static struct wined3d_so_statistics_query *wined3d_so_statistics_query_from_query(struct wined3d_query *query)
168 return CONTAINING_RECORD(query, struct wined3d_so_statistics_query, query);
171 static struct wined3d_pipeline_statistics_query *wined3d_pipeline_statistics_query_from_query(
172 struct wined3d_query *query)
174 return CONTAINING_RECORD(query, struct wined3d_pipeline_statistics_query, query);
177 enum wined3d_fence_result wined3d_fence_test(const struct wined3d_fence *fence,
178 struct wined3d_device *device, uint32_t flags)
180 const struct wined3d_gl_info *gl_info;
181 struct wined3d_context_gl *context_gl;
182 enum wined3d_fence_result ret;
183 BOOL fence_result;
185 TRACE("fence %p, device %p, flags %#x.\n", fence, device, flags);
187 if (!fence->context_gl)
189 TRACE("Fence not issued.\n");
190 return WINED3D_FENCE_NOT_STARTED;
193 if (!(context_gl = wined3d_context_gl_reacquire(fence->context_gl)))
195 if (!fence->context_gl->gl_info->supported[ARB_SYNC])
197 WARN("Fence tested from wrong thread.\n");
198 return WINED3D_FENCE_WRONG_THREAD;
200 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
202 gl_info = context_gl->gl_info;
204 if (gl_info->supported[ARB_SYNC])
206 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
207 (flags & WINED3DGETDATA_FLUSH) ? GL_SYNC_FLUSH_COMMANDS_BIT : 0, 0));
208 checkGLcall("glClientWaitSync");
210 switch (gl_ret)
212 case GL_ALREADY_SIGNALED:
213 case GL_CONDITION_SATISFIED:
214 ret = WINED3D_FENCE_OK;
215 break;
217 case GL_TIMEOUT_EXPIRED:
218 ret = WINED3D_FENCE_WAITING;
219 break;
221 case GL_WAIT_FAILED:
222 default:
223 ERR("glClientWaitSync returned %#x.\n", gl_ret);
224 ret = WINED3D_FENCE_ERROR;
227 else if (gl_info->supported[APPLE_FENCE])
229 fence_result = GL_EXTCALL(glTestFenceAPPLE(fence->object.id));
230 checkGLcall("glTestFenceAPPLE");
231 if (fence_result)
232 ret = WINED3D_FENCE_OK;
233 else
234 ret = WINED3D_FENCE_WAITING;
236 else if (gl_info->supported[NV_FENCE])
238 fence_result = GL_EXTCALL(glTestFenceNV(fence->object.id));
239 checkGLcall("glTestFenceNV");
240 if (fence_result)
241 ret = WINED3D_FENCE_OK;
242 else
243 ret = WINED3D_FENCE_WAITING;
245 else
247 ERR("Fence created despite lack of GL support.\n");
248 ret = WINED3D_FENCE_ERROR;
251 context_release(&context_gl->c);
252 return ret;
255 enum wined3d_fence_result wined3d_fence_wait(const struct wined3d_fence *fence,
256 struct wined3d_device *device)
258 const struct wined3d_gl_info *gl_info;
259 struct wined3d_context_gl *context_gl;
260 enum wined3d_fence_result ret;
262 TRACE("fence %p, device %p.\n", fence, device);
264 if (!fence->context_gl)
266 TRACE("Fence not issued.\n");
267 return WINED3D_FENCE_NOT_STARTED;
269 gl_info = fence->context_gl->gl_info;
271 if (!(context_gl = wined3d_context_gl_reacquire(fence->context_gl)))
273 /* A glFinish does not reliably wait for draws in other contexts. The caller has
274 * to find its own way to cope with the thread switch
276 if (!gl_info->supported[ARB_SYNC])
278 WARN("Fence finished from wrong thread.\n");
279 return WINED3D_FENCE_WRONG_THREAD;
281 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
283 gl_info = context_gl->gl_info;
285 if (gl_info->supported[ARB_SYNC])
287 /* Timeouts near 0xffffffffffffffff may immediately return GL_TIMEOUT_EXPIRED,
288 * possibly because macOS internally adds some slop to the timer. To avoid this,
289 * we use a large number that isn't near the point of overflow (macOS 10.12.5).
291 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
292 GL_SYNC_FLUSH_COMMANDS_BIT, ~(GLuint64)0 >> 1));
293 checkGLcall("glClientWaitSync");
295 switch (gl_ret)
297 case GL_ALREADY_SIGNALED:
298 case GL_CONDITION_SATISFIED:
299 ret = WINED3D_FENCE_OK;
300 break;
302 /* We don't expect a timeout for a ~292 year wait */
303 default:
304 ERR("glClientWaitSync returned %#x.\n", gl_ret);
305 ret = WINED3D_FENCE_ERROR;
308 else if (gl_info->supported[APPLE_FENCE])
310 GL_EXTCALL(glFinishFenceAPPLE(fence->object.id));
311 checkGLcall("glFinishFenceAPPLE");
312 ret = WINED3D_FENCE_OK;
314 else if (gl_info->supported[NV_FENCE])
316 GL_EXTCALL(glFinishFenceNV(fence->object.id));
317 checkGLcall("glFinishFenceNV");
318 ret = WINED3D_FENCE_OK;
320 else
322 ERR("Fence created without GL support.\n");
323 ret = WINED3D_FENCE_ERROR;
326 context_release(&context_gl->c);
327 return ret;
330 void wined3d_fence_issue(struct wined3d_fence *fence, struct wined3d_device *device)
332 struct wined3d_context_gl *context_gl = NULL;
333 const struct wined3d_gl_info *gl_info;
335 if (fence->context_gl && !(context_gl = wined3d_context_gl_reacquire(fence->context_gl))
336 && !fence->context_gl->gl_info->supported[ARB_SYNC])
337 wined3d_context_gl_free_fence(fence);
338 if (!context_gl)
339 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
340 gl_info = context_gl->gl_info;
341 if (!fence->context_gl)
342 wined3d_context_gl_alloc_fence(context_gl, fence);
344 if (gl_info->supported[ARB_SYNC])
346 if (fence->object.sync)
347 GL_EXTCALL(glDeleteSync(fence->object.sync));
348 checkGLcall("glDeleteSync");
349 fence->object.sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
350 checkGLcall("glFenceSync");
352 else if (gl_info->supported[APPLE_FENCE])
354 GL_EXTCALL(glSetFenceAPPLE(fence->object.id));
355 checkGLcall("glSetFenceAPPLE");
357 else if (gl_info->supported[NV_FENCE])
359 GL_EXTCALL(glSetFenceNV(fence->object.id, GL_ALL_COMPLETED_NV));
360 checkGLcall("glSetFenceNV");
363 context_release(&context_gl->c);
366 static void wined3d_fence_free(struct wined3d_fence *fence)
368 if (fence->context_gl)
369 wined3d_context_gl_free_fence(fence);
372 void wined3d_fence_destroy(struct wined3d_fence *fence)
374 wined3d_fence_free(fence);
375 heap_free(fence);
378 static HRESULT wined3d_fence_init(struct wined3d_fence *fence, const struct wined3d_gl_info *gl_info)
380 if (!wined3d_fence_supported(gl_info))
382 WARN("Fences not supported.\n");
383 return WINED3DERR_NOTAVAILABLE;
386 return WINED3D_OK;
389 HRESULT wined3d_fence_create(struct wined3d_device *device, struct wined3d_fence **fence)
391 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
392 struct wined3d_fence *object;
393 HRESULT hr;
395 TRACE("device %p, fence %p.\n", device, fence);
397 if (!(object = heap_alloc_zero(sizeof(*object))))
398 return E_OUTOFMEMORY;
400 if (FAILED(hr = wined3d_fence_init(object, gl_info)))
402 heap_free(object);
403 return hr;
406 TRACE("Created fence %p.\n", object);
407 *fence = object;
409 return WINED3D_OK;
412 ULONG CDECL wined3d_query_incref(struct wined3d_query *query)
414 unsigned int refcount = InterlockedIncrement(&query->ref);
416 TRACE("%p increasing refcount to %u.\n", query, refcount);
418 return refcount;
421 static void wined3d_query_destroy_object(void *object)
423 struct wined3d_query *query = object;
425 TRACE("query %p.\n", query);
427 if (!list_empty(&query->poll_list_entry))
428 list_remove(&query->poll_list_entry);
431 ULONG CDECL wined3d_query_decref(struct wined3d_query *query)
433 unsigned int refcount = InterlockedDecrement(&query->ref);
435 TRACE("%p decreasing refcount to %u.\n", query, refcount);
437 if (!refcount)
439 struct wined3d_device *device = query->device;
441 wined3d_mutex_lock();
442 query->parent_ops->wined3d_object_destroyed(query->parent);
443 wined3d_cs_destroy_object(device->cs, wined3d_query_destroy_object, query);
444 device->adapter->adapter_ops->adapter_destroy_query(query);
445 wined3d_mutex_unlock();
448 return refcount;
451 HRESULT CDECL wined3d_query_get_data(struct wined3d_query *query,
452 void *data, UINT data_size, uint32_t flags)
454 TRACE("query %p, data %p, data_size %u, flags %#x.\n",
455 query, data, data_size, flags);
457 if (query->state == QUERY_BUILDING)
459 WARN("Query is building, returning S_FALSE.\n");
460 return S_FALSE;
463 if (query->state == QUERY_CREATED)
465 WARN("Query wasn't started yet.\n");
466 return WINED3DERR_INVALIDCALL;
469 if (query->counter_main != query->counter_retrieved
470 || (query->buffer_object && !wined3d_query_buffer_is_valid(query)))
472 if (flags & WINED3DGETDATA_FLUSH && !query->device->cs->queries_flushed)
473 query->device->cs->c.ops->flush(&query->device->cs->c);
474 return S_FALSE;
476 else if (!query->poll_in_cs && !query->query_ops->query_poll(query, flags))
478 return S_FALSE;
481 if (query->buffer_object)
482 query->data = query->map_ptr;
484 if (data)
485 memcpy(data, query->data, min(data_size, query->data_size));
487 return S_OK;
490 UINT CDECL wined3d_query_get_data_size(const struct wined3d_query *query)
492 TRACE("query %p.\n", query);
494 return query->data_size;
497 HRESULT CDECL wined3d_query_issue(struct wined3d_query *query, uint32_t flags)
499 TRACE("query %p, flags %#x.\n", query, flags);
501 wined3d_device_context_issue_query(&query->device->cs->c, query, flags);
503 return WINED3D_OK;
506 static BOOL wined3d_occlusion_query_ops_poll(struct wined3d_query *query, uint32_t flags)
508 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
509 const struct wined3d_gl_info *gl_info;
510 struct wined3d_context_gl *context_gl;
511 GLuint available;
513 TRACE("query %p, flags %#x.\n", query, flags);
515 if (!(context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
517 FIXME("%p Wrong thread, returning 1.\n", query);
518 oq->samples = 1;
519 return TRUE;
521 gl_info = context_gl->gl_info;
523 GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT_AVAILABLE, &available));
524 TRACE("Available %#x.\n", available);
526 if (available)
528 oq->samples = get_query_result64(oq->id, gl_info);
529 TRACE("Returning 0x%s samples.\n", wine_dbgstr_longlong(oq->samples));
532 checkGLcall("poll occlusion query");
533 context_release(&context_gl->c);
535 return available;
538 static BOOL wined3d_event_query_ops_poll(struct wined3d_query *query, uint32_t flags)
540 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
541 enum wined3d_fence_result ret;
543 TRACE("query %p, flags %#x.\n", query, flags);
545 ret = wined3d_fence_test(&event_query->fence, query->device, flags);
546 switch (ret)
548 case WINED3D_FENCE_OK:
549 case WINED3D_FENCE_NOT_STARTED:
550 return event_query->signalled = TRUE;
552 case WINED3D_FENCE_WAITING:
553 return event_query->signalled = FALSE;
555 case WINED3D_FENCE_WRONG_THREAD:
556 FIXME("(%p) Wrong thread, reporting GPU idle.\n", query);
557 return event_query->signalled = TRUE;
559 case WINED3D_FENCE_ERROR:
560 ERR("The GL event query failed.\n");
561 return event_query->signalled = TRUE;
563 default:
564 ERR("Unexpected wined3d_event_query_test result %#x.\n", ret);
565 return event_query->signalled = TRUE;
569 void * CDECL wined3d_query_get_parent(const struct wined3d_query *query)
571 TRACE("query %p.\n", query);
573 return query->parent;
576 enum wined3d_query_type CDECL wined3d_query_get_type(const struct wined3d_query *query)
578 TRACE("query %p.\n", query);
580 return query->type;
583 static BOOL wined3d_event_query_ops_issue(struct wined3d_query *query, uint32_t flags)
585 TRACE("query %p, flags %#x.\n", query, flags);
587 if (flags & WINED3DISSUE_END)
589 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
591 wined3d_fence_issue(&event_query->fence, query->device);
592 return TRUE;
594 else if (flags & WINED3DISSUE_BEGIN)
596 /* Started implicitly at query creation. */
597 ERR("Event query issued with START flag - what to do?\n");
600 return FALSE;
603 static BOOL wined3d_occlusion_query_ops_issue(struct wined3d_query *query, uint32_t flags)
605 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
606 struct wined3d_device *device = query->device;
607 const struct wined3d_gl_info *gl_info;
608 struct wined3d_context_gl *context_gl;
609 BOOL poll = FALSE;
611 TRACE("query %p, flags %#x.\n", query, flags);
613 /* This is allowed according to MSDN and our tests. Reset the query and
614 * restart. */
615 if (flags & WINED3DISSUE_BEGIN)
617 if (oq->started)
619 if ((context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
621 gl_info = context_gl->gl_info;
622 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
623 checkGLcall("glEndQuery()");
625 else
627 FIXME("Wrong thread, can't restart query.\n");
628 wined3d_context_gl_free_occlusion_query(oq);
629 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
630 wined3d_context_gl_alloc_occlusion_query(context_gl, oq);
633 else
635 if (oq->context_gl)
636 wined3d_context_gl_free_occlusion_query(oq);
637 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
638 wined3d_context_gl_alloc_occlusion_query(context_gl, oq);
640 gl_info = context_gl->gl_info;
642 GL_EXTCALL(glBeginQuery(GL_SAMPLES_PASSED, oq->id));
643 checkGLcall("glBeginQuery()");
645 context_release(&context_gl->c);
646 oq->started = TRUE;
648 if (flags & WINED3DISSUE_END)
650 /* MSDN says END on a non-building occlusion query returns an error,
651 * but our tests show that it returns OK. But OpenGL doesn't like it,
652 * so avoid generating an error. */
653 if (oq->started)
655 if ((context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
657 gl_info = context_gl->gl_info;
658 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
659 checkGLcall("glEndQuery()");
660 wined3d_query_buffer_queue_result(context_gl, query, oq->id);
662 context_release(&context_gl->c);
663 poll = TRUE;
665 else
667 FIXME("Wrong thread, can't end query.\n");
670 oq->started = FALSE;
673 return poll;
676 static BOOL wined3d_timestamp_query_ops_poll(struct wined3d_query *query, uint32_t flags)
678 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
679 const struct wined3d_gl_info *gl_info;
680 struct wined3d_context_gl *context_gl;
681 GLuint64 timestamp;
682 GLuint available;
684 TRACE("query %p, flags %#x.\n", query, flags);
686 if (!(context_gl = wined3d_context_gl_reacquire(tq->context_gl)))
688 FIXME("%p Wrong thread, returning 1.\n", query);
689 tq->timestamp = 1;
690 return TRUE;
692 gl_info = context_gl->gl_info;
694 GL_EXTCALL(glGetQueryObjectuiv(tq->id, GL_QUERY_RESULT_AVAILABLE, &available));
695 checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
696 TRACE("available %#x.\n", available);
698 if (available)
700 GL_EXTCALL(glGetQueryObjectui64v(tq->id, GL_QUERY_RESULT, &timestamp));
701 checkGLcall("glGetQueryObjectui64v(GL_QUERY_RESULT)");
702 TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp));
703 tq->timestamp = timestamp;
706 context_release(&context_gl->c);
708 return available;
711 static BOOL wined3d_timestamp_query_ops_issue(struct wined3d_query *query, uint32_t flags)
713 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
714 const struct wined3d_gl_info *gl_info;
715 struct wined3d_context_gl *context_gl;
717 TRACE("query %p, flags %#x.\n", query, flags);
719 if (flags & WINED3DISSUE_BEGIN)
721 WARN("Ignoring WINED3DISSUE_BEGIN with a TIMESTAMP query.\n");
723 if (flags & WINED3DISSUE_END)
725 if (tq->context_gl)
726 wined3d_context_gl_free_timestamp_query(tq);
727 context_gl = wined3d_context_gl(context_acquire(query->device, NULL, 0));
728 gl_info = context_gl->gl_info;
729 wined3d_context_gl_alloc_timestamp_query(context_gl, tq);
730 GL_EXTCALL(glQueryCounter(tq->id, GL_TIMESTAMP));
731 checkGLcall("glQueryCounter()");
732 context_release(&context_gl->c);
734 return TRUE;
737 return FALSE;
740 static BOOL wined3d_timestamp_disjoint_query_ops_poll(struct wined3d_query *query, uint32_t flags)
742 TRACE("query %p, flags %#x.\n", query, flags);
744 return TRUE;
747 static BOOL wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query *query, uint32_t flags)
749 TRACE("query %p, flags %#x.\n", query, flags);
751 return FALSE;
754 static BOOL wined3d_so_statistics_query_ops_poll(struct wined3d_query *query, uint32_t flags)
756 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
757 GLuint written_available, generated_available;
758 const struct wined3d_gl_info *gl_info;
759 struct wined3d_context_gl *context_gl;
761 TRACE("query %p, flags %#x.\n", query, flags);
763 if (!(context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
765 FIXME("%p Wrong thread, returning 0 primitives.\n", query);
766 memset(&pq->statistics, 0, sizeof(pq->statistics));
767 return TRUE;
769 gl_info = context_gl->gl_info;
771 GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.written,
772 GL_QUERY_RESULT_AVAILABLE, &written_available));
773 GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.generated,
774 GL_QUERY_RESULT_AVAILABLE, &generated_available));
775 TRACE("Available %#x, %#x.\n", written_available, generated_available);
777 if (written_available && generated_available)
779 pq->statistics.primitives_written = get_query_result64(pq->u.query.written, gl_info);
780 pq->statistics.primitives_generated = get_query_result64(pq->u.query.generated, gl_info);
781 TRACE("Returning %s, %s primitives.\n",
782 wine_dbgstr_longlong(pq->statistics.primitives_written),
783 wine_dbgstr_longlong(pq->statistics.primitives_generated));
786 checkGLcall("poll SO statistics query");
787 context_release(&context_gl->c);
789 return written_available && generated_available;
792 static void wined3d_so_statistics_query_end(struct wined3d_so_statistics_query *query,
793 struct wined3d_context_gl *context_gl)
795 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
797 if (gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
799 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query->stream_idx));
800 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED, query->stream_idx));
802 else
804 GL_EXTCALL(glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN));
805 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_GENERATED));
807 checkGLcall("end query");
810 static BOOL wined3d_so_statistics_query_ops_issue(struct wined3d_query *query, uint32_t flags)
812 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
813 struct wined3d_device *device = query->device;
814 const struct wined3d_gl_info *gl_info;
815 struct wined3d_context_gl *context_gl;
816 BOOL poll = FALSE;
818 TRACE("query %p, flags %#x.\n", query, flags);
820 if (flags & WINED3DISSUE_BEGIN)
822 if (pq->started)
824 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
826 wined3d_so_statistics_query_end(pq, context_gl);
828 else
830 FIXME("Wrong thread, can't restart query.\n");
831 wined3d_context_gl_free_so_statistics_query(pq);
832 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
833 wined3d_context_gl_alloc_so_statistics_query(context_gl, pq);
836 else
838 if (pq->context_gl)
839 wined3d_context_gl_free_so_statistics_query(pq);
840 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
841 wined3d_context_gl_alloc_so_statistics_query(context_gl, pq);
843 gl_info = context_gl->gl_info;
845 if (gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
847 GL_EXTCALL(glBeginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
848 pq->stream_idx, pq->u.query.written));
849 GL_EXTCALL(glBeginQueryIndexed(GL_PRIMITIVES_GENERATED,
850 pq->stream_idx, pq->u.query.generated));
852 else
854 GL_EXTCALL(glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
855 pq->u.query.written));
856 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_GENERATED,
857 pq->u.query.generated));
859 checkGLcall("begin query");
861 context_release(&context_gl->c);
862 pq->started = TRUE;
864 if (flags & WINED3DISSUE_END)
866 if (pq->started)
868 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
870 wined3d_so_statistics_query_end(pq, context_gl);
872 context_release(&context_gl->c);
873 poll = TRUE;
875 else
877 FIXME("Wrong thread, can't end query.\n");
880 pq->started = FALSE;
883 return poll;
886 static BOOL wined3d_pipeline_query_ops_poll(struct wined3d_query *query, uint32_t flags)
888 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
889 const struct wined3d_gl_info *gl_info;
890 struct wined3d_context_gl *context_gl;
891 GLuint available;
892 int i;
894 TRACE("query %p, flags %#x.\n", query, flags);
896 if (!(context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
898 FIXME("%p Wrong thread.\n", query);
899 memset(&pq->statistics, 0, sizeof(pq->statistics));
900 return TRUE;
902 gl_info = context_gl->gl_info;
904 for (i = 0; i < ARRAY_SIZE(pq->u.id); ++i)
906 GL_EXTCALL(glGetQueryObjectuiv(pq->u.id[i], GL_QUERY_RESULT_AVAILABLE, &available));
907 if (!available)
908 break;
911 if (available)
913 pq->statistics.vertices_submitted = get_query_result64(pq->u.query.vertices, gl_info);
914 pq->statistics.primitives_submitted = get_query_result64(pq->u.query.primitives, gl_info);
915 pq->statistics.vs_invocations = get_query_result64(pq->u.query.vertex_shader, gl_info);
916 pq->statistics.hs_invocations = get_query_result64(pq->u.query.tess_control_shader, gl_info);
917 pq->statistics.ds_invocations = get_query_result64(pq->u.query.tess_eval_shader, gl_info);
918 pq->statistics.gs_invocations = get_query_result64(pq->u.query.geometry_shader, gl_info);
919 pq->statistics.gs_primitives = get_query_result64(pq->u.query.geometry_primitives, gl_info);
920 pq->statistics.ps_invocations = get_query_result64(pq->u.query.fragment_shader, gl_info);
921 pq->statistics.cs_invocations = get_query_result64(pq->u.query.compute_shader, gl_info);
922 pq->statistics.clipping_input_primitives = get_query_result64(pq->u.query.clipping_input, gl_info);
923 pq->statistics.clipping_output_primitives = get_query_result64(pq->u.query.clipping_output, gl_info);
926 checkGLcall("poll pipeline statistics query");
927 context_release(&context_gl->c);
928 return available;
931 static void wined3d_pipeline_statistics_query_end(struct wined3d_pipeline_statistics_query *query,
932 struct wined3d_context_gl *context_gl)
934 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
936 GL_EXTCALL(glEndQuery(GL_VERTICES_SUBMITTED_ARB));
937 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_SUBMITTED_ARB));
938 GL_EXTCALL(glEndQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB));
939 GL_EXTCALL(glEndQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB));
940 GL_EXTCALL(glEndQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB));
941 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_INVOCATIONS));
942 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB));
943 GL_EXTCALL(glEndQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB));
944 GL_EXTCALL(glEndQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB));
945 GL_EXTCALL(glEndQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB));
946 GL_EXTCALL(glEndQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB));
947 checkGLcall("end query");
950 static BOOL wined3d_pipeline_query_ops_issue(struct wined3d_query *query, uint32_t flags)
952 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
953 struct wined3d_device *device = query->device;
954 const struct wined3d_gl_info *gl_info;
955 struct wined3d_context_gl *context_gl;
956 BOOL poll = FALSE;
958 TRACE("query %p, flags %#x.\n", query, flags);
960 if (flags & WINED3DISSUE_BEGIN)
962 if (pq->started)
964 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
966 wined3d_pipeline_statistics_query_end(pq, context_gl);
968 else
970 FIXME("Wrong thread, can't restart query.\n");
971 wined3d_context_gl_free_pipeline_statistics_query(pq);
972 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
973 wined3d_context_gl_alloc_pipeline_statistics_query(context_gl, pq);
976 else
978 if (pq->context_gl)
979 wined3d_context_gl_free_pipeline_statistics_query(pq);
980 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
981 wined3d_context_gl_alloc_pipeline_statistics_query(context_gl, pq);
983 gl_info = context_gl->gl_info;
985 GL_EXTCALL(glBeginQuery(GL_VERTICES_SUBMITTED_ARB, pq->u.query.vertices));
986 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_SUBMITTED_ARB, pq->u.query.primitives));
987 GL_EXTCALL(glBeginQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB, pq->u.query.vertex_shader));
988 GL_EXTCALL(glBeginQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB, pq->u.query.tess_control_shader));
989 GL_EXTCALL(glBeginQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB, pq->u.query.tess_eval_shader));
990 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_INVOCATIONS, pq->u.query.geometry_shader));
991 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB, pq->u.query.geometry_primitives));
992 GL_EXTCALL(glBeginQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB, pq->u.query.fragment_shader));
993 GL_EXTCALL(glBeginQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB, pq->u.query.compute_shader));
994 GL_EXTCALL(glBeginQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB, pq->u.query.clipping_input));
995 GL_EXTCALL(glBeginQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB, pq->u.query.clipping_output));
996 checkGLcall("begin query");
998 context_release(&context_gl->c);
999 pq->started = TRUE;
1001 if (flags & WINED3DISSUE_END)
1003 if (pq->started)
1005 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
1007 wined3d_pipeline_statistics_query_end(pq, context_gl);
1008 context_release(&context_gl->c);
1009 poll = TRUE;
1011 else
1013 FIXME("Wrong thread, can't end query.\n");
1016 pq->started = FALSE;
1019 return poll;
1022 static void wined3d_event_query_ops_destroy(struct wined3d_query *query)
1024 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
1026 wined3d_fence_free(&event_query->fence);
1027 heap_free(event_query);
1030 static const struct wined3d_query_ops event_query_ops =
1032 wined3d_event_query_ops_poll,
1033 wined3d_event_query_ops_issue,
1034 wined3d_event_query_ops_destroy,
1037 static HRESULT wined3d_event_query_create(struct wined3d_device *device,
1038 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1039 struct wined3d_query **query)
1041 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1042 struct wined3d_event_query *object;
1043 HRESULT hr;
1045 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1046 device, type, parent, parent_ops, query);
1048 if (!(object = heap_alloc_zero(sizeof(*object))))
1049 return E_OUTOFMEMORY;
1051 if (FAILED(hr = wined3d_fence_init(&object->fence, gl_info)))
1053 WARN("Event queries not supported.\n");
1054 heap_free(object);
1055 return hr;
1058 wined3d_query_init(&object->query, device, type, &object->signalled,
1059 sizeof(object->signalled), &event_query_ops, parent, parent_ops);
1061 TRACE("Created query %p.\n", object);
1062 *query = &object->query;
1064 return WINED3D_OK;
1067 static void wined3d_occlusion_query_ops_destroy(struct wined3d_query *query)
1069 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
1071 if (oq->context_gl)
1072 wined3d_context_gl_free_occlusion_query(oq);
1073 heap_free(oq);
1076 static const struct wined3d_query_ops occlusion_query_ops =
1078 wined3d_occlusion_query_ops_poll,
1079 wined3d_occlusion_query_ops_issue,
1080 wined3d_occlusion_query_ops_destroy,
1083 static HRESULT wined3d_occlusion_query_create(struct wined3d_device *device,
1084 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1085 struct wined3d_query **query)
1087 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1088 struct wined3d_occlusion_query *object;
1090 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1091 device, type, parent, parent_ops, query);
1093 if (!gl_info->supported[ARB_OCCLUSION_QUERY])
1095 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
1096 return WINED3DERR_NOTAVAILABLE;
1099 if (!(object = heap_alloc_zero(sizeof(*object))))
1100 return E_OUTOFMEMORY;
1102 wined3d_query_init(&object->query, device, type, &object->samples,
1103 sizeof(object->samples), &occlusion_query_ops, parent, parent_ops);
1105 TRACE("Created query %p.\n", object);
1106 *query = &object->query;
1108 return WINED3D_OK;
1111 static void wined3d_timestamp_query_ops_destroy(struct wined3d_query *query)
1113 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
1115 if (tq->context_gl)
1116 wined3d_context_gl_free_timestamp_query(tq);
1117 heap_free(tq);
1120 static const struct wined3d_query_ops timestamp_query_ops =
1122 wined3d_timestamp_query_ops_poll,
1123 wined3d_timestamp_query_ops_issue,
1124 wined3d_timestamp_query_ops_destroy,
1127 static HRESULT wined3d_timestamp_query_create(struct wined3d_device *device,
1128 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1129 struct wined3d_query **query)
1131 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1132 struct wined3d_timestamp_query *object;
1134 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1135 device, type, parent, parent_ops, query);
1137 if (!gl_info->supported[ARB_TIMER_QUERY])
1139 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1140 return WINED3DERR_NOTAVAILABLE;
1143 if (!(object = heap_alloc_zero(sizeof(*object))))
1144 return E_OUTOFMEMORY;
1146 wined3d_query_init(&object->query, device, type, &object->timestamp,
1147 sizeof(object->timestamp), &timestamp_query_ops, parent, parent_ops);
1149 TRACE("Created query %p.\n", object);
1150 *query = &object->query;
1152 return WINED3D_OK;
1155 static void wined3d_timestamp_disjoint_query_ops_destroy(struct wined3d_query *query)
1157 heap_free(query);
1160 static const struct wined3d_query_ops timestamp_disjoint_query_ops =
1162 wined3d_timestamp_disjoint_query_ops_poll,
1163 wined3d_timestamp_disjoint_query_ops_issue,
1164 wined3d_timestamp_disjoint_query_ops_destroy,
1167 static HRESULT wined3d_timestamp_disjoint_query_create(struct wined3d_device *device,
1168 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1169 struct wined3d_query **query)
1171 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1172 struct wined3d_query *object;
1174 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1175 device, type, parent, parent_ops, query);
1177 if (!gl_info->supported[ARB_TIMER_QUERY])
1179 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1180 return WINED3DERR_NOTAVAILABLE;
1183 if (!(object = heap_alloc_zero(sizeof(*object))))
1184 return E_OUTOFMEMORY;
1186 if (type == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT)
1188 static const struct wined3d_query_data_timestamp_disjoint disjoint_data = {1000 * 1000 * 1000, FALSE};
1190 wined3d_query_init(object, device, type, &disjoint_data,
1191 sizeof(disjoint_data), &timestamp_disjoint_query_ops, parent, parent_ops);
1193 else
1195 static const UINT64 freq = 1000 * 1000 * 1000;
1197 wined3d_query_init(object, device, type, &freq,
1198 sizeof(freq), &timestamp_disjoint_query_ops, parent, parent_ops);
1201 TRACE("Created query %p.\n", object);
1202 *query = object;
1204 return WINED3D_OK;
1207 static void wined3d_so_statistics_query_ops_destroy(struct wined3d_query *query)
1209 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
1211 if (pq->context_gl)
1212 wined3d_context_gl_free_so_statistics_query(pq);
1213 heap_free(pq);
1216 static const struct wined3d_query_ops so_statistics_query_ops =
1218 wined3d_so_statistics_query_ops_poll,
1219 wined3d_so_statistics_query_ops_issue,
1220 wined3d_so_statistics_query_ops_destroy,
1223 static HRESULT wined3d_so_statistics_query_create(struct wined3d_device *device,
1224 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1225 struct wined3d_query **query)
1227 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1228 struct wined3d_so_statistics_query *object;
1229 unsigned int stream_idx;
1231 if (WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0 <= type && type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1232 stream_idx = type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0;
1233 else if (type == WINED3D_QUERY_TYPE_SO_STATISTICS)
1234 stream_idx = 0;
1235 else
1236 return WINED3DERR_NOTAVAILABLE;
1238 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1239 device, type, parent, parent_ops, query);
1241 if (!gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY])
1243 WARN("OpenGL implementation does not support primitive queries.\n");
1244 return WINED3DERR_NOTAVAILABLE;
1246 if (stream_idx && !gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
1248 WARN("OpenGL implementation does not support indexed queries.\n");
1249 return WINED3DERR_NOTAVAILABLE;
1252 if (!(object = heap_alloc_zero(sizeof(*object))))
1253 return E_OUTOFMEMORY;
1255 wined3d_query_init(&object->query, device, type, &object->statistics,
1256 sizeof(object->statistics), &so_statistics_query_ops, parent, parent_ops);
1257 object->stream_idx = stream_idx;
1259 TRACE("Created query %p.\n", object);
1260 *query = &object->query;
1262 return WINED3D_OK;
1265 static void wined3d_pipeline_query_ops_destroy(struct wined3d_query *query)
1267 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
1268 if (pq->context_gl)
1269 wined3d_context_gl_free_pipeline_statistics_query(pq);
1270 heap_free(pq);
1273 static const struct wined3d_query_ops pipeline_query_ops =
1275 wined3d_pipeline_query_ops_poll,
1276 wined3d_pipeline_query_ops_issue,
1277 wined3d_pipeline_query_ops_destroy,
1280 static HRESULT wined3d_pipeline_query_create(struct wined3d_device *device,
1281 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1282 struct wined3d_query **query)
1284 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1285 struct wined3d_pipeline_statistics_query *object;
1287 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1288 device, type, parent, parent_ops, query);
1290 if (!gl_info->supported[ARB_PIPELINE_STATISTICS_QUERY])
1292 WARN("OpenGL implementation does not support pipeline statistics queries.\n");
1293 return WINED3DERR_NOTAVAILABLE;
1296 if (!(object = heap_alloc_zero(sizeof(*object))))
1297 return E_OUTOFMEMORY;
1299 wined3d_query_init(&object->query, device, type, &object->statistics,
1300 sizeof(object->statistics), &pipeline_query_ops, parent, parent_ops);
1302 TRACE("Created query %p.\n", object);
1303 *query = &object->query;
1305 return WINED3D_OK;
1308 HRESULT wined3d_query_gl_create(struct wined3d_device *device, enum wined3d_query_type type,
1309 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1311 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1312 device, type, parent, parent_ops, query);
1314 switch (type)
1316 case WINED3D_QUERY_TYPE_EVENT:
1317 return wined3d_event_query_create(device, type, parent, parent_ops, query);
1319 case WINED3D_QUERY_TYPE_OCCLUSION:
1320 return wined3d_occlusion_query_create(device, type, parent, parent_ops, query);
1322 case WINED3D_QUERY_TYPE_TIMESTAMP:
1323 return wined3d_timestamp_query_create(device, type, parent, parent_ops, query);
1325 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1326 case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ:
1327 return wined3d_timestamp_disjoint_query_create(device, type, parent, parent_ops, query);
1329 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1330 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1331 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1332 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1333 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1334 return wined3d_so_statistics_query_create(device, type, parent, parent_ops, query);
1336 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1337 return wined3d_pipeline_query_create(device, type, parent, parent_ops, query);
1339 default:
1340 FIXME("Unhandled query type %#x.\n", type);
1341 return WINED3DERR_NOTAVAILABLE;
1345 static void wined3d_query_pool_vk_mark_complete(struct wined3d_query_pool_vk *pool_vk, size_t idx,
1346 struct wined3d_context_vk *context_vk)
1348 /* Don't reset completed queries right away, as vkCmdResetQueryPool() needs to happen
1349 * outside of a render pass. Queue the query to be reset at the very end of the current
1350 * command buffer instead. */
1351 wined3d_bitmap_set(pool_vk->completed, idx);
1352 if (list_empty(&pool_vk->completed_entry))
1353 list_add_tail(&context_vk->completed_query_pools, &pool_vk->completed_entry);
1356 bool wined3d_query_pool_vk_allocate_query(struct wined3d_query_pool_vk *pool_vk, size_t *idx)
1358 if ((*idx = wined3d_bitmap_ffz(pool_vk->allocated, WINED3D_QUERY_POOL_SIZE, 0)) > WINED3D_QUERY_POOL_SIZE)
1359 return false;
1360 wined3d_bitmap_set(pool_vk->allocated, *idx);
1362 return true;
1365 void wined3d_query_pool_vk_mark_free(struct wined3d_context_vk *context_vk, struct wined3d_query_pool_vk *pool_vk,
1366 uint32_t start, uint32_t count)
1368 unsigned int idx, end = start + count;
1370 for (idx = start; idx < end; ++idx)
1371 wined3d_bitmap_clear(pool_vk->allocated, idx);
1373 if (list_empty(&pool_vk->entry))
1374 list_add_tail(pool_vk->free_list, &pool_vk->entry);
1377 void wined3d_query_pool_vk_cleanup(struct wined3d_query_pool_vk *pool_vk, struct wined3d_context_vk *context_vk)
1379 struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
1380 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1382 VK_CALL(vkDestroyQueryPool(device_vk->vk_device, pool_vk->vk_query_pool, NULL));
1383 if (pool_vk->vk_event)
1384 VK_CALL(vkDestroyEvent(device_vk->vk_device, pool_vk->vk_event, NULL));
1385 list_remove(&pool_vk->entry);
1386 list_remove(&pool_vk->completed_entry);
1389 bool wined3d_query_pool_vk_init(struct wined3d_query_pool_vk *pool_vk,
1390 struct wined3d_context_vk *context_vk, enum wined3d_query_type type, struct list *free_pools)
1392 struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
1393 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1394 VkQueryPoolCreateInfo pool_info;
1395 VkResult vr;
1397 list_init(&pool_vk->entry);
1398 list_init(&pool_vk->completed_entry);
1399 pool_vk->free_list = free_pools;
1401 pool_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1402 pool_info.pNext = NULL;
1403 pool_info.flags = 0;
1404 pool_info.queryCount = WINED3D_QUERY_POOL_SIZE;
1406 switch (type)
1408 case WINED3D_QUERY_TYPE_OCCLUSION:
1409 pool_info.queryType = VK_QUERY_TYPE_OCCLUSION;
1410 pool_info.pipelineStatistics = 0;
1411 break;
1413 case WINED3D_QUERY_TYPE_TIMESTAMP:
1414 pool_info.queryType = VK_QUERY_TYPE_TIMESTAMP;
1415 pool_info.pipelineStatistics = 0;
1416 break;
1418 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1419 pool_info.queryType = VK_QUERY_TYPE_PIPELINE_STATISTICS;
1420 pool_info.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT
1421 | VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT
1422 | VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT
1423 | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT
1424 | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT
1425 | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT
1426 | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT
1427 | VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT
1428 | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT
1429 | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT
1430 | VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT;
1431 break;
1433 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1434 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1435 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1436 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1437 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1438 pool_info.queryType = VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT;
1439 pool_info.pipelineStatistics = 0;
1440 break;
1442 default:
1443 FIXME("Unhandled query type %#x.\n", type);
1444 return false;
1447 if ((vr = VK_CALL(vkCreateQueryPool(device_vk->vk_device, &pool_info, NULL, &pool_vk->vk_query_pool))) < 0)
1449 ERR("Failed to create Vulkan query pool, vr %s.\n", wined3d_debug_vkresult(vr));
1450 return false;
1453 list_add_head(free_pools, &pool_vk->entry);
1455 return true;
1458 bool wined3d_query_vk_accumulate_data(struct wined3d_query_vk *query_vk,
1459 struct wined3d_device_vk *device_vk, const struct wined3d_query_pool_idx_vk *pool_idx)
1461 const struct wined3d_query_data_pipeline_statistics *ps_tmp;
1462 const struct wined3d_vk_info *vk_info = &device_vk->vk_info;
1463 struct wined3d_query_data_pipeline_statistics *ps_result;
1464 VkResult vr;
1465 union
1467 uint64_t occlusion;
1468 uint64_t timestamp;
1469 struct wined3d_query_data_pipeline_statistics pipeline_statistics;
1470 struct wined3d_query_data_so_statistics so_statistics;
1471 } tmp, *result;
1473 if (pool_idx->pool_vk->vk_event)
1475 /* Check if the pool's initial reset command executed. */
1476 vr = VK_CALL(vkGetEventStatus(device_vk->vk_device,
1477 pool_idx->pool_vk->vk_event));
1478 if (vr == VK_EVENT_RESET)
1479 return false;
1480 else if (vr != VK_EVENT_SET)
1482 ERR("Failed to get event status, vr %s\n", wined3d_debug_vkresult(vr));
1483 return false;
1487 if ((vr = VK_CALL(vkGetQueryPoolResults(device_vk->vk_device, pool_idx->pool_vk->vk_query_pool,
1488 pool_idx->idx, 1, sizeof(tmp), &tmp, sizeof(tmp), VK_QUERY_RESULT_64_BIT))) < 0)
1490 ERR("Failed to get query results, vr %s.\n", wined3d_debug_vkresult(vr));
1491 return false;
1494 if (vr == VK_NOT_READY)
1495 return false;
1497 result = (void *)query_vk->q.data;
1498 switch (query_vk->q.type)
1500 case WINED3D_QUERY_TYPE_OCCLUSION:
1501 result->occlusion += tmp.occlusion;
1502 break;
1504 case WINED3D_QUERY_TYPE_TIMESTAMP:
1505 result->timestamp = tmp.timestamp;
1506 break;
1508 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1509 ps_result = &result->pipeline_statistics;
1510 ps_tmp = &tmp.pipeline_statistics;
1511 ps_result->vertices_submitted += ps_tmp->vertices_submitted;
1512 ps_result->primitives_submitted += ps_tmp->primitives_submitted;
1513 ps_result->vs_invocations += ps_tmp->vs_invocations;
1514 ps_result->gs_invocations += ps_tmp->gs_invocations;
1515 ps_result->gs_primitives += ps_tmp->gs_primitives;
1516 ps_result->clipping_input_primitives += ps_tmp->clipping_input_primitives;
1517 ps_result->clipping_output_primitives += ps_tmp->clipping_output_primitives;
1518 ps_result->ps_invocations += ps_tmp->ps_invocations;
1519 ps_result->hs_invocations += ps_tmp->hs_invocations;
1520 ps_result->ds_invocations += ps_tmp->ds_invocations;
1521 ps_result->cs_invocations += ps_tmp->cs_invocations;
1522 break;
1524 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1525 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1526 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1527 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1528 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1529 result->so_statistics.primitives_written += tmp.so_statistics.primitives_written;
1530 result->so_statistics.primitives_generated += tmp.so_statistics.primitives_generated;
1531 break;
1533 default:
1534 FIXME("Unhandled query type %#x.\n", query_vk->q.type);
1535 return false;
1538 return true;
1541 static void wined3d_query_vk_begin(struct wined3d_query_vk *query_vk,
1542 struct wined3d_context_vk *context_vk, VkCommandBuffer vk_command_buffer)
1544 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1545 struct wined3d_query_pool_vk *pool_vk;
1546 size_t idx;
1548 pool_vk = query_vk->pool_idx.pool_vk;
1549 idx = query_vk->pool_idx.idx;
1551 if (query_vk->q.type >= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
1552 && query_vk->q.type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1553 VK_CALL(vkCmdBeginQueryIndexedEXT(vk_command_buffer, pool_vk->vk_query_pool, idx,
1554 query_vk->control_flags, query_vk->q.type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0));
1555 else
1556 VK_CALL(vkCmdBeginQuery(vk_command_buffer, pool_vk->vk_query_pool, idx, query_vk->control_flags));
1557 wined3d_context_vk_reference_query(context_vk, query_vk);
1560 static void wined3d_query_vk_end(struct wined3d_query_vk *query_vk,
1561 struct wined3d_context_vk *context_vk, VkCommandBuffer vk_command_buffer)
1563 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1564 struct wined3d_query_pool_vk *pool_vk;
1565 size_t idx;
1567 pool_vk = query_vk->pool_idx.pool_vk;
1568 idx = query_vk->pool_idx.idx;
1570 if (query_vk->q.type >= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
1571 && query_vk->q.type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1572 VK_CALL(vkCmdEndQueryIndexedEXT(vk_command_buffer, pool_vk->vk_query_pool,
1573 idx, query_vk->q.type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0));
1574 else
1575 VK_CALL(vkCmdEndQuery(vk_command_buffer, pool_vk->vk_query_pool, idx));
1578 void wined3d_query_vk_resume(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk)
1580 VkCommandBuffer vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer;
1582 wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
1583 query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE;
1586 void wined3d_query_vk_suspend(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk)
1588 VkCommandBuffer vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer;
1590 wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
1592 if (!wined3d_array_reserve((void **)&query_vk->pending, &query_vk->pending_size,
1593 query_vk->pending_count + 1, sizeof(*query_vk->pending)))
1595 ERR("Failed to allocate entry.\n");
1596 return;
1599 query_vk->pending[query_vk->pending_count++] = query_vk->pool_idx;
1600 query_vk->pool_idx.pool_vk = NULL;
1601 query_vk->flags &= ~WINED3D_QUERY_VK_FLAG_ACTIVE;
1604 static BOOL wined3d_query_vk_poll(struct wined3d_query *query, uint32_t flags)
1606 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1607 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1608 unsigned int i;
1610 memset((void *)query->data, 0, query->data_size);
1612 if (query_vk->pool_idx.pool_vk && !wined3d_query_vk_accumulate_data(query_vk, device_vk, &query_vk->pool_idx))
1613 goto unavailable;
1615 for (i = 0; i < query_vk->pending_count; ++i)
1617 if (!wined3d_query_vk_accumulate_data(query_vk, device_vk, &query_vk->pending[i]))
1618 goto unavailable;
1621 return TRUE;
1623 unavailable:
1624 if ((flags & WINED3DGETDATA_FLUSH) && !query->device->cs->queries_flushed)
1625 query->device->cs->c.ops->flush(&query->device->cs->c);
1627 return FALSE;
1630 static void wined3d_query_vk_remove_pending_queries(struct wined3d_context_vk *context_vk,
1631 struct wined3d_query_vk *query_vk)
1633 size_t i;
1635 for (i = 0; i < query_vk->pending_count; ++i)
1636 wined3d_query_pool_vk_mark_complete(query_vk->pending[i].pool_vk, query_vk->pending[i].idx, context_vk);
1638 query_vk->pending_count = 0;
1641 static BOOL wined3d_query_vk_issue(struct wined3d_query *query, uint32_t flags)
1643 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1644 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1645 struct wined3d_context_vk *context_vk;
1646 VkCommandBuffer vk_command_buffer;
1647 bool poll = false;
1649 TRACE("query %p, flags %#x.\n", query, flags);
1651 if (flags & WINED3DISSUE_BEGIN)
1653 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1655 if (query_vk->pending_count)
1656 wined3d_query_vk_remove_pending_queries(context_vk, query_vk);
1657 vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
1658 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED)
1660 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_ACTIVE)
1661 wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
1662 list_remove(&query_vk->entry);
1664 if (query_vk->pool_idx.pool_vk)
1665 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk,
1666 query_vk->pool_idx.idx, context_vk);
1668 if (!wined3d_context_vk_allocate_query(context_vk, query_vk->q.type, &query_vk->pool_idx))
1670 ERR("Failed to allocate new query.\n");
1671 return false;
1674 /* A query needs to either begin and end inside a single render pass
1675 * or begin and end outside of a render pass. Occlusion queries, if
1676 * issued outside of a render pass, are queued up and only begun when
1677 * a render pass is started, to avoid interrupting the render pass
1678 * when the query ends. */
1679 if (context_vk->vk_render_pass)
1681 wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
1682 list_add_head(&context_vk->render_pass_queries, &query_vk->entry);
1683 query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE | WINED3D_QUERY_VK_FLAG_RENDER_PASS;
1685 else if (query->type == WINED3D_QUERY_TYPE_OCCLUSION)
1687 list_add_head(&context_vk->render_pass_queries, &query_vk->entry);
1688 query_vk->flags |= WINED3D_QUERY_VK_FLAG_RENDER_PASS;
1690 else
1692 wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
1693 list_add_head(&context_vk->active_queries, &query_vk->entry);
1694 query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE;
1697 query_vk->flags |= WINED3D_QUERY_VK_FLAG_STARTED;
1698 context_release(&context_vk->c);
1700 if (flags & WINED3DISSUE_END && query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED)
1702 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1704 /* If the query was already ended because the command buffer was
1705 * flushed or the render pass ended, we don't need to end it here. */
1706 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_ACTIVE)
1708 vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
1709 if (!(query_vk->flags & WINED3D_QUERY_VK_FLAG_RENDER_PASS))
1710 wined3d_context_vk_end_current_render_pass(context_vk);
1711 wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
1713 else if (query_vk->pool_idx.pool_vk)
1715 /* It was queued, but never activated. */
1716 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk,
1717 query_vk->pool_idx.idx, context_vk);
1718 query_vk->pool_idx.pool_vk = NULL;
1720 list_remove(&query_vk->entry);
1721 query_vk->flags = 0;
1722 poll = true;
1724 context_release(&context_vk->c);
1727 return poll;
1730 static void wined3d_query_vk_destroy(struct wined3d_query *query)
1732 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1733 struct wined3d_context_vk *context_vk;
1735 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED)
1736 list_remove(&query_vk->entry);
1737 context_vk = wined3d_context_vk(context_acquire(query_vk->q.device, NULL, 0));
1738 wined3d_query_vk_remove_pending_queries(context_vk, query_vk);
1739 if (query_vk->pool_idx.pool_vk)
1740 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk, query_vk->pool_idx.idx, context_vk);
1741 if (query_vk->vk_event)
1742 wined3d_context_vk_destroy_vk_event(context_vk, query_vk->vk_event, query_vk->command_buffer_id);
1743 context_release(&context_vk->c);
1744 heap_free(query_vk->pending);
1745 heap_free(query_vk);
1748 static const struct wined3d_query_ops wined3d_query_vk_ops =
1750 .query_poll = wined3d_query_vk_poll,
1751 .query_issue = wined3d_query_vk_issue,
1752 .query_destroy = wined3d_query_vk_destroy,
1755 static BOOL wined3d_query_event_vk_poll(struct wined3d_query *query, uint32_t flags)
1757 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1758 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1759 const struct wined3d_vk_info *vk_info = &device_vk->vk_info;
1760 BOOL signalled;
1762 signalled = VK_CALL(vkGetEventStatus(device_vk->vk_device, query_vk->vk_event))
1763 == VK_EVENT_SET;
1764 if (!signalled && (flags & WINED3DGETDATA_FLUSH) && !query->device->cs->queries_flushed)
1765 query->device->cs->c.ops->flush(&query->device->cs->c);
1766 return *(BOOL *)query->data = signalled;
1769 static BOOL wined3d_query_event_vk_issue(struct wined3d_query *query, uint32_t flags)
1771 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1772 const struct wined3d_vk_info *vk_info = &device_vk->vk_info;
1773 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1774 struct wined3d_context_vk *context_vk;
1775 VkEventCreateInfo create_info;
1776 VkResult vr;
1778 TRACE("query %p, flags %#x.\n", query, flags);
1780 if (flags & WINED3DISSUE_END)
1782 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1783 wined3d_context_vk_end_current_render_pass(context_vk);
1785 if (query_vk->vk_event)
1787 if (query_vk->command_buffer_id > context_vk->completed_command_buffer_id)
1789 /* Cannot reuse this event, as it may still get signalled by previous usage. */
1790 /* Throw it away and create a new one, but if that happens a lot we may want to pool instead. */
1791 wined3d_context_vk_destroy_vk_event(context_vk, query_vk->vk_event, query_vk->command_buffer_id);
1792 query_vk->vk_event = VK_NULL_HANDLE;
1794 else
1796 VK_CALL(vkResetEvent(device_vk->vk_device, query_vk->vk_event));
1800 if (!query_vk->vk_event)
1802 create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
1803 create_info.pNext = NULL;
1804 create_info.flags = 0;
1806 vr = VK_CALL(vkCreateEvent(device_vk->vk_device, &create_info, NULL, &query_vk->vk_event));
1807 if (vr != VK_SUCCESS)
1809 ERR("Failed to create Vulkan event, vr %s\n", wined3d_debug_vkresult(vr));
1810 context_release(&context_vk->c);
1811 return FALSE;
1815 wined3d_context_vk_reference_query(context_vk, query_vk);
1816 VK_CALL(vkCmdSetEvent(wined3d_context_vk_get_command_buffer(context_vk), query_vk->vk_event,
1817 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT));
1818 context_release(&context_vk->c);
1820 return TRUE;
1823 return FALSE;
1826 static const struct wined3d_query_ops wined3d_query_event_vk_ops =
1828 .query_poll = wined3d_query_event_vk_poll,
1829 .query_issue = wined3d_query_event_vk_issue,
1830 .query_destroy = wined3d_query_vk_destroy,
1833 static BOOL wined3d_query_timestamp_vk_issue(struct wined3d_query *query, uint32_t flags)
1835 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1836 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1837 const struct wined3d_vk_info *vk_info;
1838 struct wined3d_context_vk *context_vk;
1839 VkCommandBuffer command_buffer;
1841 TRACE("query %p, flags %#x.\n", query, flags);
1843 if (flags & WINED3DISSUE_BEGIN)
1844 TRACE("Ignoring WINED3DISSUE_BEGIN.\n");
1846 if (flags & WINED3DISSUE_END)
1848 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1849 vk_info = context_vk->vk_info;
1851 command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
1852 if (query_vk->pool_idx.pool_vk)
1853 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk, query_vk->pool_idx.idx, context_vk);
1854 if (!wined3d_context_vk_allocate_query(context_vk, query_vk->q.type, &query_vk->pool_idx))
1856 ERR("Failed to allocate new query.\n");
1857 return FALSE;
1859 VK_CALL(vkCmdWriteTimestamp(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1860 query_vk->pool_idx.pool_vk->vk_query_pool, query_vk->pool_idx.idx));
1861 wined3d_context_vk_reference_query(context_vk, query_vk);
1863 context_release(&context_vk->c);
1865 return TRUE;
1868 return FALSE;
1871 static const struct wined3d_query_ops wined3d_query_timestamp_vk_ops =
1873 .query_poll = wined3d_query_vk_poll,
1874 .query_issue = wined3d_query_timestamp_vk_issue,
1875 .query_destroy = wined3d_query_vk_destroy,
1878 static const struct wined3d_query_ops wined3d_query_timestamp_disjoint_vk_ops =
1880 .query_poll = wined3d_timestamp_disjoint_query_ops_poll,
1881 .query_issue = wined3d_timestamp_disjoint_query_ops_issue,
1882 .query_destroy = wined3d_query_vk_destroy,
1885 HRESULT wined3d_query_vk_create(struct wined3d_device *device, enum wined3d_query_type type,
1886 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1888 struct wined3d_query_data_timestamp_disjoint *disjoint_data;
1889 const struct wined3d_query_ops *ops = &wined3d_query_vk_ops;
1890 struct wined3d_query_vk *query_vk;
1891 unsigned int data_size;
1892 void *data;
1894 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1895 device, type, parent, parent_ops, query);
1897 switch (type)
1899 case WINED3D_QUERY_TYPE_EVENT:
1900 ops = &wined3d_query_event_vk_ops;
1901 data_size = sizeof(BOOL);
1902 break;
1904 case WINED3D_QUERY_TYPE_OCCLUSION:
1905 data_size = sizeof(uint64_t);
1906 break;
1908 case WINED3D_QUERY_TYPE_TIMESTAMP:
1909 if (!wined3d_device_vk(device)->timestamp_bits)
1911 WARN("Timestamp queries not supported.\n");
1912 return WINED3DERR_NOTAVAILABLE;
1914 ops = &wined3d_query_timestamp_vk_ops;
1915 data_size = sizeof(uint64_t);
1916 break;
1918 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1919 if (!wined3d_device_vk(device)->timestamp_bits)
1921 WARN("Timestamp queries not supported.\n");
1922 return WINED3DERR_NOTAVAILABLE;
1924 ops = &wined3d_query_timestamp_disjoint_vk_ops;
1925 data_size = sizeof(struct wined3d_query_data_timestamp_disjoint);
1926 break;
1928 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1929 data_size = sizeof(struct wined3d_query_data_pipeline_statistics);
1930 break;
1932 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1933 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1934 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1935 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1936 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1937 if (!wined3d_adapter_vk(device->adapter)->vk_info.supported[WINED3D_VK_EXT_TRANSFORM_FEEDBACK])
1939 WARN("Stream output queries not supported.\n");
1940 return WINED3DERR_NOTAVAILABLE;
1942 data_size = sizeof(struct wined3d_query_data_so_statistics);
1943 break;
1945 default:
1946 FIXME("Unhandled query type %#x.\n", type);
1947 return WINED3DERR_NOTAVAILABLE;
1950 if (!(query_vk = heap_alloc_zero(sizeof(*query_vk) + data_size)))
1951 return E_OUTOFMEMORY;
1952 data = query_vk + 1;
1954 wined3d_query_init(&query_vk->q, device, type, data, data_size, ops, parent, parent_ops);
1955 query_vk->q.poll_in_cs = false;
1957 switch (type)
1959 case WINED3D_QUERY_TYPE_OCCLUSION:
1960 query_vk->control_flags = VK_QUERY_CONTROL_PRECISE_BIT;
1961 break;
1963 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1964 disjoint_data = data;
1965 disjoint_data->frequency = 1000000000 / wined3d_adapter_vk(device->adapter)->device_limits.timestampPeriod;
1966 disjoint_data->disjoint = FALSE;
1967 break;
1969 default:
1970 break;
1973 TRACE("Created query %p.\n", query_vk);
1974 *query = &query_vk->q;
1976 return WINED3D_OK;
1979 HRESULT CDECL wined3d_query_create(struct wined3d_device *device, enum wined3d_query_type type,
1980 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1982 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1983 device, type, parent, parent_ops, query);
1985 return device->adapter->adapter_ops->adapter_create_query(device, type, parent, parent_ops, query);