diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 64261e93e7f0..5b115df27878 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -501,7 +501,7 @@ bool DrawEngineCommon::ApplyFramebufferRead(bool *fboTexNeedsBind) { lastFrameBlit = gpuStats.numFlips; } ++blitsThisFrame; - if (blitsThisFrame > MAX_REASONABLE_BLITS_PER_FRAME * 2) { + if (blitsThisFrame > MAX_REASONABLE_BLITS_PER_FRAME * 4) { WARN_LOG_ONCE(blendingBlit2, G3D, "Skipping additional blits needed for obscure blending: %d per frame, blend %d/%d/%d", blitsThisFrame, gstate.getBlendFuncA(), gstate.getBlendFuncB(), gstate.getBlendEq()); return false; } diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 47fc87a5e027..d3eec7c9ecfd 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -1033,7 +1033,7 @@ void ConvertMaskState(GenericMaskState &maskState, bool allowFramebufferRead) { } // Called even if AlphaBlendEnable == false - it also deals with stencil-related blend state. -void ConvertBlendState(GenericBlendState &blendState, bool allowFramebufferRead) { +void ConvertBlendState(GenericBlendState &blendState, bool allowFramebufferRead, bool forceReplaceBlend) { // Blending is a bit complex to emulate. This is due to several reasons: // // * Doubled blend modes (src, dst, inversed) aren't supported in OpenGL. @@ -1050,6 +1050,9 @@ void ConvertBlendState(GenericBlendState &blendState, bool allowFramebufferRead) blendState.replaceAlphaWithStencil = REPLACE_ALPHA_NO; ReplaceBlendType replaceBlend = ReplaceBlendWithShader(allowFramebufferRead, gstate.FrameBufFormat()); + if (forceReplaceBlend) { + replaceBlend = REPLACE_BLEND_COPY_FBO; + } ReplaceAlphaType replaceAlphaWithStencil = ReplaceAlphaWithStencil(replaceBlend); bool usePreSrc = false; diff --git a/GPU/Common/GPUStateUtils.h b/GPU/Common/GPUStateUtils.h index 0361c2886e5a..d61baca4f547 100644 --- a/GPU/Common/GPUStateUtils.h +++ b/GPU/Common/GPUStateUtils.h @@ -166,7 +166,7 @@ struct GenericBlendState { } }; -void ConvertBlendState(GenericBlendState &blendState, bool allowShaderBlend); +void ConvertBlendState(GenericBlendState &blendState, bool allowShaderBlend, bool forceReplaceBlend); void ApplyStencilReplaceAndLogicOpIgnoreBlend(ReplaceAlphaType replaceAlphaWithStencil, GenericBlendState &blendState); struct GenericMaskState { diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 04293021c971..5cdbc17afc45 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -253,6 +253,9 @@ void ComputeFragmentShaderID(FShaderID *id_out, const Draw::Bugs &bugs) { // Note how we here recompute some of the work already done in state mapping. // Not ideal! At least we share the code. ReplaceBlendType replaceBlend = ReplaceBlendWithShader(gstate_c.allowFramebufferRead, gstate.FrameBufFormat()); + if (colorWriteMask) { + replaceBlend = REPLACE_BLEND_COPY_FBO; + } ReplaceAlphaType stencilToAlpha = ReplaceAlphaWithStencil(replaceBlend); // All texfuncs except replace are the same for RGB as for RGBA with full alpha. diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index 2707bc422632..0452d9f75169 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -155,13 +155,14 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { keys_.blend.colorWriteMask = (colorMask ? (1 | 2 | 4) : 0) | (alphaMask ? 8 : 0); } else { keys_.blend.value = 0; - // Set blend - unless we need to do it in the shader. - GenericBlendState blendState; - ConvertBlendState(blendState, gstate_c.allowFramebufferRead); GenericMaskState maskState; ConvertMaskState(maskState, gstate_c.allowFramebufferRead); + // Set blend - unless we need to do it in the shader. + GenericBlendState blendState; + ConvertBlendState(blendState, gstate_c.allowFramebufferRead, maskState.applyFramebufferRead); + if (blendState.applyFramebufferRead || maskState.applyFramebufferRead) { if (ApplyFramebufferRead(&fboTexNeedsBind_)) { // The shader takes over the responsibility for blending, so recompute. diff --git a/GPU/Directx9/StateMappingDX9.cpp b/GPU/Directx9/StateMappingDX9.cpp index f189bfa5f6e5..8db33388134a 100644 --- a/GPU/Directx9/StateMappingDX9.cpp +++ b/GPU/Directx9/StateMappingDX9.cpp @@ -125,13 +125,13 @@ void DrawEngineDX9::ApplyDrawState(int prim) { bool alphaMask = gstate.isClearModeAlphaMask(); dxstate.colorMask.set(colorMask, colorMask, colorMask, alphaMask); } else { - // Set blend - unless we need to do it in the shader. - GenericBlendState blendState; - ConvertBlendState(blendState, gstate_c.allowFramebufferRead); - GenericMaskState maskState; ConvertMaskState(maskState, gstate_c.allowFramebufferRead); + // Set blend - unless we need to do it in the shader. + GenericBlendState blendState; + ConvertBlendState(blendState, gstate_c.allowFramebufferRead, maskState.applyFramebufferRead); + if (blendState.applyFramebufferRead || maskState.applyFramebufferRead) { if (ApplyFramebufferRead(&fboTexNeedsBind_)) { // The shader takes over the responsibility for blending, so recompute. diff --git a/GPU/GLES/StateMappingGLES.cpp b/GPU/GLES/StateMappingGLES.cpp index 36e3982a48f7..d6f0211cd178 100644 --- a/GPU/GLES/StateMappingGLES.cpp +++ b/GPU/GLES/StateMappingGLES.cpp @@ -155,12 +155,13 @@ void DrawEngineGLES::ApplyDrawState(int prim) { } else { // Do the large chunks of state conversion. We might be able to hide these two behind a dirty-flag each, // to avoid recomputing heavy stuff unnecessarily every draw call. - GenericBlendState blendState; - ConvertBlendState(blendState, gstate_c.allowFramebufferRead); GenericMaskState maskState; ConvertMaskState(maskState, gstate_c.allowFramebufferRead); + GenericBlendState blendState; + ConvertBlendState(blendState, gstate_c.allowFramebufferRead, maskState.applyFramebufferRead); + if (blendState.applyFramebufferRead || maskState.applyFramebufferRead) { if (ApplyFramebufferRead(&fboTexNeedsBind_)) { // The shader takes over the responsibility for blending, so recompute. diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index e4ed83ee35e7..56ef6941bd74 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -161,13 +161,13 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag key.logicOp = VK_LOGIC_OP_CLEAR; } - // Set blend - unless we need to do it in the shader. - GenericBlendState blendState; - ConvertBlendState(blendState, gstate_c.allowFramebufferRead); - GenericMaskState maskState; ConvertMaskState(maskState, gstate_c.allowFramebufferRead); + // Set blend - unless we need to do it in the shader. + GenericBlendState blendState; + ConvertBlendState(blendState, gstate_c.allowFramebufferRead, maskState.applyFramebufferRead); + if (blendState.applyFramebufferRead || maskState.applyFramebufferRead) { if (ApplyFramebufferRead(&fboTexNeedsBind_)) { // The shader takes over the responsibility for blending, so recompute. diff --git a/assets/compat.ini b/assets/compat.ini index 9c22da742f92..c49b4c7490f9 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -1025,6 +1025,12 @@ ULES01441 = true ULJM05600 = true ULJM05775 = true +# Split/Second +ULES01402 = true +ULUS10513 = true +ULJM05812 = true +NPJH50371 = true + [ShaderColorBitmask] # Outrun 2006: Coast to Coast - issue #11358 ULES00262 = true @@ -1037,6 +1043,12 @@ ULJM05533 = true NPJH50006 = true ULES01301 = true +# Split/Second +ULES01402 = true +ULUS10513 = true +ULJM05812 = true +NPJH50371 = true + [DisableFirstFrameReadback] # Wipeout Pure: Temporary workaround for lens flare flicker. See #13344 UCUS98612 = true