Files
Brian Degenhardt e9f8f83669 GS/HW: carry the blend-mix factor in the output alpha without dual-source blend
A blend mix hands the blend unit exactly one number - the alpha factor, on the
PS2's 0..2 scale where 128 is opaque. A second fragment output is the usual way
to carry a value on that scale, but it is not the only one: fixed-function
SRC_ALPHA reads the first output's alpha, and the shader can put the factor
there instead. Two cases make that free.

When the target holds its alpha double-scaled, the alpha the shader would write
IS the factor - tfx computes both as C.a/128 under RTA correction - so scaling
the target is the whole change. Otherwise the substitution is free whenever the
pass writes no alpha at all, because the output alpha is discarded on the way to
the target: a draw whose alpha is masked outright, or one whose alpha write has
moved into a second pass under SPLIT_RGB_ONLY.

Only the plain mix1 shape qualifies. The other mix cases rewrite the second
output's RGB independently of its alpha, so there the two outputs really do
carry different values and no substitution exists.

Without this, a GPU with no dual-source blend emulates the equation in the
shader, which needs a fresh destination read per primitive. With neither a
texture barrier nor a multidraw framebuffer copy available, all it gets is one
snapshot taken before the draw, so every primitive after the first composites
against stale pixels. That is what hollowed out God of War II's menu glyphs on
Mali r44p1, where the whole text is a single draw whose drop-shadow and bright
quads overlap each other 200 times.

Measured against a dual-source GPU rendering the same dump: over the text the
mean per-pixel error falls from 3.351 to 0.109 and the worst pixel from 163 to
25, with the lit-pixel count landing on 3896 against the reference's 3898.
Frame-wide it removes 25k of the 49k differing pixels and introduces 22. It
needs no barriers and no target copies at all, where matching this by refreshing
the snapshot per primitive group cost ~1000 render-pass breaks a frame and two
thirds of the frame rate on device.

No effect where dual-source blending exists: 33 frames across 11 dumps are byte
identical.
2026-08-09 17:49:51 -07:00
..
2026-03-26 16:04:49 -04:00
2025-01-04 17:17:39 -05:00