AMD: the fragment shuffle fallback on RADV too (RDNA1 flicker) #1893

Open
CleoMenezesJr wants to merge 1 commit from CleoMenezesJr/fix/radv-fragment-shuffle-fallback into main
CleoMenezesJr commented 2026-11-10 19:46:07 +00:00 (Migrated from github.com)

Builds on #1507 (its three commits are included until it is merged; only the last commit is new).

Problem

On an RX 5500 XT (RDNA1 / NAVI14, Mesa RADV, Fedora, no mesh shaders so the compute mesh fallback runs), objects such as the ladder of Link's house in Kokiri Forest flipped frame to frame between correct, speckled/dotted and glowing white while moving or turning the camera (the "moving" half of #1126 / #997).

Bisect

Switches set in the game folder's hookshot_env.txt, same spot each run:

Switches Flicker
RX_VK_NO_DESC_REUSE=1, RX_VK_PICK_BIND_GEN=1 yes
+ RX_VK_PER_QUEUE_FENCES=0, RX_VK_SAMPLER_CACHE=0, RX_VK_MIRROR=0 yes
+ RX_VK_BARRIER_EVERY_DRAW=1, RX_VK_WAIT_GPU=1, RX_VK_HANDLES_LIVE=1, RX_VK_BATCH=0, RX_VK_NO_EVICT=1 yes
RX_VK_WARP64=0 + RX_VK_FRAG_SHUFFLE_FALLBACK=1 no
RX_VK_FRAG_SHUFFLE_FALLBACK=1 alone no

Change

has_broken_spirv_fragment_shuffle is now on for VK_DRIVER_ID_MESA_RADV as well as VK_DRIVER_ID_AMD_PROPRIETARY. tests/test_amd_fragment_warp.py is updated and passes.

  • RX_VK_FRAG_SHUFFLE_FALLBACK=0 still keeps native shuffles.
  • The flag is in the program cache stamp, so RADV users retranslate once.

Testing

Tested on RDNA1 only. Other RADV GPUs (RDNA2/3/4, APUs) are untested. Reports welcome; if it turns out RDNA1-specific, the check can be narrowed.

Builds on #1507 (its three commits are included until it is merged; only the last commit is new). ## Problem On an RX 5500 XT (RDNA1 / NAVI14, Mesa RADV, Fedora, no mesh shaders so the compute mesh fallback runs), objects such as the ladder of Link's house in Kokiri Forest flipped frame to frame between correct, speckled/dotted and glowing white while moving or turning the camera (the "moving" half of #1126 / #997). ## Bisect Switches set in the game folder's hookshot_env.txt, same spot each run: | Switches | Flicker | |---|---| | RX_VK_NO_DESC_REUSE=1, RX_VK_PICK_BIND_GEN=1 | yes | | + RX_VK_PER_QUEUE_FENCES=0, RX_VK_SAMPLER_CACHE=0, RX_VK_MIRROR=0 | yes | | + RX_VK_BARRIER_EVERY_DRAW=1, RX_VK_WAIT_GPU=1, RX_VK_HANDLES_LIVE=1, RX_VK_BATCH=0, RX_VK_NO_EVICT=1 | yes | | RX_VK_WARP64=0 + RX_VK_FRAG_SHUFFLE_FALLBACK=1 | no | | RX_VK_FRAG_SHUFFLE_FALLBACK=1 alone | **no** | ## Change `has_broken_spirv_fragment_shuffle` is now on for `VK_DRIVER_ID_MESA_RADV` as well as `VK_DRIVER_ID_AMD_PROPRIETARY`. `tests/test_amd_fragment_warp.py` is updated and passes. - `RX_VK_FRAG_SHUFFLE_FALLBACK=0` still keeps native shuffles. - The flag is in the program cache stamp, so RADV users retranslate once. ## Testing Tested on RDNA1 only. Other RADV GPUs (RDNA2/3/4, APUs) are untested. Reports welcome; if it turns out RDNA1-specific, the check can be narrowed.
hckrman101 (Migrated from github.com) reviewed 2026-11-10 20:51:33 +00:00
hckrman101 (Migrated from github.com) left a comment

Thanks for the bisect table, it makes this easy to follow. The change itself is small and correct for what it does. One thing to be aware of on scope, which is what I checked for.

The flag is gated on the driver id only, so it now turns on for every RADV device, not just RDNA1. That is the only behaviour change: AMD_PROPRIETARY keeps what it had, AMD_OPEN_SOURCE (AMDVLK), NVIDIA, Intel and others are untouched, and the flag only feeds the shader profile and the program-cache stamp (vk_shader.cpp:1064), so RADV users retranslate once and nothing else moves. RX_VK_FRAG_SHUFFLE_FALLBACK=0 still forces native shuffles, so anyone who regresses has an escape hatch.

On RDNA2/3/4 and GCN under RADV this swaps native fragment-stage shuffles for the broadcast/select path with no evidence they were broken there. It should be correct but is slower in fragment shaders that use shuffles, and nobody has measured it. Your bisect also shows RX_VK_WARP64=0 fixes it too, so the real trigger may be the 64-lane path from #1507 rather than shuffles as such. If an RDNA2+ tester reports a perf hit or no flicker to begin with, narrowing this to RDNA1 (e.g. by device name or by whether the 64-lane path is active for the stage) would be the follow-up. Fine to land as is given that you said so in the description.

