From 9f94a6dc1198f08e791e8f34ba25198caed2b01c Mon Sep 17 00:00:00 2001 From: kd-11 Date: Wed, 11 Dec 2019 19:28:57 +0300 Subject: [PATCH] vk: Refactoring and optimizations to query handling - Caches query results when looking up report availability to avoid entering driver code twice. - Minor code restructuring --- rpcs3/Emu/RSX/VK/VKGSRender.cpp | 51 ++++++--------- rpcs3/Emu/RSX/VK/VKHelpers.h | 109 +++++++++++++++++++++----------- 2 files changed, 92 insertions(+), 68 deletions(-) diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index b6f47e8235..7f09548fd9 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -2224,52 +2224,43 @@ void VKGSRender::sync_hint(rsx::FIFO_hint hint, void* args) verify(HERE), args; rsx::thread::sync_hint(hint, args); + // Occlusion queries not enabled, do nothing + if (!(m_current_command_buffer->flags & vk::command_buffer::cb_has_occlusion_task)) + return; + + // Check if the required report is synced to this CB + auto occlusion_info = static_cast(args); + auto& data = m_occlusion_map[occlusion_info->driver_handle]; + + if (data.command_buffer_to_wait != m_current_command_buffer || data.indices.empty()) + return; + // Occlusion test result evaluation is coming up, avoid a hard sync switch (hint) { case rsx::FIFO_hint::hint_conditional_render_eval: { - // Occlusion queries not enabled, do nothing - if (!(m_current_command_buffer->flags & vk::command_buffer::cb_has_occlusion_task)) - return; - // If a flush request is already enqueued, do nothing if (m_flush_requests.pending()) return; - // Check if the required report is synced to this CB - auto occlusion_info = static_cast(args); - auto& data = m_occlusion_map[occlusion_info->driver_handle]; - - if (data.command_buffer_to_wait == m_current_command_buffer && !data.indices.empty()) - { - // Confirmed hard sync coming up, post a sync request - m_flush_requests.post(false); - m_flush_requests.remove_one(); - } - + // Schedule a sync on the next loop iteration + m_flush_requests.post(false); + m_flush_requests.remove_one(); break; } case rsx::FIFO_hint::hint_zcull_sync: { - if (!(m_current_command_buffer->flags & vk::command_buffer::cb_has_occlusion_task)) - return; + // Unavoidable hard sync coming up, flush immediately + // This heavyweight hint should be used with caution + std::lock_guard lock(m_flush_queue_mutex); + flush_command_queue(); - auto occlusion_info = static_cast(args); - auto& data = m_occlusion_map[occlusion_info->driver_handle]; - - if (data.command_buffer_to_wait == m_current_command_buffer && !data.indices.empty()) + if (m_flush_requests.pending()) { - std::lock_guard lock(m_flush_queue_mutex); - flush_command_queue(); - - if (m_flush_requests.pending()) - { - // Clear without wait - m_flush_requests.clear_pending_flag(); - } + // Clear without wait + m_flush_requests.clear_pending_flag(); } - break; } } diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.h b/rpcs3/Emu/RSX/VK/VKHelpers.h index fb776dfb7c..f11e072453 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.h +++ b/rpcs3/Emu/RSX/VK/VKHelpers.h @@ -2991,11 +2991,62 @@ public: class occlusion_query_pool { + struct query_slot_info + { + bool any_passed; + bool active; + bool ready; + }; + VkQueryPool query_pool = VK_NULL_HANDLE; vk::render_device* owner = nullptr; std::deque available_slots; - std::vector query_active_status; + std::vector query_slot_status; + + inline bool poke_query(query_slot_info& query, u32 index) + { + // Query is ready if: + // 1. Any sample has been determined to have passed the Z test + // 2. The backend has fully processed the query and found no hits + + u32 result[2] = { 0, 0 }; + switch (const auto error = vkGetQueryPoolResults(*owner, query_pool, index, 1, 8, result, 8, VK_QUERY_RESULT_PARTIAL_BIT | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)) + { + case VK_SUCCESS: + { + if (result[0]) + { + query.any_passed = true; + query.ready = true; + return true; + } + else if (result[1]) + { + query.any_passed = false; + query.ready = true; + return true; + } + + return false; + } + case VK_NOT_READY: + { + if (result[0]) + { + query.any_passed = true; + query.ready = true; + return true; + } + + return false; + } + default: + die_with_error(HERE, error); + return false; + } + } + public: void create(vk::render_device &dev, u32 num_entries) @@ -3009,7 +3060,7 @@ public: owner = &dev; // From spec: "After query pool creation, each query must be reset before it is used." - query_active_status.resize(num_entries, true); + query_slot_status.resize(num_entries, {}); } void destroy() @@ -3025,10 +3076,11 @@ public: void initialize(vk::command_buffer &cmd) { - const u32 count = ::size32(query_active_status); + const u32 count = ::size32(query_slot_status); vkCmdResetQueryPool(cmd, query_pool, 0, count); - std::fill(query_active_status.begin(), query_active_status.end(), false); + query_slot_info value{}; + std::fill(query_slot_status.begin(), query_slot_status.end(), value); for (u32 n = 0; n < count; ++n) { @@ -3038,14 +3090,15 @@ public: void begin_query(vk::command_buffer &cmd, u32 index) { - if (query_active_status[index]) + if (query_slot_status[index].active) { //Synchronization must be done externally vkCmdResetQueryPool(cmd, query_pool, index, 1); + query_slot_status[index] = {}; } vkCmdBeginQuery(cmd, query_pool, index, 0);//VK_QUERY_CONTROL_PRECISE_BIT); - query_active_status[index] = true; + query_slot_status[index].active = true; } void end_query(vk::command_buffer &cmd, u32 index) @@ -3055,40 +3108,20 @@ public: bool check_query_status(u32 index) { - u32 result[2] = {0, 0}; - switch (const auto error = vkGetQueryPoolResults(*owner, query_pool, index, 1, 8, result, 8, VK_QUERY_RESULT_PARTIAL_BIT | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)) - { - case VK_SUCCESS: - return (result[0] || result[1]); - case VK_NOT_READY: - return false; - default: - die_with_error(HERE, error); - return false; - } + return poke_query(query_slot_status[index], index); } u32 get_query_result(u32 index) { - u32 result[2] = { 0, 0 }; + // Check for cached result + auto& query_info = query_slot_status[index]; - do + while (!query_info.ready) { - switch (const auto error = vkGetQueryPoolResults(*owner, query_pool, index, 1, 8, result, 8, VK_QUERY_RESULT_PARTIAL_BIT | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)) - { - case VK_SUCCESS: - if (result[0]) return 1u; - if (result[1]) return 0u; // Partial result can return SUCCESS when unavailable - continue; - case VK_NOT_READY: - if (result[0]) return 1u; // Partial result can return NOT_READY when unavailable - continue; - default: - die_with_error(HERE, error); - return false; - } + poke_query(query_info, index); } - while (true); + + return query_info.any_passed ? 1 : 0; } void get_query_result_indirect(vk::command_buffer &cmd, u32 index, VkBuffer dst, VkDeviceSize dst_offset) @@ -3098,11 +3131,11 @@ public: void reset_query(vk::command_buffer &cmd, u32 index) { - if (query_active_status[index]) + if (query_slot_status[index].active) { vkCmdResetQueryPool(cmd, query_pool, index, 1); - query_active_status[index] = false; + query_slot_status[index] = {}; available_slots.push_back(index); } } @@ -3116,9 +3149,9 @@ public: void reset_all(vk::command_buffer &cmd) { - for (u32 n = 0; n < query_active_status.size(); n++) + for (u32 n = 0; n < query_slot_status.size(); n++) { - if (query_active_status[n]) + if (query_slot_status[n].active) reset_query(cmd, n); } } @@ -3133,7 +3166,7 @@ public: u32 result = available_slots.front(); available_slots.pop_front(); - verify(HERE), !query_active_status[result]; + verify(HERE), !query_slot_status[result].active; return result; } };