wined3d: Avoid waiting for a command buffer to finish executing to read off its queries.

Some games wait for query results on the frame executing the query,
expecting that enough time have passed for it to be available. By
requiring that the entire command buffer is done, we risk stalling the
whole frame if it wasn't flushed along the way. This patch drops this
requirement.

Mainly, we need to ensure that we don't call vkGetQueryPoolResults()
before the reset command is executed, and accidentally retrieve result
from previous usage. Using host query reset doesn't quite solve the
problem, as it might get called too early, if the application decides to
reuse a query without waiting for results. Besides, we want to support
devices where host query reset is not available.

To make it work, when a Vulkan query is no longer needed, we queue it
for resetting at command buffer submission time, and only mark it free
for reuse after this command buffer is finished executing.

Signed-off-by: Jan Sikorski <jsikorski@codeweavers.com>
Signed-off-by: Henri Verbeet <hverbeet@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jan Sikorski 2022-02-10 15:21:56 +01:00 committed by Alexandre Julliard
parent 8981c32fa2
commit 9a799898a1
3 changed files with 124 additions and 62 deletions

View File

@ -906,6 +906,41 @@ void wined3d_context_vk_destroy_vk_image_view(struct wined3d_context_vk *context
o->command_buffer_id = command_buffer_id; o->command_buffer_id = command_buffer_id;
} }
static void wined3d_context_vk_reset_completed_queries(struct wined3d_context_vk *context_vk,
struct wined3d_query_pool_vk *pool_vk, struct wined3d_command_buffer_vk *buffer)
{
const struct wined3d_vk_info *vk_info = context_vk->vk_info;
struct wined3d_retired_object_vk *o;
struct wined3d_range range;
unsigned int start = 0;
for (;;)
{
if (!wined3d_bitmap_get_range(pool_vk->completed, WINED3D_QUERY_POOL_SIZE, start, &range))
break;
VK_CALL(vkCmdResetQueryPool(buffer->vk_command_buffer, pool_vk->vk_query_pool, range.offset, range.size));
if (!(o = wined3d_context_vk_get_retired_object_vk(context_vk)))
{
ERR("Freeing query range %u+%u in pool %p.\n", range.offset, range.size, pool_vk);
wined3d_query_pool_vk_mark_free(context_vk, pool_vk, range.offset, range.size);
}
else
{
o->type = WINED3D_RETIRED_QUERY_POOL_VK;
o->u.queries.pool_vk = pool_vk;
o->u.queries.start = range.offset;
o->u.queries.count = range.size;
o->command_buffer_id = buffer->id;
}
start = range.offset + range.size;
}
memset(pool_vk->completed, 0, sizeof(pool_vk->completed));
}
void wined3d_context_vk_destroy_vk_sampler(struct wined3d_context_vk *context_vk, void wined3d_context_vk_destroy_vk_sampler(struct wined3d_context_vk *context_vk,
VkSampler vk_sampler, uint64_t command_buffer_id) VkSampler vk_sampler, uint64_t command_buffer_id)
{ {
@ -1084,6 +1119,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)); TRACE("Destroyed sampler 0x%s.\n", wine_dbgstr_longlong(o->u.vk_sampler));
break; break;
case WINED3D_RETIRED_QUERY_POOL_VK:
wined3d_query_pool_vk_mark_free(context_vk, o->u.queries.pool_vk, o->u.queries.start, o->u.queries.count);
TRACE("Freed query range %u+%u in pool %p.\n", o->u.queries.start, o->u.queries.count, o->u.queries.pool_vk);
break;
default: default:
ERR("Unhandled object type %#x.\n", o->type); ERR("Unhandled object type %#x.\n", o->type);
break; break;
@ -1339,7 +1379,6 @@ 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; VkCommandBuffer vk_command_buffer = context_vk->current_command_buffer.vk_command_buffer;
const struct wined3d_vk_info *vk_info = context_vk->vk_info; 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; struct wined3d_query_vk *query_vk;
if (context_vk->vk_render_pass) if (context_vk->vk_render_pass)
@ -1368,17 +1407,6 @@ void wined3d_context_vk_end_current_render_pass(struct wined3d_context_vk *conte
context_vk->vk_framebuffer, context_vk->current_command_buffer.id); context_vk->vk_framebuffer, context_vk->current_command_buffer.id);
context_vk->vk_framebuffer = VK_NULL_HANDLE; context_vk->vk_framebuffer = VK_NULL_HANDLE;
} }
if (vk_command_buffer)
{
LIST_FOR_EACH_ENTRY_SAFE(pool_vk, pool_vk_next, &context_vk->completed_query_pools,
struct wined3d_query_pool_vk, completed_entry)
{
list_remove(&pool_vk->completed_entry);
list_init(&pool_vk->completed_entry);
wined3d_query_pool_vk_reset(pool_vk, context_vk, vk_command_buffer);
}
}
} }
static void wined3d_context_vk_destroy_render_pass(struct wine_rb_entry *entry, void *ctx) static void wined3d_context_vk_destroy_render_pass(struct wine_rb_entry *entry, void *ctx)
@ -1411,7 +1439,9 @@ bool wined3d_context_vk_allocate_query(struct wined3d_context_vk *context_vk,
{ {
const struct wined3d_vk_info *vk_info = context_vk->vk_info; const struct wined3d_vk_info *vk_info = context_vk->vk_info;
struct wined3d_query_pool_vk *pool_vk, *entry; struct wined3d_query_pool_vk *pool_vk, *entry;
struct wined3d_device_vk *device_vk;
struct list *free_pools; struct list *free_pools;
VkResult vr;
size_t idx; size_t idx;
switch (type) switch (type)
@ -1457,16 +1487,39 @@ bool wined3d_context_vk_allocate_query(struct wined3d_context_vk *context_vk,
return false; return false;
} }
device_vk = wined3d_device_vk(context_vk->c.device);
if (vk_info->supported[WINED3D_VK_EXT_HOST_QUERY_RESET]) if (vk_info->supported[WINED3D_VK_EXT_HOST_QUERY_RESET])
{ {
VK_CALL(vkResetQueryPoolEXT(wined3d_device_vk(context_vk->c.device)->vk_device, VK_CALL(vkResetQueryPoolEXT(device_vk->vk_device,
pool_vk->vk_query_pool, 0, WINED3D_QUERY_POOL_SIZE)); pool_vk->vk_query_pool, 0, WINED3D_QUERY_POOL_SIZE));
} }
else else
{ {
VkEventCreateInfo event_create_info;
wined3d_context_vk_end_current_render_pass(context_vk); wined3d_context_vk_end_current_render_pass(context_vk);
VK_CALL(vkCmdResetQueryPool(wined3d_context_vk_get_command_buffer(context_vk), VK_CALL(vkCmdResetQueryPool(wined3d_context_vk_get_command_buffer(context_vk),
pool_vk->vk_query_pool, 0, WINED3D_QUERY_POOL_SIZE)); pool_vk->vk_query_pool, 0, WINED3D_QUERY_POOL_SIZE));
event_create_info.sType = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
event_create_info.pNext = NULL;
event_create_info.flags = 0;
/* We probably shouldn't call vkGetQueryPoolResults() without synchronizing with vkCmdResetQueryPool()
* even if the query pool is freshly allocated. wined3d_query_vk_accumulate_data() will check this event
* before returning results. */
vr = VK_CALL(vkCreateEvent(device_vk->vk_device, &event_create_info, NULL, &pool_vk->vk_event));
if (vr == VK_SUCCESS)
{
/* At which stage vkCmdResetQueryPool() executes? */
VK_CALL(vkCmdSetEvent(wined3d_context_vk_get_command_buffer(context_vk), pool_vk->vk_event,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT));
}
else
{
ERR("Failed to create event, vr %s.\n", wined3d_debug_vkresult(vr));
}
} }
if (!wined3d_query_pool_vk_allocate_query(pool_vk, &idx)) if (!wined3d_query_pool_vk_allocate_query(pool_vk, &idx))
@ -1662,6 +1715,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); struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
const struct wined3d_vk_info *vk_info = context_vk->vk_info; const struct wined3d_vk_info *vk_info = context_vk->vk_info;
struct wined3d_query_pool_vk *pool_vk, *pool_vk_next;
struct wined3d_command_buffer_vk *buffer; struct wined3d_command_buffer_vk *buffer;
struct wined3d_query_vk *query_vk; struct wined3d_query_vk *query_vk;
VkFenceCreateInfo fence_desc; VkFenceCreateInfo fence_desc;
@ -1682,6 +1736,15 @@ void wined3d_context_vk_submit_command_buffer(struct wined3d_context_vk *context
wined3d_context_vk_end_current_render_pass(context_vk); wined3d_context_vk_end_current_render_pass(context_vk);
LIST_FOR_EACH_ENTRY_SAFE(pool_vk, pool_vk_next, &context_vk->completed_query_pools,
struct wined3d_query_pool_vk, completed_entry)
{
list_remove(&pool_vk->completed_entry);
list_init(&pool_vk->completed_entry);
wined3d_context_vk_reset_completed_queries(context_vk, pool_vk, buffer);
}
LIST_FOR_EACH_ENTRY(query_vk, &context_vk->active_queries, struct wined3d_query_vk, entry) LIST_FOR_EACH_ENTRY(query_vk, &context_vk->active_queries, struct wined3d_query_vk, entry)
wined3d_query_vk_suspend(query_vk, context_vk); wined3d_query_vk_suspend(query_vk, context_vk);

View File

@ -1351,26 +1351,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, static void wined3d_query_pool_vk_mark_complete(struct wined3d_query_pool_vk *pool_vk, size_t idx,
struct wined3d_context_vk *context_vk) struct wined3d_context_vk *context_vk)
{ {
const struct wined3d_vk_info *vk_info = context_vk->vk_info; /* Don't reset completed queries right away, as vkCmdResetQueryPool() needs to happen
* outside of a render pass. Queue the query to be reset at the very end of the current
if (vk_info->supported[WINED3D_VK_EXT_HOST_QUERY_RESET]) * command buffer instead. */
{ wined3d_bitmap_set(pool_vk->completed, idx);
VK_CALL(vkResetQueryPoolEXT(wined3d_device_vk(context_vk->c.device)->vk_device, if (list_empty(&pool_vk->completed_entry))
pool_vk->vk_query_pool, idx, 1)); list_add_tail(&context_vk->completed_query_pools, &pool_vk->completed_entry);
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) bool wined3d_query_pool_vk_allocate_query(struct wined3d_query_pool_vk *pool_vk, size_t *idx)
@ -1382,38 +1368,30 @@ bool wined3d_query_pool_vk_allocate_query(struct wined3d_query_pool_vk *pool_vk,
return true; return true;
} }
void wined3d_query_pool_vk_mark_free(struct wined3d_context_vk *context_vk, struct wined3d_query_pool_vk *pool_vk,
uint32_t start, uint32_t count)
{
unsigned int idx, end = start + count;
for (idx = start; idx < end; ++idx)
wined3d_bitmap_clear(pool_vk->allocated, idx);
if (list_empty(&pool_vk->entry))
list_add_tail(pool_vk->free_list, &pool_vk->entry);
}
void wined3d_query_pool_vk_cleanup(struct wined3d_query_pool_vk *pool_vk, struct wined3d_context_vk *context_vk) 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); struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
const struct wined3d_vk_info *vk_info = context_vk->vk_info; const struct wined3d_vk_info *vk_info = context_vk->vk_info;
VK_CALL(vkDestroyQueryPool(device_vk->vk_device, pool_vk->vk_query_pool, NULL)); VK_CALL(vkDestroyQueryPool(device_vk->vk_device, pool_vk->vk_query_pool, NULL));
if (pool_vk->vk_event)
VK_CALL(vkDestroyEvent(device_vk->vk_device, pool_vk->vk_event, NULL));
list_remove(&pool_vk->entry); list_remove(&pool_vk->entry);
list_remove(&pool_vk->completed_entry); list_remove(&pool_vk->completed_entry);
} }
void wined3d_query_pool_vk_reset(struct wined3d_query_pool_vk *pool_vk, struct wined3d_context_vk *context_vk,
VkCommandBuffer vk_command_buffer)
{
const struct wined3d_vk_info *vk_info = context_vk->vk_info;
unsigned int start = 0, idx;
struct wined3d_range range;
for (;;)
{
if (!wined3d_bitmap_get_range(pool_vk->completed, WINED3D_QUERY_POOL_SIZE, start, &range))
break;
VK_CALL(vkCmdResetQueryPool(vk_command_buffer, pool_vk->vk_query_pool, range.offset, range.size));
start = range.offset + range.size;
for (idx = range.offset; idx < start; ++idx)
wined3d_bitmap_clear(pool_vk->allocated, idx);
}
memset(pool_vk->completed, 0, sizeof(pool_vk->completed));
if (list_empty(&pool_vk->entry))
list_add_tail(pool_vk->free_list, &pool_vk->entry);
}
bool wined3d_query_pool_vk_init(struct wined3d_query_pool_vk *pool_vk, 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_context_vk *context_vk, enum wined3d_query_type type, struct list *free_pools)
{ {
@ -1499,6 +1477,23 @@ bool wined3d_query_vk_accumulate_data(struct wined3d_query_vk *query_vk,
struct wined3d_query_data_so_statistics so_statistics; struct wined3d_query_data_so_statistics so_statistics;
} tmp, *result; } tmp, *result;
if (pool_idx->pool_vk->vk_event)
{
/* Check if the pool's initial reset command executed. */
vr = VK_CALL(vkGetEventStatus(device_vk->vk_device,
pool_idx->pool_vk->vk_event));
if (vr == VK_EVENT_RESET)
return false;
else if (vr != VK_EVENT_SET)
{
ERR("Failed to get event status, vr %s\n", wined3d_debug_vkresult(vr));
return false;
}
VK_CALL(vkDestroyEvent(device_vk->vk_device, pool_idx->pool_vk->vk_event, NULL));
pool_idx->pool_vk->vk_event = VK_NULL_HANDLE;
}
if ((vr = VK_CALL(vkGetQueryPoolResults(device_vk->vk_device, pool_idx->pool_vk->vk_query_pool, 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) pool_idx->idx, 1, sizeof(tmp), &tmp, sizeof(tmp), VK_QUERY_RESULT_64_BIT))) < 0)
{ {
@ -1622,11 +1617,6 @@ static BOOL wined3d_query_vk_poll(struct wined3d_query *query, uint32_t flags)
if (query_vk->command_buffer_id == context_vk->current_command_buffer.id) if (query_vk->command_buffer_id == context_vk->current_command_buffer.id)
goto unavailable; 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) if (query_vk->pending_count)
wined3d_context_vk_accumulate_pending_queries(context_vk); wined3d_context_vk_accumulate_pending_queries(context_vk);
if (query_vk->pending_count) if (query_vk->pending_count)

View File

@ -2083,15 +2083,17 @@ struct wined3d_query_pool_vk
struct list *free_list; struct list *free_list;
VkQueryPool vk_query_pool; VkQueryPool vk_query_pool;
VkEvent vk_event;
uint32_t allocated[WINED3D_BITMAP_SIZE(WINED3D_QUERY_POOL_SIZE)]; uint32_t allocated[WINED3D_BITMAP_SIZE(WINED3D_QUERY_POOL_SIZE)];
uint32_t completed[WINED3D_BITMAP_SIZE(WINED3D_QUERY_POOL_SIZE)]; uint32_t completed[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; bool wined3d_query_pool_vk_allocate_query(struct wined3d_query_pool_vk *pool_vk, size_t *idx) DECLSPEC_HIDDEN;
void wined3d_query_pool_vk_mark_free(struct wined3d_context_vk *context_vk, struct wined3d_query_pool_vk *pool_vk,
uint32_t start, uint32_t count) DECLSPEC_HIDDEN;
void wined3d_query_pool_vk_cleanup(struct wined3d_query_pool_vk *pool_vk, void wined3d_query_pool_vk_cleanup(struct wined3d_query_pool_vk *pool_vk,
struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN; struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN;
void wined3d_query_pool_vk_reset(struct wined3d_query_pool_vk *pool_vk, struct wined3d_context_vk *context_vk,
VkCommandBuffer vk_command_buffer) DECLSPEC_HIDDEN;
bool wined3d_query_pool_vk_init(struct wined3d_query_pool_vk *pool_vk, struct wined3d_context_vk *context_vk, 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; enum wined3d_query_type type, struct list *free_pools) DECLSPEC_HIDDEN;
@ -2439,6 +2441,7 @@ enum wined3d_retired_object_type_vk
WINED3D_RETIRED_BUFFER_VIEW_VK, WINED3D_RETIRED_BUFFER_VIEW_VK,
WINED3D_RETIRED_IMAGE_VIEW_VK, WINED3D_RETIRED_IMAGE_VIEW_VK,
WINED3D_RETIRED_SAMPLER_VK, WINED3D_RETIRED_SAMPLER_VK,
WINED3D_RETIRED_QUERY_POOL_VK,
}; };
struct wined3d_retired_object_vk struct wined3d_retired_object_vk
@ -2461,6 +2464,12 @@ struct wined3d_retired_object_vk
VkBufferView vk_buffer_view; VkBufferView vk_buffer_view;
VkImageView vk_image_view; VkImageView vk_image_view;
VkSampler vk_sampler; VkSampler vk_sampler;
struct
{
struct wined3d_query_pool_vk *pool_vk;
uint32_t start;
uint32_t count;
} queries;
} u; } u;
uint64_t command_buffer_id; uint64_t command_buffer_id;
}; };