mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-14 15:00:30 +02:00
Keep the GE-exact FIXA/FIXB blend within fp16's range
Compute the product as (c+0.5) * (2f+1)/512, which is still exact in fp32, and use mediump where highp isn't available instead of falling back to the old blend. Simulated over all inputs, about 3% of fp16 results come out a level too bright, against nearly half with the plain blend factors. With mediump forced on NVIDIA's Vulkan driver (which runs it as fp16), the Split/Second bloom dumps land within 2% of the highp result. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
b882155d23
commit
ce310e69a6
2 files changed
+9
-8
No files matched your search
@@ -1018,14 +1018,16 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
||||
// Sampler), and rounding the GPU's finer filtered value instead makes each texel about a level
|
||||
// brighter. That doubles God Eater Burst's faint bloom, which feeds back into itself pass after pass.
|
||||
// The 0.01 keeps an unfiltered texel's exact integer from flooring a level down on float error.
|
||||
// This needs highp: the product reaches 511*511, past fp16's range, and the default precision is lowp,
|
||||
// which NVIDIA's Vulkan driver runs as fp16.
|
||||
WRITE(p, " highp vec3 fixA2 = u_blendFixA;\n");
|
||||
WRITE(p, " highp vec3 fixB2 = u_blendFixB;\n");
|
||||
WRITE(p, " highp vec3 srcTerm = v.rgb;\n");
|
||||
// The product is computed as (c+0.5) * (2f+1)/512 to stay within fp16's range. That's exact in fp32,
|
||||
// while in fp16 about 3% of results come out a level too bright, so use highp where we have it.
|
||||
// The default precision is lowp, which can be fixed point, and NVIDIA's Vulkan driver runs it as fp16.
|
||||
const char *prec = gstate_c.Use(GPU_USE_FULL_PRECISION_IN_FRAGMENT) ? "highp" : "mediump";
|
||||
WRITE(p, " %s vec3 fixA2 = u_blendFixA;\n", prec);
|
||||
WRITE(p, " %s vec3 fixB2 = u_blendFixB;\n", prec);
|
||||
WRITE(p, " %s vec3 srcTerm = v.rgb;\n", prec);
|
||||
WRITE(p, " fixA2 = floor(fixA2 * 510.0 + 0.5) + 1.0;\n");
|
||||
WRITE(p, " fixB2 = floor(fixB2 * 510.0 + 0.5) + 1.0;\n");
|
||||
WRITE(p, " srcTerm = floor((floor(srcTerm * 255.0 + 0.01) * 2.0 + 1.0) * fixA2 / 1024.0);\n");
|
||||
WRITE(p, " srcTerm = floor((floor(srcTerm * 255.0 + 0.01) + 0.5) * (fixA2 / 512.0));\n");
|
||||
WRITE(p, " v.rgb = (srcTerm - 0.5 + fixB2 / 1024.0) / 255.0;\n");
|
||||
} else {
|
||||
WRITE(p, " v.rgb = v.rgb * %s;\n", srcFactor);
|
||||
|
||||
@@ -69,9 +69,8 @@ ReplaceAlphaType ReplaceAlphaWithStencil(ReplaceBlendType replaceBlend);
|
||||
ReplaceBlendType ReplaceBlendWithShader(GEBufferFormat bufferFormat);
|
||||
|
||||
// Fixed color blends (with FIXA as the src factor) that REPLACE_BLEND_PRE_SRC computes like the GE.
|
||||
// The math needs highp floats in the fragment shader, which some old GLES devices lack.
|
||||
inline bool IsGEExactFixedBlend(GEBlendDstFactor funcB, GEBlendMode eq) {
|
||||
return funcB == GE_DSTBLEND_FIXB && eq == GE_BLENDMODE_MUL_AND_ADD && gstate_c.Use(GPU_USE_FULL_PRECISION_IN_FRAGMENT);
|
||||
return funcB == GE_DSTBLEND_FIXB && eq == GE_BLENDMODE_MUL_AND_ADD;
|
||||
}
|
||||
|
||||
// This is for the fallback path if real logic ops are not available.
|
||||
|
||||
Reference in new issue
Block a user