From d52fdafa3c1c35d95320095242622679a895dc48 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 3 Aug 2014 10:25:37 -0700 Subject: [PATCH 01/10] Note the location of a memset variant. --- Core/MIPS/MIPSAnalyst.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index 263ac0d89e..7de092670a 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -388,7 +388,7 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0xe83a7a9d80a21c11, 4448, "_strtod_r", }, { 0xe894bda909a8a8f9, 1064, "expensive_wipeout_pulse", }, { 0xe8ad7719be44e7c8, 276, "strchr", }, - { 0xeabb9c1b4f83d2b4, 52, "memset", }, + { 0xeabb9c1b4f83d2b4, 52, "memset", }, // Crisis Core { 0xeb0f7bf63d52ece9, 88, "strncat", }, { 0xeb8c0834d8bbc28c, 416, "fmodf", }, { 0xedbbe9bf9fbceca8, 172, "dl_write_viewport2", }, From 44620c92ed90e796d28299fb290b658622fc316f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 3 Aug 2014 10:28:14 -0700 Subject: [PATCH 02/10] Premultiply for doubled alpha blending if possible. This makes the effect more accurate where the values were being clamped before. Some obscure methods of blending may be slower. --- GPU/GLES/FragmentShaderGenerator.cpp | 285 ++++++++++++--------------- GPU/GLES/FragmentShaderGenerator.h | 13 +- GPU/GLES/StateMapping.cpp | 75 +++---- GPU/GLES/TextureCache.cpp | 1 + 4 files changed, 181 insertions(+), 193 deletions(-) diff --git a/GPU/GLES/FragmentShaderGenerator.cpp b/GPU/GLES/FragmentShaderGenerator.cpp index 65364bd1e6..9d2d0cde94 100644 --- a/GPU/GLES/FragmentShaderGenerator.cpp +++ b/GPU/GLES/FragmentShaderGenerator.cpp @@ -145,7 +145,7 @@ ReplaceAlphaType ReplaceAlphaWithStencil() { if (gstate.isAlphaBlendEnabled()) { if (nonAlphaSrcFactors[gstate.getBlendFuncA()] && nonAlphaDestFactors[gstate.getBlendFuncB()]) { return REPLACE_ALPHA_YES; - } else if (ShouldUseShaderBlending()) { + } else if (ReplaceBlendWithShader() == REPLACE_BLEND_COPY_FBO) { return REPLACE_ALPHA_YES; } else { if (gl_extensions.ARB_blend_func_extended) { @@ -232,149 +232,110 @@ bool IsColorTestTriviallyTrue() { } } -static bool AlphaToColorDoubling() { - if (!gstate.isAlphaBlendEnabled()) { - return false; - } - // 2x alpha in the source function and not in the dest = source color doubling. - switch (gstate.getBlendFuncA()) { - case GE_SRCBLEND_DOUBLESRCALPHA: - case GE_SRCBLEND_DOUBLEINVSRCALPHA: - break; - - case GE_SRCBLEND_DOUBLEDSTALPHA: - case GE_SRCBLEND_DOUBLEINVDSTALPHA: - // Even dest alpha is safe, since we're moving the * 2.0 into the src color. - break; - - default: - return false; - } - switch (gstate.getBlendFuncB()) { - case GE_DSTBLEND_SRCCOLOR: - case GE_DSTBLEND_INVSRCCOLOR: - // Can't double, we need the source color to be correct. - return false; - - case GE_DSTBLEND_DOUBLESRCALPHA: - case GE_DSTBLEND_DOUBLEINVSRCALPHA: - case GE_DSTBLEND_DOUBLEDSTALPHA: - case GE_DSTBLEND_DOUBLEINVDSTALPHA: - // Won't do the trick, would be better to double both sides. - return false; - - default: - // In all other cases, we're pre-multiplying the src side by 2. - // For example, src * (2.0 * a) + dst * fixB, we're just moving the 2.0. - return true; - } -} - -static bool CanDoubleSrcBlendMode() { - if (!gstate.isAlphaBlendEnabled()) { - return false; - } - - int funcA = gstate.getBlendFuncA(); - int funcB = gstate.getBlendFuncB(); - if (funcA != GE_SRCBLEND_DOUBLESRCALPHA && funcA != GE_SRCBLEND_DOUBLEINVSRCALPHA) { - funcB = funcA; - funcA = gstate.getBlendFuncB(); - } - if (funcA != GE_SRCBLEND_DOUBLESRCALPHA && funcA != GE_SRCBLEND_DOUBLEINVSRCALPHA) { - return false; - } - - // One side should be doubled. Let's check the other side. - // LittleBigPlanet and Persona 2, for example, uses 2.0 * src.a, 1.0 - src.a, which can't double. - // In that case, we can double the src rgb instead. - switch (funcB) { - case GE_DSTBLEND_SRCALPHA: - case GE_DSTBLEND_INVSRCALPHA: - return false; - - default: - return true; - } -} - -// TODO: Setting to disable? -bool ShouldUseShaderBlending() { - if (!gstate.isAlphaBlendEnabled()) { - return false; - } - if (g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) { - return false; +ReplaceBlendType ReplaceBlendWithShader() { + if (!gstate.isAlphaBlendEnabled() || gstate.isModeClear()) { + return REPLACE_BLEND_NO; } GEBlendSrcFactor funcA = gstate.getBlendFuncA(); GEBlendDstFactor funcB = gstate.getBlendFuncB(); GEBlendMode eq = gstate.getBlendEq(); + // Let's get the non-factor modes out of the way first. switch (eq) { case GE_BLENDMODE_ABSDIFF: - return !g_Config.bDisableSlowFramebufEffects; + return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; case GE_BLENDMODE_MIN: case GE_BLENDMODE_MAX: - // These don't use the factors. - return !gl_extensions.EXT_blend_minmax && !gl_extensions.GLES3 && !g_Config.bDisableSlowFramebufEffects; - - default: - break; - } - - // This normally involves a blit, so try to skip it. - if (AlphaToColorDoubling() || CanDoubleSrcBlendMode()) { - return false; - } - - switch (funcA) { - case GE_SRCBLEND_DOUBLESRCALPHA: - case GE_SRCBLEND_DOUBLEINVSRCALPHA: - case GE_SRCBLEND_DOUBLEDSTALPHA: - case GE_SRCBLEND_DOUBLEINVDSTALPHA: - return !g_Config.bDisableSlowFramebufEffects; - - case GE_SRCBLEND_FIXA: - if (funcB == GE_DSTBLEND_FIXB) { - u32 fixA = gstate.getFixA(); - u32 fixB = gstate.getFixB(); - // OpenGL only supports one constant color, so check if we could be more exact. - if (fixA != fixB && fixA != 0xFFFFFF - fixB && fixA != 0 && fixB != 0 && fixA != 0xFFFFFF && fixB != 0xFFFFFF) { - return true; - } + if (gl_extensions.EXT_blend_minmax || gl_extensions.GLES3) { + return REPLACE_BLEND_STANDARD; + } else { + return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; } default: break; } - switch (funcB) { - case GE_DSTBLEND_DOUBLESRCALPHA: - case GE_DSTBLEND_DOUBLEINVSRCALPHA: - case GE_DSTBLEND_DOUBLEDSTALPHA: - case GE_DSTBLEND_DOUBLEINVDSTALPHA: - return !g_Config.bDisableSlowFramebufEffects; + switch (funcA) { + case GE_SRCBLEND_DOUBLESRCALPHA: + case GE_SRCBLEND_DOUBLEINVSRCALPHA: + // 2x alpha in the source function and not in the dest = source color doubling. + // Even dest alpha is safe, since we're moving the * 2.0 into the src color. + switch (funcB) { + case GE_DSTBLEND_SRCCOLOR: + case GE_DSTBLEND_INVSRCCOLOR: + // Can't double, we need the source color to be correct. + return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_2X_ALPHA : REPLACE_BLEND_COPY_FBO; + + case GE_DSTBLEND_DOUBLEDSTALPHA: + case GE_DSTBLEND_DOUBLEINVDSTALPHA: + return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_2X_ALPHA : REPLACE_BLEND_COPY_FBO; + + case GE_DSTBLEND_DOUBLESRCALPHA: + case GE_DSTBLEND_DOUBLEINVSRCALPHA: + // We can't technically do this correctly (due to clamping) without reading the dst color. + if (g_Config.bDisableSlowFramebufEffects) { + return REPLACE_BLEND_PRE_SRC_2X_ALPHA; + } else { + return REPLACE_BLEND_COPY_FBO; + } + + default: + // TODO: Could use vertexFullAlpha, but it's not calculated yet. + return REPLACE_BLEND_PRE_SRC; + } + + case GE_SRCBLEND_DOUBLEDSTALPHA: + case GE_SRCBLEND_DOUBLEINVDSTALPHA: + switch (funcB) { + case GE_DSTBLEND_SRCCOLOR: + case GE_DSTBLEND_INVSRCCOLOR: + // Can't double, we need the source color to be correct. + return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; + + case GE_DSTBLEND_DOUBLEDSTALPHA: + case GE_DSTBLEND_DOUBLEINVDSTALPHA: + case GE_DSTBLEND_DOUBLESRCALPHA: + case GE_DSTBLEND_DOUBLEINVSRCALPHA: + return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_2X_SRC : REPLACE_BLEND_COPY_FBO; + + default: + // We can't technically do this correctly (due to clamping) without reading the dst alpha. + return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_2X_SRC : REPLACE_BLEND_COPY_FBO; + } + + case GE_SRCBLEND_FIXA: + switch (funcB) { + case GE_DSTBLEND_DOUBLESRCALPHA: + case GE_DSTBLEND_DOUBLEINVSRCALPHA: + // Can't safely double alpha, will clamp. + return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_2X_ALPHA : REPLACE_BLEND_COPY_FBO; + + case GE_DSTBLEND_DOUBLEDSTALPHA: + case GE_DSTBLEND_DOUBLEINVDSTALPHA: + return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; + + case GE_DSTBLEND_FIXB: + return REPLACE_BLEND_PRE_SRC; + + default: + return REPLACE_BLEND_STANDARD; + } default: - break; - } + switch (funcB) { + case GE_DSTBLEND_DOUBLESRCALPHA: + case GE_DSTBLEND_DOUBLEINVSRCALPHA: + case GE_DSTBLEND_DOUBLEDSTALPHA: + case GE_DSTBLEND_DOUBLEINVDSTALPHA: + return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; - return false; -} - -// Doesn't need to be in the shader id, ShouldUseShaderBlending contains all parts. -bool ShouldUseShaderFixedBlending() { - if (!ShouldUseShaderBlending()) { - return false; + default: + return REPLACE_BLEND_STANDARD; + } } - - if (gstate.getBlendFuncA() == GE_SRCBLEND_FIXA && gstate.getBlendFuncB() == GE_DSTBLEND_FIXB) { - GEBlendMode blendEq = gstate.getBlendEq(); - return blendEq != GE_BLENDMODE_MIN && blendEq != GE_BLENDMODE_MAX && blendEq != GE_BLENDMODE_ABSDIFF; - } - return false; } // Here we must take all the bits of the gstate that determine what the fragment shader will @@ -391,14 +352,11 @@ void ComputeFragmentShaderID(FragmentShaderID *id) { bool enableAlphaTest = gstate.isAlphaTestEnabled() && !IsAlphaTestTriviallyTrue() && !g_Config.bDisableAlphaTest; bool alphaTestAgainstZero = gstate.getAlphaTestRef() == 0 && gstate.getAlphaTestMask() == 0xFF; bool enableColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue(); - bool useShaderBlending = ShouldUseShaderBlending(); - bool alphaToColorDoubling = AlphaToColorDoubling() && !useShaderBlending; - bool enableColorDoubling = (gstate.isColorDoublingEnabled() && gstate.isTextureMapEnabled()) || alphaToColorDoubling; - // This isn't really correct, but it's a hack to get doubled blend modes to work more correctly. - bool enableAlphaDoubling = !alphaToColorDoubling && !useShaderBlending && CanDoubleSrcBlendMode(); + bool enableColorDoubling = gstate.isColorDoublingEnabled() && gstate.isTextureMapEnabled(); bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX; bool doTextureAlpha = gstate.isTextureAlphaUsed(); ReplaceAlphaType stencilToAlpha = ReplaceAlphaWithStencil(); + ReplaceBlendType replaceBlend = ReplaceBlendWithShader(); // All texfuncs except replace are the same for RGB as for RGBA with full alpha. if (gstate_c.textureFullAlpha && gstate.getTextureFunction() != GE_TEXFUNC_REPLACE) @@ -435,29 +393,29 @@ void ComputeFragmentShaderID(FragmentShaderID *id) { id0 |= (enableFog & 1) << 19; id0 |= (doTextureProjection & 1) << 20; id0 |= (enableColorDoubling & 1) << 21; - id0 |= (enableAlphaDoubling & 1) << 22; // 2 bits - id0 |= (stencilToAlpha) << 23; + id0 |= (stencilToAlpha) << 22; if (stencilToAlpha != REPLACE_ALPHA_NO) { // 3 bits - id0 |= ReplaceAlphaWithStencilType() << 25; + id0 |= ReplaceAlphaWithStencilType() << 24; } - id0 |= (alphaTestAgainstZero & 1) << 28; + id0 |= (alphaTestAgainstZero & 1) << 27; if (enableAlphaTest) gpuStats.numAlphaTestedDraws++; else gpuStats.numNonAlphaTestedDraws++; - // 29 - 31 are free. + // 28 - 31 are free. - if (useShaderBlending) { - // 12 bits total. - id1 |= 1 << 0; - id1 |= gstate.getBlendEq() << 1; - id1 |= gstate.getBlendFuncA() << 4; - id1 |= gstate.getBlendFuncB() << 8; + // 3 bits. + id1 |= replaceBlend << 0; + if (replaceBlend > REPLACE_BLEND_STANDARD) { + // 11 bits total. + id1 |= gstate.getBlendEq() << 3; + id1 |= gstate.getBlendFuncA() << 6; + id1 |= gstate.getBlendFuncB() << 10; } } @@ -548,23 +506,20 @@ void GenerateFragmentShader(char *buffer) { bool enableAlphaTest = gstate.isAlphaTestEnabled() && !IsAlphaTestTriviallyTrue() && !gstate.isModeClear() && !g_Config.bDisableAlphaTest; bool alphaTestAgainstZero = gstate.getAlphaTestRef() == 0 && gstate.getAlphaTestMask() == 0xFF; bool enableColorTest = gstate.isColorTestEnabled() && !IsColorTestTriviallyTrue() && !gstate.isModeClear(); - bool useShaderBlending = ShouldUseShaderBlending(); - bool alphaToColorDoubling = AlphaToColorDoubling() && !useShaderBlending; - bool enableColorDoubling = (gstate.isColorDoublingEnabled() && gstate.isTextureMapEnabled()) || alphaToColorDoubling; - // This isn't really correct, but it's a hack to get doubled blend modes to work more correctly. - bool enableAlphaDoubling = !alphaToColorDoubling && !useShaderBlending && CanDoubleSrcBlendMode(); + bool enableColorDoubling = gstate.isColorDoublingEnabled() && gstate.isTextureMapEnabled(); bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX; bool doTextureAlpha = gstate.isTextureAlphaUsed(); bool textureAtOffset = gstate_c.curTextureXOffset != 0 || gstate_c.curTextureYOffset != 0; ReplaceAlphaType stencilToAlpha = ReplaceAlphaWithStencil(); + ReplaceBlendType replaceBlend = ReplaceBlendWithShader(); if (gstate_c.textureFullAlpha && gstate.getTextureFunction() != GE_TEXFUNC_REPLACE) doTextureAlpha = false; if (doTexture) WRITE(p, "uniform sampler2D tex;\n"); - if (!gstate.isModeClear() && useShaderBlending) { - if (!gl_extensions.NV_shader_framebuffer_fetch) { + if (!gstate.isModeClear() && replaceBlend > REPLACE_BLEND_STANDARD) { + if (!gl_extensions.NV_shader_framebuffer_fetch && replaceBlend == REPLACE_BLEND_COPY_FBO) { if (!texelFetch) { WRITE(p, "uniform vec2 u_fbotexSize;\n"); } @@ -815,12 +770,10 @@ void GenerateFragmentShader(char *buffer) { } // Color doubling happens after the color test. - if (enableColorDoubling && enableAlphaDoubling) { - WRITE(p, " v = v * 2.0;\n"); - } else if (enableColorDoubling) { + if (enableColorDoubling && replaceBlend == REPLACE_BLEND_2X_SRC) { + WRITE(p, " v.rgb = v.rgb * 4.0;\n"); + } else if (enableColorDoubling || replaceBlend == REPLACE_BLEND_2X_SRC) { WRITE(p, " v.rgb = v.rgb * 2.0;\n"); - } else if (enableAlphaDoubling) { - WRITE(p, " v.a = v.a * 2.0;\n"); } if (enableFog) { @@ -829,10 +782,28 @@ void GenerateFragmentShader(char *buffer) { // WRITE(p, " v.x = v_depth;\n"); } - if (ShouldUseShaderFixedBlending()) { - // Just premultiply by u_blendFixA. - WRITE(p, " v.rgb = v.rgb * u_blendFixA;\n"); - } else if (useShaderBlending) { + if (replaceBlend == REPLACE_BLEND_PRE_SRC || replaceBlend == REPLACE_BLEND_PRE_SRC_2X_ALPHA) { + GEBlendSrcFactor funcA = gstate.getBlendFuncA(); + const char *srcFactor = "ERROR"; + switch (funcA) { + case GE_SRCBLEND_DSTCOLOR: srcFactor = "ERROR"; break; + case GE_SRCBLEND_INVDSTCOLOR: srcFactor = "ERROR"; break; + case GE_SRCBLEND_SRCALPHA: srcFactor = "vec3(v.a)"; break; + case GE_SRCBLEND_INVSRCALPHA: srcFactor = "vec3(1.0 - v.a)"; break; + case GE_SRCBLEND_DSTALPHA: srcFactor = "ERROR"; break; + case GE_SRCBLEND_INVDSTALPHA: srcFactor = "ERROR"; break; + case GE_SRCBLEND_DOUBLESRCALPHA: srcFactor = "vec3(v.a * 2.0)"; break; + // TODO: Double inverse, or inverse double? Following softgpu for now... + case GE_SRCBLEND_DOUBLEINVSRCALPHA: srcFactor = "vec3(1.0 - v.a * 2.0)"; break; + case GE_SRCBLEND_DOUBLEDSTALPHA: srcFactor = "ERROR"; break; + case GE_SRCBLEND_DOUBLEINVDSTALPHA: srcFactor = "ERROR"; break; + case GE_SRCBLEND_FIXA: srcFactor = "u_blendFixA"; break; + } + + WRITE(p, " v.rgb = v.rgb * %s;\n", srcFactor); + } + + if (replaceBlend == REPLACE_BLEND_COPY_FBO) { // If we have NV_shader_framebuffer_fetch / EXT_shader_framebuffer_fetch, we skip the blit. // We can just read the prev value more directly. // TODO: EXT_shader_framebuffer_fetch on iOS 6, possibly others. @@ -903,6 +874,10 @@ void GenerateFragmentShader(char *buffer) { break; } } + + if (replaceBlend == REPLACE_BLEND_2X_ALPHA || replaceBlend == REPLACE_BLEND_PRE_SRC_2X_ALPHA) { + WRITE(p, " v.a = v.a * 2.0;\n"); + } } switch (stencilToAlpha) { diff --git a/GPU/GLES/FragmentShaderGenerator.h b/GPU/GLES/FragmentShaderGenerator.h index c931c5efe5..1ae6f35201 100644 --- a/GPU/GLES/FragmentShaderGenerator.h +++ b/GPU/GLES/FragmentShaderGenerator.h @@ -58,9 +58,18 @@ enum ReplaceAlphaType { REPLACE_ALPHA_DUALSOURCE = 2, }; +enum ReplaceBlendType { + REPLACE_BLEND_NO, + REPLACE_BLEND_STANDARD, + REPLACE_BLEND_PRE_SRC, + REPLACE_BLEND_PRE_SRC_2X_ALPHA, + REPLACE_BLEND_2X_ALPHA, + REPLACE_BLEND_2X_SRC, + REPLACE_BLEND_COPY_FBO, +}; + bool IsAlphaTestTriviallyTrue(); bool IsColorTestTriviallyTrue(); StencilValueType ReplaceAlphaWithStencilType(); ReplaceAlphaType ReplaceAlphaWithStencil(); -bool ShouldUseShaderBlending(); -bool ShouldUseShaderFixedBlending(); +ReplaceBlendType ReplaceBlendWithShader(); diff --git a/GPU/GLES/StateMapping.cpp b/GPU/GLES/StateMapping.cpp index 1875c4aa63..c981f71808 100644 --- a/GPU/GLES/StateMapping.cpp +++ b/GPU/GLES/StateMapping.cpp @@ -213,51 +213,51 @@ void TransformDrawEngine::ApplyBlendState() { // // * Doubled blend modes (src, dst, inversed) aren't supported in OpenGL. // If possible, we double the src color or src alpha in the shader to account for these. - // These may clip incorrectly, but they're close. + // These may clip incorrectly, so we avoid unfortunately. // * OpenGL only has one arbitrary fixed color. We premultiply the other in the shader. // * The written output alpha should actually be the stencil value. Alpha is not written. // // If we can't apply blending, we make a copy of the framebuffer and do it manually. - GEBlendMode blendFuncEq = gstate.getBlendEq(); + ReplaceBlendType replaceBlend = ReplaceBlendWithShader(); + bool usePreSrc = false; - if (ShouldUseShaderBlending()) { - if (ShouldUseShaderFixedBlending()) { - // If both sides are fixed, we can do this without a blit but still in the shader. - Vec3f fixB = Vec3f::FromRGB(gstate.getFixB()); + switch (replaceBlend) { + case REPLACE_BLEND_NO: + glstate.blend.disable(); + ResetShaderBlending(); + return; - // Okay, so we'll use src * 1.0 + dst * fixB, and then premultiply in the shader. - const float blendColor[4] = {fixB.x, fixB.y, fixB.z, 1.0f}; - glstate.blend.enable(); - glstate.blendColor.set(blendColor); - - ReplaceAlphaType replaceAlphaWithStencil = ReplaceAlphaWithStencil(); - if (replaceAlphaWithStencil != REPLACE_ALPHA_NO) { - glstate.blendFuncSeparate.set(GL_ONE, GL_CONSTANT_COLOR, GL_ONE, GL_ZERO); - } else { - glstate.blendFuncSeparate.set(GL_ONE, GL_CONSTANT_COLOR, GL_ZERO, GL_ONE); - } - - // Min/max/absdiff are not possible here. - glstate.blendEquationSeparate.set(eqLookup[blendFuncEq], GL_FUNC_ADD); - - shaderManager_->DirtyUniform(DIRTY_SHADERBLEND); - ResetShaderBlending(); - return; - } else if (ApplyShaderBlending()) { + case REPLACE_BLEND_COPY_FBO: + if (ApplyShaderBlending()) { // None of the below logic is interesting, we're gonna do it entirely in the shader. glstate.blend.disable(); return; } + // TODO: Otherwise, we probably apply shading wrong. Hmm. + break; + + case REPLACE_BLEND_PRE_SRC: + case REPLACE_BLEND_PRE_SRC_2X_ALPHA: + usePreSrc = true; + break; + + case REPLACE_BLEND_STANDARD: + case REPLACE_BLEND_2X_ALPHA: + case REPLACE_BLEND_2X_SRC: + break; } - ResetShaderBlending(); glstate.blend.enable(); + ResetShaderBlending(); + GEBlendMode blendFuncEq = gstate.getBlendEq(); int blendFuncA = gstate.getBlendFuncA(); int blendFuncB = gstate.getBlendFuncB(); - if (blendFuncA > GE_SRCBLEND_FIXA) blendFuncA = GE_SRCBLEND_FIXA; - if (blendFuncB > GE_DSTBLEND_FIXB) blendFuncB = GE_DSTBLEND_FIXB; + if (blendFuncA > GE_SRCBLEND_FIXA) + blendFuncA = GE_SRCBLEND_FIXA; + if (blendFuncB > GE_DSTBLEND_FIXB) + blendFuncB = GE_DSTBLEND_FIXB; float constantAlpha = 1.0f; ReplaceAlphaType replaceAlphaWithStencil = ReplaceAlphaWithStencil(); @@ -271,6 +271,10 @@ void TransformDrawEngine::ApplyBlendState() { GLuint glBlendFuncA = blendFuncA == GE_SRCBLEND_FIXA ? blendColor2Func(gstate.getFixA()) : aLookup[blendFuncA]; GLuint glBlendFuncB = blendFuncB == GE_DSTBLEND_FIXB ? blendColor2Func(gstate.getFixB()) : bLookup[blendFuncB]; + if (usePreSrc) { + glBlendFuncA = GL_ONE; + } + if (replaceAlphaWithStencil == REPLACE_ALPHA_DUALSOURCE) { glBlendFuncA = toDualSource(glBlendFuncA); glBlendFuncB = toDualSource(glBlendFuncB); @@ -326,7 +330,7 @@ void TransformDrawEngine::ApplyBlendState() { } else { // We optimized both, but that's probably not necessary, so let's pick one to be constant. // For now let's just pick whichever was fixed instead of checking error. - if (blendFuncA == GE_SRCBLEND_FIXA) { + if (blendFuncA == GE_SRCBLEND_FIXA && !usePreSrc) { glBlendFuncA = GL_CONSTANT_COLOR; const float blendColor[4] = {fixA.x, fixA.y, fixA.z, constantAlpha}; glstate.blendColor.set(blendColor); @@ -375,7 +379,11 @@ void TransformDrawEngine::ApplyBlendState() { break; case STENCIL_VALUE_UNIFORM: // This won't give a correct value (it multiplies) but it may be better than random values. - glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_CONSTANT_ALPHA, GL_ZERO); + if (constantAlpha < 1.0f) { + glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_CONSTANT_ALPHA, GL_ZERO); + } else { + glstate.blendFuncSeparate.set(glBlendFuncA, glBlendFuncB, GL_ONE, GL_ZERO); + } break; case STENCIL_VALUE_UNKNOWN: // For now, let's err at zero. This is INVERT or INCR/DECR. @@ -408,12 +416,7 @@ void TransformDrawEngine::ApplyDrawState(int prim) { } // Set blend - unless we need to do it in the shader. - if (!gstate.isModeClear() && gstate.isAlphaBlendEnabled()) { - ApplyBlendState(); - } else { - glstate.blend.disable(); - ResetShaderBlending(); - } + ApplyBlendState(); bool alwaysDepthWrite = g_Config.bAlwaysDepthWrite; bool enableStencilTest = !g_Config.bDisableStencilTest; diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index 9d97e0d46c..e16244a5d0 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -619,6 +619,7 @@ void TextureCache::GetSamplingParams(int &minFilt, int &magFilt, bool &sClamp, b minFilt |= 1; } if (g_Config.iTexFiltering == LINEAR && (!gstate.isColorTestEnabled() || IsColorTestTriviallyTrue())) { + // TODO: IsAlphaTestTriviallyTrue() is unsafe here. vertexFullAlpha is not calculated yet. if (!gstate.isAlphaTestEnabled() || IsAlphaTestTriviallyTrue()) { magFilt |= 1; minFilt |= 1; From 24a0dd12efac06d69da7c031b72980abc259d9b6 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 3 Aug 2014 10:32:53 -0700 Subject: [PATCH 03/10] Avoid recalculating replaceBlend so many times. --- GPU/GLES/FragmentShaderGenerator.cpp | 10 ++++------ GPU/GLES/FragmentShaderGenerator.h | 2 +- GPU/GLES/StateMapping.cpp | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/GPU/GLES/FragmentShaderGenerator.cpp b/GPU/GLES/FragmentShaderGenerator.cpp index 9d2d0cde94..fc82108bdb 100644 --- a/GPU/GLES/FragmentShaderGenerator.cpp +++ b/GPU/GLES/FragmentShaderGenerator.cpp @@ -137,16 +137,14 @@ const bool nonAlphaDestFactors[16] = { true, // GE_DSTBLEND_FIXB, }; -ReplaceAlphaType ReplaceAlphaWithStencil() { +ReplaceAlphaType ReplaceAlphaWithStencil(ReplaceBlendType replaceBlend) { if (!gstate.isStencilTestEnabled() || gstate.isModeClear()) { return REPLACE_ALPHA_NO; } - if (gstate.isAlphaBlendEnabled()) { + if (replaceBlend != REPLACE_BLEND_NO && replaceBlend != REPLACE_BLEND_COPY_FBO) { if (nonAlphaSrcFactors[gstate.getBlendFuncA()] && nonAlphaDestFactors[gstate.getBlendFuncB()]) { return REPLACE_ALPHA_YES; - } else if (ReplaceBlendWithShader() == REPLACE_BLEND_COPY_FBO) { - return REPLACE_ALPHA_YES; } else { if (gl_extensions.ARB_blend_func_extended) { return REPLACE_ALPHA_DUALSOURCE; @@ -355,8 +353,8 @@ void ComputeFragmentShaderID(FragmentShaderID *id) { bool enableColorDoubling = gstate.isColorDoublingEnabled() && gstate.isTextureMapEnabled(); bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX; bool doTextureAlpha = gstate.isTextureAlphaUsed(); - ReplaceAlphaType stencilToAlpha = ReplaceAlphaWithStencil(); ReplaceBlendType replaceBlend = ReplaceBlendWithShader(); + ReplaceAlphaType stencilToAlpha = ReplaceAlphaWithStencil(replaceBlend); // All texfuncs except replace are the same for RGB as for RGBA with full alpha. if (gstate_c.textureFullAlpha && gstate.getTextureFunction() != GE_TEXFUNC_REPLACE) @@ -510,8 +508,8 @@ void GenerateFragmentShader(char *buffer) { bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX; bool doTextureAlpha = gstate.isTextureAlphaUsed(); bool textureAtOffset = gstate_c.curTextureXOffset != 0 || gstate_c.curTextureYOffset != 0; - ReplaceAlphaType stencilToAlpha = ReplaceAlphaWithStencil(); ReplaceBlendType replaceBlend = ReplaceBlendWithShader(); + ReplaceAlphaType stencilToAlpha = ReplaceAlphaWithStencil(replaceBlend); if (gstate_c.textureFullAlpha && gstate.getTextureFunction() != GE_TEXFUNC_REPLACE) doTextureAlpha = false; diff --git a/GPU/GLES/FragmentShaderGenerator.h b/GPU/GLES/FragmentShaderGenerator.h index 1ae6f35201..429514d370 100644 --- a/GPU/GLES/FragmentShaderGenerator.h +++ b/GPU/GLES/FragmentShaderGenerator.h @@ -71,5 +71,5 @@ enum ReplaceBlendType { bool IsAlphaTestTriviallyTrue(); bool IsColorTestTriviallyTrue(); StencilValueType ReplaceAlphaWithStencilType(); -ReplaceAlphaType ReplaceAlphaWithStencil(); +ReplaceAlphaType ReplaceAlphaWithStencil(ReplaceBlendType replaceBlend); ReplaceBlendType ReplaceBlendWithShader(); diff --git a/GPU/GLES/StateMapping.cpp b/GPU/GLES/StateMapping.cpp index c981f71808..fbcb140ec4 100644 --- a/GPU/GLES/StateMapping.cpp +++ b/GPU/GLES/StateMapping.cpp @@ -260,7 +260,7 @@ void TransformDrawEngine::ApplyBlendState() { blendFuncB = GE_DSTBLEND_FIXB; float constantAlpha = 1.0f; - ReplaceAlphaType replaceAlphaWithStencil = ReplaceAlphaWithStencil(); + ReplaceAlphaType replaceAlphaWithStencil = ReplaceAlphaWithStencil(replaceBlend); if (gstate.isStencilTestEnabled() && replaceAlphaWithStencil == REPLACE_ALPHA_NO) { if (ReplaceAlphaWithStencilType() == STENCIL_VALUE_UNIFORM) { constantAlpha = (float) gstate.getStencilTestRef() * (1.0f / 255.0f); From a41333c012980ae1c257876e7795800008aaa508 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 3 Aug 2014 10:38:08 -0700 Subject: [PATCH 04/10] Avoid premultiplying easy fixed colors. --- GPU/GLES/FragmentShaderGenerator.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/GPU/GLES/FragmentShaderGenerator.cpp b/GPU/GLES/FragmentShaderGenerator.cpp index fc82108bdb..7dc1c61b6f 100644 --- a/GPU/GLES/FragmentShaderGenerator.cpp +++ b/GPU/GLES/FragmentShaderGenerator.cpp @@ -316,7 +316,11 @@ ReplaceBlendType ReplaceBlendWithShader() { return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; case GE_DSTBLEND_FIXB: - return REPLACE_BLEND_PRE_SRC; + if (gstate.getFixA() == 0xFFFFFF || gstate.getFixA() == 0x000000) { + return REPLACE_BLEND_STANDARD; + } else { + return REPLACE_BLEND_PRE_SRC; + } default: return REPLACE_BLEND_STANDARD; From 5d1b1ab547c1a3c13edf05dcab9af3bb04e660c6 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 3 Aug 2014 10:39:46 -0700 Subject: [PATCH 05/10] Dirty the fixed color when premultiplying. --- GPU/GLES/StateMapping.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/GPU/GLES/StateMapping.cpp b/GPU/GLES/StateMapping.cpp index fbcb140ec4..30309f4074 100644 --- a/GPU/GLES/StateMapping.cpp +++ b/GPU/GLES/StateMapping.cpp @@ -273,6 +273,10 @@ void TransformDrawEngine::ApplyBlendState() { if (usePreSrc) { glBlendFuncA = GL_ONE; + // Need to pull in the fixed color. + if (blendFuncA == GE_SRCBLEND_FIXA) { + shaderManager_->DirtyUniform(DIRTY_SHADERBLEND); + } } if (replaceAlphaWithStencil == REPLACE_ALPHA_DUALSOURCE) { From 0904085eb53d1f1bc55aa0ce194d174d66a2a9d0 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 3 Aug 2014 11:10:53 -0700 Subject: [PATCH 06/10] Avoid using fbo copies for the common 2a + 1-2a. We won't even get it right that often since the copy doesn't deal with overlap properly. --- GPU/GLES/FragmentShaderGenerator.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/GPU/GLES/FragmentShaderGenerator.cpp b/GPU/GLES/FragmentShaderGenerator.cpp index 7dc1c61b6f..b69bd2741f 100644 --- a/GPU/GLES/FragmentShaderGenerator.cpp +++ b/GPU/GLES/FragmentShaderGenerator.cpp @@ -274,11 +274,8 @@ ReplaceBlendType ReplaceBlendWithShader() { case GE_DSTBLEND_DOUBLESRCALPHA: case GE_DSTBLEND_DOUBLEINVSRCALPHA: // We can't technically do this correctly (due to clamping) without reading the dst color. - if (g_Config.bDisableSlowFramebufEffects) { - return REPLACE_BLEND_PRE_SRC_2X_ALPHA; - } else { - return REPLACE_BLEND_COPY_FBO; - } + // Using a copy isn't accurate either, though, when there's overlap. + return REPLACE_BLEND_PRE_SRC_2X_ALPHA; default: // TODO: Could use vertexFullAlpha, but it's not calculated yet. From b79e4d22b86b201320638649b0888bc600864223 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 3 Aug 2014 11:18:08 -0700 Subject: [PATCH 07/10] Improve a possible obscure blend mode. Seems like this would be likely to get overlap problems. --- GPU/GLES/FragmentShaderGenerator.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/GPU/GLES/FragmentShaderGenerator.cpp b/GPU/GLES/FragmentShaderGenerator.cpp index b69bd2741f..edcb32e6a2 100644 --- a/GPU/GLES/FragmentShaderGenerator.cpp +++ b/GPU/GLES/FragmentShaderGenerator.cpp @@ -327,6 +327,12 @@ ReplaceBlendType ReplaceBlendWithShader() { switch (funcB) { case GE_DSTBLEND_DOUBLESRCALPHA: case GE_DSTBLEND_DOUBLEINVSRCALPHA: + if (funcA == GE_SRCBLEND_SRCALPHA || funcA == GE_SRCBLEND_INVSRCALPHA) { + // Can't safely double alpha, will clamp. However, a copy may easily be worse due to overlap. + return REPLACE_BLEND_PRE_SRC_2X_ALPHA; + } + return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; + case GE_DSTBLEND_DOUBLEDSTALPHA: case GE_DSTBLEND_DOUBLEINVDSTALPHA: return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; From 422db252773c77a731232d6428d6c6255d97c6ad Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 3 Aug 2014 11:47:08 -0700 Subject: [PATCH 08/10] Optimize fixed color blending that isn't blending. Gods Eater Burst uses this, for example. --- GPU/GLES/FragmentShaderGenerator.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/GPU/GLES/FragmentShaderGenerator.cpp b/GPU/GLES/FragmentShaderGenerator.cpp index edcb32e6a2..becd952c5a 100644 --- a/GPU/GLES/FragmentShaderGenerator.cpp +++ b/GPU/GLES/FragmentShaderGenerator.cpp @@ -313,7 +313,10 @@ ReplaceBlendType ReplaceBlendWithShader() { return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; case GE_DSTBLEND_FIXB: - if (gstate.getFixA() == 0xFFFFFF || gstate.getFixA() == 0x000000) { + if (gstate.getFixA() == 0xFFFFFF && gstate.getFixB() == 0x000000) { + // Some games specify this. Some cards may prefer blending off entirely. + return REPLACE_BLEND_NO; + } else if (gstate.getFixA() == 0xFFFFFF || gstate.getFixA() == 0x000000 || gstate.getFixB() == 0xFFFFFF || gstate.getFixB() == 0x000000) { return REPLACE_BLEND_STANDARD; } else { return REPLACE_BLEND_PRE_SRC; From a43c3771a30917e1497c9413d623ceb6dff30015 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 3 Aug 2014 19:56:53 -0700 Subject: [PATCH 09/10] More correctly blend when hitting the frame cap. If we hit too many blits per frame, fall back correctly in the shader. --- GPU/GLES/FragmentShaderGenerator.cpp | 22 +++++++++++----------- GPU/GLES/StateMapping.cpp | 4 +++- GPU/GPUState.h | 1 + 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/GPU/GLES/FragmentShaderGenerator.cpp b/GPU/GLES/FragmentShaderGenerator.cpp index becd952c5a..0dd76308d4 100644 --- a/GPU/GLES/FragmentShaderGenerator.cpp +++ b/GPU/GLES/FragmentShaderGenerator.cpp @@ -242,14 +242,14 @@ ReplaceBlendType ReplaceBlendWithShader() { // Let's get the non-factor modes out of the way first. switch (eq) { case GE_BLENDMODE_ABSDIFF: - return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; + return !gstate_c.allowShaderBlend ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; case GE_BLENDMODE_MIN: case GE_BLENDMODE_MAX: if (gl_extensions.EXT_blend_minmax || gl_extensions.GLES3) { return REPLACE_BLEND_STANDARD; } else { - return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; + return !gstate_c.allowShaderBlend ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; } default: @@ -265,11 +265,11 @@ ReplaceBlendType ReplaceBlendWithShader() { case GE_DSTBLEND_SRCCOLOR: case GE_DSTBLEND_INVSRCCOLOR: // Can't double, we need the source color to be correct. - return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_2X_ALPHA : REPLACE_BLEND_COPY_FBO; + return !gstate_c.allowShaderBlend ? REPLACE_BLEND_2X_ALPHA : REPLACE_BLEND_COPY_FBO; case GE_DSTBLEND_DOUBLEDSTALPHA: case GE_DSTBLEND_DOUBLEINVDSTALPHA: - return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_2X_ALPHA : REPLACE_BLEND_COPY_FBO; + return !gstate_c.allowShaderBlend ? REPLACE_BLEND_2X_ALPHA : REPLACE_BLEND_COPY_FBO; case GE_DSTBLEND_DOUBLESRCALPHA: case GE_DSTBLEND_DOUBLEINVSRCALPHA: @@ -288,17 +288,17 @@ ReplaceBlendType ReplaceBlendWithShader() { case GE_DSTBLEND_SRCCOLOR: case GE_DSTBLEND_INVSRCCOLOR: // Can't double, we need the source color to be correct. - return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; + return !gstate_c.allowShaderBlend ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; case GE_DSTBLEND_DOUBLEDSTALPHA: case GE_DSTBLEND_DOUBLEINVDSTALPHA: case GE_DSTBLEND_DOUBLESRCALPHA: case GE_DSTBLEND_DOUBLEINVSRCALPHA: - return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_2X_SRC : REPLACE_BLEND_COPY_FBO; + return !gstate_c.allowShaderBlend ? REPLACE_BLEND_2X_SRC : REPLACE_BLEND_COPY_FBO; default: // We can't technically do this correctly (due to clamping) without reading the dst alpha. - return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_2X_SRC : REPLACE_BLEND_COPY_FBO; + return !gstate_c.allowShaderBlend ? REPLACE_BLEND_2X_SRC : REPLACE_BLEND_COPY_FBO; } case GE_SRCBLEND_FIXA: @@ -306,11 +306,11 @@ ReplaceBlendType ReplaceBlendWithShader() { case GE_DSTBLEND_DOUBLESRCALPHA: case GE_DSTBLEND_DOUBLEINVSRCALPHA: // Can't safely double alpha, will clamp. - return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_2X_ALPHA : REPLACE_BLEND_COPY_FBO; + return !gstate_c.allowShaderBlend ? REPLACE_BLEND_2X_ALPHA : REPLACE_BLEND_COPY_FBO; case GE_DSTBLEND_DOUBLEDSTALPHA: case GE_DSTBLEND_DOUBLEINVDSTALPHA: - return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; + return !gstate_c.allowShaderBlend ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; case GE_DSTBLEND_FIXB: if (gstate.getFixA() == 0xFFFFFF && gstate.getFixB() == 0x000000) { @@ -334,11 +334,11 @@ ReplaceBlendType ReplaceBlendWithShader() { // Can't safely double alpha, will clamp. However, a copy may easily be worse due to overlap. return REPLACE_BLEND_PRE_SRC_2X_ALPHA; } - return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; + return !gstate_c.allowShaderBlend ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; case GE_DSTBLEND_DOUBLEDSTALPHA: case GE_DSTBLEND_DOUBLEINVDSTALPHA: - return g_Config.bDisableSlowFramebufEffects ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; + return !gstate_c.allowShaderBlend ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; default: return REPLACE_BLEND_STANDARD; diff --git a/GPU/GLES/StateMapping.cpp b/GPU/GLES/StateMapping.cpp index 30309f4074..eadb11896d 100644 --- a/GPU/GLES/StateMapping.cpp +++ b/GPU/GLES/StateMapping.cpp @@ -218,6 +218,7 @@ void TransformDrawEngine::ApplyBlendState() { // * The written output alpha should actually be the stencil value. Alpha is not written. // // If we can't apply blending, we make a copy of the framebuffer and do it manually. + gstate_c.allowShaderBlend = !g_Config.bDisableSlowFramebufEffects; ReplaceBlendType replaceBlend = ReplaceBlendWithShader(); bool usePreSrc = false; @@ -234,7 +235,8 @@ void TransformDrawEngine::ApplyBlendState() { glstate.blend.disable(); return; } - // TODO: Otherwise, we probably apply shading wrong. Hmm. + // Until next time, force it off. + gstate_c.allowShaderBlend = false; break; case REPLACE_BLEND_PRE_SRC: diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 30db2b0775..310200941e 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -461,6 +461,7 @@ struct GPUStateCache UVScale uv; bool flipTexture; bool needShaderTexClamp; + bool allowShaderBlend; float morphWeights[8]; From 7f61da2e5a9c9c266545be499f34c70dfbf5b544 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 3 Aug 2014 21:11:54 -0700 Subject: [PATCH 10/10] Add a hack for Silent Hill games. Either way has different problems, but it sounds like this will work better for Silent Hill. Probably still rendering wrong, unfortunately. --- GPU/GLES/FragmentShaderGenerator.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/GPU/GLES/FragmentShaderGenerator.cpp b/GPU/GLES/FragmentShaderGenerator.cpp index 0dd76308d4..2298e87bc0 100644 --- a/GPU/GLES/FragmentShaderGenerator.cpp +++ b/GPU/GLES/FragmentShaderGenerator.cpp @@ -333,8 +333,12 @@ ReplaceBlendType ReplaceBlendWithShader() { if (funcA == GE_SRCBLEND_SRCALPHA || funcA == GE_SRCBLEND_INVSRCALPHA) { // Can't safely double alpha, will clamp. However, a copy may easily be worse due to overlap. return REPLACE_BLEND_PRE_SRC_2X_ALPHA; + } else { + // This means dst alpha/color is used in the src factor. + // Unfortunately, copying here causes overlap problems in Silent Hill games (it seems?) + // We will just hope that doubling alpha for the dst factor will not clamp too badly. + return REPLACE_BLEND_2X_ALPHA; } - return !gstate_c.allowShaderBlend ? REPLACE_BLEND_STANDARD : REPLACE_BLEND_COPY_FBO; case GE_DSTBLEND_DOUBLEDSTALPHA: case GE_DSTBLEND_DOUBLEINVDSTALPHA: