hidclass.sys: Pass sizeof(packet) as input for IOCTL_HID_SET_OUTPUT_REPORT.
[wine.git] / dlls / wined3d / query.c
blobc84fcba7d7d2a802d93e0e4d95345a32a2101683
1 /*
2 * Copyright 2005 Oliver Stieber
3 * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
4 * Copyright 2009-2010 Henri Verbeet for CodeWeavers.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
23 #include "wine/port.h"
24 #include "wined3d_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
28 static void wined3d_query_buffer_invalidate(struct wined3d_query *query)
30 /* map[0] != map[1]: exact values do not have any significance. */
31 query->map_ptr[0] = 0;
32 query->map_ptr[1] = ~(UINT64)0;
35 static BOOL wined3d_query_buffer_is_valid(struct wined3d_query *query)
37 return query->map_ptr[0] == query->map_ptr[1];
40 static void wined3d_query_create_buffer_object(struct wined3d_context_gl *context_gl, struct wined3d_query *query)
42 const GLuint map_flags = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
43 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
44 GLuint buffer_object;
46 GL_EXTCALL(glGenBuffers(1, &buffer_object));
47 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, buffer_object));
48 GL_EXTCALL(glBufferStorage(GL_QUERY_BUFFER, sizeof(query->map_ptr[0]) * 2, NULL, map_flags));
49 query->map_ptr = GL_EXTCALL(glMapBufferRange(GL_QUERY_BUFFER, 0, sizeof(query->map_ptr[0]) * 2, map_flags));
50 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, 0));
51 checkGLcall("query buffer object creation");
53 wined3d_query_buffer_invalidate(query);
54 query->buffer_object = buffer_object;
57 void wined3d_query_gl_destroy_buffer_object(struct wined3d_context_gl *context_gl, struct wined3d_query *query)
59 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
61 GL_EXTCALL(glDeleteBuffers(1, &query->buffer_object));
62 checkGLcall("query buffer object destruction");
64 query->buffer_object = 0;
65 query->map_ptr = NULL;
68 /* From ARB_occlusion_query: "Querying the state for a given occlusion query
69 * forces that occlusion query to complete within a finite amount of time."
70 * In practice, that means drivers flush when retrieving
71 * GL_QUERY_RESULT_AVAILABLE, which can be undesirable when applications use a
72 * significant number of queries. Using a persistently mapped query buffer
73 * object allows us to avoid these implicit flushes. An additional benefit is
74 * that it allows us to poll the query status from the application-thread
75 * instead of from the csmt-thread. */
76 static BOOL wined3d_query_buffer_queue_result(struct wined3d_context_gl *context_gl,
77 struct wined3d_query *query, GLuint id)
79 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
80 GLsync tmp_sync;
82 if (!gl_info->supported[ARB_QUERY_BUFFER_OBJECT] || !gl_info->supported[ARB_BUFFER_STORAGE])
83 return FALSE;
84 /* Don't use query buffers without CSMT, mainly for simplicity. */
85 if (!context_gl->c.device->cs->thread)
86 return FALSE;
88 if (query->buffer_object)
90 /* If there's still a query result in-flight for the existing buffer
91 * object (i.e., the query was restarted before we received its
92 * result), we can't reuse the existing buffer object. */
93 if (wined3d_query_buffer_is_valid(query))
94 wined3d_query_buffer_invalidate(query);
95 else
96 wined3d_query_gl_destroy_buffer_object(context_gl, query);
99 if (!query->buffer_object)
100 wined3d_query_create_buffer_object(context_gl, query);
102 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, query->buffer_object));
103 /* Read the same value twice. We know we have the result if map_ptr[0] == map_ptr[1]. */
104 GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, (void *)0));
105 GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, (void *)sizeof(query->map_ptr[0])));
106 GL_EXTCALL(glBindBuffer(GL_QUERY_BUFFER, 0));
107 checkGLcall("queue query result");
109 /* ARB_buffer_storage requires the client to call FenceSync with
110 * SYNC_GPU_COMMANDS_COMPLETE after the server does a write. This behavior
111 * is not enforced by Mesa.
113 tmp_sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
114 GL_EXTCALL(glDeleteSync(tmp_sync));
115 checkGLcall("query buffer sync");
117 return TRUE;
120 static UINT64 get_query_result64(GLuint id, const struct wined3d_gl_info *gl_info)
122 if (gl_info->supported[ARB_TIMER_QUERY])
124 GLuint64 result;
125 GL_EXTCALL(glGetQueryObjectui64v(id, GL_QUERY_RESULT, &result));
126 return result;
128 else
130 GLuint result;
131 GL_EXTCALL(glGetQueryObjectuiv(id, GL_QUERY_RESULT, &result));
132 return result;
136 static void wined3d_query_init(struct wined3d_query *query, struct wined3d_device *device,
137 enum wined3d_query_type type, const void *data, DWORD data_size,
138 const struct wined3d_query_ops *query_ops, void *parent, const struct wined3d_parent_ops *parent_ops)
140 query->ref = 1;
141 query->parent = parent;
142 query->parent_ops = parent_ops;
143 query->device = device;
144 query->state = QUERY_CREATED;
145 query->type = type;
146 query->data = data;
147 query->data_size = data_size;
148 query->query_ops = query_ops;
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 static BOOL wined3d_fence_supported(const struct wined3d_gl_info *gl_info)
180 return gl_info->supported[ARB_SYNC] || gl_info->supported[NV_FENCE] || gl_info->supported[APPLE_FENCE];
183 enum wined3d_fence_result wined3d_fence_test(const struct wined3d_fence *fence,
184 struct wined3d_device *device, DWORD flags)
186 const struct wined3d_gl_info *gl_info;
187 struct wined3d_context_gl *context_gl;
188 enum wined3d_fence_result ret;
189 BOOL fence_result;
191 TRACE("fence %p, device %p, flags %#x.\n", fence, device, flags);
193 if (!fence->context_gl)
195 TRACE("Fence not issued.\n");
196 return WINED3D_FENCE_NOT_STARTED;
199 if (!(context_gl = wined3d_context_gl_reacquire(fence->context_gl)))
201 if (!fence->context_gl->gl_info->supported[ARB_SYNC])
203 WARN("Fence tested from wrong thread.\n");
204 return WINED3D_FENCE_WRONG_THREAD;
206 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
208 gl_info = context_gl->gl_info;
210 if (gl_info->supported[ARB_SYNC])
212 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
213 (flags & WINED3DGETDATA_FLUSH) ? GL_SYNC_FLUSH_COMMANDS_BIT : 0, 0));
214 checkGLcall("glClientWaitSync");
216 switch (gl_ret)
218 case GL_ALREADY_SIGNALED:
219 case GL_CONDITION_SATISFIED:
220 ret = WINED3D_FENCE_OK;
221 break;
223 case GL_TIMEOUT_EXPIRED:
224 ret = WINED3D_FENCE_WAITING;
225 break;
227 case GL_WAIT_FAILED:
228 default:
229 ERR("glClientWaitSync returned %#x.\n", gl_ret);
230 ret = WINED3D_FENCE_ERROR;
233 else if (gl_info->supported[APPLE_FENCE])
235 fence_result = GL_EXTCALL(glTestFenceAPPLE(fence->object.id));
236 checkGLcall("glTestFenceAPPLE");
237 if (fence_result)
238 ret = WINED3D_FENCE_OK;
239 else
240 ret = WINED3D_FENCE_WAITING;
242 else if (gl_info->supported[NV_FENCE])
244 fence_result = GL_EXTCALL(glTestFenceNV(fence->object.id));
245 checkGLcall("glTestFenceNV");
246 if (fence_result)
247 ret = WINED3D_FENCE_OK;
248 else
249 ret = WINED3D_FENCE_WAITING;
251 else
253 ERR("Fence created despite lack of GL support.\n");
254 ret = WINED3D_FENCE_ERROR;
257 context_release(&context_gl->c);
258 return ret;
261 enum wined3d_fence_result wined3d_fence_wait(const struct wined3d_fence *fence,
262 struct wined3d_device *device)
264 const struct wined3d_gl_info *gl_info;
265 struct wined3d_context_gl *context_gl;
266 enum wined3d_fence_result ret;
268 TRACE("fence %p, device %p.\n", fence, device);
270 if (!fence->context_gl)
272 TRACE("Fence not issued.\n");
273 return WINED3D_FENCE_NOT_STARTED;
275 gl_info = fence->context_gl->gl_info;
277 if (!(context_gl = wined3d_context_gl_reacquire(fence->context_gl)))
279 /* A glFinish does not reliably wait for draws in other contexts. The caller has
280 * to find its own way to cope with the thread switch
282 if (!gl_info->supported[ARB_SYNC])
284 WARN("Fence finished from wrong thread.\n");
285 return WINED3D_FENCE_WRONG_THREAD;
287 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
289 gl_info = context_gl->gl_info;
291 if (gl_info->supported[ARB_SYNC])
293 /* Timeouts near 0xffffffffffffffff may immediately return GL_TIMEOUT_EXPIRED,
294 * possibly because macOS internally adds some slop to the timer. To avoid this,
295 * we use a large number that isn't near the point of overflow (macOS 10.12.5).
297 GLenum gl_ret = GL_EXTCALL(glClientWaitSync(fence->object.sync,
298 GL_SYNC_FLUSH_COMMANDS_BIT, ~(GLuint64)0 >> 1));
299 checkGLcall("glClientWaitSync");
301 switch (gl_ret)
303 case GL_ALREADY_SIGNALED:
304 case GL_CONDITION_SATISFIED:
305 ret = WINED3D_FENCE_OK;
306 break;
308 /* We don't expect a timeout for a ~292 year wait */
309 default:
310 ERR("glClientWaitSync returned %#x.\n", gl_ret);
311 ret = WINED3D_FENCE_ERROR;
314 else if (gl_info->supported[APPLE_FENCE])
316 GL_EXTCALL(glFinishFenceAPPLE(fence->object.id));
317 checkGLcall("glFinishFenceAPPLE");
318 ret = WINED3D_FENCE_OK;
320 else if (gl_info->supported[NV_FENCE])
322 GL_EXTCALL(glFinishFenceNV(fence->object.id));
323 checkGLcall("glFinishFenceNV");
324 ret = WINED3D_FENCE_OK;
326 else
328 ERR("Fence created without GL support.\n");
329 ret = WINED3D_FENCE_ERROR;
332 context_release(&context_gl->c);
333 return ret;
336 void wined3d_fence_issue(struct wined3d_fence *fence, struct wined3d_device *device)
338 struct wined3d_context_gl *context_gl = NULL;
339 const struct wined3d_gl_info *gl_info;
341 if (fence->context_gl && !(context_gl = wined3d_context_gl_reacquire(fence->context_gl))
342 && !fence->context_gl->gl_info->supported[ARB_SYNC])
343 wined3d_context_gl_free_fence(fence);
344 if (!context_gl)
345 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
346 gl_info = context_gl->gl_info;
347 if (!fence->context_gl)
348 wined3d_context_gl_alloc_fence(context_gl, fence);
350 if (gl_info->supported[ARB_SYNC])
352 if (fence->object.sync)
353 GL_EXTCALL(glDeleteSync(fence->object.sync));
354 checkGLcall("glDeleteSync");
355 fence->object.sync = GL_EXTCALL(glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0));
356 checkGLcall("glFenceSync");
358 else if (gl_info->supported[APPLE_FENCE])
360 GL_EXTCALL(glSetFenceAPPLE(fence->object.id));
361 checkGLcall("glSetFenceAPPLE");
363 else if (gl_info->supported[NV_FENCE])
365 GL_EXTCALL(glSetFenceNV(fence->object.id, GL_ALL_COMPLETED_NV));
366 checkGLcall("glSetFenceNV");
369 context_release(&context_gl->c);
372 static void wined3d_fence_free(struct wined3d_fence *fence)
374 if (fence->context_gl)
375 wined3d_context_gl_free_fence(fence);
378 void wined3d_fence_destroy(struct wined3d_fence *fence)
380 wined3d_fence_free(fence);
381 heap_free(fence);
384 static HRESULT wined3d_fence_init(struct wined3d_fence *fence, const struct wined3d_gl_info *gl_info)
386 if (!wined3d_fence_supported(gl_info))
388 WARN("Fences not supported.\n");
389 return WINED3DERR_NOTAVAILABLE;
392 return WINED3D_OK;
395 HRESULT wined3d_fence_create(struct wined3d_device *device, struct wined3d_fence **fence)
397 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
398 struct wined3d_fence *object;
399 HRESULT hr;
401 TRACE("device %p, fence %p.\n", device, fence);
403 if (!(object = heap_alloc_zero(sizeof(*object))))
404 return E_OUTOFMEMORY;
406 if (FAILED(hr = wined3d_fence_init(object, gl_info)))
408 heap_free(object);
409 return hr;
412 TRACE("Created fence %p.\n", object);
413 *fence = object;
415 return WINED3D_OK;
418 ULONG CDECL wined3d_query_incref(struct wined3d_query *query)
420 ULONG refcount = InterlockedIncrement(&query->ref);
422 TRACE("%p increasing refcount to %u.\n", query, refcount);
424 return refcount;
427 static void wined3d_query_destroy_object(void *object)
429 struct wined3d_query *query = object;
431 TRACE("query %p.\n", query);
433 if (!list_empty(&query->poll_list_entry))
434 list_remove(&query->poll_list_entry);
437 ULONG CDECL wined3d_query_decref(struct wined3d_query *query)
439 ULONG refcount = InterlockedDecrement(&query->ref);
441 TRACE("%p decreasing refcount to %u.\n", query, refcount);
443 if (!refcount)
445 struct wined3d_device *device = query->device;
447 query->parent_ops->wined3d_object_destroyed(query->parent);
448 wined3d_cs_destroy_object(device->cs, wined3d_query_destroy_object, query);
449 device->adapter->adapter_ops->adapter_destroy_query(query);
452 return refcount;
455 HRESULT CDECL wined3d_query_get_data(struct wined3d_query *query,
456 void *data, UINT data_size, DWORD flags)
458 TRACE("query %p, data %p, data_size %u, flags %#x.\n",
459 query, data, data_size, flags);
461 if (query->state == QUERY_BUILDING)
463 WARN("Query is building, returning S_FALSE.\n");
464 return S_FALSE;
467 if (query->state == QUERY_CREATED)
469 WARN("Query wasn't started yet.\n");
470 return WINED3DERR_INVALIDCALL;
473 if (query->device->cs->thread)
475 if (query->counter_main != query->counter_retrieved
476 || (query->buffer_object && !wined3d_query_buffer_is_valid(query)))
478 if (flags & WINED3DGETDATA_FLUSH && !query->device->cs->queries_flushed)
479 query->device->cs->c.ops->flush(&query->device->cs->c);
480 return S_FALSE;
482 if (query->buffer_object)
483 query->data = query->map_ptr;
485 else if (!query->query_ops->query_poll(query, flags))
487 return S_FALSE;
490 if (data)
491 memcpy(data, query->data, min(data_size, query->data_size));
493 return S_OK;
496 UINT CDECL wined3d_query_get_data_size(const struct wined3d_query *query)
498 TRACE("query %p.\n", query);
500 return query->data_size;
503 HRESULT CDECL wined3d_query_issue(struct wined3d_query *query, DWORD flags)
505 TRACE("query %p, flags %#x.\n", query, flags);
507 wined3d_device_context_issue_query(&query->device->cs->c, query, flags);
509 return WINED3D_OK;
512 static BOOL wined3d_occlusion_query_ops_poll(struct wined3d_query *query, DWORD flags)
514 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
515 const struct wined3d_gl_info *gl_info;
516 struct wined3d_context_gl *context_gl;
517 GLuint available;
519 TRACE("query %p, flags %#x.\n", query, flags);
521 if (!(context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
523 FIXME("%p Wrong thread, returning 1.\n", query);
524 oq->samples = 1;
525 return TRUE;
527 gl_info = context_gl->gl_info;
529 GL_EXTCALL(glGetQueryObjectuiv(oq->id, GL_QUERY_RESULT_AVAILABLE, &available));
530 TRACE("Available %#x.\n", available);
532 if (available)
534 oq->samples = get_query_result64(oq->id, gl_info);
535 TRACE("Returning 0x%s samples.\n", wine_dbgstr_longlong(oq->samples));
538 checkGLcall("poll occlusion query");
539 context_release(&context_gl->c);
541 return available;
544 static BOOL wined3d_event_query_ops_poll(struct wined3d_query *query, DWORD flags)
546 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
547 enum wined3d_fence_result ret;
549 TRACE("query %p, flags %#x.\n", query, flags);
551 ret = wined3d_fence_test(&event_query->fence, query->device, flags);
552 switch (ret)
554 case WINED3D_FENCE_OK:
555 case WINED3D_FENCE_NOT_STARTED:
556 return event_query->signalled = TRUE;
558 case WINED3D_FENCE_WAITING:
559 return event_query->signalled = FALSE;
561 case WINED3D_FENCE_WRONG_THREAD:
562 FIXME("(%p) Wrong thread, reporting GPU idle.\n", query);
563 return event_query->signalled = TRUE;
565 case WINED3D_FENCE_ERROR:
566 ERR("The GL event query failed.\n");
567 return event_query->signalled = TRUE;
569 default:
570 ERR("Unexpected wined3d_event_query_test result %#x.\n", ret);
571 return event_query->signalled = TRUE;
575 void * CDECL wined3d_query_get_parent(const struct wined3d_query *query)
577 TRACE("query %p.\n", query);
579 return query->parent;
582 enum wined3d_query_type CDECL wined3d_query_get_type(const struct wined3d_query *query)
584 TRACE("query %p.\n", query);
586 return query->type;
589 static BOOL wined3d_event_query_ops_issue(struct wined3d_query *query, DWORD flags)
591 TRACE("query %p, flags %#x.\n", query, flags);
593 if (flags & WINED3DISSUE_END)
595 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
597 wined3d_fence_issue(&event_query->fence, query->device);
598 return TRUE;
600 else if (flags & WINED3DISSUE_BEGIN)
602 /* Started implicitly at query creation. */
603 ERR("Event query issued with START flag - what to do?\n");
606 return FALSE;
609 static BOOL wined3d_occlusion_query_ops_issue(struct wined3d_query *query, DWORD flags)
611 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
612 struct wined3d_device *device = query->device;
613 const struct wined3d_gl_info *gl_info;
614 struct wined3d_context_gl *context_gl;
615 BOOL poll = FALSE;
617 TRACE("query %p, flags %#x.\n", query, flags);
619 /* This is allowed according to MSDN and our tests. Reset the query and
620 * restart. */
621 if (flags & WINED3DISSUE_BEGIN)
623 if (oq->started)
625 if ((context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
627 gl_info = context_gl->gl_info;
628 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
629 checkGLcall("glEndQuery()");
631 else
633 FIXME("Wrong thread, can't restart query.\n");
634 wined3d_context_gl_free_occlusion_query(oq);
635 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
636 wined3d_context_gl_alloc_occlusion_query(context_gl, oq);
639 else
641 if (oq->context_gl)
642 wined3d_context_gl_free_occlusion_query(oq);
643 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
644 wined3d_context_gl_alloc_occlusion_query(context_gl, oq);
646 gl_info = context_gl->gl_info;
648 GL_EXTCALL(glBeginQuery(GL_SAMPLES_PASSED, oq->id));
649 checkGLcall("glBeginQuery()");
651 context_release(&context_gl->c);
652 oq->started = TRUE;
654 if (flags & WINED3DISSUE_END)
656 /* MSDN says END on a non-building occlusion query returns an error,
657 * but our tests show that it returns OK. But OpenGL doesn't like it,
658 * so avoid generating an error. */
659 if (oq->started)
661 if ((context_gl = wined3d_context_gl_reacquire(oq->context_gl)))
663 gl_info = context_gl->gl_info;
664 GL_EXTCALL(glEndQuery(GL_SAMPLES_PASSED));
665 checkGLcall("glEndQuery()");
666 wined3d_query_buffer_queue_result(context_gl, query, oq->id);
668 context_release(&context_gl->c);
669 poll = TRUE;
671 else
673 FIXME("Wrong thread, can't end query.\n");
676 oq->started = FALSE;
679 return poll;
682 static BOOL wined3d_timestamp_query_ops_poll(struct wined3d_query *query, DWORD flags)
684 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
685 const struct wined3d_gl_info *gl_info;
686 struct wined3d_context_gl *context_gl;
687 GLuint64 timestamp;
688 GLuint available;
690 TRACE("query %p, flags %#x.\n", query, flags);
692 if (!(context_gl = wined3d_context_gl_reacquire(tq->context_gl)))
694 FIXME("%p Wrong thread, returning 1.\n", query);
695 tq->timestamp = 1;
696 return TRUE;
698 gl_info = context_gl->gl_info;
700 GL_EXTCALL(glGetQueryObjectuiv(tq->id, GL_QUERY_RESULT_AVAILABLE, &available));
701 checkGLcall("glGetQueryObjectuiv(GL_QUERY_RESULT_AVAILABLE)");
702 TRACE("available %#x.\n", available);
704 if (available)
706 GL_EXTCALL(glGetQueryObjectui64v(tq->id, GL_QUERY_RESULT, &timestamp));
707 checkGLcall("glGetQueryObjectui64v(GL_QUERY_RESULT)");
708 TRACE("Returning timestamp %s.\n", wine_dbgstr_longlong(timestamp));
709 tq->timestamp = timestamp;
712 context_release(&context_gl->c);
714 return available;
717 static BOOL wined3d_timestamp_query_ops_issue(struct wined3d_query *query, DWORD flags)
719 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
720 const struct wined3d_gl_info *gl_info;
721 struct wined3d_context_gl *context_gl;
723 TRACE("query %p, flags %#x.\n", query, flags);
725 if (flags & WINED3DISSUE_BEGIN)
727 WARN("Ignoring WINED3DISSUE_BEGIN with a TIMESTAMP query.\n");
729 if (flags & WINED3DISSUE_END)
731 if (tq->context_gl)
732 wined3d_context_gl_free_timestamp_query(tq);
733 context_gl = wined3d_context_gl(context_acquire(query->device, NULL, 0));
734 gl_info = context_gl->gl_info;
735 wined3d_context_gl_alloc_timestamp_query(context_gl, tq);
736 GL_EXTCALL(glQueryCounter(tq->id, GL_TIMESTAMP));
737 checkGLcall("glQueryCounter()");
738 context_release(&context_gl->c);
740 return TRUE;
743 return FALSE;
746 static BOOL wined3d_timestamp_disjoint_query_ops_poll(struct wined3d_query *query, DWORD flags)
748 TRACE("query %p, flags %#x.\n", query, flags);
750 return TRUE;
753 static BOOL wined3d_timestamp_disjoint_query_ops_issue(struct wined3d_query *query, DWORD flags)
755 TRACE("query %p, flags %#x.\n", query, flags);
757 return FALSE;
760 static BOOL wined3d_so_statistics_query_ops_poll(struct wined3d_query *query, DWORD flags)
762 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
763 GLuint written_available, generated_available;
764 const struct wined3d_gl_info *gl_info;
765 struct wined3d_context_gl *context_gl;
767 TRACE("query %p, flags %#x.\n", query, flags);
769 if (!(context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
771 FIXME("%p Wrong thread, returning 0 primitives.\n", query);
772 memset(&pq->statistics, 0, sizeof(pq->statistics));
773 return TRUE;
775 gl_info = context_gl->gl_info;
777 GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.written,
778 GL_QUERY_RESULT_AVAILABLE, &written_available));
779 GL_EXTCALL(glGetQueryObjectuiv(pq->u.query.generated,
780 GL_QUERY_RESULT_AVAILABLE, &generated_available));
781 TRACE("Available %#x, %#x.\n", written_available, generated_available);
783 if (written_available && generated_available)
785 pq->statistics.primitives_written = get_query_result64(pq->u.query.written, gl_info);
786 pq->statistics.primitives_generated = get_query_result64(pq->u.query.generated, gl_info);
787 TRACE("Returning %s, %s primitives.\n",
788 wine_dbgstr_longlong(pq->statistics.primitives_written),
789 wine_dbgstr_longlong(pq->statistics.primitives_generated));
792 checkGLcall("poll SO statistics query");
793 context_release(&context_gl->c);
795 return written_available && generated_available;
798 static void wined3d_so_statistics_query_end(struct wined3d_so_statistics_query *query,
799 struct wined3d_context_gl *context_gl)
801 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
803 if (gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
805 GL_EXTCALL(glEndQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query->stream_idx));
806 GL_EXTCALL(glEndQueryIndexed(GL_PRIMITIVES_GENERATED, query->stream_idx));
808 else
810 GL_EXTCALL(glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN));
811 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_GENERATED));
813 checkGLcall("end query");
816 static BOOL wined3d_so_statistics_query_ops_issue(struct wined3d_query *query, DWORD flags)
818 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
819 struct wined3d_device *device = query->device;
820 const struct wined3d_gl_info *gl_info;
821 struct wined3d_context_gl *context_gl;
822 BOOL poll = FALSE;
824 TRACE("query %p, flags %#x.\n", query, flags);
826 if (flags & WINED3DISSUE_BEGIN)
828 if (pq->started)
830 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
832 wined3d_so_statistics_query_end(pq, context_gl);
834 else
836 FIXME("Wrong thread, can't restart query.\n");
837 wined3d_context_gl_free_so_statistics_query(pq);
838 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
839 wined3d_context_gl_alloc_so_statistics_query(context_gl, pq);
842 else
844 if (pq->context_gl)
845 wined3d_context_gl_free_so_statistics_query(pq);
846 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
847 wined3d_context_gl_alloc_so_statistics_query(context_gl, pq);
849 gl_info = context_gl->gl_info;
851 if (gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
853 GL_EXTCALL(glBeginQueryIndexed(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
854 pq->stream_idx, pq->u.query.written));
855 GL_EXTCALL(glBeginQueryIndexed(GL_PRIMITIVES_GENERATED,
856 pq->stream_idx, pq->u.query.generated));
858 else
860 GL_EXTCALL(glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,
861 pq->u.query.written));
862 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_GENERATED,
863 pq->u.query.generated));
865 checkGLcall("begin query");
867 context_release(&context_gl->c);
868 pq->started = TRUE;
870 if (flags & WINED3DISSUE_END)
872 if (pq->started)
874 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
876 wined3d_so_statistics_query_end(pq, context_gl);
878 context_release(&context_gl->c);
879 poll = TRUE;
881 else
883 FIXME("Wrong thread, can't end query.\n");
886 pq->started = FALSE;
889 return poll;
892 static BOOL wined3d_pipeline_query_ops_poll(struct wined3d_query *query, DWORD flags)
894 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
895 const struct wined3d_gl_info *gl_info;
896 struct wined3d_context_gl *context_gl;
897 GLuint available;
898 int i;
900 TRACE("query %p, flags %#x.\n", query, flags);
902 if (!(context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
904 FIXME("%p Wrong thread.\n", query);
905 memset(&pq->statistics, 0, sizeof(pq->statistics));
906 return TRUE;
908 gl_info = context_gl->gl_info;
910 for (i = 0; i < ARRAY_SIZE(pq->u.id); ++i)
912 GL_EXTCALL(glGetQueryObjectuiv(pq->u.id[i], GL_QUERY_RESULT_AVAILABLE, &available));
913 if (!available)
914 break;
917 if (available)
919 pq->statistics.vertices_submitted = get_query_result64(pq->u.query.vertices, gl_info);
920 pq->statistics.primitives_submitted = get_query_result64(pq->u.query.primitives, gl_info);
921 pq->statistics.vs_invocations = get_query_result64(pq->u.query.vertex_shader, gl_info);
922 pq->statistics.hs_invocations = get_query_result64(pq->u.query.tess_control_shader, gl_info);
923 pq->statistics.ds_invocations = get_query_result64(pq->u.query.tess_eval_shader, gl_info);
924 pq->statistics.gs_invocations = get_query_result64(pq->u.query.geometry_shader, gl_info);
925 pq->statistics.gs_primitives = get_query_result64(pq->u.query.geometry_primitives, gl_info);
926 pq->statistics.ps_invocations = get_query_result64(pq->u.query.fragment_shader, gl_info);
927 pq->statistics.cs_invocations = get_query_result64(pq->u.query.compute_shader, gl_info);
928 pq->statistics.clipping_input_primitives = get_query_result64(pq->u.query.clipping_input, gl_info);
929 pq->statistics.clipping_output_primitives = get_query_result64(pq->u.query.clipping_output, gl_info);
932 checkGLcall("poll pipeline statistics query");
933 context_release(&context_gl->c);
934 return available;
937 static void wined3d_pipeline_statistics_query_end(struct wined3d_pipeline_statistics_query *query,
938 struct wined3d_context_gl *context_gl)
940 const struct wined3d_gl_info *gl_info = context_gl->gl_info;
942 GL_EXTCALL(glEndQuery(GL_VERTICES_SUBMITTED_ARB));
943 GL_EXTCALL(glEndQuery(GL_PRIMITIVES_SUBMITTED_ARB));
944 GL_EXTCALL(glEndQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB));
945 GL_EXTCALL(glEndQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB));
946 GL_EXTCALL(glEndQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB));
947 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_INVOCATIONS));
948 GL_EXTCALL(glEndQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB));
949 GL_EXTCALL(glEndQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB));
950 GL_EXTCALL(glEndQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB));
951 GL_EXTCALL(glEndQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB));
952 GL_EXTCALL(glEndQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB));
953 checkGLcall("end query");
956 static BOOL wined3d_pipeline_query_ops_issue(struct wined3d_query *query, DWORD flags)
958 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
959 struct wined3d_device *device = query->device;
960 const struct wined3d_gl_info *gl_info;
961 struct wined3d_context_gl *context_gl;
962 BOOL poll = FALSE;
964 TRACE("query %p, flags %#x.\n", query, flags);
966 if (flags & WINED3DISSUE_BEGIN)
968 if (pq->started)
970 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
972 wined3d_pipeline_statistics_query_end(pq, context_gl);
974 else
976 FIXME("Wrong thread, can't restart query.\n");
977 wined3d_context_gl_free_pipeline_statistics_query(pq);
978 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
979 wined3d_context_gl_alloc_pipeline_statistics_query(context_gl, pq);
982 else
984 if (pq->context_gl)
985 wined3d_context_gl_free_pipeline_statistics_query(pq);
986 context_gl = wined3d_context_gl(context_acquire(device, NULL, 0));
987 wined3d_context_gl_alloc_pipeline_statistics_query(context_gl, pq);
989 gl_info = context_gl->gl_info;
991 GL_EXTCALL(glBeginQuery(GL_VERTICES_SUBMITTED_ARB, pq->u.query.vertices));
992 GL_EXTCALL(glBeginQuery(GL_PRIMITIVES_SUBMITTED_ARB, pq->u.query.primitives));
993 GL_EXTCALL(glBeginQuery(GL_VERTEX_SHADER_INVOCATIONS_ARB, pq->u.query.vertex_shader));
994 GL_EXTCALL(glBeginQuery(GL_TESS_CONTROL_SHADER_PATCHES_ARB, pq->u.query.tess_control_shader));
995 GL_EXTCALL(glBeginQuery(GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB, pq->u.query.tess_eval_shader));
996 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_INVOCATIONS, pq->u.query.geometry_shader));
997 GL_EXTCALL(glBeginQuery(GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB, pq->u.query.geometry_primitives));
998 GL_EXTCALL(glBeginQuery(GL_FRAGMENT_SHADER_INVOCATIONS_ARB, pq->u.query.fragment_shader));
999 GL_EXTCALL(glBeginQuery(GL_COMPUTE_SHADER_INVOCATIONS_ARB, pq->u.query.compute_shader));
1000 GL_EXTCALL(glBeginQuery(GL_CLIPPING_INPUT_PRIMITIVES_ARB, pq->u.query.clipping_input));
1001 GL_EXTCALL(glBeginQuery(GL_CLIPPING_OUTPUT_PRIMITIVES_ARB, pq->u.query.clipping_output));
1002 checkGLcall("begin query");
1004 context_release(&context_gl->c);
1005 pq->started = TRUE;
1007 if (flags & WINED3DISSUE_END)
1009 if (pq->started)
1011 if ((context_gl = wined3d_context_gl_reacquire(pq->context_gl)))
1013 wined3d_pipeline_statistics_query_end(pq, context_gl);
1014 context_release(&context_gl->c);
1015 poll = TRUE;
1017 else
1019 FIXME("Wrong thread, can't end query.\n");
1022 pq->started = FALSE;
1025 return poll;
1028 static void wined3d_event_query_ops_destroy(struct wined3d_query *query)
1030 struct wined3d_event_query *event_query = wined3d_event_query_from_query(query);
1032 wined3d_fence_free(&event_query->fence);
1033 heap_free(event_query);
1036 static const struct wined3d_query_ops event_query_ops =
1038 wined3d_event_query_ops_poll,
1039 wined3d_event_query_ops_issue,
1040 wined3d_event_query_ops_destroy,
1043 static HRESULT wined3d_event_query_create(struct wined3d_device *device,
1044 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1045 struct wined3d_query **query)
1047 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1048 struct wined3d_event_query *object;
1049 HRESULT hr;
1051 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1052 device, type, parent, parent_ops, query);
1054 if (!(object = heap_alloc_zero(sizeof(*object))))
1055 return E_OUTOFMEMORY;
1057 if (FAILED(hr = wined3d_fence_init(&object->fence, gl_info)))
1059 WARN("Event queries not supported.\n");
1060 heap_free(object);
1061 return hr;
1064 wined3d_query_init(&object->query, device, type, &object->signalled,
1065 sizeof(object->signalled), &event_query_ops, parent, parent_ops);
1067 TRACE("Created query %p.\n", object);
1068 *query = &object->query;
1070 return WINED3D_OK;
1073 static void wined3d_occlusion_query_ops_destroy(struct wined3d_query *query)
1075 struct wined3d_occlusion_query *oq = wined3d_occlusion_query_from_query(query);
1077 if (oq->context_gl)
1078 wined3d_context_gl_free_occlusion_query(oq);
1079 heap_free(oq);
1082 static const struct wined3d_query_ops occlusion_query_ops =
1084 wined3d_occlusion_query_ops_poll,
1085 wined3d_occlusion_query_ops_issue,
1086 wined3d_occlusion_query_ops_destroy,
1089 static HRESULT wined3d_occlusion_query_create(struct wined3d_device *device,
1090 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1091 struct wined3d_query **query)
1093 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1094 struct wined3d_occlusion_query *object;
1096 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1097 device, type, parent, parent_ops, query);
1099 if (!gl_info->supported[ARB_OCCLUSION_QUERY])
1101 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY.\n");
1102 return WINED3DERR_NOTAVAILABLE;
1105 if (!(object = heap_alloc_zero(sizeof(*object))))
1106 return E_OUTOFMEMORY;
1108 wined3d_query_init(&object->query, device, type, &object->samples,
1109 sizeof(object->samples), &occlusion_query_ops, parent, parent_ops);
1111 TRACE("Created query %p.\n", object);
1112 *query = &object->query;
1114 return WINED3D_OK;
1117 static void wined3d_timestamp_query_ops_destroy(struct wined3d_query *query)
1119 struct wined3d_timestamp_query *tq = wined3d_timestamp_query_from_query(query);
1121 if (tq->context_gl)
1122 wined3d_context_gl_free_timestamp_query(tq);
1123 heap_free(tq);
1126 static const struct wined3d_query_ops timestamp_query_ops =
1128 wined3d_timestamp_query_ops_poll,
1129 wined3d_timestamp_query_ops_issue,
1130 wined3d_timestamp_query_ops_destroy,
1133 static HRESULT wined3d_timestamp_query_create(struct wined3d_device *device,
1134 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1135 struct wined3d_query **query)
1137 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1138 struct wined3d_timestamp_query *object;
1140 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1141 device, type, parent, parent_ops, query);
1143 if (!gl_info->supported[ARB_TIMER_QUERY])
1145 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1146 return WINED3DERR_NOTAVAILABLE;
1149 if (!(object = heap_alloc_zero(sizeof(*object))))
1150 return E_OUTOFMEMORY;
1152 wined3d_query_init(&object->query, device, type, &object->timestamp,
1153 sizeof(object->timestamp), &timestamp_query_ops, parent, parent_ops);
1155 TRACE("Created query %p.\n", object);
1156 *query = &object->query;
1158 return WINED3D_OK;
1161 static void wined3d_timestamp_disjoint_query_ops_destroy(struct wined3d_query *query)
1163 heap_free(query);
1166 static const struct wined3d_query_ops timestamp_disjoint_query_ops =
1168 wined3d_timestamp_disjoint_query_ops_poll,
1169 wined3d_timestamp_disjoint_query_ops_issue,
1170 wined3d_timestamp_disjoint_query_ops_destroy,
1173 static HRESULT wined3d_timestamp_disjoint_query_create(struct wined3d_device *device,
1174 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1175 struct wined3d_query **query)
1177 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1178 struct wined3d_query *object;
1180 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1181 device, type, parent, parent_ops, query);
1183 if (!gl_info->supported[ARB_TIMER_QUERY])
1185 WARN("Unsupported in local OpenGL implementation: ARB_TIMER_QUERY.\n");
1186 return WINED3DERR_NOTAVAILABLE;
1189 if (!(object = heap_alloc_zero(sizeof(*object))))
1190 return E_OUTOFMEMORY;
1192 if (type == WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT)
1194 static const struct wined3d_query_data_timestamp_disjoint disjoint_data = {1000 * 1000 * 1000, FALSE};
1196 wined3d_query_init(object, device, type, &disjoint_data,
1197 sizeof(disjoint_data), &timestamp_disjoint_query_ops, parent, parent_ops);
1199 else
1201 static const UINT64 freq = 1000 * 1000 * 1000;
1203 wined3d_query_init(object, device, type, &freq,
1204 sizeof(freq), &timestamp_disjoint_query_ops, parent, parent_ops);
1207 TRACE("Created query %p.\n", object);
1208 *query = object;
1210 return WINED3D_OK;
1213 static void wined3d_so_statistics_query_ops_destroy(struct wined3d_query *query)
1215 struct wined3d_so_statistics_query *pq = wined3d_so_statistics_query_from_query(query);
1217 if (pq->context_gl)
1218 wined3d_context_gl_free_so_statistics_query(pq);
1219 heap_free(pq);
1222 static const struct wined3d_query_ops so_statistics_query_ops =
1224 wined3d_so_statistics_query_ops_poll,
1225 wined3d_so_statistics_query_ops_issue,
1226 wined3d_so_statistics_query_ops_destroy,
1229 static HRESULT wined3d_so_statistics_query_create(struct wined3d_device *device,
1230 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1231 struct wined3d_query **query)
1233 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1234 struct wined3d_so_statistics_query *object;
1235 unsigned int stream_idx;
1237 if (WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0 <= type && type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1238 stream_idx = type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0;
1239 else if (type == WINED3D_QUERY_TYPE_SO_STATISTICS)
1240 stream_idx = 0;
1241 else
1242 return WINED3DERR_NOTAVAILABLE;
1244 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1245 device, type, parent, parent_ops, query);
1247 if (!gl_info->supported[WINED3D_GL_PRIMITIVE_QUERY])
1249 WARN("OpenGL implementation does not support primitive queries.\n");
1250 return WINED3DERR_NOTAVAILABLE;
1252 if (stream_idx && !gl_info->supported[ARB_TRANSFORM_FEEDBACK3])
1254 WARN("OpenGL implementation does not support indexed queries.\n");
1255 return WINED3DERR_NOTAVAILABLE;
1258 if (!(object = heap_alloc_zero(sizeof(*object))))
1259 return E_OUTOFMEMORY;
1261 wined3d_query_init(&object->query, device, type, &object->statistics,
1262 sizeof(object->statistics), &so_statistics_query_ops, parent, parent_ops);
1263 object->stream_idx = stream_idx;
1265 TRACE("Created query %p.\n", object);
1266 *query = &object->query;
1268 return WINED3D_OK;
1271 static void wined3d_pipeline_query_ops_destroy(struct wined3d_query *query)
1273 struct wined3d_pipeline_statistics_query *pq = wined3d_pipeline_statistics_query_from_query(query);
1274 if (pq->context_gl)
1275 wined3d_context_gl_free_pipeline_statistics_query(pq);
1276 heap_free(pq);
1279 static const struct wined3d_query_ops pipeline_query_ops =
1281 wined3d_pipeline_query_ops_poll,
1282 wined3d_pipeline_query_ops_issue,
1283 wined3d_pipeline_query_ops_destroy,
1286 static HRESULT wined3d_pipeline_query_create(struct wined3d_device *device,
1287 enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops,
1288 struct wined3d_query **query)
1290 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1291 struct wined3d_pipeline_statistics_query *object;
1293 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1294 device, type, parent, parent_ops, query);
1296 if (!gl_info->supported[ARB_PIPELINE_STATISTICS_QUERY])
1298 WARN("OpenGL implementation does not support pipeline statistics queries.\n");
1299 return WINED3DERR_NOTAVAILABLE;
1302 if (!(object = heap_alloc_zero(sizeof(*object))))
1303 return E_OUTOFMEMORY;
1305 wined3d_query_init(&object->query, device, type, &object->statistics,
1306 sizeof(object->statistics), &pipeline_query_ops, parent, parent_ops);
1308 TRACE("Created query %p.\n", object);
1309 *query = &object->query;
1311 return WINED3D_OK;
1314 HRESULT wined3d_query_gl_create(struct wined3d_device *device, enum wined3d_query_type type,
1315 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1317 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1318 device, type, parent, parent_ops, query);
1320 switch (type)
1322 case WINED3D_QUERY_TYPE_EVENT:
1323 return wined3d_event_query_create(device, type, parent, parent_ops, query);
1325 case WINED3D_QUERY_TYPE_OCCLUSION:
1326 return wined3d_occlusion_query_create(device, type, parent, parent_ops, query);
1328 case WINED3D_QUERY_TYPE_TIMESTAMP:
1329 return wined3d_timestamp_query_create(device, type, parent, parent_ops, query);
1331 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1332 case WINED3D_QUERY_TYPE_TIMESTAMP_FREQ:
1333 return wined3d_timestamp_disjoint_query_create(device, type, parent, parent_ops, query);
1335 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1336 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1337 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1338 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1339 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1340 return wined3d_so_statistics_query_create(device, type, parent, parent_ops, query);
1342 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1343 return wined3d_pipeline_query_create(device, type, parent, parent_ops, query);
1345 default:
1346 FIXME("Unhandled query type %#x.\n", type);
1347 return WINED3DERR_NOTAVAILABLE;
1351 static void wined3d_query_pool_vk_mark_complete(struct wined3d_query_pool_vk *pool_vk, size_t idx,
1352 struct wined3d_context_vk *context_vk)
1354 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1356 if (vk_info->supported[WINED3D_VK_EXT_HOST_QUERY_RESET])
1358 VK_CALL(vkResetQueryPoolEXT(wined3d_device_vk(context_vk->c.device)->vk_device,
1359 pool_vk->vk_query_pool, idx, 1));
1361 wined3d_bitmap_clear(pool_vk->allocated, idx);
1362 if (list_empty(&pool_vk->entry))
1363 list_add_tail(pool_vk->free_list, &pool_vk->entry);
1365 else
1367 /* Don't reset completed queries right away, as vkCmdResetQueryPool() needs to happen
1368 * outside of a render pass. Queue the query to be reset in wined3d_query_pool_vk_reset()
1369 * instead, which is called when the render pass ends. */
1370 wined3d_bitmap_set(pool_vk->completed, idx);
1371 if (list_empty(&pool_vk->completed_entry))
1372 list_add_tail(&context_vk->completed_query_pools, &pool_vk->completed_entry);
1376 bool wined3d_query_pool_vk_allocate_query(struct wined3d_query_pool_vk *pool_vk, size_t *idx)
1378 if ((*idx = wined3d_bitmap_ffz(pool_vk->allocated, WINED3D_QUERY_POOL_SIZE, 0)) > WINED3D_QUERY_POOL_SIZE)
1379 return false;
1380 wined3d_bitmap_set(pool_vk->allocated, *idx);
1382 return true;
1385 void wined3d_query_pool_vk_cleanup(struct wined3d_query_pool_vk *pool_vk, struct wined3d_context_vk *context_vk)
1387 struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
1388 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1390 VK_CALL(vkDestroyQueryPool(device_vk->vk_device, pool_vk->vk_query_pool, NULL));
1391 list_remove(&pool_vk->entry);
1392 list_remove(&pool_vk->completed_entry);
1395 void wined3d_query_pool_vk_reset(struct wined3d_query_pool_vk *pool_vk, struct wined3d_context_vk *context_vk,
1396 VkCommandBuffer vk_command_buffer)
1398 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1399 unsigned int start = 0, idx;
1400 struct wined3d_range range;
1402 for (;;)
1404 if (!wined3d_bitmap_get_range(pool_vk->completed, WINED3D_QUERY_POOL_SIZE, start, &range))
1405 break;
1407 VK_CALL(vkCmdResetQueryPool(vk_command_buffer, pool_vk->vk_query_pool, range.offset, range.size));
1408 start = range.offset + range.size;
1409 for (idx = range.offset; idx < start; ++idx)
1410 wined3d_bitmap_clear(pool_vk->allocated, idx);
1412 memset(pool_vk->completed, 0, sizeof(pool_vk->completed));
1413 if (list_empty(&pool_vk->entry))
1414 list_add_tail(pool_vk->free_list, &pool_vk->entry);
1417 bool wined3d_query_pool_vk_init(struct wined3d_query_pool_vk *pool_vk,
1418 struct wined3d_context_vk *context_vk, enum wined3d_query_type type, struct list *free_pools)
1420 struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
1421 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1422 VkQueryPoolCreateInfo pool_info;
1423 VkResult vr;
1425 list_init(&pool_vk->entry);
1426 list_init(&pool_vk->completed_entry);
1427 pool_vk->free_list = free_pools;
1429 pool_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1430 pool_info.pNext = NULL;
1431 pool_info.flags = 0;
1432 pool_info.queryCount = WINED3D_QUERY_POOL_SIZE;
1434 switch (type)
1436 case WINED3D_QUERY_TYPE_OCCLUSION:
1437 pool_info.queryType = VK_QUERY_TYPE_OCCLUSION;
1438 pool_info.pipelineStatistics = 0;
1439 break;
1441 case WINED3D_QUERY_TYPE_TIMESTAMP:
1442 pool_info.queryType = VK_QUERY_TYPE_TIMESTAMP;
1443 pool_info.pipelineStatistics = 0;
1444 break;
1446 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1447 pool_info.queryType = VK_QUERY_TYPE_PIPELINE_STATISTICS;
1448 pool_info.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT
1449 | VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT
1450 | VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT
1451 | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT
1452 | VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT
1453 | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT
1454 | VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT
1455 | VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT
1456 | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT
1457 | VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT
1458 | VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT;
1459 break;
1461 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1462 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1463 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1464 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1465 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1466 pool_info.queryType = VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT;
1467 pool_info.pipelineStatistics = 0;
1468 break;
1470 default:
1471 FIXME("Unhandled query type %#x.\n", type);
1472 return false;
1475 if ((vr = VK_CALL(vkCreateQueryPool(device_vk->vk_device, &pool_info, NULL, &pool_vk->vk_query_pool))) < 0)
1477 ERR("Failed to create Vulkan query pool, vr %s.\n", wined3d_debug_vkresult(vr));
1478 return false;
1481 list_add_head(free_pools, &pool_vk->entry);
1483 return true;
1486 bool wined3d_query_vk_accumulate_data(struct wined3d_query_vk *query_vk,
1487 struct wined3d_context_vk *context_vk, const struct wined3d_query_pool_idx_vk *pool_idx)
1489 struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
1490 const struct wined3d_query_data_pipeline_statistics *ps_tmp;
1491 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1492 struct wined3d_query_data_pipeline_statistics *ps_result;
1493 VkResult vr;
1494 union
1496 uint64_t occlusion;
1497 uint64_t timestamp;
1498 struct wined3d_query_data_pipeline_statistics pipeline_statistics;
1499 struct wined3d_query_data_so_statistics so_statistics;
1500 } tmp, *result;
1502 if ((vr = VK_CALL(vkGetQueryPoolResults(device_vk->vk_device, pool_idx->pool_vk->vk_query_pool,
1503 pool_idx->idx, 1, sizeof(tmp), &tmp, sizeof(tmp), VK_QUERY_RESULT_64_BIT))) < 0)
1505 ERR("Failed to get query results, vr %s.\n", wined3d_debug_vkresult(vr));
1506 return false;
1509 if (vr == VK_NOT_READY)
1510 return false;
1512 wined3d_query_pool_vk_mark_complete(pool_idx->pool_vk, pool_idx->idx, context_vk);
1514 result = (void *)query_vk->q.data;
1515 switch (query_vk->q.type)
1517 case WINED3D_QUERY_TYPE_OCCLUSION:
1518 result->occlusion += tmp.occlusion;
1519 break;
1521 case WINED3D_QUERY_TYPE_TIMESTAMP:
1522 result->timestamp = tmp.timestamp;
1523 break;
1525 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1526 ps_result = &result->pipeline_statistics;
1527 ps_tmp = &tmp.pipeline_statistics;
1528 ps_result->vertices_submitted += ps_tmp->vertices_submitted;
1529 ps_result->primitives_submitted += ps_tmp->primitives_submitted;
1530 ps_result->vs_invocations += ps_tmp->vs_invocations;
1531 ps_result->gs_invocations += ps_tmp->gs_invocations;
1532 ps_result->gs_primitives += ps_tmp->gs_primitives;
1533 ps_result->clipping_input_primitives += ps_tmp->clipping_input_primitives;
1534 ps_result->clipping_output_primitives += ps_tmp->clipping_output_primitives;
1535 ps_result->ps_invocations += ps_tmp->ps_invocations;
1536 ps_result->hs_invocations += ps_tmp->hs_invocations;
1537 ps_result->ds_invocations += ps_tmp->ds_invocations;
1538 ps_result->cs_invocations += ps_tmp->cs_invocations;
1539 break;
1541 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1542 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1543 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1544 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1545 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1546 result->so_statistics.primitives_written += tmp.so_statistics.primitives_written;
1547 result->so_statistics.primitives_generated += tmp.so_statistics.primitives_generated;
1548 break;
1550 default:
1551 FIXME("Unhandled query type %#x.\n", query_vk->q.type);
1552 return false;
1555 return true;
1558 static void wined3d_query_vk_begin(struct wined3d_query_vk *query_vk,
1559 struct wined3d_context_vk *context_vk, VkCommandBuffer vk_command_buffer)
1561 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1562 struct wined3d_query_pool_vk *pool_vk;
1563 size_t idx;
1565 pool_vk = query_vk->pool_idx.pool_vk;
1566 idx = query_vk->pool_idx.idx;
1568 if (query_vk->q.type >= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
1569 && query_vk->q.type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1570 VK_CALL(vkCmdBeginQueryIndexedEXT(vk_command_buffer, pool_vk->vk_query_pool, idx,
1571 query_vk->control_flags, query_vk->q.type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0));
1572 else
1573 VK_CALL(vkCmdBeginQuery(vk_command_buffer, pool_vk->vk_query_pool, idx, query_vk->control_flags));
1574 wined3d_context_vk_reference_query(context_vk, query_vk);
1577 static void wined3d_query_vk_end(struct wined3d_query_vk *query_vk,
1578 struct wined3d_context_vk *context_vk, VkCommandBuffer vk_command_buffer)
1580 const struct wined3d_vk_info *vk_info = context_vk->vk_info;
1581 struct wined3d_query_pool_vk *pool_vk;
1582 size_t idx;
1584 pool_vk = query_vk->pool_idx.pool_vk;
1585 idx = query_vk->pool_idx.idx;
1587 if (query_vk->q.type >= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1
1588 && query_vk->q.type <= WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3)
1589 VK_CALL(vkCmdEndQueryIndexedEXT(vk_command_buffer, pool_vk->vk_query_pool,
1590 idx, query_vk->q.type - WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0));
1591 else
1592 VK_CALL(vkCmdEndQuery(vk_command_buffer, pool_vk->vk_query_pool, idx));
1595 void wined3d_query_vk_resume(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk)
1597 VkCommandBuffer vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer;
1599 wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
1600 query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE;
1603 void wined3d_query_vk_suspend(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk)
1605 VkCommandBuffer vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer;
1607 wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
1608 wined3d_context_vk_add_pending_query(context_vk, query_vk);
1609 query_vk->pool_idx.pool_vk = NULL;
1610 query_vk->flags &= ~WINED3D_QUERY_VK_FLAG_ACTIVE;
1613 static BOOL wined3d_query_vk_poll(struct wined3d_query *query, uint32_t flags)
1615 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1616 struct wined3d_context_vk *context_vk;
1618 context_vk = wined3d_context_vk(context_acquire(query->device, NULL, 0));
1620 if (flags & WINED3DGETDATA_FLUSH)
1621 wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, 0, NULL);
1622 if (query_vk->command_buffer_id == context_vk->current_command_buffer.id)
1623 goto unavailable;
1625 if (query_vk->command_buffer_id > context_vk->completed_command_buffer_id)
1626 wined3d_context_vk_poll_command_buffers(context_vk);
1627 if (query_vk->command_buffer_id > context_vk->completed_command_buffer_id)
1628 goto unavailable;
1630 if (query_vk->pending_count)
1631 wined3d_context_vk_accumulate_pending_queries(context_vk);
1632 if (query_vk->pending_count)
1633 goto unavailable;
1635 /* If the query was suspended, and then ended before it was resumed,
1636 * there's no data to accumulate here. */
1637 if (query_vk->pool_idx.pool_vk && !wined3d_query_vk_accumulate_data(query_vk, context_vk, &query_vk->pool_idx))
1638 goto unavailable;
1640 query_vk->pool_idx.pool_vk = NULL;
1641 context_release(&context_vk->c);
1643 return TRUE;
1645 unavailable:
1646 context_release(&context_vk->c);
1647 return FALSE;
1650 static BOOL wined3d_query_vk_issue(struct wined3d_query *query, uint32_t flags)
1652 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1653 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1654 struct wined3d_context_vk *context_vk;
1655 VkCommandBuffer vk_command_buffer;
1656 bool poll = false;
1658 TRACE("query %p, flags %#x.\n", query, flags);
1660 if (flags & WINED3DISSUE_BEGIN)
1662 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1664 list_remove(&query_vk->entry);
1665 if (query_vk->pending_count)
1666 wined3d_context_vk_remove_pending_queries(context_vk, query_vk);
1667 memset((void *)query->data, 0, query->data_size);
1668 vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
1669 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED)
1671 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_ACTIVE)
1672 wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
1673 list_remove(&query_vk->entry);
1675 if (query_vk->pool_idx.pool_vk)
1676 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk,
1677 query_vk->pool_idx.idx, context_vk);
1679 if (!wined3d_context_vk_allocate_query(context_vk, query_vk->q.type, &query_vk->pool_idx))
1681 ERR("Failed to allocate new query.\n");
1682 return false;
1685 /* A query need to either begin and end inside a single render pass,
1686 * or begin and end ouside of a render pass. Occlusion queries, if issued
1687 * ouside of a render pass, are queued up and only begun when a render
1688 * pass is started, to avoid interrupting it when the query ends. */
1689 if (context_vk->vk_render_pass)
1691 wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
1692 list_add_head(&context_vk->render_pass_queries, &query_vk->entry);
1693 query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE | WINED3D_QUERY_VK_FLAG_RENDER_PASS;
1695 else if (query->type == WINED3D_QUERY_TYPE_OCCLUSION)
1697 list_add_head(&context_vk->render_pass_queries, &query_vk->entry);
1698 query_vk->flags |= WINED3D_QUERY_VK_FLAG_RENDER_PASS;
1700 else
1702 wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
1703 list_add_head(&context_vk->active_queries, &query_vk->entry);
1704 query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE;
1707 query_vk->flags |= WINED3D_QUERY_VK_FLAG_STARTED;
1708 context_release(&context_vk->c);
1710 if (flags & WINED3DISSUE_END && query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED)
1712 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1714 /* If the query was already ended because the command buffer was
1715 * flushed or the render pass ended, we don't need to end it here. */
1716 if (query_vk->flags & WINED3D_QUERY_VK_FLAG_ACTIVE)
1718 vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
1719 if (!(query_vk->flags & WINED3D_QUERY_VK_FLAG_RENDER_PASS))
1720 wined3d_context_vk_end_current_render_pass(context_vk);
1721 wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
1723 else if (query_vk->pool_idx.pool_vk)
1725 /* It was queued, but never activated. */
1726 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk,
1727 query_vk->pool_idx.idx, context_vk);
1728 query_vk->pool_idx.pool_vk = NULL;
1730 list_remove(&query_vk->entry);
1731 query_vk->flags = 0;
1732 poll = true;
1734 context_release(&context_vk->c);
1737 return poll;
1740 static void wined3d_query_vk_destroy(struct wined3d_query *query)
1742 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1743 struct wined3d_context_vk *context_vk;
1745 list_remove(&query_vk->entry);
1746 if (query_vk->pending_count)
1748 context_vk = wined3d_context_vk(context_acquire(query_vk->q.device, NULL, 0));
1749 wined3d_context_vk_remove_pending_queries(context_vk, query_vk);
1750 context_release(&context_vk->c);
1752 heap_free(query_vk);
1755 static const struct wined3d_query_ops wined3d_query_vk_ops =
1757 .query_poll = wined3d_query_vk_poll,
1758 .query_issue = wined3d_query_vk_issue,
1759 .query_destroy = wined3d_query_vk_destroy,
1762 static BOOL wined3d_query_event_vk_poll(struct wined3d_query *query, uint32_t flags)
1764 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1765 struct wined3d_context_vk *context_vk;
1766 BOOL *signalled;
1768 context_vk = wined3d_context_vk(context_acquire(query->device, NULL, 0));
1770 signalled = (BOOL *)query->data;
1771 if (flags & WINED3DGETDATA_FLUSH)
1772 wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, 0, NULL);
1773 if (query_vk->command_buffer_id == context_vk->current_command_buffer.id)
1775 context_release(&context_vk->c);
1776 return *signalled = FALSE;
1779 if (query_vk->command_buffer_id > context_vk->completed_command_buffer_id)
1780 wined3d_context_vk_poll_command_buffers(context_vk);
1781 *signalled = context_vk->completed_command_buffer_id >= query_vk->command_buffer_id;
1783 context_release(&context_vk->c);
1785 return *signalled;
1788 static BOOL wined3d_query_event_vk_issue(struct wined3d_query *query, uint32_t flags)
1790 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1791 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1792 struct wined3d_context_vk *context_vk;
1794 TRACE("query %p, flags %#x.\n", query, flags);
1796 if (flags & WINED3DISSUE_END)
1798 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1799 wined3d_context_vk_reference_query(context_vk, query_vk);
1800 /* Because we don't actually submit any commands to the command buffer
1801 * for event queries, the context's current command buffer may still
1802 * be empty, and we should wait on the preceding command buffer
1803 * instead. That's not merely an optimisation; if the command buffer
1804 * referenced by the query is still empty by the time the application
1805 * waits for it, that wait will never complete. */
1806 if (!context_vk->current_command_buffer.vk_command_buffer)
1807 --query_vk->command_buffer_id;
1808 context_release(&context_vk->c);
1810 return TRUE;
1813 return FALSE;
1816 static const struct wined3d_query_ops wined3d_query_event_vk_ops =
1818 .query_poll = wined3d_query_event_vk_poll,
1819 .query_issue = wined3d_query_event_vk_issue,
1820 .query_destroy = wined3d_query_vk_destroy,
1823 static BOOL wined3d_query_timestamp_vk_issue(struct wined3d_query *query, uint32_t flags)
1825 struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device);
1826 struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
1827 const struct wined3d_vk_info *vk_info;
1828 struct wined3d_context_vk *context_vk;
1829 VkCommandBuffer command_buffer;
1831 TRACE("query %p, flags %#x.\n", query, flags);
1833 if (flags & WINED3DISSUE_BEGIN)
1834 TRACE("Ignoring WINED3DISSUE_BEGIN.\n");
1836 if (flags & WINED3DISSUE_END)
1838 context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
1839 vk_info = context_vk->vk_info;
1841 command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
1842 if (query_vk->pool_idx.pool_vk)
1843 wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk, query_vk->pool_idx.idx, context_vk);
1844 if (!wined3d_context_vk_allocate_query(context_vk, query_vk->q.type, &query_vk->pool_idx))
1846 ERR("Failed to allocate new query.\n");
1847 return FALSE;
1849 VK_CALL(vkCmdWriteTimestamp(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
1850 query_vk->pool_idx.pool_vk->vk_query_pool, query_vk->pool_idx.idx));
1851 wined3d_context_vk_reference_query(context_vk, query_vk);
1853 context_release(&context_vk->c);
1855 return TRUE;
1858 return FALSE;
1861 static const struct wined3d_query_ops wined3d_query_timestamp_vk_ops =
1863 .query_poll = wined3d_query_vk_poll,
1864 .query_issue = wined3d_query_timestamp_vk_issue,
1865 .query_destroy = wined3d_query_vk_destroy,
1868 static const struct wined3d_query_ops wined3d_query_timestamp_disjoint_vk_ops =
1870 .query_poll = wined3d_timestamp_disjoint_query_ops_poll,
1871 .query_issue = wined3d_timestamp_disjoint_query_ops_issue,
1872 .query_destroy = wined3d_query_vk_destroy,
1875 HRESULT wined3d_query_vk_create(struct wined3d_device *device, enum wined3d_query_type type,
1876 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1878 struct wined3d_query_data_timestamp_disjoint *disjoint_data;
1879 const struct wined3d_query_ops *ops = &wined3d_query_vk_ops;
1880 struct wined3d_query_vk *query_vk;
1881 unsigned int data_size;
1882 void *data;
1884 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1885 device, type, parent, parent_ops, query);
1887 switch (type)
1889 case WINED3D_QUERY_TYPE_EVENT:
1890 ops = &wined3d_query_event_vk_ops;
1891 data_size = sizeof(BOOL);
1892 break;
1894 case WINED3D_QUERY_TYPE_OCCLUSION:
1895 data_size = sizeof(uint64_t);
1896 break;
1898 case WINED3D_QUERY_TYPE_TIMESTAMP:
1899 if (!wined3d_device_vk(device)->timestamp_bits)
1901 WARN("Timestamp queries not supported.\n");
1902 return WINED3DERR_NOTAVAILABLE;
1904 ops = &wined3d_query_timestamp_vk_ops;
1905 data_size = sizeof(uint64_t);
1906 break;
1908 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1909 if (!wined3d_device_vk(device)->timestamp_bits)
1911 WARN("Timestamp queries not supported.\n");
1912 return WINED3DERR_NOTAVAILABLE;
1914 ops = &wined3d_query_timestamp_disjoint_vk_ops;
1915 data_size = sizeof(struct wined3d_query_data_timestamp_disjoint);
1916 break;
1918 case WINED3D_QUERY_TYPE_PIPELINE_STATISTICS:
1919 data_size = sizeof(struct wined3d_query_data_pipeline_statistics);
1920 break;
1922 case WINED3D_QUERY_TYPE_SO_STATISTICS:
1923 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM0:
1924 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM1:
1925 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM2:
1926 case WINED3D_QUERY_TYPE_SO_STATISTICS_STREAM3:
1927 if (!wined3d_adapter_vk(device->adapter)->vk_info.supported[WINED3D_VK_EXT_TRANSFORM_FEEDBACK])
1929 WARN("Stream output queries not supported.\n");
1930 return WINED3DERR_NOTAVAILABLE;
1932 data_size = sizeof(struct wined3d_query_data_so_statistics);
1933 break;
1935 default:
1936 FIXME("Unhandled query type %#x.\n", type);
1937 return WINED3DERR_NOTAVAILABLE;
1940 if (!(query_vk = heap_alloc_zero(sizeof(*query_vk) + data_size)))
1941 return E_OUTOFMEMORY;
1942 data = query_vk + 1;
1944 wined3d_query_init(&query_vk->q, device, type, data, data_size, ops, parent, parent_ops);
1945 list_init(&query_vk->entry);
1947 switch (type)
1949 case WINED3D_QUERY_TYPE_OCCLUSION:
1950 query_vk->control_flags = VK_QUERY_CONTROL_PRECISE_BIT;
1951 break;
1953 case WINED3D_QUERY_TYPE_TIMESTAMP_DISJOINT:
1954 disjoint_data = data;
1955 disjoint_data->frequency = 1000000000 / wined3d_adapter_vk(device->adapter)->device_limits.timestampPeriod;
1956 disjoint_data->disjoint = FALSE;
1957 break;
1959 default:
1960 break;
1963 TRACE("Created query %p.\n", query_vk);
1964 *query = &query_vk->q;
1966 return WINED3D_OK;
1969 HRESULT CDECL wined3d_query_create(struct wined3d_device *device, enum wined3d_query_type type,
1970 void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
1972 TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
1973 device, type, parent, parent_ops, query);
1975 return device->adapter->adapter_ops->adapter_create_query(device, type, parent, parent_ops, query);