[PATCH 3/5] wined3d: Implement occlusion queries for the Vulkan adapter.

Henri Verbeet hverbeet at codeweavers.com
Tue May 26 11:10:11 CDT 2020


Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
---
 dlls/wined3d/adapter_vk.c      |  15 +-
 dlls/wined3d/context_vk.c      | 157 +++++++++++++++++-
 dlls/wined3d/query.c           | 287 +++++++++++++++++++++++++++++++++
 dlls/wined3d/wined3d_private.h |  86 ++++++++++
 4 files changed, 539 insertions(+), 6 deletions(-)

diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c
index 8cbd8206617..84eda1e551b 100644
--- a/dlls/wined3d/adapter_vk.c
+++ b/dlls/wined3d/adapter_vk.c
@@ -1609,12 +1609,23 @@ static HRESULT adapter_vk_create_query(struct wined3d_device *device, enum wined
     TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
             device, type, parent, parent_ops, query);
 
-    return WINED3DERR_NOTAVAILABLE;
+    return wined3d_query_vk_create(device, type, parent, parent_ops, query);
+}
+
+static void wined3d_query_vk_destroy_object(void *object)
+{
+    struct wined3d_query_vk *query_vk = object;
+
+    query_vk->q.query_ops->query_destroy(&query_vk->q);
 }
 
 static void adapter_vk_destroy_query(struct wined3d_query *query)
 {
-    TRACE("query %p.\n", query);
+    struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
+
+    TRACE("query_vk %p.\n", query_vk);
+
+    wined3d_cs_destroy_object(query->device->cs, wined3d_query_vk_destroy_object, query_vk);
 }
 
 static void adapter_vk_flush_context(struct wined3d_context *context)
diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c
index 3a6671036e2..2964eb30cc4 100644
--- a/dlls/wined3d/context_vk.c
+++ b/dlls/wined3d/context_vk.c
@@ -813,14 +813,11 @@ void wined3d_context_vk_destroy_bo(struct wined3d_context_vk *context_vk, const
     wined3d_context_vk_destroy_memory(context_vk, bo->vk_memory, bo->command_buffer_id);
 }
 
-static void wined3d_context_vk_cleanup_resources(struct wined3d_context_vk *context_vk)
+void wined3d_context_vk_poll_command_buffers(struct wined3d_context_vk *context_vk)
 {
     struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
-    struct wined3d_retired_objects_vk *retired = &context_vk->retired;
     const struct wined3d_vk_info *vk_info = context_vk->vk_info;
     struct wined3d_command_buffer_vk *buffer;
-    struct wined3d_retired_object_vk *o;
-    uint64_t command_buffer_id;
     SIZE_T i = 0;
 
     while (i < context_vk->submitted.buffer_count)
@@ -842,6 +839,18 @@ static void wined3d_context_vk_cleanup_resources(struct wined3d_context_vk *cont
             context_vk->completed_command_buffer_id = buffer->id;
         *buffer = context_vk->submitted.buffers[--context_vk->submitted.buffer_count];
     }
+}
+
+static void wined3d_context_vk_cleanup_resources(struct wined3d_context_vk *context_vk)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
+    struct wined3d_retired_objects_vk *retired = &context_vk->retired;
+    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+    struct wined3d_retired_object_vk *o;
+    uint64_t command_buffer_id;
+    SIZE_T i = 0;
+
+    wined3d_context_vk_poll_command_buffers(context_vk);
     command_buffer_id = context_vk->completed_command_buffer_id;
 
     retired->free = NULL;
@@ -1194,6 +1203,64 @@ static void wined3d_shader_descriptor_writes_vk_cleanup(struct wined3d_shader_de
     heap_free(writes->writes);
 }
 
