Repository navigation
Game-mode draw passes hold the next pass's task and mesh shaders until their fragments are done - #1707
Game-mode draw passes hold the next pass's task and mesh shaders until their fragments are done#1707cocoman93 wants to merge 1 commit into
Conversation
…l their fragments are done, as they already did fragments, compute and copies With draw_barriers game a draw pass ends with a barrier that lets the next pass start its vertex work while this pass's fragments still run. Its later stages (beforeQueueStages) were fragment, dispatch and blit. Metal tracks the object (task) and mesh stages apart from the vertex stage, so the next pass's task and mesh shaders, including the mesh pipelines that replay some geometry-shader draws, did not wait either and could read what the previous pass had not written yet. Its earlier stages (barrierAfterStages) did not list object. The end barrier now adds object to its earlier and object and mesh to its later stages; vertex work still overlaps, as the mode intends. t_pass_end_stages drives two production passes in game mode: each fragment of a slow pass adds to a counter, and the next pass reads it from a vertex shader (the control: it reads early in nearly every run), a mesh shader and a task shader, which must see every fragment's add. Without the change 18 to 29 of 32 mesh and task reads came early, in both encoder modes; with it none, on an M4 Max. In Ocarina of Time, with this profile's draw_barriers game, the whole picture turned darker for one frame at a fixed place in Kokiri Forest in 4 of 9 walks on a build of main 7fe9fc4 with two local shader changes; it did not show there with full barriers (0 of 4 walks), an All -> All end barrier (0 of 4) or object and mesh added to the later stages (0 of 6). On main 24fe1e5 it did not show in 15 walks with or without the change, while the 7fe9fc4 build showed it in 2 of 5 the same day. GPU time unchanged (median 14.88 ms without, 14.82 ms with, 14.98 ms with full barriers; the scene passes stayed at the game's full 1536x864 throughout). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
A run of this PR against the Ocarina of Time hang (#1326, #1605), on an M1 Pro (16 GB, macOS 26.6.1): main e940e1f plus this PR (the profile's The hang still came: two sessions, both ended in That agrees with @ralph-ferza's run with |
|
Thanks for the careful runs and the test. We're holding this for now. Adding object to the barrier's earlier side is correct, but making the next pass's task and mesh stages wait while vertex doesn't goes further than NVN, where all of them overlap the previous pass's fragments without a barrier. The flash also doesn't reproduce on main, and which shader reads early is still unknown. What would move it forward, on a build where the flash still reproduces:
If the game issues a barrier that the host loses, that's a host fix for every game. If it doesn't, the fix belongs in game mode's rules for all the early stages, not in the mesh and task bits alone. |
|
Thanks, that was the right question. Here is what a build where the flash still reproduces shows. Build: main Barriers: the game's are not lost. Game mode gives the next draw pass the full consumer barrier whenever the game called
The reader: not found. The dump shows no dependency between 35125 and 35126: 35125 writes only its attachments, 35126's task and mesh bind no textures, and no binding in the frame writes the storage buffers they read. Their raw global reads have no addresses in the dump. I measured instead, with a diagnostic host that is not part of this PR: a queue barrier from earlier work's vertex, object, mesh and fragment stages before the matching task / mesh draws, 58 s walks, the same flash rule:
I could not narrow it further: at about 1 in 15 walks a split needs far more walks than is reasonable, and a GPU load beside the game, which I tried to raise the rate, produced a different one-frame effect that stays even with every task and mesh draw waiting. So by your rule: the game issues no barrier between the overlapping passes, so this is not a lost barrier, and a fix would belong in game mode's rules for all the early stages. On this M4 Max even full barriers cost nothing measurable in this walk (GPU p50 14.88 ms base, 14.98 ms full), but that walk does not exercise what game mode was made for. I can rework this into one rule for all the early stages and measure its cost on the games I have that draw with vertex and mesh shaders (Donkey Kong Bananza, Mario Kart World, Kirby Air Riders), or close it if you would rather keep game mode as it is until a game shows the race on main. Your call. |
|
Found the cause, and it is not a barrier problem. The flash is most likely the cross-queue wait race from #1703 and #1245, which main fixed in ea0c98d, whose message says these fixes "address Ocarina's scene flashes". All the mains I measured on before ( Test: main
What this does and does not show: it proves the race on current main once the waits are dropped. That the rare flash on the older builds was the same race rests on the identical look and on ea0c98d's own description. The same load on the old Either way, on main the waits ea0c98d honours remove the flash and this PR is not needed, so I'm closing it. If you want object added to the barrier's earlier side on its own, as you said is correct, tell me and I'll open it separately. Side finding on Kokiri's shaded path: the flat near-black leaves that lay on the stones in builds before ea0c98d also appeared in three of the seven flash frames checked by eye, and only in the flash frame. So ea0c98d most likely fixed those as well. |
# Conflicts: # dm/games/0400486024DEC000/README.md # docs/env_switches.tsv
…d mesh shaders until their fragments are done Upstream pull requests applied in this commit (their authors' work, brought onto this tree with a three-way merge; the description is in each PR): - seedds#1707 by cocoman93 (closed): Game-mode draw passes hold the next pass's task and mesh shaders until their fragments are done
What and why
With
draw_barriers game(orDM_NVN_BARRIER=game) a draw pass ends with a barrier that lets the next pass start its vertex work while this pass's fragments still run (enc_r_end_passinnvn_mtl.m). Its later stages (beforeQueueStages) were fragment, dispatch and blit. Metal tracks the object (task) and mesh stages apart from the vertex stage, so the next pass's task and mesh shaders, including the mesh pipelines that replay some geometry-shader draws, did not wait either and could read what the previous pass had not written yet. Its earlier stages (barrierAfterStages) did not list object.The end barrier adds
MTLStageObjectto its earlier andMTLStageObject | MTLStageMeshto its later stages. Vertex work still overlaps, as the mode intends. New reference entry "Mesh shaders that start before the previous draw pass is done" indocs/reference/rendering.md; the game note gets a line under "Found on this game", and the barrier mode's rows indocs/agents/04-graphics.md,docs/env_switches.tsvanddm/games/README.mdsay which stages wait.Checked
check_t_pass_end_stages: two production passes in game mode; each of the 4,096 fragments of a slow pass adds to a counter, and the next pass reads it from a vertex shader (the control: it reads early in nearly every run, so the window exists), a mesh shader and a task shader, which must see every add. 32 runs, with and without the encode thread, under the Metal debug layer. Without the change 18 to 29 of 32 mesh and task reads came early; with it none.make -C dm/gfx/tests GAME=0400486024DEC000 runon the Mac, every check passed;python3 dm/tools/tests/test_docs.pyandpython3 dm/tools/docs_symptoms.py --checkpass.python3 dm/tools/lint_c.py tidyon the two changed C files: no new finding (nvn_mtl.m's two checks above the baseline are the same onmain).0400486024DEC000, v131072 (1.1.1), the one profile that setsdraw_barriers game, Mac apps on the same route from the same save, 58 s recordings of every frame, a flash counted as a one-frame drop of at least 3.5 in average brightness after recording frame 500:On a build of
main7fe9fc4dwith two local shader changes: the whole picture turned darker for one frame at a fixed place in Kokiri Forest in 4 of 9 walks. It did not show with full barriers (0 of 4 walks), an All → All end barrier (0 of 4) or object and mesh added to the later stages (0 of 6); with only the earlier stages widened it did (2 of 8).The flash on that build, slowed down (the fog over the path drops out for one frame), and the average brightness of every frame around it: a one-frame drop, then a smooth recovery; the rest of the curve is the camera moving.
On
main24fe1e5a, one build, with and without this change (the host swapped, nothing else different): no flash in 15 walks either way, while the build above still showed it in 2 of 5 walks the same day (both looked at by eye: the haze over the whole picture weaker for one frame). What hides it onmainis not separated, so onmainthe change rests on the test above.GPU time per frame, median of 300-frame windows over two walks each: 14.88 ms without, 14.82 ms with this change, 14.98 ms with
DM_NVN_BARRIER=full; the scene passes stayed at the game's full 1536x864 in every profiled frame of all three. Full barriers cost nothing measurable here either, so the game mode's gain recorded in frame-rate.md cannot be compared on this Mac.The game runs used
main24fe1e5a; the branch is onbd979ced, where the tests above ran.regress.py impactmaps the change to every NVN game throughnvn_mtl.m, but the changed barrier only runs underdraw_barriers gameorDM_NVN_BARRIER=game/ab, and only Ocarina of Time's profile sets it; Ocarina of Time has no smoke route, so its walks above stand in forregress.py check.DM_NVN_BARRIER=game.Docs
docs/reference/<subsystem>.mdentry, andpython3 dm/tools/docs_symptoms.pywas run (the symptom index)🤖 Generated with Claude Code