From 7d24fca4e22bec969f3fd5d05f186c91a9f7af48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 25 Oct 2024 12:00:28 +0200 Subject: [PATCH] Crashfix when switching buffered/non-buffered with the game running --- Common/GPU/Vulkan/VulkanRenderManager.cpp | 12 ++++++++---- Core/System.cpp | 1 - GPU/Common/FramebufferManagerCommon.cpp | 6 ++++++ UI/EmuScreen.cpp | 7 +++++-- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index b774d4123d..259cac7dcc 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -370,8 +370,10 @@ void VulkanRenderManager::StartThreads() { // Called from main thread. void VulkanRenderManager::StopThreads() { - // Make sure we don't have an open render pass. - EndCurRenderStep(); + // Make sure we don't have an open non-backbuffer render pass + if (curRenderStep_ && curRenderStep_->render.framebuffer != nullptr) { + EndCurRenderStep(); + } // Not sure this is a sensible check - should be ok even if not. // _dbg_assert_(steps_.empty()); @@ -1140,6 +1142,8 @@ void VulkanRenderManager::CopyImageToMemorySync(VkImage image, int mipLevel, int // Need to call this after FlushSync so the pixels are guaranteed to be ready in CPU-accessible VRAM. queueRunner_.CopyReadbackBuffer(frameData_[vulkan_->GetCurFrame()], nullptr, w, h, destFormat, destFormat, pixelStride, pixels); + + _dbg_assert_(steps_.empty()); } static void RemoveDrawCommands(FastVec *cmds) { @@ -1338,8 +1342,6 @@ void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, } } - EndCurRenderStep(); - // Sanity check. Added an assert to try to gather more info. // Got this assert in NPJH50443 FINAL FANTASY TYPE-0, but pretty rare. Moving back to debug assert. if (aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { @@ -1352,6 +1354,8 @@ void VulkanRenderManager::BlitFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, } } + EndCurRenderStep(); + VKRStep *step = new VKRStep{ VKRStepType::BLIT }; step->blit.aspectMask = aspectMask; step->blit.src = src; diff --git a/Core/System.cpp b/Core/System.cpp index 9bca1c1705..b8cb8f2182 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -594,7 +594,6 @@ bool PSP_Reboot(std::string *error_string) { } void PSP_BeginHostFrame() { - // Reapply the graphics state of the PSP if (gpu) { gpu->BeginHostFrame(); } diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 6b6de5288f..305aff0bf4 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -89,6 +89,7 @@ void FramebufferManagerCommon::Init(int msaaLevel) { NotifyRenderResized(msaaLevel); } +// Returns true if we need to stop the render thread bool FramebufferManagerCommon::UpdateRenderSize(int msaaLevel) { const bool newRender = renderWidth_ != (float)PSP_CoreParameter().renderWidth || renderHeight_ != (float)PSP_CoreParameter().renderHeight || msaaLevel_ != msaaLevel; @@ -111,6 +112,11 @@ bool FramebufferManagerCommon::UpdateRenderSize(int msaaLevel) { useBufferedRendering_ = newBuffered; presentation_->UpdateRenderSize(renderWidth_, renderHeight_); + + // If just switching TO buffered rendering, no need to pause the threads. In fact this causes problems due to the open backbuffer renderpass. + if (!useBufferedRendering_ && newBuffered) { + return false; + } return newRender || newSettings; } diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index d01bcdf73b..496ebf1050 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1395,6 +1395,10 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) { if (!framebufferBound) { draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, }, "EmuScreen_Behind"); } + + Draw::BackendState state = draw->GetCurrentBackendState(); + _assert_msg_(!state.valid || state.passes >= 1, "skipB: %d sw: %d mode: %d back: %d tag: %s", (int)skipBufferEffects, (int)g_Config.bSoftwareRendering, (int)mode, (int)g_Config.iGPUBackend, screenManager()->topScreen()->tag()); + // Need to make sure the UI texture is available, for "darken". screenManager()->getUIContext()->BeginFrame(); draw->SetViewport(viewport); @@ -1515,13 +1519,12 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) { draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, clearColor }, "EmuScreen_NoFrame"); draw->SetViewport(viewport); draw->SetScissorRect(0, 0, g_display.pixel_xres, g_display.pixel_yres); - framebufferBound = true; } Draw::BackendState state = draw->GetCurrentBackendState(); // We allow if !state.valid, that means it's not the Vulkan backend. - _assert_msg_(!state.valid || state.passes >= 1, "skipB: %d sw: %d mode: %d back: %d", (int)skipBufferEffects, (int)g_Config.bSoftwareRendering, (int)mode, (int)g_Config.iGPUBackend); + _assert_msg_(!state.valid || state.passes >= 1, "skipB: %d sw: %d mode: %d back: %d bound: %d", (int)skipBufferEffects, (int)g_Config.bSoftwareRendering, (int)mode, (int)g_Config.iGPUBackend, (int)framebufferBound); screenManager()->getUIContext()->BeginFrame();