fix(vk): size the mesh index map in whole 32-primitive blocks #2312
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!2312
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/mesh-index-map-blocks"
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?
Flashing triangles over the foliage and ground in Kokiri Forest: a stray vertex from mesh programs with 126 primitives, which are most of OoT's.
What changed: a mesh program writes the index bytes of every 32-primitive block, including lanes past
max_primitives(a count of 0 wrapsmin(count - 1, lane)onto every lane). The index map was sized tomax_primitives, so those writes were clamped onto its last byte, the last primitive's last corner.DefineMeshnow sizes the map like the attributes, in whole blocks of 32 primitives. nxnative found the same thing ("primitive index bytes for every primitive block").tests/test_mesh_point_topology.pychecks the new size.Tested: Steam Deck LCD, Mesa RADV, Kokiri Forest. I compared 150–200 screenshots per run, each against the previous one: no flashes remain, and the biggest changes are Navi moving and the lighting fading in.
tests/run_all.py: no new failures againstmain.🤖 Generated with Claude Code
Looks right to me. The map is laid out linearly (byte
4 + corners * primitive + corner, both in the epilogue and in the fallback's record copy), so a program that writes index bytes for a whole 32-lane primitive block reaches up to4 + corners * DivCeil(max_primitives, 32) * 32 - 1. With the old size,EmitIsbeWriteMapU8'sClamped(address, mesh_map_bytes)folded every out-of-range byte onto the last one, so for 126 primitives the 6 bytes of lanes 126/127 raced with primitive 125's last corner. That fits the flashing-triangle symptom well, and sizing the map in whole blocks matches howmesh_attribute_wordsalready sizes the primitive attributes.Other things I checked:
< count(bounded bymax_primitives), so the extra bytes are scratch and never read back. The prologue zeroing walks the new size too.mesh_mapis defined before theif (mesh_fallback) return;, so the compute fallback path gets the fix as well, not only native mesh shaders.max_primitives == 0still gives 4 bytes, same as before.No overlap with #2311 (
vk_draw.cpp) or #2362 (vk_main.cpp/vk_menu.cpp); they touch different files and this fix helps whichever mesh path ends up the default on RADV.CI: only the title check has run; the build and game-free regression workflows are waiting for approval to run on this fork, so those should go green before merging.
github-sync referenced this pull request2026-11-12 06:22:54 +00:00