From d426ce511801472f729d13628e771822569d2623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 10 Feb 2023 00:42:46 +0100 Subject: [PATCH] Clear depth buffers after changing depth rounding mode. And thus change of depth buffer scale/offset. Previously, old depth buffers with values that now are out of range could stick around, causing #16941. This clears them to the expected 0 value, which helps Outrun. Ideally we should convert depth buffers to the new format, but if we can get away without that, that's also nice. This is enough for #16941. --- GPU/Common/FramebufferManagerCommon.cpp | 15 ++++++++++++++- GPU/Common/FramebufferManagerCommon.h | 5 +++++ GPU/D3D11/GPU_D3D11.cpp | 3 ++- GPU/Directx9/GPU_DX9.cpp | 3 ++- GPU/GLES/GPU_GLES.cpp | 3 ++- GPU/Vulkan/GPU_Vulkan.cpp | 5 ++++- 6 files changed, 29 insertions(+), 5 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 1e2dcc11fa..a5332d934c 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -1059,7 +1059,14 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe if (useBufferedRendering_) { if (vfb->fbo) { shaderManager_->DirtyLastShader(); - draw_->BindFramebufferAsRenderTarget(vfb->fbo, {Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP}, "FBSwitch"); + Draw::RPAction depthAction = Draw::RPAction::KEEP; + float clearDepth = 0.0f; + if (vfb->usageFlags & FB_USAGE_INVALIDATE_DEPTH) { + depthAction = Draw::RPAction::CLEAR; + clearDepth = GetDepthScaleFactors().offset; + vfb->usageFlags &= ~FB_USAGE_INVALIDATE_DEPTH; + } + draw_->BindFramebufferAsRenderTarget(vfb->fbo, {Draw::RPAction::KEEP, depthAction, Draw::RPAction::KEEP, 0, clearDepth}, "FBSwitch"); } else { // This should only happen very briefly when toggling useBufferedRendering_. ResizeFramebufFBO(vfb, vfb->width, vfb->height, true); @@ -2573,6 +2580,12 @@ void FramebufferManagerCommon::ShowScreenResolution() { INFO_LOG(SYSTEM, "%s", messageStream.str().c_str()); } +void FramebufferManagerCommon::ClearAllDepthBuffers() { + for (auto vfb : vfbs_) { + vfb->usageFlags |= FB_USAGE_INVALIDATE_DEPTH; + } +} + // We might also want to implement an asynchronous callback-style version of this. Would probably // only be possible to implement optimally on Vulkan, but on GL and D3D11 we could do pixel buffers // and read on the next frame, then call the callback. diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 37650a57ba..df33d549b4 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -46,6 +46,7 @@ enum { FB_USAGE_FIRST_FRAME_SAVED = 128, FB_USAGE_RENDER_DEPTH = 256, FB_USAGE_COLOR_MIXED_DEPTH = 512, + FB_USAGE_INVALIDATE_DEPTH = 1024, // used to clear depth buffers. }; enum { @@ -317,6 +318,10 @@ public: void ApplyClearToMemory(int x1, int y1, int x2, int y2, u32 clearColor); bool PerformWriteStencilFromMemory(u32 addr, int size, WriteStencil flags); + // We changed our depth mode, gotta start over. + // Ideally, we should convert depth buffers here, not just clear them. + void ClearAllDepthBuffers(); + // Returns true if it's sure this is a direct FBO->FBO transfer and it has already handle it. // In that case we hardly need to actually copy the bytes in VRAM, they will be wrong anyway (unless // read framebuffers is on, in which case this should always return false). diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 342f033738..5706c45fca 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -161,8 +161,9 @@ void GPU_D3D11::BeginFrame() { if (gstate_c.useFlagsChanged) { // TODO: It'd be better to recompile them in the background, probably? // This most likely means that saw equal depth changed. - WARN_LOG(G3D, "Shader use flags changed, clearing all shaders"); + WARN_LOG(G3D, "Shader use flags changed, clearing all shaders and depth buffers"); shaderManagerD3D11_->ClearShaders(); + framebufferManager_->ClearAllDepthBuffers(); drawEngine_.ClearInputLayoutMap(); gstate_c.useFlagsChanged = false; } diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index a7398018e9..af8d80e327 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -159,8 +159,9 @@ void GPU_DX9::BeginFrame() { if (gstate_c.useFlagsChanged) { // TODO: It'd be better to recompile them in the background, probably? // This most likely means that saw equal depth changed. - WARN_LOG(G3D, "Shader use flags changed, clearing all shaders"); + WARN_LOG(G3D, "Shader use flags changed, clearing all shaders and depth buffers"); shaderManagerDX9_->ClearCache(true); + framebufferManager_->ClearAllDepthBuffers(); gstate_c.useFlagsChanged = false; } } diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 034e8bd660..3646fc802c 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -283,8 +283,9 @@ void GPU_GLES::BeginHostFrame() { if (gstate_c.useFlagsChanged) { // TODO: It'd be better to recompile them in the background, probably? // This most likely means that saw equal depth changed. - WARN_LOG(G3D, "Shader use flags changed, clearing all shaders"); + WARN_LOG(G3D, "Shader use flags changed, clearing all shaders and depth buffers"); shaderManagerGL_->ClearCache(true); + framebufferManager_->ClearAllDepthBuffers(); gstate_c.useFlagsChanged = false; } } diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 5543c15e37..8e1ad1e2d1 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -310,9 +310,12 @@ void GPU_Vulkan::BeginHostFrame() { if (gstate_c.useFlagsChanged) { // TODO: It'd be better to recompile them in the background, probably? // This most likely means that saw equal depth changed. - WARN_LOG(G3D, "Shader use flags changed, clearing all shaders"); + WARN_LOG(G3D, "Shader use flags changed, clearing all shaders and depth buffers"); + // TODO: Not all shaders need to be recompiled. In fact, quite few? Of course, depends on + // the use flag change.. This is a major frame rate hitch in the start of a race in Outrun. shaderManagerVulkan_->ClearShaders(); pipelineManager_->Clear(); + framebufferManager_->ClearAllDepthBuffers(); gstate_c.useFlagsChanged = false; }