+static void wined3d_context_vk_destroy_query_pools(struct wined3d_context_vk *context_vk, struct list *free_pools)
+{
+    struct wined3d_query_pool_vk *pool_vk, *entry;
+
+    LIST_FOR_EACH_ENTRY_SAFE(pool_vk, entry, free_pools, struct wined3d_query_pool_vk, entry)
+    {
+        wined3d_query_pool_vk_cleanup(pool_vk, context_vk);
+        heap_free(pool_vk);
+    }
+}
+
+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)
+{
+    struct wined3d_query_pool_vk *pool_vk, *entry;
+    struct list *free_pools;
+    size_t idx;
+
+    switch (type)
+    {
+        case WINED3D_QUERY_TYPE_OCCLUSION:
+            free_pools = &context_vk->free_occlusion_query_pools;
+            break;
+
+        default:
+            FIXME("Unhandled query type %#x.\n", type);
+            return false;
+    }
+
+    LIST_FOR_EACH_ENTRY_SAFE(pool_vk, entry, free_pools, struct wined3d_query_pool_vk, entry)
+    {
+        if (wined3d_query_pool_vk_allocate_query(pool_vk, &idx))
+            goto done;
+        list_remove(&pool_vk->entry);
+    }
+
+    if (!(pool_vk = heap_alloc_zero(sizeof(*pool_vk))))
+        return false;
+    if (!wined3d_query_pool_vk_init(pool_vk, context_vk, type, free_pools))
+    {
+        heap_free(pool_vk);
+        return false;
+    }
+
+    if (!wined3d_query_pool_vk_allocate_query(pool_vk, &idx))
+    {
+        wined3d_query_pool_vk_cleanup(pool_vk, context_vk);
+        heap_free(pool_vk);
+        return false;
+    }
+
+done:
+    pool_idx->pool_vk = pool_vk;
+    pool_idx->idx = idx;
+
+    return true;
+}
+
 void wined3d_context_vk_cleanup(struct wined3d_context_vk *context_vk)
 {
     struct wined3d_command_buffer_vk *buffer = &context_vk->current_command_buffer;
@@ -1218,7 +1285,9 @@ void wined3d_context_vk_cleanup(struct wined3d_context_vk *context_vk)
         VK_CALL(vkDestroyFramebuffer(device_vk->vk_device, context_vk->vk_framebuffer, NULL));
     VK_CALL(vkDestroyCommandPool(device_vk->vk_device, context_vk->vk_command_pool, NULL));
     wined3d_context_vk_cleanup_resources(context_vk);
+    wined3d_context_vk_destroy_query_pools(context_vk, &context_vk->free_occlusion_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);
 
@@ -1230,6 +1299,70 @@ 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;
+            wined3d_query_pool_vk_free_query(p->pool_idx.pool_vk, p->pool_idx.idx);
+            --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);
@@ -1237,6 +1370,7 @@ VkCommandBuffer wined3d_context_vk_get_command_buffer(struct wined3d_context_vk
     VkCommandBufferAllocateInfo command_buffer_info;
     struct wined3d_command_buffer_vk *buffer;
     VkCommandBufferBeginInfo begin_info;
+    struct wined3d_query_vk *query_vk;
     VkResult vr;
 
     TRACE("context_vk %p.\n", context_vk);
@@ -1273,6 +1407,12 @@ 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)
+    {
+        wined3d_query_vk_resume(query_vk, context_vk);
+    }
+
     TRACE("Created new command buffer %p with id 0x%s.\n",
             buffer->vk_command_buffer, wine_dbgstr_longlong(buffer->id));
 
