fix(vk): RADV on GCN 1-4 skips the two mesh fallback programs its compiler never finishes #2525
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
No milestone
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!2525
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/radv-gcn-mesh-fallback"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
On an RX 580 (Polaris 10, Mesa 26.2.6 RADV), a cold
--prepare-shadersgot through the translation and the prediction, then ran out of memory in the precompile. It grew past 24 GB and was killed, on main too. The game's own first start does the same precompile, so a player with an RX 400/500-class card can't get through the first start: it pushes the desktop into swap or the OOM killer.The cause is two mesh programs' fallback compute pipelines,
93e3e999f2fb9fd8(stage 1) andea4dd64df9c8f2b7(stage 0). RADV never finishes compiling them on GCN 1-4 (GFX6-8), and its thread keeps the memory it grew to. A time limit wouldn't help for that reason.What makes them different from the other mesh programs:
I compiled the dumped modules with RADV itself, through Mesa's amdgpu drm-shim (no AMD GPU needed), under a 6 GB cap:
ea4dd64df9c8f2b7mesh (79,947 phis)ecbbff63280b68e2mesh (29,372 phis)cf987f56b971bdb3mesh (28,506 phis)RX_VK_NOOPT(DISABLE_OPTIMIZATION) doesn't change it. The spiller runs either way. GFX6-8 have no scratch instructions. ACO spills there through buffer instructions, and these programs' scratch is past their offset range, so ACO takes its overflow path for every spill and reload (aco_spill.cpp). With this many spills it doesn't finish. That's my reading of the source, not profiled.I couldn't find a translation-side change that compiles these two normally. Their register pressure and block count come from the native program and the shared goto-elimination structurizer. Changing either would retranslate every shader for every GPU. So this PR leaves just these two out on the cards whose compiler can't build them.
What changes
gpu/vk/fallback_size_policy.h(new):spirv_phis()counts a module's OpPhi instructions.too_big()decides whether a mesh fallback compute stage should be skipped: the device is RADV on GCN 1-4, and the stage has more than 50,000 phis. 50,000 sits between the 29,400 that build in seconds and the 80,000 that never finish.vk_progcache.cpp: each stage's phi count is recorded where its SPIR-V passes through the program cache. That is on save, which every translated program goes through, and on read. It's done there and not invk_shader.cppbecausevk_shader.cppis part of the translator stamp, and touching it would retranslate every player's programs. The record format is unchanged.vk_main.cpp/vk_internal.h:dev.radv_gcnis set when the driver is RADV andstorageInputOutput16is false. RADV sets that feature from packed 16-bit math, which means GFX9 and later. Checked through the drm-shim: false on Polaris and Pitcairn, true on Vega 10 and Navi 10.vk_draw.cppfallback_compute_pipelines: before anything is built, a program with a stage over the limit goes into the same "failed" set as a pipeline the driver refuses. It logs one line, and its draws are left out (as #2382 leaves out draws whose fallback isn't ready). The precompile and the in-play builds both go through this function.RX_VK_FALLBACK_PHI_LIMIT=<n>sets another limit, and0turns it off. It's documented indocs/development.md.tests/test_fallback_size_policy.pychecks the counter on well-formed, cut-short and non-SPIR-V input, checks the limit, and checks that the source still calls the policy before any fallback pipeline is built.program_cache_cleanup_test.cppnow includes the header.What's lost: on RADV with an RX 400/500, R9 2xx/3xx or Fury card, the draws of these two mesh programs. Neither was drawn in the lab's Kokiri Forest or Hyrule Field runs, so I don't know yet which objects they are. Nothing changes on Vega and later, on AMD's Windows driver, on NVIDIA, or on Intel. The SPIR-V of every program is unchanged.
Verified
RX_VK_DUMP_MESH_SPV). Both modules passspirv-val --target-env vulkan1.3 --uniform-buffer-standard-layout --scalar-block-layout. This PR doesn't change any SPIR-V.python -I -B tests/run_all.py fallback_size_policy program_cache_cleanup mesh_fallback mesh_fallback_failed_once program_cache_reader driver_faults run_all_declarations(8 passed), plus the program cache, prediction and recorder tests (all pass).hookshot_vk.sobuilds on the current main, ABI check ok.Not tested
RX_VK_FALLBACK_PHI_LIMIT=0or a version check is added.Tested on the real card: RX 580 (Polaris 10), Mesa 26.2.6 RADV, i7-9700K, 15 GB. This PR (
42d84fc9) built natively, with a cold--prepare-shaders(empty caches, the precompile on), capped at 12 GB RAM + 4 GB swap.The prepare finishes. On main it was killed in the precompile every time, past 24 GB.
Peak memory: 10.6 GB (8.4 GB RAM + 2.1 GB swap, at the start of the precompile).
The log has
RADV on GCN 1-4: yes, and exactly the two expected skip lines:A warm second start and a play run in Kokiri and Hyrule Field follow; I'll add them here.
The rest of the RX 580 check:
So whatever the two skipped programs draw, it isn't in those two areas.
github-sync referenced this pull request2026-11-12 06:22:54 +00:00