Small things: the PR says it builds on #1507, so it should merge after that; and no CI checks are reported on this head commit yet, so the test run is the local one you mention. The test update matches the source change.

Thanks for the bisect table, it makes this easy to follow. The change itself is small and correct for what it does. One thing to be aware of on scope, which is what I checked for. The flag is gated on the driver id only, so it now turns on for every RADV device, not just RDNA1. That is the only behaviour change: AMD_PROPRIETARY keeps what it had, AMD_OPEN_SOURCE (AMDVLK), NVIDIA, Intel and others are untouched, and the flag only feeds the shader profile and the program-cache stamp (vk_shader.cpp:1064), so RADV users retranslate once and nothing else moves. `RX_VK_FRAG_SHUFFLE_FALLBACK=0` still forces native shuffles, so anyone who regresses has an escape hatch. On RDNA2/3/4 and GCN under RADV this swaps native fragment-stage shuffles for the broadcast/select path with no evidence they were broken there. It should be correct but is slower in fragment shaders that use shuffles, and nobody has measured it. Your bisect also shows `RX_VK_WARP64=0` fixes it too, so the real trigger may be the 64-lane path from #1507 rather than shuffles as such. If an RDNA2+ tester reports a perf hit or no flicker to begin with, narrowing this to RDNA1 (e.g. by device name or by whether the 64-lane path is active for the stage) would be the follow-up. Fine to land as is given that you said so in the description. Small things: the PR says it builds on #1507, so it should merge after that; and no CI checks are reported on this head commit yet, so the test run is the local one you mention. The test update matches the source change.
Joey-Magnus (Migrated from github.com) reviewed 2026-11-11 21:46:14 +00:00
Joey-Magnus (Migrated from github.com) left a comment

The change is one line, and the test passes on current main (I merged it locally and ran tests/test_amd_fragment_warp.py). But two things changed since you bisected. #1657 merged after this was opened. It handles RDNA1's wave32/wave64 stages: unpinned stages now take subgroup_max, which was the RX 5500 XT family's problem, and that may be what fixed the ladder. Could you re-run the same spot on current main without this patch, with RX_VK_FRAG_SHUFFLE_FALLBACK unset? Second, this turns the fallback on for every RADV device, Steam Deck included. On RADV max_subgroup_size is 64, so each fragment shuffle becomes 64 broadcasts and selects (ShuffleAbsolute in emit_spirv_warp.cpp). That's the most-used Linux AMD tier, and the cost hasn't been measured. If the flicker is still there on main, I'd narrow the check to RDNA1 or bring a Deck frame-rate number. CI hasn't run on this branch.

The change is one line, and the test passes on current main (I merged it locally and ran tests/test_amd_fragment_warp.py). But two things changed since you bisected. #1657 merged after this was opened. It handles RDNA1's wave32/wave64 stages: unpinned stages now take subgroup_max, which was the RX 5500 XT family's problem, and that may be what fixed the ladder. Could you re-run the same spot on current main without this patch, with RX_VK_FRAG_SHUFFLE_FALLBACK unset? Second, this turns the fallback on for every RADV device, Steam Deck included. On RADV max_subgroup_size is 64, so each fragment shuffle becomes 64 broadcasts and selects (ShuffleAbsolute in emit_spirv_warp.cpp). That's the most-used Linux AMD tier, and the cost hasn't been measured. If the flicker is still there on main, I'd narrow the check to RDNA1 or bring a Deck frame-rate number. CI hasn't run on this branch.
hckrman101 (Migrated from github.com) reviewed 2026-11-11 22:17:36 +00:00
hckrman101 (Migrated from github.com) left a comment

No new commits since my last review, so this is just a follow-up to @Joey-Magnus's point, which changes what I said.

I wrote "fine to land as is", but #1657 (RDNA1 wave32/wave64 stage handling) merged after this was bisected, and it targets the same RX 5500 XT family. I agree with Joey: please re-run the same spot on current main without this patch and with RX_VK_FRAG_SHUFFLE_FALLBACK unset. If the ladder no longer flickers, this PR isn't needed. If it still does, the RADV-wide gate should be narrowed to RDNA1 (or come with a Steam Deck frame-rate number), since the Deck is RADV too and would pay the 64-wide broadcast/select cost in every fragment shuffle.

#1507 is merged now, so a rebase on main would leave just the one commit here. CI still hasn't run on this branch.

No new commits since my last review, so this is just a follow-up to @Joey-Magnus's point, which changes what I said. I wrote "fine to land as is", but #1657 (RDNA1 wave32/wave64 stage handling) merged after this was bisected, and it targets the same RX 5500 XT family. I agree with Joey: please re-run the same spot on current main without this patch and with `RX_VK_FRAG_SHUFFLE_FALLBACK` unset. If the ladder no longer flickers, this PR isn't needed. If it still does, the RADV-wide gate should be narrowed to RDNA1 (or come with a Steam Deck frame-rate number), since the Deck is RADV too and would pay the 64-wide broadcast/select cost in every fragment shuffle. #1507 is merged now, so a rebase on main would leave just the one commit here. CI still hasn't run on this branch.
Commenting is not possible because the repository is archived.
No description provided.