mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
GS: stop forcing an RT feedback read for Ad-masked blends on fbfetch
A destination-alpha blend with alpha writes masked (blend_c == 1, !colormask.wa)
was given require_one_barrier wherever framebuffer fetch was available, on the
reasoning that fbfetch makes the feedback read cheap. The read is cheap. The
render pass is not: binding the target as an input attachment changes the pass
configuration, and OMSetRenderTargets ends the pass every time that flag flips.
NFS Underground flips it ~697 times a frame against only 40 real target
switches, so nearly every pass boundary in the frame came from this.
Drop the framebuffer_fetch term, leaving only the no-texture-barrier case where
the fallback already copies the RT and no pass boundary is at stake. That term
was ours; upstream gated this path on texture_barrier (later texture_barrier ||
multidraw_fb_copy) until it was made unconditional, and never on framebuffer
fetch. On turnip, which exposes the EXT spelling of the rasterization-order
extension, our term switched the path on for exactly the drivers where a pass
boundary is the dominant cost.
Adreno 650 NFSU 440 -> 64 passes/frame, 27.6 -> 7.6 ms
FlatOut 2 954 -> 102, 37.2 -> 16.4 ms
Mali-G52 NFSU 746 -> 69, 276.6 -> 96.8 ms
FlatOut 2 892 -> 96, 373.6 -> 145.0 ms
Correctness is unaffected: Ad blends that genuinely need software blending are
still forced into it by blend_requires_barrier, which tests blend_ad against the
RT alpha scaling separately. Scored per-pixel against the software renderer both
GPUs came out more accurate, not less - on Adreno the worst-case error in NFSU
halves, 19 to 8, with no pixel off by more than 16. Katamari, MGS3 and Ratchet &
Clank are bit-identical on both.
This commit is contained in:
@@ -7033,12 +7033,19 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, DATEOptio
|
||||
// Replace Ad with As, blend flags will be used from As since we are chaging the blend_index value.
|
||||
// Must be done before index calculation, after blending equation optimizations
|
||||
const bool blend_ad = m_conf.ps.blend_c == 1;
|
||||
// On Vulkan without framebuffer fetch (notably Mali, which reads Cd through texture-barrier), this
|
||||
// path forces thousands of RT feedback reads in blend-heavy scenes — a heavy cost and a source of
|
||||
// stale-tile artifacts (the G615/G57 rainbow-box blinks). Keep it only where feedback is cheap
|
||||
// (fbfetch) or where the fallback already copies the RT (no texture_barrier). Ported from
|
||||
// sashkinbro/EmuCoreX (Fix Vulkan Basic blending feedback cost).
|
||||
const bool fast_ad_alpha_masked_feedback = features.framebuffer_fetch || !features.texture_barrier;
|
||||
// This path forces an RT feedback read per Ad-masked draw. It used to be taken wherever
|
||||
// feedback was believed cheap - framebuffer fetch reads the target in-tile, so the read
|
||||
// itself costs almost nothing. But on a tiler the read is not what you pay for: binding
|
||||
// the target as an input attachment changes the render pass configuration, and
|
||||
// OMSetRenderTargets ends the pass every time that flag flips. NFS Underground toggles it
|
||||
// ~697 times a frame, which is 440 render passes on Adreno and 746 on Mali. Restrict it to
|
||||
// the case the fallback already copies the RT, where no pass boundary is at stake.
|
||||
//
|
||||
// Correctness is unaffected: Ad blends that genuinely need software blending are still
|
||||
// forced into it by blend_requires_barrier below (Ad is 0.5 not 1 for 128). Measured
|
||||
// against the software renderer, dropping this made both GPUs *more* accurate, not less.
|
||||
// Ported originally from sashkinbro/EmuCoreX (Fix Vulkan Basic blending feedback cost).
|
||||
const bool fast_ad_alpha_masked_feedback = !features.texture_barrier;
|
||||
bool blend_ad_alpha_masked = blend_ad && !m_conf.colormask.wa && fast_ad_alpha_masked_feedback;
|
||||
const bool is_basic_blend = GSConfig.AccurateBlendingUnit != AccBlendLevel::Minimum;
|
||||
if (blend_ad_alpha_masked && ((is_basic_blend || (COLCLAMP.CLAMP == 0) || m_conf.require_one_barrier)))
|
||||
|
||||
Reference in New Issue
Block a user