Its eventual purpose is to allow for skipping the poll list mechanism by calling query_poll() in the application thread. In this patch it is only used for when we don't have a separate CS thread.
Signed-off-by: Jan Sikorski jsikorski@codeweavers.com --- dlls/wined3d/cs.c | 6 +++++- dlls/wined3d/query.c | 21 ++++++++++----------- dlls/wined3d/wined3d_private.h | 1 + 3 files changed, 16 insertions(+), 12 deletions(-)
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 9bdd2c8ed98..e27b5b37aa4 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -2396,8 +2396,12 @@ static void wined3d_cs_exec_query_issue(struct wined3d_cs *cs, const void *data)
poll = query->query_ops->query_issue(query, op->flags);
- if (!cs->thread) + if (!query->poll_in_cs) + { + if (op->flags & WINED3DISSUE_END) + InterlockedIncrement(&query->counter_retrieved); return; + }
if (poll && list_empty(&query->poll_list_entry)) { diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c index 1b38eb5e311..77999c62ab1 100644 --- a/dlls/wined3d/query.c +++ b/dlls/wined3d/query.c @@ -146,6 +146,7 @@ static void wined3d_query_init(struct wined3d_query *query, struct wined3d_devic query->data = data; query->data_size = data_size; query->query_ops = query_ops; + query->poll_in_cs = !!device->cs->thread; list_init(&query->poll_list_entry); }
@@ -472,23 +473,21 @@ HRESULT CDECL wined3d_query_get_data(struct wined3d_query *query, return WINED3DERR_INVALIDCALL; }
- if (query->device->cs->thread) + if (query->counter_main != query->counter_retrieved + || (query->buffer_object && !wined3d_query_buffer_is_valid(query))) { - if (query->counter_main != query->counter_retrieved - || (query->buffer_object && !wined3d_query_buffer_is_valid(query))) - { - if (flags & WINED3DGETDATA_FLUSH && !query->device->cs->queries_flushed) - query->device->cs->c.ops->flush(&query->device->cs->c); - return S_FALSE; - } - if (query->buffer_object) - query->data = query->map_ptr; + if (flags & WINED3DGETDATA_FLUSH && !query->device->cs->queries_flushed) + query->device->cs->c.ops->flush(&query->device->cs->c); + return S_FALSE; } - else if (!query->query_ops->query_poll(query, flags)) + else if (!query->poll_in_cs && !query->query_ops->query_poll(query, flags)) { return S_FALSE; }
+ if (query->buffer_object) + query->data = query->map_ptr; + if (data) memcpy(data, query->data, min(data_size, query->data_size));
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 2fce585c6b1..d1136599319 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1973,6 +1973,7 @@ struct wined3d_query
GLuint buffer_object; UINT64 *map_ptr; + bool poll_in_cs; };
HRESULT wined3d_query_gl_create(struct wined3d_device *device, enum wined3d_query_type type, void *parent,
We want to avoid using the poll list, for occlusion queries especially, as in some games the number of occlusion queries can reach the hundreds. OpenGL backend already does this by using ARB_QUERY_BUFFER_OBJECT. We could mimic this in Vulkan too using compute shaders to accumulate pending queries, however, unlike with OpenGL, we can also just directly call vkGetQueryPoolResults() from the application's thread. To make it work, we need to keep the list of pending queries separately for each query, which also happens to be simpler than the current pending queries tracking. A second issue that is fixed here, incidentally, is that query results can be retrieved before the command buffer containing the queries ends. This makes a difference when a game wants the data from queries from the beginning of a frame, shortly after the frame ends. If the command buffer was not flushed during the frame, current code would stall polling until after the entire frame is rendered. A downside of the approach taken here is that Vulkan queries allocated to a wined3d_query are only released after the query is reused or destroyed. In principle, if this ever becomes a problem, it could be avoided by protecting the query pool with a mutex and releasing queries after reading the results.
Signed-off-by: Jan Sikorski jsikorski@codeweavers.com --- dlls/wined3d/context_vk.c | 65 -------------------- dlls/wined3d/query.c | 106 +++++++++++++++------------------ dlls/wined3d/wined3d_private.h | 27 ++------- 3 files changed, 54 insertions(+), 144 deletions(-)
diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c index 56b2da53060..b3dd557c0ec 100644 --- a/dlls/wined3d/context_vk.c +++ b/dlls/wined3d/context_vk.c @@ -1512,7 +1512,6 @@ void wined3d_context_vk_cleanup(struct wined3d_context_vk *context_vk) wined3d_context_vk_destroy_query_pools(context_vk, &context_vk->free_pipeline_statistics_query_pools); wined3d_context_vk_destroy_query_pools(context_vk, &context_vk->free_stream_output_statistics_query_pools); wine_rb_destroy(&context_vk->bo_slab_available, wined3d_context_vk_destroy_bo_slab, context_vk); - heap_free(context_vk->pending_queries.queries); heap_free(context_vk->submitted.buffers); heap_free(context_vk->retired.objects);
@@ -1524,69 +1523,6 @@ void wined3d_context_vk_cleanup(struct wined3d_context_vk *context_vk) wined3d_context_cleanup(&context_vk->c); }
-void wined3d_context_vk_remove_pending_queries(struct wined3d_context_vk *context_vk, - struct wined3d_query_vk *query_vk) -{ - struct wined3d_pending_queries_vk *pending = &context_vk->pending_queries; - struct wined3d_pending_query_vk *p; - size_t i; - - pending->free_idx = ~(size_t)0; - for (i = pending->count; i; --i) - { - p = &pending->queries[i - 1]; - - if (p->query_vk) - { - if (p->query_vk != query_vk && !wined3d_query_vk_accumulate_data(p->query_vk, context_vk, &p->pool_idx)) - continue; - --p->query_vk->pending_count; - } - - if (i == pending->count) - { - --pending->count; - continue; - } - - p->query_vk = NULL; - p->pool_idx.pool_vk = NULL; - p->pool_idx.idx = pending->free_idx; - pending->free_idx = i - 1; - } -} - -void wined3d_context_vk_accumulate_pending_queries(struct wined3d_context_vk *context_vk) -{ - wined3d_context_vk_remove_pending_queries(context_vk, NULL); -} - -void wined3d_context_vk_add_pending_query(struct wined3d_context_vk *context_vk, struct wined3d_query_vk *query_vk) -{ - struct wined3d_pending_queries_vk *pending = &context_vk->pending_queries; - struct wined3d_pending_query_vk *p; - - if (pending->free_idx != ~(size_t)0) - { - p = &pending->queries[pending->free_idx]; - pending->free_idx = p->pool_idx.idx; - } - else - { - if (!wined3d_array_reserve((void **)&pending->queries, &pending->size, - pending->count + 1, sizeof(*pending->queries))) - { - ERR("Failed to allocate entry.\n"); - return; - } - p = &pending->queries[pending->count++]; - } - - p->query_vk = query_vk; - p->pool_idx = query_vk->pool_idx; - ++query_vk->pending_count; -} - VkCommandBuffer wined3d_context_vk_get_command_buffer(struct wined3d_context_vk *context_vk) { struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device); @@ -1636,7 +1572,6 @@ VkCommandBuffer wined3d_context_vk_get_command_buffer(struct wined3d_context_vk return buffer->vk_command_buffer = VK_NULL_HANDLE; }
- wined3d_context_vk_accumulate_pending_queries(context_vk); LIST_FOR_EACH_ENTRY(query_vk, &context_vk->active_queries, struct wined3d_query_vk, entry) { if (!wined3d_context_vk_allocate_query(context_vk, query_vk->q.type, &query_vk->pool_idx)) diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c index 77999c62ab1..b25ce0f1d7c 100644 --- a/dlls/wined3d/query.c +++ b/dlls/wined3d/query.c @@ -1352,26 +1352,12 @@ HRESULT wined3d_query_gl_create(struct wined3d_device *device, enum wined3d_quer static void wined3d_query_pool_vk_mark_complete(struct wined3d_query_pool_vk *pool_vk, size_t idx, struct wined3d_context_vk *context_vk) { - const struct wined3d_vk_info *vk_info = context_vk->vk_info; - - if (vk_info->supported[WINED3D_VK_EXT_HOST_QUERY_RESET]) - { - VK_CALL(vkResetQueryPoolEXT(wined3d_device_vk(context_vk->c.device)->vk_device, - pool_vk->vk_query_pool, idx, 1)); - - wined3d_bitmap_clear(pool_vk->allocated, idx); - if (list_empty(&pool_vk->entry)) - list_add_tail(pool_vk->free_list, &pool_vk->entry); - } - else - { - /* Don't reset completed queries right away, as vkCmdResetQueryPool() needs to happen - * outside of a render pass. Queue the query to be reset in wined3d_query_pool_vk_reset() - * instead, which is called when the render pass ends. */ - wined3d_bitmap_set(pool_vk->completed, idx); - if (list_empty(&pool_vk->completed_entry)) - list_add_tail(&context_vk->completed_query_pools, &pool_vk->completed_entry); - } + /* Don't reset completed queries right away, as vkCmdResetQueryPool() needs to happen + * outside of a render pass. Queue the query to be reset in wined3d_query_pool_vk_reset() + * instead, which is called when the render pass ends. */ + wined3d_bitmap_set(pool_vk->completed, idx); + if (list_empty(&pool_vk->completed_entry)) + list_add_tail(&context_vk->completed_query_pools, &pool_vk->completed_entry); }
bool wined3d_query_pool_vk_allocate_query(struct wined3d_query_pool_vk *pool_vk, size_t *idx) @@ -1485,11 +1471,10 @@ bool wined3d_query_pool_vk_init(struct wined3d_query_pool_vk *pool_vk, }
bool wined3d_query_vk_accumulate_data(struct wined3d_query_vk *query_vk, - struct wined3d_context_vk *context_vk, const struct wined3d_query_pool_idx_vk *pool_idx) + struct wined3d_device_vk *device_vk, const struct wined3d_query_pool_idx_vk *pool_idx) { - struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device); const struct wined3d_query_data_pipeline_statistics *ps_tmp; - const struct wined3d_vk_info *vk_info = context_vk->vk_info; + const struct wined3d_vk_info *vk_info = &device_vk->vk_info; struct wined3d_query_data_pipeline_statistics *ps_result; VkResult vr; union @@ -1510,8 +1495,6 @@ bool wined3d_query_vk_accumulate_data(struct wined3d_query_vk *query_vk, if (vr == VK_NOT_READY) return false;
- wined3d_query_pool_vk_mark_complete(pool_idx->pool_vk, pool_idx->idx, context_vk); - result = (void *)query_vk->q.data; switch (query_vk->q.type) { @@ -1606,48 +1589,55 @@ void wined3d_query_vk_suspend(struct wined3d_query_vk *query_vk, struct wined3d_ VkCommandBuffer vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer;
wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer); - wined3d_context_vk_add_pending_query(context_vk, query_vk); + + if (!wined3d_array_reserve((void **)&query_vk->pending, &query_vk->pending_size, + query_vk->pending_count + 1, sizeof(*query_vk->pending))) + { + ERR("Failed to allocate entry.\n"); + return; + } + + query_vk->pending[query_vk->pending_count++] = query_vk->pool_idx; query_vk->pool_idx.pool_vk = NULL; query_vk->flags &= ~WINED3D_QUERY_VK_FLAG_ACTIVE; }
static BOOL wined3d_query_vk_poll(struct wined3d_query *query, uint32_t flags) { + struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device); struct wined3d_query_vk *query_vk = wined3d_query_vk(query); - struct wined3d_context_vk *context_vk; + size_t i;
- context_vk = wined3d_context_vk(context_acquire(query->device, NULL, 0)); + memset((void *)query_vk->q.data, 0, query_vk->q.data_size);
- if (flags & WINED3DGETDATA_FLUSH) - wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, 0, NULL); - if (query_vk->command_buffer_id == context_vk->current_command_buffer.id) + if (query_vk->pool_idx.pool_vk && !wined3d_query_vk_accumulate_data(query_vk, device_vk, &query_vk->pool_idx)) goto unavailable;
- if (query_vk->command_buffer_id > context_vk->completed_command_buffer_id) - wined3d_context_vk_poll_command_buffers(context_vk); - if (query_vk->command_buffer_id > context_vk->completed_command_buffer_id) - goto unavailable; - - if (query_vk->pending_count) - wined3d_context_vk_accumulate_pending_queries(context_vk); - if (query_vk->pending_count) - goto unavailable; - - /* If the query was suspended, and then ended before it was resumed, - * there's no data to accumulate here. */ - if (query_vk->pool_idx.pool_vk && !wined3d_query_vk_accumulate_data(query_vk, context_vk, &query_vk->pool_idx)) - goto unavailable; - - query_vk->pool_idx.pool_vk = NULL; - context_release(&context_vk->c); + for (i = 0; i < query_vk->pending_count; ++i) + { + if (!wined3d_query_vk_accumulate_data(query_vk, device_vk, &query_vk->pending[i])) + goto unavailable; + }
return TRUE;
unavailable: - context_release(&context_vk->c); + if ((flags & WINED3DGETDATA_FLUSH) && !query->device->cs->queries_flushed) + query->device->cs->c.ops->flush(&query->device->cs->c); return FALSE; }
+static void wined3d_query_vk_remove_pending_queries(struct wined3d_context_vk *context_vk, + struct wined3d_query_vk *query_vk) +{ + size_t i; + + for (i = 0; i < query_vk->pending_count; ++i) + wined3d_query_pool_vk_mark_complete(query_vk->pending[i].pool_vk, query_vk->pending[i].idx, context_vk); + + query_vk->pending_count = 0; +} + static BOOL wined3d_query_vk_issue(struct wined3d_query *query, uint32_t flags) { struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device); @@ -1663,8 +1653,7 @@ static BOOL wined3d_query_vk_issue(struct wined3d_query *query, uint32_t flags) context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
if (query_vk->pending_count) - wined3d_context_vk_remove_pending_queries(context_vk, query_vk); - memset((void *)query->data, 0, query->data_size); + wined3d_query_vk_remove_pending_queries(context_vk, query_vk); vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk); if (query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED) { @@ -1744,12 +1733,12 @@ static void wined3d_query_vk_destroy(struct wined3d_query *query)
if (query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED) list_remove(&query_vk->entry); - if (query_vk->pending_count) - { - context_vk = wined3d_context_vk(context_acquire(query_vk->q.device, NULL, 0)); - wined3d_context_vk_remove_pending_queries(context_vk, query_vk); - context_release(&context_vk->c); - } + context_vk = wined3d_context_vk(context_acquire(query_vk->q.device, NULL, 0)); + wined3d_query_vk_remove_pending_queries(context_vk, query_vk); + if (query_vk->pool_idx.pool_vk) + wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk, query_vk->pool_idx.idx, context_vk); + context_release(&context_vk->c); + heap_free(query_vk->pending); heap_free(query_vk); }
@@ -1944,6 +1933,9 @@ HRESULT wined3d_query_vk_create(struct wined3d_device *device, enum wined3d_quer
wined3d_query_init(&query_vk->q, device, type, data, data_size, ops, parent, parent_ops);
+ if (type != WINED3D_QUERY_TYPE_EVENT) + query_vk->q.poll_in_cs = false; + switch (type) { case WINED3D_QUERY_TYPE_OCCLUSION: diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index d1136599319..c34fa62a53b 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2102,7 +2102,8 @@ struct wined3d_query_vk uint8_t flags; uint64_t command_buffer_id; uint32_t control_flags; - size_t pending_count; + SIZE_T pending_count, pending_size; + struct wined3d_query_pool_idx_vk *pending; };
static inline struct wined3d_query_vk *wined3d_query_vk(struct wined3d_query *query) @@ -2110,7 +2111,9 @@ static inline struct wined3d_query_vk *wined3d_query_vk(struct wined3d_query *qu return CONTAINING_RECORD(query, struct wined3d_query_vk, q); }
-bool wined3d_query_vk_accumulate_data(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk, +struct wined3d_device_vk; + +bool wined3d_query_vk_accumulate_data(struct wined3d_query_vk *query_vk, struct wined3d_device_vk *device_vk, const struct wined3d_query_pool_idx_vk *pool_idx) DECLSPEC_HIDDEN; HRESULT wined3d_query_vk_create(struct wined3d_device *device, enum wined3d_query_type type, void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query) DECLSPEC_HIDDEN; @@ -2558,20 +2561,6 @@ struct wined3d_shader_descriptor_writes_vk SIZE_T size, count; };
-struct wined3d_pending_query_vk -{ - struct wined3d_query_vk *query_vk; - struct wined3d_query_pool_idx_vk pool_idx; -}; - -struct wined3d_pending_queries_vk -{ - struct wined3d_pending_query_vk *queries; - SIZE_T free_idx; - SIZE_T size; - SIZE_T count; -}; - struct wined3d_context_vk { struct wined3d_context c; @@ -2627,7 +2616,6 @@ struct wined3d_context_vk
struct list render_pass_queries; struct list active_queries; - struct wined3d_pending_queries_vk pending_queries; struct list completed_query_pools; struct list free_occlusion_query_pools; struct list free_timestamp_query_pools; @@ -2646,9 +2634,6 @@ static inline struct wined3d_context_vk *wined3d_context_vk(struct wined3d_conte return CONTAINING_RECORD(context, struct wined3d_context_vk, c); }
-void wined3d_context_vk_accumulate_pending_queries(struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN; -void wined3d_context_vk_add_pending_query(struct wined3d_context_vk *context_vk, - struct wined3d_query_vk *query_vk) DECLSPEC_HIDDEN; bool wined3d_context_vk_allocate_query(struct wined3d_context_vk *context_vk, enum wined3d_query_type type, struct wined3d_query_pool_idx_vk *pool_idx) DECLSPEC_HIDDEN; VkDeviceMemory wined3d_context_vk_allocate_vram_chunk_memory(struct wined3d_context_vk *context_vk, @@ -2696,8 +2681,6 @@ void wined3d_context_vk_image_barrier(struct wined3d_context_vk *context_vk, HRESULT wined3d_context_vk_init(struct wined3d_context_vk *context_vk, struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN; void wined3d_context_vk_poll_command_buffers(struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN; -void wined3d_context_vk_remove_pending_queries(struct wined3d_context_vk *context_vk, - struct wined3d_query_vk *query_vk) DECLSPEC_HIDDEN; void wined3d_context_vk_submit_command_buffer(struct wined3d_context_vk *context_vk, unsigned int wait_semaphore_count, const VkSemaphore *wait_semaphores, const VkPipelineStageFlags *wait_stages, unsigned int signal_semaphore_count, const VkSemaphore *signal_semaphores) DECLSPEC_HIDDEN;
This makes event results available sooner, i.e. after they are executed by the GPU, and also moves the polling from CS to application's thread.
Signed-off-by: Jan Sikorski jsikorski@codeweavers.com --- I thought event queries may be implicated in some of the hitching during resource updates, but I haven't measured any concrete improvements. Still, it seems preferable to have this kind of implementation. --- dlls/wined3d/context_vk.c | 30 +++++++++++++ dlls/wined3d/query.c | 79 +++++++++++++++++++++------------- dlls/wined3d/wined3d_private.h | 5 +++ 3 files changed, 83 insertions(+), 31 deletions(-)
diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c index b3dd557c0ec..b4d12d838f1 100644 --- a/dlls/wined3d/context_vk.c +++ b/dlls/wined3d/context_vk.c @@ -930,6 +930,31 @@ void wined3d_context_vk_destroy_vk_sampler(struct wined3d_context_vk *context_vk o->command_buffer_id = command_buffer_id; }
+void wined3d_context_vk_destroy_vk_event(struct wined3d_context_vk *context_vk, + VkEvent vk_event, uint64_t command_buffer_id) +{ + struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device); + const struct wined3d_vk_info *vk_info = context_vk->vk_info; + struct wined3d_retired_object_vk *o; + + if (context_vk->completed_command_buffer_id > command_buffer_id) + { + VK_CALL(vkDestroyEvent(device_vk->vk_device, vk_event, NULL)); + TRACE("Destroyed event 0x%s.\n", wine_dbgstr_longlong(vk_event)); + return; + } + + if (!(o = wined3d_context_vk_get_retired_object_vk(context_vk))) + { + ERR("Leaking event 0x%s.\n", wine_dbgstr_longlong(vk_event)); + return; + } + + o->type = WINED3D_RETIRED_EVENT_VK; + o->u.vk_event = vk_event; + o->command_buffer_id = command_buffer_id; +} + void wined3d_context_vk_destroy_image(struct wined3d_context_vk *context_vk, struct wined3d_image_vk *image) { wined3d_context_vk_destroy_vk_image(context_vk, image->vk_image, image->command_buffer_id); @@ -1083,6 +1108,11 @@ static void wined3d_context_vk_cleanup_resources(struct wined3d_context_vk *cont TRACE("Destroyed sampler 0x%s.\n", wine_dbgstr_longlong(o->u.vk_sampler)); break;
+ case WINED3D_RETIRED_EVENT_VK: + VK_CALL(vkDestroyEvent(device_vk->vk_device, o->u.vk_event, NULL)); + TRACE("Destroyed event 0x%s.\n", wine_dbgstr_longlong(o->u.vk_event)); + break; + default: ERR("Unhandled object type %#x.\n", o->type); break; diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c index b25ce0f1d7c..38d5f90c9d3 100644 --- a/dlls/wined3d/query.c +++ b/dlls/wined3d/query.c @@ -1737,6 +1737,8 @@ static void wined3d_query_vk_destroy(struct wined3d_query *query) wined3d_query_vk_remove_pending_queries(context_vk, query_vk); if (query_vk->pool_idx.pool_vk) wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk, query_vk->pool_idx.idx, context_vk); + if (query_vk->vk_event) + wined3d_context_vk_destroy_vk_event(context_vk, query_vk->vk_event, query_vk->command_buffer_id); context_release(&context_vk->c); heap_free(query_vk->pending); heap_free(query_vk); @@ -1751,50 +1753,67 @@ static const struct wined3d_query_ops wined3d_query_vk_ops =
static BOOL wined3d_query_event_vk_poll(struct wined3d_query *query, uint32_t flags) { + struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device); struct wined3d_query_vk *query_vk = wined3d_query_vk(query); - struct wined3d_context_vk *context_vk; - BOOL *signalled; - - context_vk = wined3d_context_vk(context_acquire(query->device, NULL, 0)); - - signalled = (BOOL *)query->data; - if (flags & WINED3DGETDATA_FLUSH) - wined3d_context_vk_submit_command_buffer(context_vk, 0, NULL, NULL, 0, NULL); - if (query_vk->command_buffer_id == context_vk->current_command_buffer.id) - { - context_release(&context_vk->c); - return *signalled = FALSE; - } - - if (query_vk->command_buffer_id > context_vk->completed_command_buffer_id) - wined3d_context_vk_poll_command_buffers(context_vk); - *signalled = context_vk->completed_command_buffer_id >= query_vk->command_buffer_id; - - context_release(&context_vk->c); + const struct wined3d_vk_info *vk_info = &device_vk->vk_info; + BOOL signalled;
- return *signalled; + signalled = VK_CALL(vkGetEventStatus(device_vk->vk_device, query_vk->vk_event)) + == VK_EVENT_SET; + if (!signalled && (flags & WINED3DGETDATA_FLUSH) && !query->device->cs->queries_flushed) + query->device->cs->c.ops->flush(&query->device->cs->c); + return *(BOOL *)query->data = signalled; }
static BOOL wined3d_query_event_vk_issue(struct wined3d_query *query, uint32_t flags) { struct wined3d_device_vk *device_vk = wined3d_device_vk(query->device); + const struct wined3d_vk_info *vk_info = &device_vk->vk_info; struct wined3d_query_vk *query_vk = wined3d_query_vk(query); struct wined3d_context_vk *context_vk; + VkEventCreateInfo create_info; + VkResult vr;
TRACE("query %p, flags %#x.\n", query, flags);
if (flags & WINED3DISSUE_END) { context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0)); + wined3d_context_vk_end_current_render_pass(context_vk); + + if (query_vk->vk_event) + { + if (query_vk->command_buffer_id > context_vk->completed_command_buffer_id) + { + /* Cannot reuse this event, as it may still get signalled by previous usage. */ + /* Throw it away and create a new one, but if that happens a lot we may want to pool instead. */ + wined3d_context_vk_destroy_vk_event(context_vk, query_vk->vk_event, query_vk->command_buffer_id); + query_vk->vk_event = VK_NULL_HANDLE; + } + else + { + VK_CALL(vkResetEvent(device_vk->vk_device, query_vk->vk_event)); + } + } + + if (!query_vk->vk_event) + { + create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO; + create_info.pNext = NULL; + create_info.flags = 0; + + vr = VK_CALL(vkCreateEvent(device_vk->vk_device, &create_info, NULL, &query_vk->vk_event)); + if (vr != VK_SUCCESS) + { + ERR("Failed to create Vulkan event, vr %s\n", wined3d_debug_vkresult(vr)); + context_release(&context_vk->c); + return FALSE; + } + } + wined3d_context_vk_reference_query(context_vk, query_vk); - /* Because we don't actually submit any commands to the command buffer - * for event queries, the context's current command buffer may still - * be empty, and we should wait on the preceding command buffer - * instead. That's not merely an optimisation; if the command buffer - * referenced by the query is still empty by the time the application - * waits for it, that wait will never complete. */ - if (!context_vk->current_command_buffer.vk_command_buffer) - --query_vk->command_buffer_id; + VK_CALL(vkCmdSetEvent(wined3d_context_vk_get_command_buffer(context_vk), query_vk->vk_event, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT)); context_release(&context_vk->c);
return TRUE; @@ -1932,9 +1951,7 @@ HRESULT wined3d_query_vk_create(struct wined3d_device *device, enum wined3d_quer data = query_vk + 1;
wined3d_query_init(&query_vk->q, device, type, data, data_size, ops, parent, parent_ops); - - if (type != WINED3D_QUERY_TYPE_EVENT) - query_vk->q.poll_in_cs = false; + query_vk->q.poll_in_cs = false;
switch (type) { diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index c34fa62a53b..6046753c3d9 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2102,6 +2102,7 @@ struct wined3d_query_vk uint8_t flags; uint64_t command_buffer_id; uint32_t control_flags; + VkEvent vk_event; SIZE_T pending_count, pending_size; struct wined3d_query_pool_idx_vk *pending; }; @@ -2428,6 +2429,7 @@ enum wined3d_retired_object_type_vk WINED3D_RETIRED_BUFFER_VIEW_VK, WINED3D_RETIRED_IMAGE_VIEW_VK, WINED3D_RETIRED_SAMPLER_VK, + WINED3D_RETIRED_EVENT_VK, };
struct wined3d_retired_object_vk @@ -2450,6 +2452,7 @@ struct wined3d_retired_object_vk VkBufferView vk_buffer_view; VkImageView vk_image_view; VkSampler vk_sampler; + VkEvent vk_event; } u; uint64_t command_buffer_id; }; @@ -2667,6 +2670,8 @@ void wined3d_context_vk_destroy_vk_memory(struct wined3d_context_vk *context_vk, VkDeviceMemory vk_memory, uint64_t command_buffer_id) DECLSPEC_HIDDEN; void wined3d_context_vk_destroy_vk_sampler(struct wined3d_context_vk *context_vk, VkSampler vk_sampler, uint64_t command_buffer_id) DECLSPEC_HIDDEN; +void wined3d_context_vk_destroy_vk_event(struct wined3d_context_vk *context_vk, + VkEvent vk_event, uint64_t command_buffer_id) DECLSPEC_HIDDEN; void wined3d_context_vk_end_current_render_pass(struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN; VkCommandBuffer wined3d_context_vk_get_command_buffer(struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN; struct wined3d_pipeline_layout_vk *wined3d_context_vk_get_pipeline_layout(struct wined3d_context_vk *context_vk,