GPU: Optimize > 0 alpha test using discard rules.

It should be equally unsafe to use src color as dest blend factor, or
use blending with a subtract or min/max equation.
This commit is contained in:
Unknown W. Brackets 2018-07-29 11:37:04 -07:00
parent 78dc07e7a3
commit 7885a88c0c

View File

@ -40,20 +40,28 @@ bool CanUseHardwareTransform(int prim) {
return !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES; return !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES;
} }
// Dest factors where it's safe to eliminate the alpha test under certain conditions bool NeedsTestDiscard() {
static const bool safeDestFactors[16] = { // We assume this is called only when enabled and not trivially true (may also be for color testing.)
true, // GE_DSTBLEND_SRCCOLOR, if (gstate.isStencilTestEnabled() && (gstate.pmska & 0xFF) != 0xFF)
true, // GE_DSTBLEND_INVSRCCOLOR, return true;
false, // GE_DSTBLEND_SRCALPHA, if (gstate.isDepthTestEnabled() && gstate.isDepthWriteEnabled())
true, // GE_DSTBLEND_INVSRCALPHA, return true;
true, // GE_DSTBLEND_DSTALPHA, if (!gstate.isAlphaBlendEnabled())
true, // GE_DSTBLEND_INVDSTALPHA, return true;
false, // GE_DSTBLEND_DOUBLESRCALPHA, if (gstate.getBlendFuncA() != GE_SRCBLEND_SRCALPHA && gstate.getBlendFuncA() != GE_DSTBLEND_DOUBLESRCALPHA)
false, // GE_DSTBLEND_DOUBLEINVSRCALPHA, return true;
true, // GE_DSTBLEND_DOUBLEDSTALPHA, // GE_DSTBLEND_DOUBLEINVSRCALPHA is actually inverse double src alpha, and doubling zero is still zero.
true, // GE_DSTBLEND_DOUBLEINVDSTALPHA, if (gstate.getBlendFuncB() != GE_DSTBLEND_INVSRCALPHA && gstate.getBlendFuncB() != GE_DSTBLEND_DOUBLEINVSRCALPHA) {
true, //GE_DSTBLEND_FIXB, if (gstate.getBlendFuncB() != GE_DSTBLEND_FIXB || gstate.getFixB() != 0xFFFFFF)
}; return true;
}
if (gstate.getBlendEq() != GE_BLENDMODE_MUL_AND_ADD && gstate.getBlendEq() != GE_BLENDMODE_MUL_AND_SUBTRACT_REVERSE)
return true;
if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY)
return true;
return false;
}
bool IsAlphaTestTriviallyTrue() { bool IsAlphaTestTriviallyTrue() {
switch (gstate.getAlphaTestFunction()) { switch (gstate.getAlphaTestFunction()) {
@ -80,25 +88,10 @@ bool IsAlphaTestTriviallyTrue() {
case GE_COMP_GREATER: case GE_COMP_GREATER:
{ {
#if 0 // If the texture and vertex only use 1.0 alpha, then the ref value doesn't matter.
// Easy way to check the values in the debugger without ruining && early-out if (gstate_c.vertexFullAlpha && (gstate_c.textureFullAlpha || !gstate.isTextureAlphaUsed()))
bool doTextureAlpha = gstate.isTextureAlphaUsed(); return true;
bool stencilTest = gstate.isStencilTestEnabled(); return gstate.getAlphaTestRef() == 0 && !NeedsTestDiscard();
bool depthTest = gstate.isDepthTestEnabled();
GEComparison depthTestFunc = gstate.getDepthTestFunction();
int alphaRef = gstate.getAlphaTestRef();
int blendA = gstate.getBlendFuncA();
bool blendEnabled = gstate.isAlphaBlendEnabled();
int blendB = gstate.getBlendFuncA();
#endif
return (gstate_c.vertexFullAlpha && (gstate_c.textureFullAlpha || !gstate.isTextureAlphaUsed())) || (
(!gstate.isStencilTestEnabled() &&
!gstate.isDepthTestEnabled() &&
(!gstate.isLogicOpEnabled() || gstate.getLogicOp() == GE_LOGIC_COPY) &&
gstate.getAlphaTestRef() == 0 &&
gstate.isAlphaBlendEnabled() &&
gstate.getBlendFuncA() == GE_SRCBLEND_SRCALPHA &&
safeDestFactors[(int)gstate.getBlendFuncB()]));
} }
case GE_COMP_LEQUAL: case GE_COMP_LEQUAL:
@ -113,29 +106,6 @@ bool IsAlphaTestTriviallyTrue() {
} }
} }
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)
return true;
if (gstate.isDepthTestEnabled() && gstate.isDepthWriteEnabled())
return true;
if (!gstate.isAlphaBlendEnabled())
return true;
if (gstate.isLogicOpEnabled() && gstate.getLogicOp() != GE_LOGIC_COPY)
return true;
if (gstate.getBlendFuncA() != GE_SRCBLEND_SRCALPHA && gstate.getBlendFuncA() != GE_DSTBLEND_DOUBLESRCALPHA)
return true;
// GE_DSTBLEND_DOUBLEINVSRCALPHA is actually inverse double src alpha, and doubling zero is still zero.
if (gstate.getBlendFuncB() != GE_DSTBLEND_INVSRCALPHA && gstate.getBlendFuncB() != GE_DSTBLEND_DOUBLEINVSRCALPHA) {
if (gstate.getBlendFuncB() != GE_DSTBLEND_FIXB || gstate.getFixB() != 0xFFFFFF)
return true;
}
if (gstate.getBlendEq() != GE_BLENDMODE_MUL_AND_ADD && gstate.getBlendEq() != GE_BLENDMODE_MUL_AND_SUBTRACT_REVERSE)
return true;
return false;
}
bool IsAlphaTestAgainstZero() { bool IsAlphaTestAgainstZero() {
return gstate.getAlphaTestRef() == 0 && gstate.getAlphaTestMask() == 0xFF; return gstate.getAlphaTestRef() == 0 && gstate.getAlphaTestMask() == 0xFF;
} }