softgpu: Force alpha test when it could skip blend.

Blending is slow, and often games do effects like smoke, sun, etc. that
has a lot of zero alpha in them.  Many games do this with alpha testing
off, which is cheap compared to blending.
This commit is contained in:
Unknown W. Brackets 2022-12-04 16:36:45 -08:00
parent 2c90dafe64
commit d6750993d7
2 changed files with 42 additions and 1 deletions

View file

@ -300,6 +300,37 @@ static RasterizerStateFlags DetectStateOptimizations(RasterizerState *state) {
}
}
if (alphaBlend && (needTextureAlpha || !alphaFull)) {
// Okay, we're blending, and we need to. Are we alpha testing?
GEComparison alphaTestFunc = pixelID.AlphaTestFunc();
if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_NE)
alphaTestFunc = GE_COMP_NOTEQUAL;
if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT)
alphaTestFunc = GE_COMP_GREATER;
if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_ON)
alphaTestFunc = GE_COMP_ALWAYS;
PixelBlendFactor src = pixelID.AlphaBlendSrc();
PixelBlendFactor dst = pixelID.AlphaBlendDst();
if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_SRC)
src = PixelBlendFactor::SRCALPHA;
if (state->flags & RasterizerStateFlags::OPTIMIZED_BLEND_DST)
dst = PixelBlendFactor::INVSRCALPHA;
if (alphaTestFunc == GE_COMP_ALWAYS && src == PixelBlendFactor::SRCALPHA && dst == PixelBlendFactor::INVSRCALPHA) {
bool usesClut = (samplerID.texfmt & 4) != 0;
bool couldHaveZeroTexAlpha = true;
if (usesClut && CheckClutAlphaFull(state))
couldHaveZeroTexAlpha = false;
if (state->flags & RasterizerStateFlags::CLUT_ALPHA_NON_ZERO)
couldHaveZeroTexAlpha = false;
// Blending is expensive, since we read the target. Force alpha testing on.
if (!pixelID.depthWrite && !pixelID.stencilTest && couldHaveZeroTexAlpha)
optimize |= RasterizerStateFlags::OPTIMIZED_ALPHATEST_ON;
}
}
bool applyFog = pixelID.applyFog || (state->flags & RasterizerStateFlags::OPTIMIZED_FOG_OFF);
if (applyFog) {
bool hasFog = state->flags & RasterizerStateFlags::VERTEX_HAS_FOG;
@ -329,6 +360,8 @@ static RasterizerStateFlags DetectStateOptimizations(RasterizerState *state) {
// > 16, 8, or similar are also very common.
if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT)
alphaTestFunc = GE_COMP_GREATER;
if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_ON)
alphaTestFunc = GE_COMP_ALWAYS;
bool alphaTest = (alphaTestFunc == GE_COMP_NOTEQUAL || alphaTestFunc == GE_COMP_GREATER) && pixelID.alphaTestRef < 0xFF && !state->pixelID.hasAlphaTestMask;
if (alphaTest) {
@ -374,6 +407,13 @@ static bool ApplyStateOptimizations(RasterizerState *state, const RasterizerStat
pixelID.alphaTestFunc = GE_COMP_NOTEQUAL;
else if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT)
pixelID.alphaTestFunc = GE_COMP_GREATER;
else if (optimize & RasterizerStateFlags::OPTIMIZED_ALPHATEST_ON) {
pixelID.alphaTestFunc = GE_COMP_NOTEQUAL;
pixelID.alphaTestRef = 0;
pixelID.hasAlphaTestMask = false;
} else if (state->flags & RasterizerStateFlags::OPTIMIZED_ALPHATEST_ON) {
pixelID.alphaTestFunc = GE_COMP_ALWAYS;
}
SingleFunc drawPixel = Rasterizer::GetSingleFunc(pixelID, nullptr);
// Can't compile during runtime. This failing is a bit of a problem when undoing...

View file

@ -54,9 +54,10 @@ enum class RasterizerStateFlags {
OPTIMIZED_FOG_OFF = 0x0020'0000,
OPTIMIZED_ALPHATEST_OFF_NE = 0x0040'0000,
OPTIMIZED_ALPHATEST_OFF_GT = 0x0080'0000,
OPTIMIZED_ALPHATEST_ON = 0x0100'0000,
// Anything that changes the actual pixel or sampler func.
OPTIMIZED_PIXELID = OPTIMIZED_BLEND_SRC | OPTIMIZED_BLEND_DST | OPTIMIZED_BLEND_OFF | OPTIMIZED_FOG_OFF | RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_NE | RasterizerStateFlags::OPTIMIZED_ALPHATEST_OFF_GT,
OPTIMIZED_PIXELID = OPTIMIZED_BLEND_SRC | OPTIMIZED_BLEND_DST | OPTIMIZED_BLEND_OFF | OPTIMIZED_FOG_OFF | OPTIMIZED_ALPHATEST_OFF_NE | OPTIMIZED_ALPHATEST_OFF_GT | OPTIMIZED_ALPHATEST_ON,
OPTIMIZED_SAMPLERID = OPTIMIZED_TEXREPLACE,
INVALID = 0x7FFFFFFF,