diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 9133cd9d1f..f5e84c22f9 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -2828,6 +2828,7 @@ void VKGSRender::close_and_submit_command_buffer(VkFence fence, VkSemaphore wait { auto open_query = m_occlusion_map[m_active_query_info->driver_handle].indices.back(); m_occlusion_query_pool.end_query(*m_current_command_buffer, open_query); + m_current_command_buffer->flags &= ~vk::command_buffer::cb_has_open_query; } m_current_command_buffer->end(); @@ -3606,6 +3607,18 @@ void VKGSRender::discard_occlusion_query(rsx::reports::occlusion_query_info* que data.indices.clear(); } +void VKGSRender::emergency_query_cleanup(vk::command_buffer* commands) +{ + verify("Command list mismatch" HERE), commands == static_cast(m_current_command_buffer); + + if (m_current_command_buffer->flags & vk::command_buffer::cb_has_open_query) + { + auto open_query = m_occlusion_map[m_active_query_info->driver_handle].indices.back(); + m_occlusion_query_pool.end_query(*m_current_command_buffer, open_query); + m_current_command_buffer->flags &= ~vk::command_buffer::cb_has_open_query; + } +} + bool VKGSRender::on_decompiler_task() { return m_prog_buffer->async_update(8, *m_device, pipeline_layout).first; diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.h b/rpcs3/Emu/RSX/VK/VKGSRender.h index 744f8ca027..6120326636 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.h +++ b/rpcs3/Emu/RSX/VK/VKGSRender.h @@ -471,6 +471,9 @@ public: void get_occlusion_query_result(rsx::reports::occlusion_query_info* query) override; void discard_occlusion_query(rsx::reports::occlusion_query_info* query) override; + // External callback in case we need to suddenly submit a commandlist unexpectedly, e.g in a violation handler + void emergency_query_cleanup(vk::command_buffer* commands); + protected: void begin() override; void end() override; diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.cpp b/rpcs3/Emu/RSX/VK/VKHelpers.cpp index 04cab4d0d1..534662dbe7 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.cpp +++ b/rpcs3/Emu/RSX/VK/VKHelpers.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "VKHelpers.h" +#include "VKGSRender.h" #include "VKCompute.h" #include "VKRenderPass.h" #include "VKFramebuffer.h" @@ -771,6 +772,14 @@ namespace vk } } + void do_query_cleanup(vk::command_buffer& cmd) + { + auto renderer = dynamic_cast(rsx::get_current_renderer()); + verify(HERE), renderer; + + renderer->emergency_query_cleanup(&cmd); + } + void die_with_error(const char* faulting_addr, VkResult error_code) { std::string error_message; diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.h b/rpcs3/Emu/RSX/VK/VKHelpers.h index 38f0150011..ba96190784 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.h +++ b/rpcs3/Emu/RSX/VK/VKHelpers.h @@ -190,6 +190,10 @@ namespace vk VkResult wait_for_fence(VkFence pFence, u64 timeout = 0ull); VkResult wait_for_event(VkEvent pEvent, u64 timeout = 0ull); + // Handle unexpected submit with dangling occlusion query + // TODO: Move queries out of the renderer! + void do_query_cleanup(vk::command_buffer& cmd); + void die_with_error(const char* faulting_addr, VkResult error_code); struct memory_type_mapping @@ -1008,6 +1012,9 @@ private: return; } + // Check for hanging queries to avoid driver hang + verify("close and submit of commandbuffer with a hanging query!" HERE), (flags & cb_has_open_query) == 0; + if (!fence) { fence = m_submit_fence; diff --git a/rpcs3/Emu/RSX/VK/VKTextureCache.h b/rpcs3/Emu/RSX/VK/VKTextureCache.h index dd0502041f..fd5113e4cf 100644 --- a/rpcs3/Emu/RSX/VK/VKTextureCache.h +++ b/rpcs3/Emu/RSX/VK/VKTextureCache.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "stdafx.h" #include "VKRenderTargets.h" #include "VKGSRender.h" @@ -292,13 +292,8 @@ namespace vk } else { - // HACK - // Deletion of queued objects and subsequent driver reuse of handles is causing race conditions here - // TODO: Proper garbage collection for these things - vkResetEvent(*m_device, dma_fence); - // If this is speculated, it should only occur once - // verify(HERE), vkGetEventStatus(*m_device, dma_fence) == VK_EVENT_RESET; + verify(HERE), vkGetEventStatus(*m_device, dma_fence) == VK_EVENT_RESET; } cmd.set_flag(vk::command_buffer::cb_has_dma_transfer); @@ -1090,6 +1085,13 @@ namespace vk void cleanup_after_dma_transfers(vk::command_buffer& cmd) override { + bool occlusion_query_active = !!(cmd.flags & vk::command_buffer::cb_has_open_query); + if (occlusion_query_active) + { + // We really stepped in it + vk::do_query_cleanup(cmd); + } + // End recording cmd.end(); @@ -1116,6 +1118,12 @@ namespace vk } verify(HERE), cmd.flags == 0; + + if (occlusion_query_active) + { + verify(HERE), cmd.is_recording(); + cmd.flags |= vk::command_buffer::cb_load_occluson_task; + } } public: