diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp index 27eeeb58ba..cd1fbd9c82 100644 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp @@ -611,7 +611,7 @@ bool FramebufferManager::PopulateColorReadbackTexture() { // Can't be in our normal render pass. StateTracker::GetInstance()->EndRenderPass(); - StateTracker::GetInstance()->OnReadback(); + StateTracker::GetInstance()->OnCPUEFBAccess(); // Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on. VkRect2D src_region = {{0, 0}, {GetEFBWidth(), GetEFBHeight()}}; @@ -684,7 +684,7 @@ bool FramebufferManager::PopulateDepthReadbackTexture() { // Can't be in our normal render pass. StateTracker::GetInstance()->EndRenderPass(); - StateTracker::GetInstance()->OnReadback(); + StateTracker::GetInstance()->OnCPUEFBAccess(); // Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on. VkRect2D src_region = {{0, 0}, {GetEFBWidth(), GetEFBHeight()}}; diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp index 38a91c61ad..f3b2752ddd 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp @@ -513,7 +513,7 @@ void StateTracker::OnDraw() } } -void StateTracker::OnReadback() +void StateTracker::OnCPUEFBAccess() { // Check this isn't another access without any draws inbetween. if (!m_cpu_accesses_this_frame.empty() && m_cpu_accesses_this_frame.back() == m_draw_counter) @@ -523,9 +523,28 @@ void StateTracker::OnReadback() m_cpu_accesses_this_frame.emplace_back(m_draw_counter); } +void StateTracker::OnEFBCopyToRAM() +{ + // If we're not deferring, try to preempt it next frame. + if (!g_ActiveConfig.bDeferEFBCopies) + { + OnCPUEFBAccess(); + return; + } + + // Otherwise, only execute if we have at least 10 objects between us and the last copy. + const u32 diff = m_draw_counter - m_last_efb_copy_draw_counter; + m_last_efb_copy_draw_counter = m_draw_counter; + if (diff < MINIMUM_DRAW_CALLS_PER_COMMAND_BUFFER_FOR_READBACK) + return; + + Util::ExecuteCurrentCommandsAndRestoreState(true); +} + void StateTracker::OnEndFrame() { m_draw_counter = 0; + m_last_efb_copy_draw_counter = 0; m_scheduled_command_buffer_kicks.clear(); // If we have no CPU access at all, leave everything in the one command buffer for maximum diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.h b/Source/Core/VideoBackends/Vulkan/StateTracker.h index 547c62f655..895e139756 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.h +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.h @@ -86,8 +86,10 @@ public: void OnDraw(); // Call after CPU access is requested. - // This can be via EFBCache or EFB2RAM. - void OnReadback(); + void OnCPUEFBAccess(); + + // Call after an EFB copy to RAM. If true, the current command buffer should be executed. + void OnEFBCopyToRAM(); // Call at the end of a frame. void OnEndFrame(); @@ -182,6 +184,7 @@ private: // CPU access tracking u32 m_draw_counter = 0; + u32 m_last_efb_copy_draw_counter = 0; std::vector m_cpu_accesses_this_frame; std::vector m_scheduled_command_buffer_kicks; bool m_allow_background_execution = true; diff --git a/Source/Core/VideoBackends/Vulkan/TextureCache.cpp b/Source/Core/VideoBackends/Vulkan/TextureCache.cpp index dd61cce377..e9b92ba1e1 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/TextureCache.cpp @@ -126,7 +126,6 @@ void TextureCache::CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams& par // The barrier has to happen after the render pass, not inside it, as we are going to be // reading from the texture immediately afterwards. StateTracker::GetInstance()->EndRenderPass(); - StateTracker::GetInstance()->OnReadback(); // Transition to shader resource before reading. VkImageLayout original_layout = src_texture->GetLayout(); @@ -139,6 +138,8 @@ void TextureCache::CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams& par // Transition back to original state src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), original_layout); + + StateTracker::GetInstance()->OnEFBCopyToRAM(); } bool TextureCache::SupportsGPUTextureDecode(TextureFormat format, TLUTFormat palette_format)