From d412cf5c64e7fd667172b0616590c26495919db4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 1 May 2013 08:00:52 -0700 Subject: [PATCH] Approximate better with two fixed blend colors. Having one be constant, or having a nearby blend, is better than fixing both to 1.0 or 0.0. --- GPU/GLES/StateMapping.cpp | 95 +++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 44 deletions(-) diff --git a/GPU/GLES/StateMapping.cpp b/GPU/GLES/StateMapping.cpp index c01da70082..9f03cbfda6 100644 --- a/GPU/GLES/StateMapping.cpp +++ b/GPU/GLES/StateMapping.cpp @@ -92,6 +92,27 @@ static const GLushort stencilOps[] = { GL_KEEP, // reserved }; +static GLenum blendColor2Func(u32 fix) { + if (fix == 0xFFFFFF) + return GL_ONE; + if (fix == 0) + return GL_ZERO; + + Vec3 fix3 = Vec3(fix); + if (fix3.x >= 0.99 && fix3.y >= 0.99 && fix3.z >= 0.99) + return GL_ONE; + else if (fix3.x <= 0.01 && fix3.y <= 0.01 && fix3.z <= 0.01) + return GL_ZERO; + return GL_INVALID_ENUM; +} + +static bool blendColorSimilar(Vec3 a, Vec3 b, float margin = 0.1f) { + Vec3 diff = a - b; + if (fabsf(diff.x) <= margin && fabsf(diff.y) <= margin && fabsf(diff.z) <= margin) + return true; + return false; +} + void TransformDrawEngine::ApplyDrawState(int prim) { // TODO: All this setup is soon so expensive that we'll need dirty flags, or simply do it in the command writes where we detect dirty by xoring. Silly to do all this work on every drawcall. @@ -127,49 +148,32 @@ void TransformDrawEngine::ApplyDrawState(int prim) { if (blendFuncA > GE_SRCBLEND_FIXA) blendFuncA = GE_SRCBLEND_FIXA; if (blendFuncB > GE_DSTBLEND_FIXB) blendFuncB = GE_DSTBLEND_FIXB; - glstate.blendEquation.set(eqLookup[blendFuncEq]); - - if (blendFuncA != GE_SRCBLEND_FIXA && blendFuncB != GE_DSTBLEND_FIXB) { - // All is valid, no blendcolor needed - glstate.blendFunc.set(aLookup[blendFuncA], bLookup[blendFuncB]); - } else { - GLuint glBlendFuncA = blendFuncA == GE_SRCBLEND_FIXA ? GL_INVALID_ENUM : aLookup[blendFuncA]; - GLuint glBlendFuncB = blendFuncB == GE_DSTBLEND_FIXB ? GL_INVALID_ENUM : bLookup[blendFuncB]; - u32 fixA = gstate.getFixA(); - u32 fixB = gstate.getFixB(); - // Shortcut by using GL_ONE where possible, no need to set blendcolor - if (glBlendFuncA == GL_INVALID_ENUM && blendFuncA == GE_SRCBLEND_FIXA) { - if (fixA == 0xFFFFFF) - glBlendFuncA = GL_ONE; - else if (fixA == 0) - glBlendFuncA = GL_ZERO; - } - if (glBlendFuncB == GL_INVALID_ENUM && blendFuncB == GE_DSTBLEND_FIXB) { - if (fixB == 0xFFFFFF) - glBlendFuncB = GL_ONE; - else if (fixB == 0) - glBlendFuncB = GL_ZERO; - } + // Shortcut by using GL_ONE where possible, no need to set blendcolor + GLuint glBlendFuncA = blendFuncA == GE_SRCBLEND_FIXA ? blendColor2Func(gstate.getFixA()) : aLookup[blendFuncA]; + GLuint glBlendFuncB = blendFuncB == GE_DSTBLEND_FIXB ? blendColor2Func(gstate.getFixB()) : bLookup[blendFuncB]; + if (blendFuncA == GE_SRCBLEND_FIXA || blendFuncB == GE_DSTBLEND_FIXB) { + Vec3 fixA = Vec3(gstate.getFixA()); + Vec3 fixB = Vec3(gstate.getFixB()); if (glBlendFuncA == GL_INVALID_ENUM && glBlendFuncB != GL_INVALID_ENUM) { // Can use blendcolor trivially. - const float blendColor[4] = {(fixA & 0xFF)/255.0f, ((fixA >> 8) & 0xFF)/255.0f, ((fixA >> 16) & 0xFF)/255.0f, 1.0f}; + const float blendColor[4] = {fixA.x, fixA.y, fixA.z, 1.0f}; glstate.blendColor.set(blendColor); glBlendFuncA = GL_CONSTANT_COLOR; } else if (glBlendFuncA != GL_INVALID_ENUM && glBlendFuncB == GL_INVALID_ENUM) { // Can use blendcolor trivially. - const float blendColor[4] = {(fixB & 0xFF)/255.0f, ((fixB >> 8) & 0xFF)/255.0f, ((fixB >> 16) & 0xFF)/255.0f, 1.0f}; + const float blendColor[4] = {fixB.x, fixB.y, fixB.z, 1.0f}; glstate.blendColor.set(blendColor); glBlendFuncB = GL_CONSTANT_COLOR; - } else if (glBlendFuncA == GL_INVALID_ENUM && glBlendFuncB == GL_INVALID_ENUM) { // Should also check for approximate equality - if (fixA == (fixB ^ 0xFFFFFF)) { + } else if (glBlendFuncA == GL_INVALID_ENUM && glBlendFuncB == GL_INVALID_ENUM) { + if (blendColorSimilar(fixA, Vec3(1.0f) - fixB)) { glBlendFuncA = GL_CONSTANT_COLOR; glBlendFuncB = GL_ONE_MINUS_CONSTANT_COLOR; - const float blendColor[4] = {(fixA & 0xFF)/255.0f, ((fixA >> 8) & 0xFF)/255.0f, ((fixA >> 16) & 0xFF)/255.0f, 1.0f}; + const float blendColor[4] = {fixA.x, fixA.y, fixA.z, 1.0f}; glstate.blendColor.set(blendColor); - } else if (fixA == fixB) { + } else if (blendColorSimilar(fixA, fixB)) { glBlendFuncA = GL_CONSTANT_COLOR; glBlendFuncB = GL_CONSTANT_COLOR; - const float blendColor[4] = {(fixA & 0xFF)/255.0f, ((fixA >> 8) & 0xFF)/255.0f, ((fixA >> 16) & 0xFF)/255.0f, 1.0f}; + const float blendColor[4] = {fixA.x, fixA.y, fixA.z, 1.0f}; glstate.blendColor.set(blendColor); } else { static bool didReportBlend = false; @@ -178,25 +182,28 @@ void TransformDrawEngine::ApplyDrawState(int prim) { didReportBlend = true; DEBUG_LOG(HLE, "ERROR INVALID blendcolorstate: FixA=%06x FixB=%06x FuncA=%i FuncB=%i", gstate.getFixA(), gstate.getFixB(), gstate.getBlendFuncA(), gstate.getBlendFuncB()); - // Let's approximate, at least. - int blendSumA = (fixA & 0xFF) + ((fixA >> 8) & 0xFF) + ((fixA >> 16) & 0xFF); - int blendSumB = (fixB & 0xFF) + ((fixB >> 8) & 0xFF) + ((fixB >> 16) & 0xFF); - if (blendSumA < 64 * 3 && blendSumB > 192 * 3) { - glBlendFuncA = GL_ZERO; - glBlendFuncB = GL_ONE; - } else if (blendSumA > 192 * 3 && blendSumB < 64 * 3) { - glBlendFuncA = GL_ONE; - glBlendFuncB = GL_ZERO; + // Let's approximate, at least. Close is better than totally off. + const bool nearZeroA = blendColorSimilar(fixA, 0.0f, 0.25f); + const bool nearZeroB = blendColorSimilar(fixB, 0.0f, 0.25f); + if (nearZeroA || blendColorSimilar(fixA, 1.0f, 0.25f)) { + glBlendFuncA = nearZeroA ? GL_ZERO : GL_ONE; + glBlendFuncB = GL_CONSTANT_COLOR; + const float blendColor[4] = {fixB.x, fixB.y, fixB.z, 1.0f}; + glstate.blendColor.set(blendColor); + // We need to pick something. Let's go with A as the fixed color. } else { - glBlendFuncA = GL_ONE; - glBlendFuncB = GL_ONE; + glBlendFuncA = GL_CONSTANT_COLOR; + glBlendFuncB = nearZeroB ? GL_ZERO : GL_ONE; + const float blendColor[4] = {fixA.x, fixA.y, fixA.z, 1.0f}; + glstate.blendColor.set(blendColor); } } } - // At this point, through all paths above, glBlendFuncA and glBlendFuncB will be set somehow. - - glstate.blendFunc.set(glBlendFuncA, glBlendFuncB); } + + // At this point, through all paths above, glBlendFuncA and glBlendFuncB will be set right somehow. + glstate.blendFunc.set(glBlendFuncA, glBlendFuncB); + glstate.blendEquation.set(eqLookup[blendFuncEq]); } // Set Dither