vk: RX_VK_MESH_NOCULL, the Steam Deck's task shader hang without leaving models out (#817) #1300
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!1300
Loading…
Reference in a new issue
No description provided.
Delete branch "deck-mesh-nocull"
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?
What
A new renderer switch,
RX_VK_MESH_NOCULL=<task shader code key prefix,...>, turns off the culling inside the task shaders it names. On a Steam Deck,RX_VK_MESH_NOCULL=2c56dc1006942f74avoids the GPU hang of #817 with every model drawn, whereRX_VK_SKIP_CODE=2c56dc1006942f74(#1165) avoids it by leaving out the ~30 programs that use that task shader, and the houses, platforms and rupees they draw.gpu/vk/vk_shader.cpp:mesh_nocull()runs on the translated task program, beforedump_ir. It looks forINotEqual(BitwiseOr32(x, BitwiseAnd32(4, GetCbufU32(3, 2320))), 0), replaces its uses withtrueand runsDeadCodeEliminationPass. If the pattern is not found, the program is left as it is and the log says so. It logs the first 8 task shaders it met.readme.md: the Deck troubleshooting row now points to this switch first, and the switch is described under Switches for testing, next toRX_VK_SKIP_CODE.Why it works
Task shader
2c56dc1006942f74projects each meshlet's bounding sphere onto a grid ofc3[3088]xc3[3092]cells and, for every covered cell, reads four words fromc3[3120 + cell * 16]by a dynamic index (two nested loops). On RDNA 2 some draws run for seconds, and past 10 s the kernel resets the ring. The shader's answer is:Bit 4 of
c3[2320]is the game's own "draw everything" switch. Making that comparison true lets dead code elimination take the grid walk with it: no loops are left, every meshlet goes to the mesh stage, and the rasterizer clips what is off screen. It costs some GPU time on cards that cull quickly, so it is off unless set. The name is underRX_VK_MESH, so the program cache starts again when it changes.Tested
Steam Deck (RADV VANGOGH), SteamOS, Game Mode,
HOS_HANDHELD=1,RX_VK_MESH_OPT=1, the memory caps from #817, with the same change on by default in a local build:RX_VK_SKIP_CODEhides are all there.tests/run_all.pygives the same results as main without the change. I did not run this exact build on the Deck: the runs above are the same function, on by default.The flashing on integrated GPUs (#1186, #1126) is a separate problem and is not touched here.
Generated with Claude Code
Looks good. I checked the pieces that could go wrong:
RX_VK_MESH*env var (vk_shader.cpp, the prefix list in the cache hash), soRX_VK_MESH_NOCULLinvalidates the cache as the comment says.passes.his included forDeadCodeEliminationPass, and the call site sits beforedump_ir, so dumps show the rewritten IR.Nit: the description says "no loops are left". DCE does not remove structured control flow, so I would expect the loop skeleton to stay with an empty body, which is still cheap. It matches your Deck results either way, so just worth wording carefully.
No CI ran on this branch, and the PR itself notes the exact build was not run on the Deck (only the same function enabled by default), which is fine for an opt-in switch.