From 20c2ec139272ef4d836b035fa55edafc67c71eba Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 6 Aug 2022 21:12:42 -0700 Subject: [PATCH] GPU: Skip alpha stencil upload when safe. Otherwise, let's not do things that give different behavior at 1x or are inconsistent. --- Common/GPU/OpenGL/GLFeatures.cpp | 2 +- Core/HLE/ReplaceTables.cpp | 2 +- GPU/Common/FramebufferManagerCommon.h | 7 +------ GPU/Common/StencilCommon.cpp | 23 +++++++++++++---------- GPU/GPUCommon.cpp | 4 ++-- GPU/GPUCommon.h | 2 +- GPU/GPUInterface.h | 8 +++++++- GPU/Software/SoftGpu.cpp | 2 +- GPU/Software/SoftGpu.h | 2 +- 9 files changed, 28 insertions(+), 24 deletions(-) diff --git a/Common/GPU/OpenGL/GLFeatures.cpp b/Common/GPU/OpenGL/GLFeatures.cpp index 05c899e1df..bf9a639e67 100644 --- a/Common/GPU/OpenGL/GLFeatures.cpp +++ b/Common/GPU/OpenGL/GLFeatures.cpp @@ -370,7 +370,7 @@ void CheckGLExtensions() { gl_extensions.ARB_depth_clamp = g_set_gl_extensions.count("GL_ARB_depth_clamp") != 0; gl_extensions.ARB_uniform_buffer_object = g_set_gl_extensions.count("GL_ARB_uniform_buffer_object") != 0; gl_extensions.ARB_explicit_attrib_location = g_set_gl_extensions.count("GL_ARB_explicit_attrib_location") != 0; - gl_extensions.ARB_texture_non_power_of_two = g_set_gl_extensions.count("GL_ARB_texture_non_power_of_two"); + gl_extensions.ARB_texture_non_power_of_two = g_set_gl_extensions.count("GL_ARB_texture_non_power_of_two") != 0; if (gl_extensions.IsGLES) { gl_extensions.EXT_blend_func_extended = g_set_gl_extensions.count("GL_EXT_blend_func_extended") != 0; gl_extensions.OES_texture_npot = g_set_gl_extensions.count("GL_OES_texture_npot") != 0; diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index 4a0e7c4cac..57603ccf2c 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -708,7 +708,7 @@ static int Hook_hexyzforce_monoclome_thread() { static int Hook_starocean_write_stencil() { const u32 fb_address = currentMIPS->r[MIPS_REG_T7]; if (Memory::IsVRAMAddress(fb_address)) { - gpu->PerformStencilUpload(fb_address, 0x00088000); + gpu->PerformStencilUpload(fb_address, 0x00088000, StencilUpload::IGNORE_ALPHA); } return 0; } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index d4f24b0fb9..a1557cfed8 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -171,11 +171,6 @@ inline DrawTextureFlags operator | (const DrawTextureFlags &lhs, const DrawTextu return DrawTextureFlags((u32)lhs | (u32)rhs); } -enum class StencilUpload { - NEEDS_CLEAR, - STENCIL_IS_ZERO, -}; - enum class TempFBO { DEPAL, BLIT, @@ -261,7 +256,7 @@ public: void NotifyVideoUpload(u32 addr, int size, int width, GEBufferFormat fmt); void UpdateFromMemory(u32 addr, int size, bool safe); void ApplyClearToMemory(int x1, int y1, int x2, int y2, u32 clearColor); - bool PerformStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR); + bool PerformStencilUpload(u32 addr, int size, StencilUpload flags); // 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/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index bd6868ab6a..cc218a44ca 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -182,17 +182,17 @@ bool FramebufferManagerCommon::PerformStencilUpload(u32 addr, int size, StencilU return false; } - shaderManager_->DirtyLastShader(); + // Otherwise, we can skip alpha in many cases, in which case we don't even use a shader. + if (flags == StencilUpload::IGNORE_ALPHA) { + shaderManager_->DirtyLastShader(); - // Let's not bother with the shader if it's just zero. - if (dstBuffer->fbo) { - draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "PerformStencilUpload_Clear"); + if (dstBuffer->fbo) { + draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "PerformStencilUpload_Clear"); + } + + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE); + return true; } - - // Here we might want to clear destination alpha by using a draw, but we haven't found a need for this yet. - // Will implement when needed... - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE); - return true; } shaderManager_->DirtyLastShader(); @@ -263,10 +263,13 @@ bool FramebufferManagerCommon::PerformStencilUpload(u32 addr, int size, StencilU // Our fragment shader (and discard) is slow. Since the source is 1x, we can stencil to 1x. // Then after we're done, we'll just blit it across and stretch it there. Not worth doing // if already at 1x size though, of course. - // TODO: This path means that we don't write color alpha... Ugh. if (dstBuffer->width == dstBuffer->renderWidth || !dstBuffer->fbo) { useBlit = false; } + // The blit path doesn't set alpha, so we can't use it if that's needed. + if (flags != StencilUpload::IGNORE_ALPHA) { + useBlit = false; + } u16 w = useBlit ? dstBuffer->width : dstBuffer->renderWidth; u16 h = useBlit ? dstBuffer->height : dstBuffer->renderHeight; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 03ab2629e8..b04fb0108a 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2931,9 +2931,9 @@ void GPUCommon::NotifyVideoUpload(u32 addr, int size, int width, int format) { InvalidateCache(addr, size, GPU_INVALIDATE_SAFE); } -bool GPUCommon::PerformStencilUpload(u32 dest, int size) { +bool GPUCommon::PerformStencilUpload(u32 dest, int size, StencilUpload flags) { if (framebufferManager_->MayIntersectFramebuffer(dest)) { - framebufferManager_->PerformStencilUpload(dest, size); + framebufferManager_->PerformStencilUpload(dest, size, flags); return true; } return false; diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 623842853c..9a9db7b062 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -124,7 +124,7 @@ public: void InvalidateCache(u32 addr, int size, GPUInvalidationType type) override; void NotifyVideoUpload(u32 addr, int size, int width, int format) override; - bool PerformStencilUpload(u32 dest, int size) override; + bool PerformStencilUpload(u32 dest, int size, StencilUpload flags) override; void Execute_OffsetAddr(u32 op, u32 diff); void Execute_Vaddr(u32 op, u32 diff); diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 19c2cc72ab..34977eba8e 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -106,6 +106,12 @@ enum GPUSyncType { GPU_SYNC_LIST, }; +enum class StencilUpload { + NEEDS_CLEAR, + STENCIL_IS_ZERO, + IGNORE_ALPHA, +}; + // Used for debug struct FramebufferInfo { u32 fb_address; @@ -216,7 +222,7 @@ public: virtual bool PerformMemorySet(u32 dest, u8 v, int size) = 0; virtual bool PerformMemoryDownload(u32 dest, int size) = 0; virtual bool PerformMemoryUpload(u32 dest, int size) = 0; - virtual bool PerformStencilUpload(u32 dest, int size) = 0; + virtual bool PerformStencilUpload(u32 dest, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) = 0; // Will cause the texture cache to be cleared at the start of the next frame. virtual void ClearCacheNextFrame() = 0; diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 6a4ddf88b7..8015a9db05 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -1161,7 +1161,7 @@ bool SoftGPU::PerformMemoryUpload(u32 dest, int size) return false; } -bool SoftGPU::PerformStencilUpload(u32 dest, int size) +bool SoftGPU::PerformStencilUpload(u32 dest, int size, StencilUpload flags) { return false; } diff --git a/GPU/Software/SoftGpu.h b/GPU/Software/SoftGpu.h index b45e6f95fa..712ec6bbdd 100644 --- a/GPU/Software/SoftGpu.h +++ b/GPU/Software/SoftGpu.h @@ -141,7 +141,7 @@ public: bool PerformMemorySet(u32 dest, u8 v, int size) override; bool PerformMemoryDownload(u32 dest, int size) override; bool PerformMemoryUpload(u32 dest, int size) override; - bool PerformStencilUpload(u32 dest, int size) override; + bool PerformStencilUpload(u32 dest, int size, StencilUpload flags) override; void ClearCacheNextFrame() override {} void DeviceLost() override;