From a397c74140cae4f46b40bc5ffe462071df013021 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 13 Sep 2022 19:07:25 -0700 Subject: [PATCH 1/2] GPU: Fix simulating logicop with blend and shader. We only need to do it in the shader, if we're doing it in the shader. --- GPU/Common/GPUStateUtils.cpp | 37 ++++++++++++++++++++++++------------ GPU/Common/GPUStateUtils.h | 1 + 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 7690156d9dbc..fb90850cb9b6 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -856,7 +856,7 @@ static inline bool blendColorSimilar(uint32_t a, uint32_t b, int margin = 25) { // Try to simulate some common logic ops by using blend, if needed. // The shader might also need modification, the below function SimulateLogicOpShaderTypeIfNeeded // takes care of that. -static void SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend, BlendEq &blendEq) { +static bool SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend, BlendEq &blendEq) { // Note: our shader solution applies logic ops BEFORE blending, not correctly after. // This is however fine for the most common ones, like CLEAR/NOOP/SET, etc. if (!gstate_c.Supports(GPU_SUPPORTS_LOGIC_OP)) { @@ -866,7 +866,7 @@ static void SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend srcBlend = BlendFactor::ZERO; dstBlend = BlendFactor::ZERO; blendEq = BlendEq::ADD; - break; + return true; case GE_LOGIC_AND: case GE_LOGIC_AND_REVERSE: WARN_LOG_REPORT_ONCE(d3dLogicOpAnd, G3D, "Unsupported AND logic op: %x", gstate.getLogicOp()); @@ -889,21 +889,23 @@ static void SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend dstBlend = BlendFactor::ONE; blendEq = BlendEq::SUBTRACT; WARN_LOG_REPORT_ONCE(d3dLogicOpInverted, G3D, "Attempted inverse for logic op: %x", gstate.getLogicOp()); - break; + return true; case GE_LOGIC_NOOP: srcBlend = BlendFactor::ZERO; dstBlend = BlendFactor::ONE; blendEq = BlendEq::ADD; - break; + return true; case GE_LOGIC_XOR: WARN_LOG_REPORT_ONCE(d3dLogicOpOrXor, G3D, "Unsupported XOR logic op: %x", gstate.getLogicOp()); break; case GE_LOGIC_OR: case GE_LOGIC_OR_INVERTED: // Inverted in shader. + srcBlend = BlendFactor::ONE; dstBlend = BlendFactor::ONE; + blendEq = BlendEq::ADD; WARN_LOG_REPORT_ONCE(d3dLogicOpOr, G3D, "Attempted or for logic op: %x", gstate.getLogicOp()); - break; + return true; case GE_LOGIC_OR_REVERSE: WARN_LOG_REPORT_ONCE(d3dLogicOpOrReverse, G3D, "Unsupported OR REVERSE logic op: %x", gstate.getLogicOp()); break; @@ -912,10 +914,12 @@ static void SimulateLogicOpIfNeeded(BlendFactor &srcBlend, BlendFactor &dstBlend dstBlend = BlendFactor::ONE; blendEq = BlendEq::ADD; WARN_LOG_REPORT_ONCE(d3dLogicOpSet, G3D, "Attempted set for logic op: %x", gstate.getLogicOp()); - break; + return true; } } } + + return false; } // Choose the shader part of the above logic op fallback simulation. @@ -950,7 +954,6 @@ void ApplyStencilReplaceAndLogicOpIgnoreBlend(ReplaceAlphaType replaceAlphaWithS BlendFactor srcBlend = BlendFactor::ONE; BlendFactor dstBlend = BlendFactor::ZERO; BlendEq blendEq = BlendEq::ADD; - SimulateLogicOpIfNeeded(srcBlend, dstBlend, blendEq); // We're not blending, but we may still want to "blend" for stencil. // This is only useful for INCR/DECR/INVERT. Others can write directly. @@ -1252,11 +1255,6 @@ static void ConvertBlendState(GenericBlendState &blendState, bool forceReplaceBl colorEq = eqLookupNoMinMax[blendFuncEq]; } - // Attempt to apply simulated logic ops, if any and if needed. - if (!forceReplaceBlend) { - SimulateLogicOpIfNeeded(glBlendFuncA, glBlendFuncB, colorEq); - } - // The stencil-to-alpha in fragment shader doesn't apply here (blending is enabled), and we shouldn't // do any blending in the alpha channel as that doesn't seem to happen on PSP. So, we attempt to // apply the stencil to the alpha, since that's what should be stored. @@ -1581,5 +1579,20 @@ void ComputedPipelineState::Convert(bool shaderBitOpsSuppported) { if (blendState.applyFramebufferRead || logicState.applyFramebufferRead) { maskState.ConvertToShaderBlend(); logicState.ConvertToShaderBlend(); + } else { + // If it isn't a read, we may need to change blending to apply the logic op. + logicState.ApplyToBlendState(blendState); + } +} + +void GenericLogicState::ApplyToBlendState(GenericBlendState &blendState) { + if (SimulateLogicOpIfNeeded(blendState.srcColor, blendState.dstColor, blendState.eqColor)) { + if (!blendState.blendEnabled) { + // If it wasn't turned on, make sure it is now. + blendState.blendEnabled = true; + blendState.srcAlpha = BlendFactor::ONE; + blendState.dstAlpha = BlendFactor::ZERO; + blendState.eqAlpha = BlendEq::ADD; + } } } diff --git a/GPU/Common/GPUStateUtils.h b/GPU/Common/GPUStateUtils.h index bc0c9ae7b15b..038091f7d8f9 100644 --- a/GPU/Common/GPUStateUtils.h +++ b/GPU/Common/GPUStateUtils.h @@ -226,6 +226,7 @@ struct GenericLogicState { // Hardware and shader generation GELogicOp logicOp; + void ApplyToBlendState(GenericBlendState &blendState); void ConvertToShaderBlend() { if (logicOp != GE_LOGIC_COPY) { logicOpEnabled = false; From 440062530e05739932bc4d193d190c222ecd63b4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 13 Sep 2022 19:07:54 -0700 Subject: [PATCH 2/2] GE Debugger: Allow fb copies while stepping. This is now causing crashes and should be allowed. --- GPU/Common/FramebufferManagerCommon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 1a8bd673d7fe..538c0ded3d7b 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -1073,7 +1073,7 @@ bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualF // currentRenderVfb_ will always be set when this is called, except from the GE debugger. // Let's just not bother with the copy in that case. - bool skipCopy = !(flags & BINDFBCOLOR_MAY_COPY) || GPUStepping::IsStepping(); + bool skipCopy = !(flags & BINDFBCOLOR_MAY_COPY); // Currently rendering to this framebuffer. Need to make a copy. if (!skipCopy && framebuffer == currentRenderVfb_) {