From 7495c99d1382e0a1e07eacb49ab6c8b13e0920af Mon Sep 17 00:00:00 2001 From: iwubcode Date: Thu, 13 Nov 2025 21:44:29 -0600 Subject: [PATCH] VideoCommon: avoid assuming global state exists for 'EndUtilityDrawing', use last stored viewport/scissors instead --- Source/Core/VideoCommon/AbstractGfx.cpp | 27 ++++++++++++++++++++++--- Source/Core/VideoCommon/AbstractGfx.h | 19 +++++++++++++++++ Source/Core/VideoCommon/BPFunctions.cpp | 8 ++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/Source/Core/VideoCommon/AbstractGfx.cpp b/Source/Core/VideoCommon/AbstractGfx.cpp index 0e7e05e0f0..77209d944e 100644 --- a/Source/Core/VideoCommon/AbstractGfx.cpp +++ b/Source/Core/VideoCommon/AbstractGfx.cpp @@ -34,10 +34,21 @@ void AbstractGfx::BeginUtilityDrawing() void AbstractGfx::EndUtilityDrawing() { - // Reset framebuffer/scissor/viewport. Pipeline will be reset at next draw. + // Reset framebuffer. Pipeline will be reset at next draw. g_framebuffer_manager->BindEFBFramebuffer(); - BPFunctions::SetScissorAndViewport(g_framebuffer_manager.get(), bpmem.scissorTL, bpmem.scissorBR, - bpmem.scissorOffset, xfmem.viewport); + + // Reset our viewport and scissors to the last stored value if we have it + // We might not have one in the scenario where we're doing utility drawing + // at the start of launching the software (ex: drawing the compile shaders + // before start dialog) + if (m_viewport_and_scissors) + { + SetViewport(m_viewport_and_scissors->viewport_x, m_viewport_and_scissors->viewport_y, + m_viewport_and_scissors->viewport_width, m_viewport_and_scissors->viewport_height, + m_viewport_and_scissors->viewport_near_depth, + m_viewport_and_scissors->viewport_far_depth); + SetScissorRect(m_viewport_and_scissors->scissors_rect); + } } void AbstractGfx::SetFramebuffer(AbstractFramebuffer* framebuffer) @@ -87,6 +98,16 @@ void AbstractGfx::ClearRegion(const MathUtil::Rectangle& target_rc, bool co EndUtilityDrawing(); } +void AbstractGfx::SetViewportAndScissor(ViewportAndScissors viewport_and_scissors) +{ + m_viewport_and_scissors = std::move(viewport_and_scissors); +} + +const std::optional& AbstractGfx::GetViewportAndScissors() const +{ + return m_viewport_and_scissors; +} + void AbstractGfx::SetViewportAndScissor(const MathUtil::Rectangle& rect, float min_depth, float max_depth) { diff --git a/Source/Core/VideoCommon/AbstractGfx.h b/Source/Core/VideoCommon/AbstractGfx.h index d9d14e1a12..41b339e88a 100644 --- a/Source/Core/VideoCommon/AbstractGfx.h +++ b/Source/Core/VideoCommon/AbstractGfx.h @@ -10,6 +10,7 @@ #include #include +#include #include class AbstractFramebuffer; @@ -126,6 +127,23 @@ public: AbstractFramebuffer* GetCurrentFramebuffer() const { return m_current_framebuffer; } + struct ViewportAndScissors + { + MathUtil::Rectangle scissors_rect; + float viewport_x; + float viewport_y; + float viewport_width; + float viewport_height; + float viewport_near_depth; + float viewport_far_depth; + }; + + // Sets the last viewport and scissors, uses it to restore on 'EndUtilityDrawing' + void SetViewportAndScissor(ViewportAndScissors viewport_and_scissors); + + // Gets the last set viewport and scissors + const std::optional& GetViewportAndScissors() const; + // Sets viewport and scissor to the specified rectangle. rect is assumed to be in framebuffer // coordinates, i.e. lower-left origin in OpenGL. void SetViewportAndScissor(const MathUtil::Rectangle& rect, float min_depth = 0.0f, @@ -177,6 +195,7 @@ protected: private: Common::EventHook m_config_changed; + std::optional m_viewport_and_scissors; }; extern std::unique_ptr g_gfx; diff --git a/Source/Core/VideoCommon/BPFunctions.cpp b/Source/Core/VideoCommon/BPFunctions.cpp index 660d85c598..49523eb03c 100644 --- a/Source/Core/VideoCommon/BPFunctions.cpp +++ b/Source/Core/VideoCommon/BPFunctions.cpp @@ -265,6 +265,14 @@ void SetScissorAndViewport(FramebufferManager* frame_buffer_manager, ScissorPos y = static_cast(g_gfx->GetCurrentFramebuffer()->GetHeight()) - y - height; g_gfx->SetViewport(x, y, width, height, near_depth, far_depth); + + g_gfx->SetViewportAndScissor(AbstractGfx::ViewportAndScissors{.scissors_rect = converted_rc, + .viewport_x = x, + .viewport_y = y, + .viewport_width = width, + .viewport_height = height, + .viewport_near_depth = near_depth, + .viewport_far_depth = far_depth}); } void SetDepthMode()