@@ -1286,6 +1426,7 @@ void wined3d_context_vk_submit_command_buffer(struct wined3d_context_vk *context
     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_command_buffer_vk *buffer;
+    struct wined3d_query_vk *query_vk;
     VkFenceCreateInfo fence_desc;
     VkSubmitInfo submit_info;
     VkResult vr;
@@ -1302,6 +1443,11 @@ void wined3d_context_vk_submit_command_buffer(struct wined3d_context_vk *context
     TRACE("Submitting command buffer %p with id 0x%s.\n",
             buffer->vk_command_buffer, wine_dbgstr_longlong(buffer->id));
 
+    LIST_FOR_EACH_ENTRY(query_vk, &context_vk->active_queries, struct wined3d_query_vk, entry)
+    {
+        wined3d_query_vk_suspend(query_vk, context_vk);
+    }
+
     wined3d_context_vk_end_current_render_pass(context_vk);
     context_vk->graphics.vk_pipeline = VK_NULL_HANDLE;
     context_vk->update_compute_pipeline = 1;
@@ -2909,6 +3055,9 @@ HRESULT wined3d_context_vk_init(struct wined3d_context_vk *context_vk, struct wi
 
     wined3d_context_vk_init_graphics_pipeline_key(context_vk);
 
+    list_init(&context_vk->active_queries);
+    list_init(&context_vk->free_occlusion_query_pools);
+
     wine_rb_init(&context_vk->render_passes, wined3d_render_pass_vk_compare);
     wine_rb_init(&context_vk->pipeline_layouts, wined3d_pipeline_layout_vk_compare);
     wine_rb_init(&context_vk->graphics_pipelines, wined3d_graphics_pipeline_vk_compare);
diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c
index ab3bb743809..b72ffd633c5 100644
--- a/dlls/wined3d/query.c
+++ b/dlls/wined3d/query.c
@@ -1354,6 +1354,293 @@ HRESULT wined3d_query_gl_create(struct wined3d_device *device, enum wined3d_quer
     }
 }
 
+void wined3d_query_pool_vk_free_query(struct wined3d_query_pool_vk *pool_vk, size_t idx)
+{
+    wined3d_bitmap_clear(pool_vk->allocated, idx);
+
+    if (list_empty(&pool_vk->entry))
+        list_add_tail(pool_vk->free_list, &pool_vk->entry);
+}
+
+bool wined3d_query_pool_vk_allocate_query(struct wined3d_query_pool_vk *pool_vk, size_t *idx)
+{
+    if ((*idx = wined3d_bitmap_ffz(pool_vk->allocated, WINED3D_QUERY_POOL_SIZE, 0)) > WINED3D_QUERY_POOL_SIZE)
+        return false;
+    wined3d_bitmap_set(pool_vk->allocated, *idx);
+
+    return true;
+}
+
+void wined3d_query_pool_vk_cleanup(struct wined3d_query_pool_vk *pool_vk, struct wined3d_context_vk *context_vk)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
+    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+
+    VK_CALL(vkDestroyQueryPool(device_vk->vk_device, pool_vk->vk_query_pool, NULL));
+    list_remove(&pool_vk->entry);
+}
+
+bool wined3d_query_pool_vk_init(struct wined3d_query_pool_vk *pool_vk,
+        struct wined3d_context_vk *context_vk, enum wined3d_query_type type, struct list *free_pools)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
+    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+    VkQueryPoolCreateInfo pool_info;
+    VkResult vr;
+
+    list_init(&pool_vk->entry);
+    pool_vk->free_list = free_pools;
+
+    pool_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
+    pool_info.pNext = NULL;
+    pool_info.flags = 0;
+    pool_info.queryCount = WINED3D_QUERY_POOL_SIZE;
+
+    switch (type)
+    {
+        case WINED3D_QUERY_TYPE_OCCLUSION:
+            pool_info.queryType = VK_QUERY_TYPE_OCCLUSION;
+            pool_info.pipelineStatistics = 0;
+            break;
+
+        default:
+            FIXME("Unhandled query type %#x.\n", type);
+            return false;
+    }
+
+    if ((vr = VK_CALL(vkCreateQueryPool(device_vk->vk_device, &pool_info, NULL, &pool_vk->vk_query_pool))) < 0)
+    {
+        ERR("Failed to create Vulkan query pool, vr %s.\n", wined3d_debug_vkresult(vr));
+        return false;
+    }
+
+    list_add_head(free_pools, &pool_vk->entry);
+
+    return true;
+}
+
+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 = wined3d_device_vk(context_vk->c.device);
+    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+    VkResult vr;
+    union
+    {
+        uint64_t occlusion;
+    } tmp, *result;
+
+    if ((vr = VK_CALL(vkGetQueryPoolResults(device_vk->vk_device, pool_idx->pool_vk->vk_query_pool,
+            pool_idx->idx, 1, sizeof(tmp), &tmp, sizeof(tmp), VK_QUERY_RESULT_64_BIT))) < 0)
+    {
+        ERR("Failed to get query results, vr %s.\n", wined3d_debug_vkresult(vr));
+        return false;
+    }
+
+    if (vr == VK_NOT_READY)
+        return false;
+
+    result = (void *)query_vk->q.data;
+    switch (query_vk->q.type)
+    {
+        case WINED3D_QUERY_TYPE_OCCLUSION:
+            result->occlusion += tmp.occlusion;
+            break;
+
+        default:
+            FIXME("Unhandled query type %#x.\n", query_vk->q.type);
+            return false;
+    }
+
+    return true;
+}
+
+static void wined3d_query_vk_begin(struct wined3d_query_vk *query_vk,
+        struct wined3d_context_vk *context_vk, VkCommandBuffer vk_command_buffer)
+{
+    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+    struct wined3d_query_pool_vk *pool_vk;
+    size_t idx;
+
+    if (!query_vk->pool_idx.pool_vk
+            && !wined3d_context_vk_allocate_query(context_vk, query_vk->q.type, &query_vk->pool_idx))
+    {
+        ERR("Failed to allocate new query.\n");
+        return;
+    }
+    pool_vk = query_vk->pool_idx.pool_vk;
+    idx = query_vk->pool_idx.idx;
+
+    VK_CALL(vkCmdResetQueryPool(vk_command_buffer, pool_vk->vk_query_pool, idx, 1));
+    VK_CALL(vkCmdBeginQuery(vk_command_buffer, pool_vk->vk_query_pool, idx, query_vk->control_flags));
+    wined3d_context_vk_reference_query(context_vk, query_vk);
+}
+
+static void wined3d_query_vk_end(struct wined3d_query_vk *query_vk,
+        struct wined3d_context_vk *context_vk, VkCommandBuffer vk_command_buffer)
+{
+    const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+    struct wined3d_query_pool_vk *pool_vk;
+    size_t idx;
+
+    pool_vk = query_vk->pool_idx.pool_vk;
+    idx = query_vk->pool_idx.idx;
+
+    VK_CALL(vkCmdEndQuery(vk_command_buffer, pool_vk->vk_query_pool, idx));
+}
+
+void wined3d_query_vk_resume(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk)
+{
+    VkCommandBuffer vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer;
+
+    wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
+}
+
+void wined3d_query_vk_suspend(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk)
+{
+    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);
+    query_vk->pool_idx.pool_vk = NULL;
+}
+
+static BOOL wined3d_query_vk_poll(struct wined3d_query *query, uint32_t flags)
+{
+    struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
+    struct wined3d_context_vk *context_vk;
+
+    context_vk = wined3d_context_vk(context_acquire(query->device, NULL, 0));
+
+    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)
+        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 (!wined3d_query_vk_accumulate_data(query_vk, context_vk, &query_vk->pool_idx))
+        goto unavailable;
+
+    context_release(&context_vk->c);
+
+    return TRUE;
+
+unavailable:
+    context_release(&context_vk->c);
+    return FALSE;
+}
+
+static BOOL wined3d_query_vk_issue(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;
+    VkCommandBuffer vk_command_buffer;
+    bool poll = false;
+
+    TRACE("query %p, flags %#x.\n", query, flags);
+
+    if (flags & WINED3DISSUE_BEGIN)
+    {
+        context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
+
+        wined3d_context_vk_end_current_render_pass(context_vk);
+        list_remove(&query_vk->entry);
+        if (query_vk->pending_count)
+            wined3d_context_vk_remove_pending_queries(context_vk, query_vk);
+        memset((void *)query->data, 0, query->data_size);
+        vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk);
+        wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer);
+        list_add_head(&context_vk->active_queries, &query_vk->entry);
+        query_vk->started = true;
+
+        context_release(&context_vk->c);
+    }
+    if (flags & WINED3DISSUE_END && query_vk->started)
+    {
+        context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
+
+        /* If the query was already ended because the command buffer was
+         * flushed, we don't need to end it here. */
+        if ((vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer))
+            wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer);
+        list_remove(&query_vk->entry);
+        query_vk->started = false;
+        poll = true;
+
+        context_release(&context_vk->c);
+    }
+
+    return poll;
+}
+
+static void wined3d_query_vk_destroy(struct wined3d_query *query)
+{
+    struct wined3d_query_vk *query_vk = wined3d_query_vk(query);
+    struct wined3d_context_vk *context_vk;
+
+    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);
+    }
+    if (query_vk->pool_idx.pool_vk)
+        wined3d_query_pool_vk_free_query(query_vk->pool_idx.pool_vk, query_vk->pool_idx.idx);
+    heap_free(query_vk);
+}
+
+static const struct wined3d_query_ops wined3d_query_vk_ops =
+{
+    .query_poll = wined3d_query_vk_poll,
+    .query_issue = wined3d_query_vk_issue,
+    .query_destroy = wined3d_query_vk_destroy,
+};
+
+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)
+{
+    struct wined3d_query_vk *query_vk;
+    unsigned int data_size;
+
+    TRACE("device %p, type %#x, parent %p, parent_ops %p, query %p.\n",
+            device, type, parent, parent_ops, query);
+
+    switch (type)
+    {
+        case WINED3D_QUERY_TYPE_OCCLUSION:
+            data_size = sizeof(uint64_t);
+            break;
+
+        default:
+            FIXME("Unhandled query type %#x.\n", type);
+            return WINED3DERR_NOTAVAILABLE;
+    }
+
+    if (!(query_vk = heap_alloc_zero(sizeof(*query_vk) + data_size)))
+        return E_OUTOFMEMORY;
+
+    wined3d_query_init(&query_vk->q, device, type, query_vk + 1, data_size, &wined3d_query_vk_ops, parent, parent_ops);
+    list_init(&query_vk->entry);
+    if (type == WINED3D_QUERY_TYPE_OCCLUSION)
+        query_vk->control_flags = VK_QUERY_CONTROL_PRECISE_BIT;
+
+    TRACE("Created query %p.\n", query_vk);
+    *query = &query_vk->q;
+
+    return WINED3D_OK;
+}
+
 HRESULT CDECL wined3d_query_create(struct wined3d_device *device, enum wined3d_query_type type,
         void *parent, const struct wined3d_parent_ops *parent_ops, struct wined3d_query **query)
 {
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index e9081e5d17d..5c92eecbf3e 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -86,6 +86,7 @@ struct wined3d_fragment_pipe_ops;
 struct wined3d_adapter;
 struct wined3d_buffer_vk;
 struct wined3d_context;
+struct wined3d_context_vk;
 struct wined3d_gl_info;
 struct wined3d_state;
 struct wined3d_swapchain_gl;
@@ -1952,6 +1953,54 @@ struct wined3d_pipeline_statistics_query
     BOOL started;
 };
 
