[PATCH 4/4] wined3d: Implement event queries using Vulkan events.

Jan Sikorski jsikorski at codeweavers.com
Fri Mar 4 11:12:59 CST 2022


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 at codeweavers.com>
---
I thought event queries may be implicated in some of the hitching, 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 dcb94eb7c1a..436973fe76f 100644
--- a/dlls/wined3d/context_vk.c
+++ b/dlls/wined3d/context_vk.c
@@ -973,6 +973,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);
@@ -1134,6 +1159,11 @@ static void wined3d_context_vk_cleanup_resources(struct wined3d_context_vk *cont
                 TRACE("Freed query range %u+%u in pool %p.\n", o->u.queries.start, o->u.queries.count, o->u.queries.pool_vk);
                 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 3a4a518fcfb..4b94cb8daea 100644
--- a/dlls/wined3d/query.c
+++ b/dlls/wined3d/query.c
@@ -1742,6 +1742,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);
@@ -1756,50 +1758,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;
@@ -1937,9 +1956,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 a9e42e0cb16..58ef6764f2d 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2086,6 +2086,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;
 };
@@ -2414,6 +2415,7 @@ enum wined3d_retired_object_type_vk
     WINED3D_RETIRED_IMAGE_VIEW_VK,
     WINED3D_RETIRED_SAMPLER_VK,
     WINED3D_RETIRED_QUERY_POOL_VK,
+    WINED3D_RETIRED_EVENT_VK,
 };
 
 struct wined3d_retired_object_vk
@@ -2436,6 +2438,7 @@ struct wined3d_retired_object_vk
         VkBufferView vk_buffer_view;
         VkImageView vk_image_view;
         VkSampler vk_sampler;
+        VkEvent vk_event;
         struct
         {
             struct wined3d_query_pool_vk *pool_vk;
@@ -2659,6 +2662,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,
-- 
2.32.0




More information about the wine-devel mailing list