Signed-off-by: Jan Sikorski jsikorski@codeweavers.com --- dlls/wined3d/context_vk.c | 28 +++++++++++++-- dlls/wined3d/query.c | 64 ++++++++++++++++++++++++++-------- dlls/wined3d/wined3d_private.h | 7 +++- 3 files changed, 81 insertions(+), 18 deletions(-)
diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c index 4b1bea38370..c718f3facd5 100644 --- a/dlls/wined3d/context_vk.c +++ b/dlls/wined3d/context_vk.c @@ -1285,13 +1285,26 @@ void wined3d_context_vk_end_current_render_pass(struct wined3d_context_vk *conte VkCommandBuffer vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer; const struct wined3d_vk_info *vk_info = context_vk->vk_info; struct wined3d_query_pool_vk *pool_vk, *pool_vk_next; + struct wined3d_query_vk *query_vk;
if (context_vk->vk_render_pass) { + LIST_FOR_EACH_ENTRY(query_vk, &context_vk->render_pass_queries, struct wined3d_query_vk, entry) + wined3d_query_vk_suspend(query_vk, context_vk); + VK_CALL(vkCmdEndRenderPass(vk_command_buffer)); context_vk->vk_render_pass = VK_NULL_HANDLE; VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 0, NULL)); + + LIST_FOR_EACH_ENTRY(query_vk, &context_vk->render_pass_queries, struct wined3d_query_vk, entry) + { + if (!wined3d_context_vk_allocate_query(context_vk, query_vk->q.type, &query_vk->pool_idx)) + { + ERR("Failed to allocate new query.\n"); + break; + } + } }
if (context_vk->vk_framebuffer) @@ -1561,6 +1574,12 @@ VkCommandBuffer wined3d_context_vk_get_command_buffer(struct wined3d_context_vk 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)) + { + ERR("Failed to allocate new query.\n"); + break; + } + wined3d_query_vk_resume(query_vk, context_vk); }
@@ -1594,12 +1613,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));
+ wined3d_context_vk_end_current_render_pass(context_vk); + 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; context_vk->update_stream_output = 1; @@ -2323,6 +2341,7 @@ static bool wined3d_context_vk_begin_render_pass(struct wined3d_context_vk *cont struct wined3d_rendertarget_view_vk *rtv_vk; struct wined3d_rendertarget_view *view; const VkPhysicalDeviceLimits *limits; + struct wined3d_query_vk *query_vk; VkRenderPassBeginInfo begin_info; unsigned int attachment_count, i; VkFramebufferCreateInfo fb_desc; @@ -2409,6 +2428,8 @@ static bool wined3d_context_vk_begin_render_pass(struct wined3d_context_vk *cont begin_info.pClearValues = NULL; VK_CALL(vkCmdBeginRenderPass(vk_command_buffer, &begin_info, VK_SUBPASS_CONTENTS_INLINE));
+ LIST_FOR_EACH_ENTRY(query_vk, &context_vk->render_pass_queries, struct wined3d_query_vk, entry) + wined3d_query_vk_resume(query_vk, context_vk); return true; }
@@ -3460,6 +3481,7 @@ 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->render_pass_queries); list_init(&context_vk->active_queries); list_init(&context_vk->completed_query_pools); list_init(&context_vk->free_occlusion_query_pools); diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c index 1e082f8ffae..4628cb98cdc 100644 --- a/dlls/wined3d/query.c +++ b/dlls/wined3d/query.c @@ -1548,11 +1548,6 @@ static void wined3d_query_vk_begin(struct wined3d_query_vk *query_vk, struct wined3d_query_pool_vk *pool_vk; size_t idx;
- if (!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;
@@ -1588,6 +1583,7 @@ void wined3d_query_vk_resume(struct wined3d_query_vk *query_vk, struct wined3d_c VkCommandBuffer vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer;
wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer); + query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE; }
void wined3d_query_vk_suspend(struct wined3d_query_vk *query_vk, struct wined3d_context_vk *context_vk) @@ -1597,6 +1593,7 @@ void wined3d_query_vk_suspend(struct wined3d_query_vk *query_vk, struct wined3d_ 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; + query_vk->flags &= ~WINED3D_QUERY_VK_FLAG_ACTIVE; }
static BOOL wined3d_query_vk_poll(struct wined3d_query *query, uint32_t flags) @@ -1655,30 +1652,69 @@ static BOOL wined3d_query_vk_issue(struct wined3d_query *query, uint32_t flags) 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); - if (query_vk->started) + if (query_vk->flags & WINED3D_QUERY_VK_FLAG_STARTED) { - wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer); + if (query_vk->flags & WINED3D_QUERY_VK_FLAG_ACTIVE) + wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer); list_remove(&query_vk->entry); } 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); - 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;
+ if (!wined3d_context_vk_allocate_query(context_vk, query_vk->q.type, &query_vk->pool_idx)) + { + ERR("Failed to allocate new query.\n"); + return false; + } + + /* A query need to either begin and end inside a single render pass, + * or begin and end ouside of a render pass. Occlusion queries, if issued + * ouside of a render pass, are queued up and only begun when a render + * pass is started, to avoid interrupting it when the query ends. */ + if (context_vk->vk_render_pass) + { + wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer); + list_add_head(&context_vk->render_pass_queries, &query_vk->entry); + query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE | WINED3D_QUERY_VK_FLAG_RENDER_PASS; + } + else if (query->type == WINED3D_QUERY_TYPE_OCCLUSION) + { + list_add_head(&context_vk->render_pass_queries, &query_vk->entry); + query_vk->flags |= WINED3D_QUERY_VK_FLAG_RENDER_PASS; + } + else + { + wined3d_query_vk_begin(query_vk, context_vk, vk_command_buffer); + list_add_head(&context_vk->active_queries, &query_vk->entry); + query_vk->flags |= WINED3D_QUERY_VK_FLAG_ACTIVE; + } + + query_vk->flags |= WINED3D_QUERY_VK_FLAG_STARTED; context_release(&context_vk->c); } - if (flags & WINED3DISSUE_END && query_vk->started) + if (flags & WINED3DISSUE_END && query_vk->flags & WINED3D_QUERY_VK_FLAG_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)) + * flushed or the render pass ended, we don't need to end it here. */ + if (query_vk->flags & WINED3D_QUERY_VK_FLAG_ACTIVE) + { + vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk); + if (!(query_vk->flags & WINED3D_QUERY_VK_FLAG_RENDER_PASS)) + wined3d_context_vk_end_current_render_pass(context_vk); wined3d_query_vk_end(query_vk, context_vk, vk_command_buffer); + } + else if (query_vk->pool_idx.pool_vk) + { + /* It was queued, but never activated. */ + wined3d_query_pool_vk_mark_complete(query_vk->pool_idx.pool_vk, + query_vk->pool_idx.idx, context_vk); + query_vk->pool_idx.pool_vk = NULL; + } list_remove(&query_vk->entry); - query_vk->started = false; + query_vk->flags = 0; poll = true;
context_release(&context_vk->c); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index a2048fc6ea6..86eae149306 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -2050,13 +2050,17 @@ struct wined3d_query_pool_idx_vk size_t idx; };
+#define WINED3D_QUERY_VK_FLAG_ACTIVE 0x00000001 +#define WINED3D_QUERY_VK_FLAG_STARTED 0x00000002 +#define WINED3D_QUERY_VK_FLAG_RENDER_PASS 0x00000004 + struct wined3d_query_vk { struct wined3d_query q;
struct list entry; struct wined3d_query_pool_idx_vk pool_idx; - bool started; + uint8_t flags; uint64_t command_buffer_id; uint32_t control_flags; size_t pending_count; @@ -2580,6 +2584,7 @@ struct wined3d_context_vk VkDeviceSize vk_so_offsets[WINED3D_MAX_STREAM_OUTPUT_BUFFERS]; struct wined3d_bo_vk vk_so_counter_bo;
+ struct list render_pass_queries; struct list active_queries; struct wined3d_pending_queries_vk pending_queries; struct list completed_query_pools;
Signed-off-by: Jan Sikorski jsikorski@codeweavers.com --- dlls/wined3d/adapter_vk.c | 9 ++++++++- dlls/wined3d/context_vk.c | 14 +++++++++++--- dlls/wined3d/query.c | 26 ++++++++++++++++++++------ dlls/wined3d/wined3d_vk.h | 4 +++- 4 files changed, 42 insertions(+), 11 deletions(-)
diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c index 850e2a6dfdb..9d419a94864 100644 --- a/dlls/wined3d/adapter_vk.c +++ b/dlls/wined3d/adapter_vk.c @@ -313,6 +313,7 @@ struct wined3d_physical_device_info { VkPhysicalDeviceTransformFeedbackFeaturesEXT xfb_features; VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vertex_divisor_features; + VkPhysicalDeviceHostQueryResetFeatures host_query_reset_features;
VkPhysicalDeviceFeatures2 features2; }; @@ -403,6 +404,7 @@ static HRESULT adapter_vk_create_device(struct wined3d *wined3d, const struct wi { const struct wined3d_adapter_vk *adapter_vk = wined3d_adapter_vk_const(adapter); VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT *vertex_divisor_features; + VkPhysicalDeviceHostQueryResetFeatures *host_query_reset_features; const struct wined3d_vk_info *vk_info = &adapter_vk->vk_info; VkPhysicalDeviceTransformFeedbackFeaturesEXT *xfb_features; struct wined3d_physical_device_info physical_device_info; @@ -435,9 +437,13 @@ static HRESULT adapter_vk_create_device(struct wined3d *wined3d, const struct wi vertex_divisor_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT; vertex_divisor_features->pNext = xfb_features;
+ host_query_reset_features = &physical_device_info.host_query_reset_features; + host_query_reset_features->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES; + host_query_reset_features->pNext = vertex_divisor_features; + features2 = &physical_device_info.features2; features2->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; - features2->pNext = vertex_divisor_features; + features2->pNext = host_query_reset_features;
if (vk_info->vk_ops.vkGetPhysicalDeviceFeatures2) VK_CALL(vkGetPhysicalDeviceFeatures2(physical_device, features2)); @@ -2195,6 +2201,7 @@ static bool wined3d_adapter_vk_init_device_extensions(struct wined3d_adapter_vk {VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME,VK_API_VERSION_1_2}, {VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, VK_API_VERSION_1_1, true}, {VK_KHR_SWAPCHAIN_EXTENSION_NAME, ~0u, true}, + {VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME, VK_API_VERSION_1_2}, };
static const struct diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c index c718f3facd5..f40e80dc3d4 100644 --- a/dlls/wined3d/context_vk.c +++ b/dlls/wined3d/context_vk.c @@ -1398,9 +1398,17 @@ bool wined3d_context_vk_allocate_query(struct wined3d_context_vk *context_vk, return false; }
- wined3d_context_vk_end_current_render_pass(context_vk); - VK_CALL(vkCmdResetQueryPool(wined3d_context_vk_get_command_buffer(context_vk), - pool_vk->vk_query_pool, 0, WINED3D_QUERY_POOL_SIZE)); + if (VK_CALL(vkResetQueryPoolEXT)) + { + VK_CALL(vkResetQueryPoolEXT(wined3d_device_vk(context_vk->c.device)->vk_device, + pool_vk->vk_query_pool, 0, WINED3D_QUERY_POOL_SIZE)); + } + else + { + wined3d_context_vk_end_current_render_pass(context_vk); + VK_CALL(vkCmdResetQueryPool(wined3d_context_vk_get_command_buffer(context_vk), + pool_vk->vk_query_pool, 0, WINED3D_QUERY_POOL_SIZE)); + }
if (!wined3d_query_pool_vk_allocate_query(pool_vk, &idx)) { diff --git a/dlls/wined3d/query.c b/dlls/wined3d/query.c index 4628cb98cdc..abec2544a45 100644 --- a/dlls/wined3d/query.c +++ b/dlls/wined3d/query.c @@ -1351,12 +1351,26 @@ 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) { - /* 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); + const struct wined3d_vk_info *vk_info = context_vk->vk_info; + + if (VK_CALL(vkResetQueryPoolEXT)) + { + 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); + } }
bool wined3d_query_pool_vk_allocate_query(struct wined3d_query_pool_vk *pool_vk, size_t *idx) diff --git a/dlls/wined3d/wined3d_vk.h b/dlls/wined3d/wined3d_vk.h index a417a795901..bba1e80218a 100644 --- a/dlls/wined3d/wined3d_vk.h +++ b/dlls/wined3d/wined3d_vk.h @@ -49,7 +49,9 @@ VK_INSTANCE_PFN(vkGetPhysicalDeviceSurfacePresentModesKHR) \ VK_INSTANCE_PFN(vkGetPhysicalDeviceSurfaceSupportKHR) \ /* VK_KHR_win32_surface */ \ - VK_INSTANCE_PFN(vkCreateWin32SurfaceKHR) + VK_INSTANCE_PFN(vkCreateWin32SurfaceKHR) \ + /* VK_EXT_host_query_reset */ \ + VK_INSTANCE_EXT_PFN(vkResetQueryPoolEXT)
#define VK_DEVICE_FUNCS() \ VK_DEVICE_PFN(vkAllocateCommandBuffers) \
On Wed, 28 Jul 2021 at 13:42, Jan Sikorski jsikorski@codeweavers.com wrote:
- if (VK_CALL(vkResetQueryPoolEXT))
- {
I think that works, but I'd prefer a proper extension check along the lines of "if (vk_info->supported[WINED3D_VK_EXT_HOST_QUERY_RESET])", similar to what we do for e.g. VK_EXT_transform_feedback.
Would it make sense to use this extension for vkd3d as well?
On 29 Jul 2021, at 16:24, Henri Verbeet hverbeet@gmail.com wrote:
On Wed, 28 Jul 2021 at 13:42, Jan Sikorski jsikorski@codeweavers.com wrote:
- if (VK_CALL(vkResetQueryPoolEXT))
- {
I think that works, but I'd prefer a proper extension check along the lines of "if (vk_info->supported[WINED3D_VK_EXT_HOST_QUERY_RESET])", similar to what we do for e.g. VK_EXT_transform_feedback.
Would it make sense to use this extension for vkd3d as well?
Looks like vkd3d could use a similar query handling upgrade - currently it halts the render pass each time a query is begun/ended, so just using host query reset won’t buy us anything.
- Jan