From 5932cbabc325bc1085eb99e37ed8f5588a56f5c9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 1 Dec 2018 14:05:29 -0800 Subject: [PATCH] GPU: Avoid stencil emulation if possible. This reduces use of replaceAlpha, and reduces use of more complicated blend states. This simplifies fragment shaders a little. --- GPU/Common/GPUStateUtils.cpp | 17 ++++++++++++++--- GPU/Common/GPUStateUtils.h | 1 + GPU/D3D11/StateMappingD3D11.cpp | 2 +- GPU/Directx9/StateMappingDX9.cpp | 2 +- GPU/GLES/StateMappingGLES.cpp | 2 +- GPU/Vulkan/StateMappingVulkan.cpp | 2 +- 6 files changed, 19 insertions(+), 7 deletions(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 2a0e88d216..1a650028bc 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -40,6 +40,17 @@ bool CanUseHardwareTransform(int prim) { return !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES; } +bool IsStencilTestOutputDisabled() { + // The mask applies on all stencil ops. + if (gstate.isStencilTestEnabled() && (gstate.pmska & 0xFF) != 0xFF) { + if (gstate.FrameBufFormat() == GE_FORMAT_565) { + return true; + } + return gstate.getStencilOpZPass() == GE_STENCILOP_KEEP && gstate.getStencilOpZFail() == GE_STENCILOP_KEEP && gstate.getStencilOpSFail() == GE_STENCILOP_KEEP; + } + return true; +} + bool NeedsTestDiscard() { // We assume this is called only when enabled and not trivially true (may also be for color testing.) if (gstate.isStencilTestEnabled() && (gstate.pmska & 0xFF) != 0xFF) @@ -169,7 +180,7 @@ const bool nonAlphaDestFactors[16] = { }; ReplaceAlphaType ReplaceAlphaWithStencil(ReplaceBlendType replaceBlend) { - if (!gstate.isStencilTestEnabled() || gstate.isModeClear()) { + if (IsStencilTestOutputDisabled() || gstate.isModeClear()) { return REPLACE_ALPHA_NO; } @@ -995,7 +1006,7 @@ void ConvertBlendState(GenericBlendState &blendState, bool allowShaderBlend) { int constantAlpha = 255; BlendFactor constantAlphaGL = BlendFactor::ONE; - if (gstate.isStencilTestEnabled() && replaceAlphaWithStencil == REPLACE_ALPHA_NO) { + if (!IsStencilTestOutputDisabled() && replaceAlphaWithStencil == REPLACE_ALPHA_NO) { switch (ReplaceAlphaWithStencilType()) { case STENCIL_VALUE_UNIFORM: constantAlpha = gstate.getStencilTestRef(); @@ -1163,7 +1174,7 @@ void ConvertBlendState(GenericBlendState &blendState, bool allowShaderBlend) { blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ONE, BlendFactor::ZERO); break; } - } else if (gstate.isStencilTestEnabled()) { + } else if (!IsStencilTestOutputDisabled()) { switch (ReplaceAlphaWithStencilType()) { case STENCIL_VALUE_KEEP: blendState.setFactors(glBlendFuncA, glBlendFuncB, BlendFactor::ZERO, BlendFactor::ONE); diff --git a/GPU/Common/GPUStateUtils.h b/GPU/Common/GPUStateUtils.h index f6a4e11c21..957c6c42b3 100644 --- a/GPU/Common/GPUStateUtils.h +++ b/GPU/Common/GPUStateUtils.h @@ -45,6 +45,7 @@ bool IsColorTestAgainstZero(); bool IsColorTestTriviallyTrue(); bool IsAlphaTestAgainstZero(); bool NeedsTestDiscard(); +bool IsStencilTestOutputDisabled(); StencilValueType ReplaceAlphaWithStencilType(); ReplaceAlphaType ReplaceAlphaWithStencil(ReplaceBlendType replaceBlend); diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index f5ff8807dc..0dc7a74e4b 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -223,7 +223,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { #endif // Let's not write to alpha if stencil isn't enabled. - if (!gstate.isStencilTestEnabled()) { + if (IsStencilTestOutputDisabled()) { amask = false; } else { // If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel. diff --git a/GPU/Directx9/StateMappingDX9.cpp b/GPU/Directx9/StateMappingDX9.cpp index f555ab3d53..3a9d8ffb0c 100644 --- a/GPU/Directx9/StateMappingDX9.cpp +++ b/GPU/Directx9/StateMappingDX9.cpp @@ -181,7 +181,7 @@ void DrawEngineDX9::ApplyDrawState(int prim) { #endif // Let's not write to alpha if stencil isn't enabled. - if (!gstate.isStencilTestEnabled()) { + if (IsStencilTestOutputDisabled()) { amask = false; } else { // If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel. diff --git a/GPU/GLES/StateMappingGLES.cpp b/GPU/GLES/StateMappingGLES.cpp index ec256cd842..5a93dbbbb4 100644 --- a/GPU/GLES/StateMappingGLES.cpp +++ b/GPU/GLES/StateMappingGLES.cpp @@ -143,7 +143,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) { // amask is needed for both stencil and blend state so we keep it outside for now bool amask = (gstate.pmska & 0xFF) < 128; // Let's not write to alpha if stencil isn't enabled. - if (!gstate.isStencilTestEnabled()) { + if (IsStencilTestOutputDisabled()) { amask = false; } else { // If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel. diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index 282b602dd8..ff6c141af5 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -225,7 +225,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag #endif // Let's not write to alpha if stencil isn't enabled. - if (!gstate.isStencilTestEnabled()) { + if (IsStencilTestOutputDisabled()) { amask = false; } else { // If the stencil type is set to KEEP, we shouldn't write to the stencil/alpha channel.