Repository navigation
The game's compute dispatches with no game barrier between them run side by side (profile key dispatch_overlap, on for Ocarina of Time): Kokiri Forest GPU p50 15.63 → 14.76 ms - #1901
Conversation
…ide by side (profile key dispatch_overlap, on for Ocarina of Time): Kokiri Forest GPU p50 15.63 -> 14.76 ms Ocarina of Time runs most of its compute at the start of a frame, many dispatches back to back with no nvnCommandBufferBarrier between them. dispatch_enc put a barrier inside the shared copy encoder before every dispatch, so each one waited for the one before it. NVN orders a dispatch after earlier work only through a barrier, as the draw passes of a game with draw_barriers game are ordered. With dispatch_overlap on (DM_NVN_DISPATCH_OVERLAP overrides it), two of the game's dispatches with nothing else between them in the copy encoder and no game barrier between them run side by side. A copy, fill or inline update between them, a dispatch of the host's own, or a game barrier keeps the barrier, and whatever follows a dispatch other than another dispatch still waits for it. The key is off by default, so every other profile keeps the barriers it has. Measured with scripts/bench.py on a --platform mac build of main d8b2b64, the kokiri-deck route, docked, Apple M4 Pro, three runs a side with a warm pipeline archive: GPU p50 15.63 -> 14.76 ms, p95 16.43 -> 15.66 ms, frames over budget 63 -> 36, the pictures alike. t_dispatch_overlap checks where the barriers go.
|
Confirmation on a second M4 Pro (20-core GPU, 24 GB, macOS 27.0.1), main 04811a6, chain 39eb2f781d07, docked, Kokiri Forest route with scripted inputs, GPU p50 with this PR: 14.41 and 14.63 ms. Without it (base and two other PR hosts, 6 runs): 15.20–15.49 ms. So about -0.7 to -0.9 ms, in line with your 15.63 -> 14.76. Frame time did not drop with it on this route: frame p50 18.38 / 18.50 ms against 17.07 / 17.68 for the base, but the PR's runs sat in the middle of the series where every variant was slower (~18.5 ms), so I would not read a regression into that. The frames here are CPU-bound. Note: on top of 04811a6 the nvn_mtl.m hunk needs a 3-way apply (context moved); it applies cleanly that way and builds. No crashes, no [RED] lines in the runs. |
…tches with no game barrier between them run side by side (dispatch_overlap, on for Ocarina of Time) Conflict with our pass-overlap branch resolved by hand: the barrier handler keeps our fragment-aware logic (g_game_barrier_full) and adds the PR's g_cs_gbar = 1 for any barrier bits; game.tsv keeps both sides. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…f its between them run side by side (on for Ocarina of Time) Net change of PR seedds#1901 at 5b7b307 (seedds/nxnative), merged by hand with this tree's g_blit_nops and g_game_bar_bits. DM_NVN_DISPATCH_OVERLAP=0 turns it off.
…nds once to half), seedds#1909 (fragment uniform reads bound to the binding length), seedds#1901 (dispatch_overlap on for Ocarina), seedds#1459 (MetalFX takes agl_ndsr_vr, no-curve variants linear), seedds#1903 (render scale stubs for Ocarina; replaces the seedds#1497 ceiling we carried) Hand-resolved: the mesh draw keeps the task isolation of seedds#1842 and the copy paths our nvn_tex_level_range / DM_SHARPEN; seedds#1497's stub, test and BINDING entry go; the build-keyed rule names the render scale function (main+0x31d3200). Chain e906c7467690. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014eD437mxrMnW2UwLZhpwc7 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#1459 by PromethOps (open): DM_UPSCALER=metalfx takes agl's agl_ndsr_vr.pck networks too, and a variant with no curve and no power is drawn as one colour space: Ocarina of Time's upscaler is MetalFX's - seedds#1497 by givethesourceplox (open): Add a render-scale ceiling for Ocarina v131072 - seedds#1842 by ycarogabriel-lgtm (open): Ocarina of Time: opt-in task isolation (DM_NVN_ISOLATE_TASK), the Hi-Z task a5288 in command buffers of its own, a workaround for its GPU hangs on an M1 - seedds#1897 by Know-It-All-Brother (closed): HMMA with an f16 accumulator rounds once per 8 products, as Ampere does (chain change) - seedds#1901 by FifteenPen (open): The game's compute dispatches with no game barrier between them run side by side (profile key dispatch_overlap, on for Ocarina of Time): Kokiri Forest GPU p50 15.63 → 14.76 ms - seedds#1902 by fxd0h (open): HFMA2 rounds once to half, as Ampere does (chain change) - seedds#1903 by FifteenPen (open): Ocarina of Time takes the launcher's Render scale: the 3D views at that fraction of the game's own size, the dynamic resolution held at its top level (Kokiri Forest docked at 0.75: GPU p50 15.77 → 14.31 ms, 60 fps held) - seedds#1909 by oz-rinkliff (open): Bound translated fragment uniform reads to the NVN binding length
seedds#1901 seedds#1459 seedds#1928 seedds#1942 seedds#1940 seedds#1952 seedds#1611 seedds#2065 seedds#2083 seedds#2008 seedds#2079 seedds#2022 seedds#2075 seedds#2077 seedds#2020 seedds#2021 onto main 04811a6 Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014eD437mxrMnW2UwLZhpwc7 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#1459 by PromethOps (open): DM_UPSCALER=metalfx takes agl's agl_ndsr_vr.pck networks too, and a variant with no curve and no power is drawn as one colour space: Ocarina of Time's upscaler is MetalFX's - seedds#1611 by Esteban-V (open): An argument block whose only change is a uniform buffer is patched instead of encoded again - seedds#1774 by uncraftablexd (closed): Compute threads that exit before a barrier keep arriving at it, and every shader loop has a cap (GPU hang defences), chain change - seedds#1824 by cocoman93 (open): Clamp texel fetches past a sampled 2D texture's edge: no hard edge in Ocarina of Time's mist - seedds#1901 by FifteenPen (open): The game's compute dispatches with no game barrier between them run side by side (profile key dispatch_overlap, on for Ocarina of Time): Kokiri Forest GPU p50 15.63 → 14.76 ms - seedds#1928 by FeReuss (open): Ocarina of Time: enc_thread on, the replay encodes on a thread of its own - seedds#1929 by FeReuss (open): Unused border corrections are compiled out of pipelines that bind no sampler with a twin (function constant DMSH_BORDER_FC) - seedds#1930 by FeReuss (open): A float add to storage memory with no result read is one native atomic add instead of a compare-and-swap loop - seedds#1940 by uncraftablexd (open): A prewarm list's lines after its #@after_first_frame line are built after the first frame, in the background, instead of in the prepare step (issue seedds#1747) - seedds#1942 by uncraftablexd (open): Frame step: late frames with the GPU idle do not step up, and a longer hold the GPU does not explain is probed - seedds#1952 by AdyaGMD (open): Compute moves ahead of scene passes past occlusion queries and conditional rendering; clears wait across dispatches - seedds#2008 by bquilty25 (open): nvn: reactive memory watchdog, 16-way view cache, and texture upload batching - seedds#2020 by padsiwono (open): Ocarina of Time v131072: Output Native draws the full output size instead of the game's 80 % frame (`DM_OUTPUT`) - seedds#2021 by padsiwono (open): Ocarina of Time v131072 renders at the launcher's Resolution (`DM_RENDER_SIZE`), docked - seedds#2022 by sleepyeyedjoe (closed): Ocarina of Time: large models no longer go black for one frame twice, 4–5 frames apart, when the game streams new textures into them (a texture ID a shader has read keeps its read mark when it gets another texture) - seedds#2030 by humanperzeus (open): A NaN colour at alpha 0 is returned as 0, as NVIDIA's blender takes a zero factor: Ocarina of Time's white clouds over the ferns are gone - seedds#2035 by Know-It-All-Brother (open): The shader build runs as worker processes, and no shader waits for a batch (Ocarina of Time's cold Mac map: 3,002 s to 1,298 s) - seedds#2065 by Raymon82777 (closed): A vertex library with layer entry points of its own gets bases for its main0 pairs: Ocarina of Time's 230 ms camera-turn hitch in Hyrule Field goes to 39 ms - seedds#2075 by sleepyeyedjoe (closed): Ocarina of Time: a patch of scenery no longer draws dark for one frame when the game gives it a sharper texture (a pool texture the walk does not make holds a stand-in of its own colours until its first read) - seedds#2077 by roandegraaf (closed): Ocarina of Time: fix the "plaid" terrain / missing texture tiles (GPU-drawn textures now reach the storage the game copies) - seedds#2079 by uncraftablexd (open): Render pipelines that share a vertex function are taken from the archive or compiled one at a time: the AGX driver crashes in createVertexProgramVariant's completion block - seedds#2083 by FifteenPen (closed): Ocarina of Time's prewarm list gets 41 more task / mesh pipelines from later play
|
Measured on an M1 Max (32-core GPU,
So about −0.8 ms of GPU here; screenshots match. Note: it no longer builds on current main. Main added a forward declaration |
Compute dispatches are ordered by the game's own barriers, for every game (PR #2250): dispatch_enc put a barrier before every dispatch in the shared copy encoder, so the GPU ran them one at a time, while NVN makes a dispatch's writes visible to later work only when the game issues nvnCommandBufferBarrier. Now a dispatch (dispatch_enc_cs) gets a barrier when the game issued one since the dispatch before it, or when one of the host's copies meets its ranges in either direction (uniform updates and uploads keep their order; copies are checked against what dispatches wrote and read, g_dw / g_dr); a dispatch with a binding whose reach is no memory range (an image, a buffer texture, a handle in a uniform slot, untraced global memory) and the host's own dispatches keep the full order on both sides. Kirby Air Riders' particle systems, about 230 dispatches a frame that share the buffers they write (91 % meet an earlier one's range, so ranges alone gain nothing): the encoder 6.6-9.8 → 0.4-1.2 ms, GPU p50 over alternating race phases 9.0 → 5.3 ms, the heaviest phase's frame p90 19.36 → 16.75 ms (PR author, M4 Pro, with PR #2254's loop guard). The PR made it a profile key for Kirby; it is the host default here, as the rule is NVN's: DM_NVN_DISPATCH_BARRIER=full brings back the barrier before every dispatch (diagnostic), ab alternates with the DM_AB phases. It replaces PR #1901's dispatch_overlap for Ocarina of Time. Also fixed on top of the PR: a new copy encoder empties the dispatch range sets (ranges from a closed encoder put needless barriers before its copies; t_dispatch_barrier's new case 6 fails without it), and bufsnap's copy is recorded as writing everything, so a later dispatch cannot overwrite what it still reads. The periodic [nvn] line counts dispatches after a game barrier, after a copy's range, in the full order and with none. Reference entry Compute dispatches that wait for each other (frame-rate.md), rendering.md's two dispatch entries point to it, Kirby's note lists it, env switch row, symptom index regenerated. Checked: t_dispatch_barrier in both orders with the encode thread on and off (27 / 31 checks), t_dispatch_own, t_copy_alias, t_tg_spill, t_cpu_tex, test_docs, test_env_switches, test_game_profile, lint_c.py tidy (at the baseline); regress.py check against 8a5c5e7 (M4 Pro): Mario Kart World PASS, 69,367 of about 1.02 M dispatches with no barrier, 59.8 / 60.0 fps, no new red line; OCTOPATH TRAVELER II PASS, but all its dispatches have a rangeless binding and keep the full order. Not run: Kirby Air Riders and Ocarina of Time in this form (no files / no route here), the iPhone Co-authored-by: FifteenPen <354289956+FifteenPen@users.noreply.github.com>
|
Superseded by 547c5db, from #2250: compute dispatches are now ordered by the game's own barriers for every game, Ocarina of Time included, so |
…ier between them run side by side (profile key dispatch_overlap, on for Ocarina of Time): Kokiri Forest GPU p50 15.63 -> 14.76 ms
…e forward declaration and in gsb_swz (the host's own dispatch, 0), which main added after seedds#1901's base
…2514d7 evaluates conditional rendering for every game) Ocarina of Time's profile drops the key and keeps seedds#1714's gpu_ts_hz; game.py keeps seedds#1901's dispatch_overlap and seedds#2341's replay_ahead beside main's warning for an old render_cond; t_nvn takes main's counter field (0) and seedds#1714's report rate. Checked: t_nvn 311, t_serial_owner, t_cpu_tex, t_view_cache, t_replay_ahead, all dm/gfx/tests programs build, test_docs, test_env_switches, test_game_profile, test_nsp_chain, the Mac host for 0400486024DEC000.
…losed, superseded by seedds#2250, on main as 547c5db (compute dispatches ordered by the game's barriers for every game) Ocarina of Time's profile drops dispatch_overlap; the barrier op records the game's bits without g_cs_gbar; dispatch_enc is main's as it was before seedds#2250. seedds#2226's ind_split and seedds#2341's replay_ahead stay.
…ered by the game's barriers (547c5db, seedds#2250) in place of seedds#1901 Kirby's note, hle_nvn.c's periodic lines (seedds#2261's GPU share and main's dispatch counts) and the tests Makefile keep both sides. Checked: t_dispatch_barrier (full and game, encode thread off and on), t_dispatch_own, t_copy_alias, t_tg_spill, t_replay_ahead, t_cpu_tex 107, t_view_cache 44, t_serial_owner 167, all dm/gfx/tests programs build, test_docs, test_env_switches, test_game_profile, test_nsp_chain, the Mac host for 0400486024DEC000.
What and why
The Legend of Zelda: Ocarina of Time (
0400486024DEC000, v131072) runs most of its compute at the start of a frame: many dispatches back to back, with nonvnCommandBufferBarrierbetween them.dispatch_encputs a barrier inside the shared copy encoder before every dispatch (Compute dispatches share the copy encoder), so each one waits for the one before it to finish.That is more ordering than NVN gives. NVN orders a dispatch after earlier work only through a barrier. The draw passes of a game with
draw_barriers gamealready follow the same rule (dm/games/README.md,draw_barriers).The change is a profile key,
dispatch_overlap(DM_NVN_DISPATCH_OVERLAPoverrides it), indispatch_enc:The key is off by default, so every other profile keeps exactly the barriers it has now. Ocarina's profile sets it on.
Docs: a new reference entry, Compute dispatches ordered by the game's own barriers, the key's row in
dm/games/README.md, the switch's row indocs/env_switches.tsv, and a line under the game note's "Found on this game".Related: #1076 and #1887 skip the same barriers by proving the dispatches' buffer ranges disjoint (opt-in). This one follows the game's own barriers instead, as
draw_barriers gamedoes for draw passes. The two can coexist: range tracking for a game whose barriers cannot be trusted, this key for one whose can.Checked
make -C dm/gfx/tests GAME=0400486024DEC000 check_t_dispatch_overlap(Metal debug layer, on this branch's base 7479adf): 7 checks, 0 failed. It counts the copy encoder's barriers:It also checks that the submission completes.
make -C dm/gfx/tests GAME=0400486024DEC000 run(Apple silicon, Metal; on base d8b2b64): every test passes exceptt_feedback's timestamp check "two reports in one command buffer read two times". That check is flaky on unchanged main too: 1 failure in 4 runs of d8b2b64 here, 2 in 4 on this change, and A draw that samples the depth attachment its render pass already wrote ends the pass first (Red Dead Redemption's sky blocks) #1866 reports 2 in 6.python3 -m unittest dm/tools/tests/test_docs.py dm/tools/tests/test_game_profile.py,dm/tools/tests/test_env_switches.py,python3 dm/tools/docs_symptoms.py.dm/tools/lint_c.py tidy(LLVM 23.1.4) on the changed files: 0 file/check pairs above the baseline.0400486024DEC000, v131072).Setup: this change's host on a
--platform macbuild of main d8b2b64 (the change was rebased onto 7479adf since; host only, no chain change).scripts/bench.py, routekokiri-deck, docked, from a Kokiri Forest save. The pipeline archive was warmed first, so every run built 0 bases. Three runs a side,DM_NVN_DISPATCH_OVERLAP=0against the profile'son, same binary.The screenshots after the window are alike. Both sides have the same single red line (
c1_full.tsvbeside the bench's profile copy).regress.py impact: Breath of the Wild, Pokémon Scarlet and Tears of the Kingdom, throughnvn_mtl.m. Their profiles leavedispatch_overlapoff, and with the key offdispatch_encplaces the same barriers as before. So Ocarina is the only game whose behaviour changes, andregress.py checkwas not run on others. No other NVN game on this Mac has a smoke route except Mario Kart World, which the key does not reach.Docs
docs/reference/<subsystem>.mdentry, andpython3 dm/tools/docs_symptoms.pywas run (the symptom index)