vk: Add support for spec-compliant query scopes

This commit is contained in:
kd-11 2024-12-22 00:20:46 +03:00 committed by kd-11
parent afc10ea112
commit 883529eaf3
6 changed files with 83 additions and 7 deletions

View File

@ -797,6 +797,16 @@ void VKGSRender::emit_geometry(u32 sub_index)
}
}
// Before starting a query, we need to match RP scope (VK_1_0 rules).
// We always want our queries to start outside a renderpass whenever possible.
// We ignore this for performance reasons whenever possible of course and only do this for sensitive drivers.
if (vk::use_strict_query_scopes() &&
vk::is_renderpass_open(*m_current_command_buffer))
{
vk::end_renderpass(*m_current_command_buffer);
emergency_query_cleanup(m_current_command_buffer);
}
// Begin query
m_occlusion_query_manager->begin_query(*m_current_command_buffer, occlusion_id);

View File

@ -2877,6 +2877,14 @@ void VKGSRender::end_occlusion_query(rsx::reports::occlusion_query_info* query)
// NOTE: flushing the queue is very expensive, do not flush just because query stopped
if (m_current_command_buffer->flags & vk::command_buffer::cb_has_open_query)
{
// VK_1_0 rules dictate that query must match subpass behavior on begin/end query.
// This is slow, so only do this for drivers that care.
if (vk::use_strict_query_scopes() &&
vk::is_renderpass_open(*m_current_command_buffer))
{
vk::end_renderpass(*m_current_command_buffer);
}
// End query
auto open_query = m_occlusion_map[m_active_query_info->driver_handle].indices.back();
m_occlusion_query_manager->end_query(*m_current_command_buffer, open_query);

View File

@ -31,6 +31,8 @@ namespace vk
bool g_drv_sanitize_fp_values = false;
bool g_drv_disable_fence_reset = false;
bool g_drv_emulate_cond_render = false;
bool g_drv_strict_query_scopes = false;
bool g_drv_force_reuse_query_pools = false;
u64 g_num_processed_frames = 0;
u64 g_num_total_frames = 0;
@ -231,6 +233,16 @@ namespace vk
return g_drv_emulate_cond_render;
}
bool use_strict_query_scopes()
{
return g_drv_strict_query_scopes;
}
bool force_reuse_query_pools()
{
return g_drv_force_reuse_query_pools;
}
void raise_status_interrupt(runtime_state status)
{
g_runtime_state |= status;

View File

@ -62,6 +62,8 @@ namespace vk
bool sanitize_fp_values();
bool fence_reset_disabled();
bool emulate_conditional_rendering();
bool use_strict_query_scopes();
bool force_reuse_query_pools();
VkFlags get_heap_compatible_buffer_types();
// Sync helpers around vkQueueSubmit

View File

@ -1,4 +1,5 @@
#include "stdafx.h"
#include "VKHelpers.h"
#include "VKQueryPool.h"
#include "VKRenderPass.h"
#include "VKResourceManager.h"
@ -74,13 +75,20 @@ namespace vk
{
ensure(!m_current_query_pool);
const u32 count = ::size32(query_slot_status);
m_current_query_pool = std::make_unique<query_pool>(*owner, query_type, count);
if (m_query_pool_cache.size() > 0)
{
m_current_query_pool = std::move(m_query_pool_cache.front());
m_query_pool_cache.pop_front();
}
else
{
const u32 count = ::size32(query_slot_status);
m_current_query_pool = std::make_unique<query_pool>(*owner, query_type, count);
}
// From spec: "After query pool creation, each query must be reset before it is used."
vkCmdResetQueryPool(cmd, *m_current_query_pool.get(), 0, count);
m_pool_lifetime_counter = count;
vkCmdResetQueryPool(cmd, *m_current_query_pool.get(), 0, m_current_query_pool->size());
m_pool_lifetime_counter = m_current_query_pool->size();
}
void query_pool_manager::reallocate_pool(vk::command_buffer& cmd)
@ -89,7 +97,8 @@ namespace vk
{
if (!m_current_query_pool->has_refs())
{
vk::get_resource_manager()->dispose(m_current_query_pool);
auto ref = std::make_unique<query_pool_ref>(this, m_current_query_pool);
vk::get_resource_manager()->dispose(ref);
}
else
{
@ -112,7 +121,8 @@ namespace vk
{
if (!(*It)->has_refs())
{
vk::get_resource_manager()->dispose(*It);
auto ref = std::make_unique<query_pool_ref>(this, *It);
vk::get_resource_manager()->dispose(ref);
It = m_consumed_pools.erase(It);
}
else
@ -219,4 +229,21 @@ namespace vk
return ~0u;
}
void query_pool_manager::on_query_pool_released(std::unique_ptr<vk::query_pool>& pool)
{
if (!vk::force_reuse_query_pools())
{
// Delete and let the driver recreate a new pool each time.
pool.reset();
return;
}
m_query_pool_cache.emplace_back(std::move(pool));
}
query_pool_manager::query_pool_ref::~query_pool_ref()
{
m_pool_man->on_query_pool_released(m_object);
}
}

View File

@ -19,7 +19,22 @@ namespace vk
u32 data;
};
class query_pool_ref
{
std::unique_ptr<query_pool> m_object;
query_pool_manager* m_pool_man;
public:
query_pool_ref(query_pool_manager* pool_man, std::unique_ptr<query_pool>& pool)
: m_object(std::move(pool))
, m_pool_man(pool_man)
{}
~query_pool_ref();
};
std::vector<std::unique_ptr<query_pool>> m_consumed_pools;
std::deque<std::unique_ptr<query_pool>> m_query_pool_cache;
std::unique_ptr<query_pool> m_current_query_pool;
std::deque<u32> m_available_slots;
u32 m_pool_lifetime_counter = 0;
@ -52,6 +67,8 @@ namespace vk
u32 allocate_query(vk::command_buffer& cmd);
void free_query(vk::command_buffer&/*cmd*/, u32 index);
void on_query_pool_released(std::unique_ptr<vk::query_pool>& pool);
template<template<class> class _List>
void free_queries(vk::command_buffer& cmd, _List<u32>& list)
{