Commit 9a799898 authored by Jan Sikorski's avatar Jan Sikorski Committed by Alexandre Julliard

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: 's avatarJan Sikorski <jsikorski@codeweavers.com> Signed-off-by: 's avatarHenri Verbeet <hverbeet@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent 8981c32f
......@@ -906,6 +906,41 @@ void wined3d_context_vk_destroy_vk_image_view(struct wined3d_context_vk *context
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,
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));
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:
ERR("Unhandled object type %#x.\n", o->type);
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;
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)
......@@ -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 = 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)
......@@ -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;
struct wined3d_query_pool_vk *pool_vk, *entry;
struct wined3d_device_vk *device_vk;
struct list *free_pools;
VkResult vr;
size_t idx;
switch (type)
......@@ -1457,16 +1487,39 @@ bool wined3d_context_vk_allocate_query(struct wined3d_context_vk *context_vk,
return false;
}
device_vk = wined3d_device_vk(context_vk->c.device);
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));
}
else
{
VkEventCreateInfo event_create_info;
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));
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))
......@@ -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);
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_query_vk *query_vk;
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);
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)
wined3d_query_vk_suspend(query_vk, context_vk);
......
......@@ -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,
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 at the very end of the current
* command buffer instead. */
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)
......@@ -1382,38 +1368,30 @@ bool wined3d_query_pool_vk_allocate_query(struct wined3d_query_pool_vk *pool_vk,
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)
{
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));
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->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,
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;
} 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,
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)
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)
......
......@@ -2083,15 +2083,17 @@ struct wined3d_query_pool_vk
struct list *free_list;
VkQueryPool vk_query_pool;
VkEvent vk_event;
uint32_t allocated[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;
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,
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,
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_IMAGE_VIEW_VK,
WINED3D_RETIRED_SAMPLER_VK,
WINED3D_RETIRED_QUERY_POOL_VK,
};
struct wined3d_retired_object_vk
......@@ -2461,6 +2464,12 @@ struct wined3d_retired_object_vk
VkBufferView vk_buffer_view;
VkImageView vk_image_view;
VkSampler vk_sampler;
struct
{
struct wined3d_query_pool_vk *pool_vk;
uint32_t start;
uint32_t count;
} queries;
} u;
uint64_t command_buffer_id;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment