From e0090024119184238032923987af1c8d7167b7b5 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Tue, 31 Jan 2023 15:44:38 +1300 Subject: [PATCH] Refactor ClearRegion And fix bug where opengl was getting the wrong coordinates --- Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp | 4 +- Source/Core/VideoBackends/D3D12/D3D12Gfx.h | 2 +- Source/Core/VideoBackends/Metal/MTLGfx.h | 2 +- Source/Core/VideoBackends/Metal/MTLGfx.mm | 5 +- Source/Core/VideoBackends/OGL/OGLGfx.cpp | 3 +- Source/Core/VideoBackends/OGL/OGLGfx.h | 2 +- Source/Core/VideoBackends/Software/SWGfx.cpp | 3 +- Source/Core/VideoBackends/Software/SWGfx.h | 2 +- Source/Core/VideoBackends/Vulkan/VKGfx.cpp | 5 +- Source/Core/VideoBackends/Vulkan/VKGfx.h | 2 +- Source/Core/VideoCommon/AbstractGfx.cpp | 30 +++++++++- Source/Core/VideoCommon/AbstractGfx.h | 3 +- Source/Core/VideoCommon/BPFunctions.cpp | 2 +- .../Core/VideoCommon/FramebufferManager.cpp | 59 ++++++++++--------- Source/Core/VideoCommon/FramebufferManager.h | 4 +- Source/Core/VideoCommon/RenderBase.cpp | 29 --------- Source/Core/VideoCommon/RenderBase.h | 2 - 17 files changed, 77 insertions(+), 82 deletions(-) diff --git a/Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp b/Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp index 68b0436134..e1c82353b2 100644 --- a/Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp +++ b/Source/Core/VideoBackends/D3D12/D3D12Gfx.cpp @@ -103,7 +103,7 @@ void Gfx::WaitForGPUIdle() ExecuteCommandList(true); } -void Gfx::ClearRegion(const MathUtil::Rectangle& rc, const MathUtil::Rectangle& target_rc, +void Gfx::ClearRegion(const MathUtil::Rectangle& target_rc, bool color_enable, bool alpha_enable, bool z_enable, u32 color, u32 z) { // Use a fast path without the shader if both color/alpha are enabled. @@ -145,7 +145,7 @@ void Gfx::ClearRegion(const MathUtil::Rectangle& rc, const MathUtil::Rectan // Anything left over, fall back to clear triangle. if (color_enable || alpha_enable || z_enable) - ::AbstractGfx::ClearRegion(rc, target_rc, color_enable, alpha_enable, z_enable, color, z); + ::AbstractGfx::ClearRegion(target_rc, color_enable, alpha_enable, z_enable, color, z); } void Gfx::SetPipeline(const AbstractPipeline* pipeline) diff --git a/Source/Core/VideoBackends/D3D12/D3D12Gfx.h b/Source/Core/VideoBackends/D3D12/D3D12Gfx.h index 26dc669ffc..e7eb015b2f 100644 --- a/Source/Core/VideoBackends/D3D12/D3D12Gfx.h +++ b/Source/Core/VideoBackends/D3D12/D3D12Gfx.h @@ -47,7 +47,7 @@ public: void Flush() override; void WaitForGPUIdle() override; - void ClearRegion(const MathUtil::Rectangle& rc, const MathUtil::Rectangle& target_rc, + void ClearRegion(const MathUtil::Rectangle& target_rc, bool color_enable, bool alpha_enable, bool z_enable, u32 color, u32 z) override; void SetPipeline(const AbstractPipeline* pipeline) override; diff --git a/Source/Core/VideoBackends/Metal/MTLGfx.h b/Source/Core/VideoBackends/Metal/MTLGfx.h index 4e2dca5662..b4c3a3d0e8 100644 --- a/Source/Core/VideoBackends/Metal/MTLGfx.h +++ b/Source/Core/VideoBackends/Metal/MTLGfx.h @@ -47,7 +47,7 @@ public: void WaitForGPUIdle() override; void OnConfigChanged(u32 bits) override; - void ClearRegion(const MathUtil::Rectangle& rc, const MathUtil::Rectangle& target_rc, + void ClearRegion(const MathUtil::Rectangle& target_rc, bool color_enable, bool alpha_enable, bool z_enable, u32 color, u32 z) override; void SetPipeline(const AbstractPipeline* pipeline) override; diff --git a/Source/Core/VideoBackends/Metal/MTLGfx.mm b/Source/Core/VideoBackends/Metal/MTLGfx.mm index f1e307d808..ba7d64e333 100644 --- a/Source/Core/VideoBackends/Metal/MTLGfx.mm +++ b/Source/Core/VideoBackends/Metal/MTLGfx.mm @@ -285,8 +285,7 @@ void Metal::Gfx::OnConfigChanged(u32 bits) } } -void Metal::Gfx::ClearRegion(const MathUtil::Rectangle& rc, - const MathUtil::Rectangle& target_rc, +void Metal::Gfx::ClearRegion(const MathUtil::Rectangle& target_rc, bool color_enable, bool alpha_enable, bool z_enable, u32 color, u32 z) { u32 framebuffer_width = m_current_framebuffer->GetWidth(); @@ -332,7 +331,7 @@ void Metal::Gfx::ClearRegion(const MathUtil::Rectangle& rc, } g_state_tracker->EnableEncoderLabel(false); - g_framebuffer_manager->ClearEFB(rc, color_enable, alpha_enable, z_enable, color, z); + AbstractGfx::ClearRegion(target_rc, color_enable, alpha_enable, z_enable, color, z); g_state_tracker->EnableEncoderLabel(true); } diff --git a/Source/Core/VideoBackends/OGL/OGLGfx.cpp b/Source/Core/VideoBackends/OGL/OGLGfx.cpp index ec0dd3181e..880b213fb8 100644 --- a/Source/Core/VideoBackends/OGL/OGLGfx.cpp +++ b/Source/Core/VideoBackends/OGL/OGLGfx.cpp @@ -373,8 +373,7 @@ void OGLGfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const Clea glDepthMask(m_current_depth_state.updateenable); } -void OGLGfx::ClearRegion(const MathUtil::Rectangle& rc, - const MathUtil::Rectangle& target_rc, bool colorEnable, +void OGLGfx::ClearRegion(const MathUtil::Rectangle& target_rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) { u32 clear_mask = 0; diff --git a/Source/Core/VideoBackends/OGL/OGLGfx.h b/Source/Core/VideoBackends/OGL/OGLGfx.h index 8d92766387..671d78ee4a 100644 --- a/Source/Core/VideoBackends/OGL/OGLGfx.h +++ b/Source/Core/VideoBackends/OGL/OGLGfx.h @@ -42,7 +42,7 @@ public: void SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer) override; void SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value = {}, float depth_value = 0.0f) override; - void ClearRegion(const MathUtil::Rectangle& rc, const MathUtil::Rectangle& target_rc, + void ClearRegion(const MathUtil::Rectangle& target_rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override; void SetScissorRect(const MathUtil::Rectangle& rc) override; void SetTexture(u32 index, const AbstractTexture* texture) override; diff --git a/Source/Core/VideoBackends/Software/SWGfx.cpp b/Source/Core/VideoBackends/Software/SWGfx.cpp index 7e8c234540..d4758a07fa 100644 --- a/Source/Core/VideoBackends/Software/SWGfx.cpp +++ b/Source/Core/VideoBackends/Software/SWGfx.cpp @@ -107,8 +107,7 @@ void SWGfx::ShowImage(const AbstractTexture* source_texture, m_window->ShowImage(source_texture, source_rc); } -void SWGfx::ClearRegion(const MathUtil::Rectangle& rc, - const MathUtil::Rectangle& target_rc, bool colorEnable, +void SWGfx::ClearRegion(const MathUtil::Rectangle& target_rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) { EfbCopy::ClearEfb(); diff --git a/Source/Core/VideoBackends/Software/SWGfx.h b/Source/Core/VideoBackends/Software/SWGfx.h index 1337d89525..6e5b328b5c 100644 --- a/Source/Core/VideoBackends/Software/SWGfx.h +++ b/Source/Core/VideoBackends/Software/SWGfx.h @@ -46,7 +46,7 @@ public: void SetScissorRect(const MathUtil::Rectangle& rc) override; - void ClearRegion(const MathUtil::Rectangle& rc, const MathUtil::Rectangle& target_rc, + void ClearRegion(const MathUtil::Rectangle& target_rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) override; private: diff --git a/Source/Core/VideoBackends/Vulkan/VKGfx.cpp b/Source/Core/VideoBackends/Vulkan/VKGfx.cpp index 35d6174cec..569fbaa32b 100644 --- a/Source/Core/VideoBackends/Vulkan/VKGfx.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKGfx.cpp @@ -100,8 +100,7 @@ void VKGfx::SetPipeline(const AbstractPipeline* pipeline) StateTracker::GetInstance()->SetPipeline(static_cast(pipeline)); } -void VKGfx::ClearRegion(const MathUtil::Rectangle& rc, - const MathUtil::Rectangle& target_rc, bool color_enable, +void VKGfx::ClearRegion(const MathUtil::Rectangle& target_rc, bool color_enable, bool alpha_enable, bool z_enable, u32 color, u32 z) { VkRect2D target_vk_rc = { @@ -191,7 +190,7 @@ void VKGfx::ClearRegion(const MathUtil::Rectangle& rc, if (!color_enable && !alpha_enable && !z_enable) return; - g_framebuffer_manager->ClearEFB(rc, color_enable, alpha_enable, z_enable, color, z); + AbstractGfx::ClearRegion(target_rc, color_enable, alpha_enable, z_enable, color, z); } void VKGfx::Flush() diff --git a/Source/Core/VideoBackends/Vulkan/VKGfx.h b/Source/Core/VideoBackends/Vulkan/VKGfx.h index 8cab073386..8275038479 100644 --- a/Source/Core/VideoBackends/Vulkan/VKGfx.h +++ b/Source/Core/VideoBackends/Vulkan/VKGfx.h @@ -53,7 +53,7 @@ public: void WaitForGPUIdle() override; void OnConfigChanged(u32 bits) override; - void ClearRegion(const MathUtil::Rectangle& rc, const MathUtil::Rectangle& target_rc, + void ClearRegion(const MathUtil::Rectangle& target_rc, bool color_enable, bool alpha_enable, bool z_enable, u32 color, u32 z) override; void SetPipeline(const AbstractPipeline* pipeline) override; diff --git a/Source/Core/VideoCommon/AbstractGfx.cpp b/Source/Core/VideoCommon/AbstractGfx.cpp index 6ec74210c9..6e1c56aa20 100644 --- a/Source/Core/VideoCommon/AbstractGfx.cpp +++ b/Source/Core/VideoCommon/AbstractGfx.cpp @@ -54,11 +54,35 @@ void AbstractGfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, m_current_framebuffer = framebuffer; } -void AbstractGfx::ClearRegion(const MathUtil::Rectangle& rc, - const MathUtil::Rectangle& target_rc, bool colorEnable, +void AbstractGfx::ClearRegion(const MathUtil::Rectangle& target_rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) { - g_framebuffer_manager->ClearEFB(rc, colorEnable, alphaEnable, zEnable, color, z); + // This is a generic fallback for any ClearRegion operations that backends don't support. + // It simply draws a Quad. + + BeginUtilityDrawing(); + + // Set up uniforms. + struct Uniforms + { + float clear_color[4]; + float clear_depth; + float padding1, padding2, padding3; + }; + static_assert(std::is_standard_layout::value); + Uniforms uniforms = {{static_cast((color >> 16) & 0xFF) / 255.0f, + static_cast((color >> 8) & 0xFF) / 255.0f, + static_cast((color >> 0) & 0xFF) / 255.0f, + static_cast((color >> 24) & 0xFF) / 255.0f}, + static_cast(z & 0xFFFFFF) / 16777216.0f}; + if (!g_ActiveConfig.backend_info.bSupportsReversedDepthRange) + uniforms.clear_depth = 1.0f - uniforms.clear_depth; + g_vertex_manager->UploadUtilityUniforms(&uniforms, sizeof(uniforms)); + + g_gfx->SetPipeline(g_framebuffer_manager->GetClearPipeline(colorEnable, alphaEnable, zEnable)); + g_gfx->SetViewportAndScissor(target_rc); + g_gfx->Draw(0, 3); + EndUtilityDrawing(); } void AbstractGfx::SetViewportAndScissor(const MathUtil::Rectangle& rect, float min_depth, diff --git a/Source/Core/VideoCommon/AbstractGfx.h b/Source/Core/VideoCommon/AbstractGfx.h index e59270871c..916bcd4e11 100644 --- a/Source/Core/VideoCommon/AbstractGfx.h +++ b/Source/Core/VideoCommon/AbstractGfx.h @@ -82,8 +82,7 @@ public: virtual void SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value = {}, float depth_value = 0.0f); - virtual void ClearRegion(const MathUtil::Rectangle& rc, - const MathUtil::Rectangle& target_rc, bool colorEnable, + virtual void ClearRegion(const MathUtil::Rectangle& target_rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z); // Drawing with currently-bound pipeline state. diff --git a/Source/Core/VideoCommon/BPFunctions.cpp b/Source/Core/VideoCommon/BPFunctions.cpp index 808e7959e5..d022f46103 100644 --- a/Source/Core/VideoCommon/BPFunctions.cpp +++ b/Source/Core/VideoCommon/BPFunctions.cpp @@ -342,7 +342,7 @@ void ClearScreen(const MathUtil::Rectangle& rc) color = RGBA8ToRGB565ToRGBA8(color); z = Z24ToZ16ToZ24(z); } - g_renderer->ClearScreen(rc, colorEnable, alphaEnable, zEnable, color, z); + g_framebuffer_manager->ClearEFB(rc, colorEnable, alphaEnable, zEnable, color, z); } } diff --git a/Source/Core/VideoCommon/FramebufferManager.cpp b/Source/Core/VideoCommon/FramebufferManager.cpp index 3032de574f..5696ebb2b8 100644 --- a/Source/Core/VideoCommon/FramebufferManager.cpp +++ b/Source/Core/VideoCommon/FramebufferManager.cpp @@ -16,6 +16,7 @@ #include "VideoCommon/AbstractShader.h" #include "VideoCommon/AbstractStagingTexture.h" #include "VideoCommon/AbstractTexture.h" +#include "VideoCommon/BPFunctions.h" #include "VideoCommon/DriverDetails.h" #include "VideoCommon/FramebufferShaderGen.h" #include "VideoCommon/RenderBase.h" @@ -787,36 +788,34 @@ void FramebufferManager::PopulateEFBCache(bool depth, u32 tile_index, bool async data.tiles[tile_index].present = true; } -void FramebufferManager::ClearEFB(const MathUtil::Rectangle& rc, bool clear_color, - bool clear_alpha, bool clear_z, u32 color, u32 z) +void FramebufferManager::ClearEFB(const MathUtil::Rectangle& rc, bool color_enable, + bool alpha_enable, bool z_enable, u32 color, u32 z) { FlushEFBPokes(); FlagPeekCacheAsOutOfDate(); - g_gfx->BeginUtilityDrawing(); - // Set up uniforms. - struct Uniforms + // Native -> EFB coordinates + MathUtil::Rectangle target_rc = g_renderer->ConvertEFBRectangle(rc); + target_rc = g_gfx->ConvertFramebufferRectangle(target_rc, m_efb_framebuffer.get()); + target_rc.ClampUL(0, 0, g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight()); + + // Determine whether the EFB has an alpha channel. If it doesn't, we can clear the alpha + // channel to 0xFF. + // On backends that don't allow masking Alpha clears, this allows us to use the fast path + // almost all the time + if (bpmem.zcontrol.pixel_format == PixelFormat::RGB565_Z16 || + bpmem.zcontrol.pixel_format == PixelFormat::RGB8_Z24 || + bpmem.zcontrol.pixel_format == PixelFormat::Z24) { - float clear_color[4]; - float clear_depth; - float padding1, padding2, padding3; - }; - static_assert(std::is_standard_layout::value); - Uniforms uniforms = {{static_cast((color >> 16) & 0xFF) / 255.0f, - static_cast((color >> 8) & 0xFF) / 255.0f, - static_cast((color >> 0) & 0xFF) / 255.0f, - static_cast((color >> 24) & 0xFF) / 255.0f}, - static_cast(z & 0xFFFFFF) / 16777216.0f}; - if (!g_ActiveConfig.backend_info.bSupportsReversedDepthRange) - uniforms.clear_depth = 1.0f - uniforms.clear_depth; - g_vertex_manager->UploadUtilityUniforms(&uniforms, sizeof(uniforms)); + // Force alpha writes, and clear the alpha channel. + alpha_enable = true; + color &= 0x00FFFFFF; + } - const auto target_rc = g_gfx->ConvertFramebufferRectangle(g_renderer->ConvertEFBRectangle(rc), - m_efb_framebuffer.get()); - g_gfx->SetPipeline(m_efb_clear_pipelines[clear_color][clear_alpha][clear_z].get()); - g_gfx->SetViewportAndScissor(target_rc); - g_gfx->Draw(0, 3); - g_gfx->EndUtilityDrawing(); + g_gfx->ClearRegion(target_rc, color_enable, alpha_enable, z_enable, color, z); + + // Scissor rect must be restored. + BPFunctions::SetScissorAndViewport(); } bool FramebufferManager::CompileClearPipelines() @@ -849,9 +848,9 @@ bool FramebufferManager::CompileClearPipelines() config.depth_state.testenable = depth_enable != 0; config.depth_state.updateenable = depth_enable != 0; - m_efb_clear_pipelines[color_enable][alpha_enable][depth_enable] = + m_clear_pipelines[color_enable][alpha_enable][depth_enable] = g_gfx->CreatePipeline(config); - if (!m_efb_clear_pipelines[color_enable][alpha_enable][depth_enable]) + if (!m_clear_pipelines[color_enable][alpha_enable][depth_enable]) return false; } } @@ -868,12 +867,18 @@ void FramebufferManager::DestroyClearPipelines() { for (u32 depth_enable = 0; depth_enable < 2; depth_enable++) { - m_efb_clear_pipelines[color_enable][alpha_enable][depth_enable].reset(); + m_clear_pipelines[color_enable][alpha_enable][depth_enable].reset(); } } } } +AbstractPipeline* FramebufferManager::GetClearPipeline(bool colorEnable, bool alphaEnable, + bool zEnable) const +{ + return m_clear_pipelines[colorEnable][alphaEnable][zEnable].get(); +} + void FramebufferManager::PokeEFBColor(u32 x, u32 y, u32 color) { // Flush if we exceeded the number of vertices per batch. diff --git a/Source/Core/VideoCommon/FramebufferManager.h b/Source/Core/VideoCommon/FramebufferManager.h index 405ef1fc3a..c3871c8e15 100644 --- a/Source/Core/VideoCommon/FramebufferManager.h +++ b/Source/Core/VideoCommon/FramebufferManager.h @@ -95,6 +95,8 @@ public: void ClearEFB(const MathUtil::Rectangle& rc, bool clear_color, bool clear_alpha, bool clear_z, u32 color, u32 z); + AbstractPipeline* GetClearPipeline(bool clear_color, bool clear_alpha, bool clear_z) const; + // Reads a framebuffer value back from the GPU. This may block if the cache is not current. u32 PeekEFBColor(u32 x, u32 y); float PeekEFBDepth(u32 x, u32 y); @@ -206,7 +208,7 @@ protected: // EFB clear pipelines // Indexed by [color_write_enabled][alpha_write_enabled][depth_write_enabled] std::array, 2>, 2>, 2> - m_efb_clear_pipelines; + m_clear_pipelines; // EFB poke drawing setup std::unique_ptr m_poke_vertex_format; diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index b02738d037..6c991c74ae 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -63,35 +63,6 @@ Renderer::Renderer() Renderer::~Renderer() = default; -void Renderer::ClearScreen(const MathUtil::Rectangle& rc, bool color_enable, bool alpha_enable, - bool z_enable, u32 color, u32 z) -{ - g_framebuffer_manager->FlushEFBPokes(); - g_framebuffer_manager->FlagPeekCacheAsOutOfDate(); - - // Native -> EFB coordinates - MathUtil::Rectangle target_rc = Renderer::ConvertEFBRectangle(rc); - target_rc.ClampUL(0, 0, m_target_width, m_target_height); - - // Determine whether the EFB has an alpha channel. If it doesn't, we can clear the alpha - // channel to 0xFF. - // On backends that don't allow masking Alpha clears, this allows us to use the fast path - // almost all the time - if (bpmem.zcontrol.pixel_format == PixelFormat::RGB565_Z16 || - bpmem.zcontrol.pixel_format == PixelFormat::RGB8_Z24 || - bpmem.zcontrol.pixel_format == PixelFormat::Z24) - { - // Force alpha writes, and clear the alpha channel. - alpha_enable = true; - color &= 0x00FFFFFF; - } - - g_gfx->ClearRegion(rc, target_rc, color_enable, alpha_enable, z_enable, color, z); - - // Scissor rect must be restored. - BPFunctions::SetScissorAndViewport(); -} - void Renderer::ReinterpretPixelData(EFBReinterpretType convtype) { g_framebuffer_manager->ReinterpretPixelData(convtype); diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index d2e0036563..c1c00aa382 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -52,8 +52,6 @@ public: float EFBToScaledXf(float x) const; float EFBToScaledYf(float y) const; - void ClearScreen(const MathUtil::Rectangle& rc, bool colorEnable, bool alphaEnable, - bool zEnable, u32 color, u32 z); virtual void ReinterpretPixelData(EFBReinterpretType convtype); virtual u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data);