+#define WINED3D_QUERY_POOL_SIZE 256
+
+struct wined3d_query_pool_vk
+{
+    struct list entry;
+
+    struct list *free_list;
+    VkQueryPool vk_query_pool;
+    uint32_t allocated[WINED3D_BITMAP_SIZE(WINED3D_QUERY_POOL_SIZE)];
+};
+
+bool wined3d_query_pool_vk_allocate_query(struct wined3d_query_pool_vk *pool_vk, size_t *idx) DECLSPEC_HIDDEN;
+void wined3d_query_pool_vk_cleanup(struct wined3d_query_pool_vk *pool_vk,
+        struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN;
+void wined3d_query_pool_vk_free_query(struct wined3d_query_pool_vk *pool_vk, size_t idx) DECLSPEC_HIDDEN;
+bool wined3d_query_pool_vk_init(struct wined3d_query_pool_vk *pool_vk, struct wined3d_context_vk *context_vk,
+        enum wined3d_query_type type, struct list *free_pools) DECLSPEC_HIDDEN;
+
+struct wined3d_query_pool_idx_vk
+{
+    struct wined3d_query_pool_vk *pool_vk;
+    size_t idx;
+};
+
+struct wined3d_query_vk
+{
+    struct wined3d_query q;
+
+    struct list entry;
+    struct wined3d_query_pool_idx_vk pool_idx;
+    bool started;
+    uint64_t command_buffer_id;
+    uint32_t control_flags;
+    size_t pending_count;
+};
+
+static inline struct wined3d_query_vk *wined3d_query_vk(struct wined3d_query *query)
+{
+    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,
+        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;
+void wined3d_query_vk_resume(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN;
+void wined3d_query_vk_suspend(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN;
+
 struct wined3d_gl_view
 {
     GLenum target;
@@ -2382,6 +2431,20 @@ 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;
@@ -2429,6 +2492,10 @@ struct wined3d_context_vk
     VkSampleCountFlagBits sample_count;
     unsigned int rt_count;
 
+    struct list active_queries;
+    struct wined3d_pending_queries_vk pending_queries;
+    struct list free_occlusion_query_pools;
+
     struct wined3d_retired_objects_vk retired;
     struct wine_rb_tree render_passes;
     struct wine_rb_tree pipeline_layouts;
@@ -2441,8 +2508,13 @@ 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;
 struct wined3d_allocator_block *wined3d_context_vk_allocate_memory(struct wined3d_context_vk *context_vk,
         unsigned int memory_type, VkDeviceSize size, VkDeviceMemory *vk_memory) 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,
         unsigned int pool, size_t size) DECLSPEC_HIDDEN;
 VkCommandBuffer wined3d_context_vk_apply_compute_state(struct wined3d_context_vk *context_vk,
@@ -2481,6 +2553,9 @@ void wined3d_context_vk_image_barrier(struct wined3d_context_vk *context_vk,
         VkImageLayout new_layout, VkImage image, VkImageAspectFlags aspect_mask) DECLSPEC_HIDDEN;
 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;
@@ -5780,6 +5855,12 @@ static inline void wined3d_context_vk_reference_texture(const struct wined3d_con
     texture_vk->command_buffer_id = context_vk->current_command_buffer.id;
 }
 
+static inline void wined3d_context_vk_reference_query(const struct wined3d_context_vk *context_vk,
+        struct wined3d_query_vk *query_vk)
+{
+    query_vk->command_buffer_id = context_vk->current_command_buffer.id;
+}
+
 static inline void wined3d_context_vk_reference_sampler(const struct wined3d_context_vk *context_vk,
         struct wined3d_sampler_vk *sampler_vk)
 {
@@ -5859,6 +5940,11 @@ static inline void wined3d_viewport_get_z_range(const struct wined3d_viewport *v
     *max_z = max(vp->max_z, vp->min_z + 0.001f);
 }
 
+static inline BOOL wined3d_bitmap_clear(uint32_t *map, unsigned int idx)
+{
+    return map[idx >> 5] &= ~(1u << (idx & 0x1f));
+}
+
 static inline BOOL wined3d_bitmap_set(uint32_t *map, unsigned int idx)
 {
     return map[idx >> 5] |= (1u << (idx & 0x1f));
-- 
2.20.1




More information about the wine-devel mailing list