diff --git a/rpcs3/Emu/RSX/VK/VKDraw.cpp b/rpcs3/Emu/RSX/VK/VKDraw.cpp index f15541a968..ef268cfda3 100644 --- a/rpcs3/Emu/RSX/VK/VKDraw.cpp +++ b/rpcs3/Emu/RSX/VK/VKDraw.cpp @@ -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); diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 5a02197548..5de8f62d92 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -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); diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.cpp b/rpcs3/Emu/RSX/VK/VKHelpers.cpp index 59ad7777ed..7789661ef2 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.cpp +++ b/rpcs3/Emu/RSX/VK/VKHelpers.cpp @@ -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; diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.h b/rpcs3/Emu/RSX/VK/VKHelpers.h index 0db4c7153f..281aab5f1b 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.h +++ b/rpcs3/Emu/RSX/VK/VKHelpers.h @@ -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 diff --git a/rpcs3/Emu/RSX/VK/VKQueryPool.cpp b/rpcs3/Emu/RSX/VK/VKQueryPool.cpp index 449d8d13b9..3fd80a8d67 100644 --- a/rpcs3/Emu/RSX/VK/VKQueryPool.cpp +++ b/rpcs3/Emu/RSX/VK/VKQueryPool.cpp @@ -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(*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(*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(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(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& 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); + } } diff --git a/rpcs3/Emu/RSX/VK/VKQueryPool.h b/rpcs3/Emu/RSX/VK/VKQueryPool.h index 6aa1e19978..009afca379 100644 --- a/rpcs3/Emu/RSX/VK/VKQueryPool.h +++ b/rpcs3/Emu/RSX/VK/VKQueryPool.h @@ -19,7 +19,22 @@ namespace vk u32 data; }; + class query_pool_ref + { + std::unique_ptr m_object; + query_pool_manager* m_pool_man; + + public: + query_pool_ref(query_pool_manager* pool_man, std::unique_ptr& pool) + : m_object(std::move(pool)) + , m_pool_man(pool_man) + {} + + ~query_pool_ref(); + }; + std::vector> m_consumed_pools; + std::deque> m_query_pool_cache; std::unique_ptr m_current_query_pool; std::deque 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& pool); + template class _List> void free_queries(vk::command_buffer& cmd, _List& list) {