Repository navigation
Conversation
…d built before their first draw (Ocarina of Time foliage)
…act with native mesh pipeline prewarming Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016qteK29T18U8p1c9LsVY8g # Conflicts: # dm/gfx/tests/t_pso_skey.m
…ws intact with native mesh pipeline prewarming
) replaces the pull request heads Upstream landed Ocarina of Time in main (chain adec7d81d970: "holds 60 fps in Kokiri Forest, 4 GB less") and closed the pull requests it folded in, with reworded and partly different code. Mixing a pull request head with its landed version hunk by hunk silently broke things (two GlobalToStorage tables, a duplicate AF2ip, two mtk_pso definitions), so the rule here is one version per feature: - Pull requests upstream closed (seedds#1299, seedds#1300, seedds#1312, seedds#1343, seedds#1345, seedds#1353, seedds#1354, seedds#1359, seedds#1360, seedds#1373, seedds#1428, seedds#1430, seedds#1434): their hunks are taken out of our side before the three-way merge, so upstream's landed version stands alone. Gone with them: bindless pool table patching (reg_bump), the ghost table's per-submission hold, the growing raw pool table and its write-log sizing, seedds#1428's pool_buf spares (upstream's pool_table_take is the same idea), the ixc-based indirect mesh draw (upstream uses mdx), and their tests (t_pool_table, t_mesh_indirect, t_gmem_raw, finalized_bindless_pool, test_bnsh_nvn2, test_ndve). - Open pull requests that upstream's landing supersedes: seedds#1394 (upstream's mtl_pool_addressed) and seedds#1393 pool_skip_retired (upstream's budgeted pool walk; the profile does not use it) are dropped with their tests and docs. seedds#1368's mesh pipeline prewarm is dropped too: upstream kept the background build in nvn_geometry.inc, and the prewarm's mtk_build / mtk_claim / g_warm_mps went with it. - Kept, as upstream does not have them: NXForge's own features (GPU watchdog, present filters and anti-aliasing, aniso floor, quick settings, pipeline archive compaction, upload breakdown, memory report lines) and the still open pull requests seedds#1304, seedds#1305, seedds#1308, seedds#1320, seedds#1331, seedds#1332, seedds#1355, seedds#1356, seedds#1369, seedds#1376, seedds#1377, seedds#1379, seedds#1382, seedds#1390, seedds#1391, seedds#1392, seedds#1414, seedds#1420, seedds#1436, seedds#1439, seedds#1446, seedds#1453. - Combined where both sides changed the same lines: GW_N 1 << 16 with seedds#1320's wide-write intervals (GW_PAGES = SBW_WPAGES, 128 slots), the CPU upload log with upstream's linear upload route, arch_open_end before the compaction limit, cbn_prog in geo_gs_one (seedds#1382). - Translator: upstream's sources and binaries, plus seedds#1414's InstEmitAmpereMem diff and the LDSM SubgroupBarrier in InstEmitAmpereTensor.cs. The binaries and dmsh_chain.lock are upstream's until the Mac rebuilds them (dotnet publish, tool_lock --update-lock, dmsh_chain --header); dmsh_chain.h is regenerated for now. - RED_ONCE keys: upstream took 153 and 154, so the present anti-aliasing lines move to 156 and 157 and seedds#1420's packaged-entry line to 158 (array 159). - Host: hle_net.c and t_net_eventfd.c are upstream's (its eventfd poll waits out the whole timeout, which our 5d7920c fixed another way). - Kept ours: dm/tools/romfs_image.py and its test, so the 26 GB RomFS image is not packed again. dm/tools tests on Linux: same failures as on 875449e (Linux-only quirks), plus test_nlg4 and test_dmsh_pool_arrays, which fail on upstream main too. Not yet built on the Mac. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016qteK29T18U8p1c9LsVY8g
|
We made the same change on our Ocarina of Time builds, so I won't open a second PR for it. Here are numbers that may help this one. Format. Our Mac (M4 Pro, handheld, 5 minutes from a Kokiri Forest save,
iPad Pro (M5, iOS 27): on a cold Metal cache a task / mesh pipeline took 1.9-5 s to build, and 0.1-45 ms once cached. Before rows were read, 56 recorded One difference: our version kept main's background build, with the draw left out until the pipeline is ready, and adds only the recording and the prewarm hand-over ( |
…so a first start prepares its pipelines before the first frame instead of freezing for them in play 8,355 shaders, 1,227 render, 144 compute and 58 task / mesh pipelines, merged from an iPad Pro's pso_user.tsv over several hours of play and the Mac's DM_PSO_RECORD runs; every shader named is in shader_map.tsv and every R row parses. The bundled list was empty. On the Mac (M4 Pro, DM_PSO_MTL4=0, a 5-minute route from a save) a fresh start compiled 1,056 pipelines on the submit thread (52 s, one frame of 17.8 s entering Kokiri Forest); with the list it prepares it in 5.1 s and builds 6 in play (1.1 s), frames over 100 ms 45 -> 5. The M rows wait for a prewarm that builds task / mesh pipelines (PR seedds#1368); main's skips them.
…er and shader chain, the branch's host services, movie clock, packing and Ocarina of Time additions Upstream reached about 60 fps in Kokiri Forest with its own versions of most of the branch's merged PRs, so where both changed the same code upstream's is kept: - The shader chain is upstream's (translator, lock, dmsh tools, Ryujinx sources), plus the branch's bracket-depth flattening (dmsh_depth.py, test_dmsh_depth.py); chain c732699d4fdb. Not carried: the LDSM subgroup fence (seedds#1376, needs a translator rebuild; upstream's HMMA/LDSM rework reports clean movies) and the shared raw-memory lookups (seedds#1405, superseded by upstream's last-entry lookups). - The renderer (dm/gfx/nvn, dm/gfx/msl) and its tests are upstream's. Not carried: seedds#1390-seedds#1394, seedds#1404, seedds#1408, seedds#1409, seedds#1417, seedds#1418, seedds#1420, seedds#1427, seedds#1320, seedds#1331, seedds#1332, seedds#1368, seedds#1285 renderer parts, pool_skip_retired, and the branch's warning fixes and prewarm progress there. They stay on oot-integration. - Ocarina of Time's profile is upstream's, with the branch's 12 movie compute rows in pso_manifest.tsv, PLAN.md and PR-AUDIT.md. - shader_split.py is upstream's plus the BAHS record check (test_split_bahs_records.py). - Host: upstream's EventFd, PlayReport send, audio lock and vibration answers; the branch's service sessions (hle_sf, hle_prepo), sync waits, AV1 movie clock and parallel decode, diag_abort frame fix and focus control are kept. - Scripts: shader.noindex, tmp.noindex, notes outside the shader key, bench and regress changes. Checked: the Mac host builds (GAME=0400486024DEC000); host unit tests pass; the Python tool tests pass on Python 3.13 except test_dmsh_pool_arrays, test_nro_pack, test_nsp_dump and test_nsp_incremental, which fail on upstream main as well. Not run: the full shader build on this chain, gameplay.
|
M3 Max prewarm validation (2026-11-06): with this PR, #1307, and the union of #1488/#1493 plus the locally recorded list (9,846 seed rows), our V3 warm run logs The Kokiri Forest save loaded and the moving route completed with clean exit 0. This is 30-core M3 Max, Metal4 and encoding thread on. These are combined-build observations, not an isolated FPS measurement of #1368. The subsequent V4 cold test logs 58 native task/mesh prewarms from the bundled union seed and also reaches the forest with foliage present. |
…/ mesh pipelines built at their first draw and prewarmed from the recorded list; Ocarina of Time's foliage no longer draws without colour until a background build finishes Applied as the PR's diff against its merge base, not its merge commits, so no older main commits come with it. test_dmsh_pool_arrays keeps NXForge's commented assertions (same checks). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016qteK3qWJVi2jG3Gz4i1eY
|
Cold-cache numbers from an M5 Max (macOS 26.6.2), Ocarina of Time v131072, main Without the PR, Kokiri Forest whites out at first sight until the foliage mesh pipelines finish in the background: 117 to 132 frames with a warm Metal cache, and 861 frames, still white when the run ended, with the cache folder moved aside. With the PR and no With 88 The seed list that landed in |
Drops NXForge's copy of nxnative seedds#1368 (mesh prewarm) for upstream's own fix, and NXForge's post-first-frame recapture for upstream's period-based compaction (keeps PSO_ARCH_COMPACT 24 and DM_PSO_ARCH_COMPACT). Shader chain 98747cde2289. The engine docs no longer describe NXForge's own scripts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016qteK4U7UAc5p3k4mJJhPJ
|
Prewarmed mesh pipelines are often dropped: Following up on ycarogabriel-lgtm's numbers above: without a prewarm, first-use mesh builds cost an M1 103.5 s per walk with a cold Metal cache. On this PR as it stands, part of the prewarm's work is thrown away and falls back to those first-draw builds. One interaction with the program-creation prefetch.
On my M2 Pro this shows as 0–29 such lines a run (six runs of 3–6 minutes with the A possible fix: in the kind-3 claim, call |
|
Thanks for the detailed trace, @Amost-. We went and read our side to see whether the same thing can happen with an archive-first path (M1 16 GB, local branch of open PRs on an older main, so treat this as a code reading plus one earlier run, not a test of your claim). What we found in our code:
Not tested: your suggested fix (claiming with the live Question for you: with the |
|
An update to the In the second session, with all of them in the user list, the start prewarmed 111 mesh pipelines (prepare 3.64 s, warm cache), and Hyrule Field, which had stalled in the first session, no longer did. The one stall left was at the castle doorway, 4.6 s at a single mesh pipeline drawn for the first time that no route had recorded yet: the first-use cost ycarogabriel-lgtm measured, for a pipeline outside the list. I haven't checked whether any of the 111 were dropped as Amost- describes; our log counts them as prewarmed, not as installed at their first draw. The rows only take effect with this PR's The 118 rows are attached as a text file (one |
|
Some numbers from a slower machine that support this PR: MacBook Air M4 ( On this machine the first-use native mesh pipelines cause the longest stalls in normal play, often when entering an area. Each of the slow compiles takes 0.6–1.65 s here:
Example, entering the Lost Woods from Goron City ( Example, Dodongo's Cavern ( A side note that might help others reading their logs: the Looking forward to this landing; on this machine it would remove the longest stalls in normal play. |
611781c to
0133369
Compare
|
@padsiwono thanks for the 118 rows. Two measurements from our side that may help whoever merges them (MacBook Pro M1, 16 GB, macOS 26.6.2, OoT v131072, one machine only):
Not measured here: any chip other than the M1, and whether any of your 111 prewarmed rows were dropped in the way @Amost- describes. |
|
@Gesalbter thanks for the M4 Air numbers. For comparison, on a MacBook Pro M1 (16 GB, macOS 26.6.2, cold Metal cache, no mesh archive) a 300 s walk built 47 task/mesh pipelines on the submit thread for 103.5 s in total, which is about 2.2 s per pipeline on average, the longest 12.76 s (12.1 s for |
…pipeline archive: Ocarina of Time's foliage, shadows and enemies no longer stall at their first draw (59.5 s of builds at the Kokiri Forest entry on an M5 Max with a cold Metal cache, one frame of 42.9 s), and its profile seeds 123 of them (PR #1368) A native mesh pipeline was built only at its first draw, through the MTLDevice, and nothing kept it: no prewarm row named one and no pipeline serializer saw it. Since ea0c98d the draw waits for its pipeline, so each one met in play was a stall on the submit thread. - mtk_pso records each pipeline it builds as an M row (the task shader's key or -, then the pso_skey hex with the mesh shader in the vertex place); pso_mesh_skey_parse refuses rows with a vertex layout, a specialized fragment or the wrong stages, and the prewarm builds the rows on its workers (kind 3), so the prepare step has them before the first frame. - warm_claim takes a prewarmed pipeline under the live shader objects when they come from the same library and entry (warm_mesh_shader_equal): the program prefetch loads objects of its own for the same keys, which claiming by identity dropped; a mesh shader loaded with its other depth entry is not taken. - mtk_build keeps the pipelines in the pipeline archive as cps_new keeps compute pipelines: looked up first (a p file when a flush holds only them), built through the MTLDevice on a miss (the system's shader cache serves it when it can) and captured into the flush period in the background (cps_harvest generalized to arch_harvest). Compaction captures one taken from an old plain file again; the flush line counts them on their own. - Ocarina of Time's pso_manifest.tsv carries 123 M rows (Kokiri Forest, Hyrule Field, Castle Town, Hyrule Castle). - prog_get returns nil for no program (draw_'s passdump line tests S.prog, the lines after it did not; clang-tidy found it once mtk_pso grew). Measured on an M6 (16 GB), Ocarina of Time's village walk with the prepare step, hosts pinned to the libraries on disk (f9f01e4f9994): main built 56 mesh pipelines at their draws; this change's first start prewarmed 121 (two seed rows need a newer chain's paired mesh outputs, 5e344a8) and built none at a draw, prepare 19.0 s against 2.7 s as 65 were not in the system's cache; the second start took all 121 from the archive, prepare 2.8 s. Contributors' runs on the rows and prewarm: M1 cold 103.5 s of builds in a 300 s walk; iPad Pro (M5) 1.9-5 s per pipeline cold. Checks: t_pso_skey, t_pso_warm (both compiler paths), t_pso_archive (mesh_pipelines), t_mesh_first_use, t_pso_bundle, t_pso_stall. From PR #1368 (nanotchec): the M row format, its parser, the prewarm task and the claim fix; its source-expansion tool is left out. Seed rows also from padsiwono (50 new) and PR #1488; Amost- diagnosed the dropped claims. Co-authored-by: nanotchec <145017345+nanotchec@users.noreply.github.com>
|
Landed as bf420fd, with you as co-author. Thank you: the What changed on the way in:
On an M6, Ocarina of Time's village walk with the prepare step:
Two seed rows fail on the older libraries I tested with, because their pixel shader reads an output the mesh shader doesn't write. 5e344a8 fixed that in the chain after those libraries were built, so I kept the rows. Thanks also to @padsiwono for the rows and the cold-cache numbers, to @Amost- for the dropped-claim diagnosis, and to @aksmith-git and @ycarogabriel-lgtm for the measurements. |
…pipeline archive: Ocarina of Time's foliage, shadows and enemies no longer stall at their first draw (59.5 s of builds at the Kokiri Forest entry on an M5 Max with a cold Metal cache, one frame of 42.9 s), and its profile seeds 123 of them (PR seedds#1368) A native mesh pipeline was built only at its first draw, through the MTLDevice, and nothing kept it: no prewarm row named one and no pipeline serializer saw it. Since 5e5e7e9 the draw waits for its pipeline, so each one met in play was a stall on the submit thread. - mtk_pso records each pipeline it builds as an M row (the task shader's key or -, then the pso_skey hex with the mesh shader in the vertex place); pso_mesh_skey_parse refuses rows with a vertex layout, a specialized fragment or the wrong stages, and the prewarm builds the rows on its workers (kind 3), so the prepare step has them before the first frame. - warm_claim takes a prewarmed pipeline under the live shader objects when they come from the same library and entry (warm_mesh_shader_equal): the program prefetch loads objects of its own for the same keys, which claiming by identity dropped; a mesh shader loaded with its other depth entry is not taken. - mtk_build keeps the pipelines in the pipeline archive as cps_new keeps compute pipelines: looked up first (a p file when a flush holds only them), built through the MTLDevice on a miss (the system's shader cache serves it when it can) and captured into the flush period in the background (cps_harvest generalized to arch_harvest). Compaction captures one taken from an old plain file again; the flush line counts them on their own. - Ocarina of Time's pso_manifest.tsv carries 123 M rows (Kokiri Forest, Hyrule Field, Castle Town, Hyrule Castle). - prog_get returns nil for no program (draw_'s passdump line tests S.prog, the lines after it did not; clang-tidy found it once mtk_pso grew). Measured on an M6 (16 GB), Ocarina of Time's village walk with the prepare step, hosts pinned to the libraries on disk (f9f01e4f9994): main built 56 mesh pipelines at their draws; this change's first start prewarmed 121 (two seed rows need a newer chain's paired mesh outputs, 7db6904) and built none at a draw, prepare 19.0 s against 2.7 s as 65 were not in the system's cache; the second start took all 121 from the archive, prepare 2.8 s. Contributors' runs on the rows and prewarm: M1 cold 103.5 s of builds in a 300 s walk; iPad Pro (M5) 1.9-5 s per pipeline cold. Checks: t_pso_skey, t_pso_warm (both compiler paths), t_pso_archive (mesh_pipelines), t_mesh_first_use, t_pso_bundle, t_pso_stall. From PR seedds#1368 (nanotchec): the M row format, its parser, the prewarm task and the claim fix; its source-expansion tool is left out. Seed rows also from padsiwono (50 new) and PR seedds#1488; Amost- diagnosed the dropped claims. Co-authored-by: nanotchec <145017345+nanotchec@users.noreply.github.com>
…eedds#1825 (process-local miss cache for base-pipeline lookups), seedds#1368 (native mesh pipelines in the prewarm manifest, 73 M rows), seedds#1842 (DM_NVN_ISOLATE_TASK) 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#1368 by nanotchec (closed): Ocarina of Time: prewarm native mesh pipelines before attacks and enemies appear - seedds#1825 by socram03 (open): Avoid repeated archive scans for missing pipeline bases - 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#1844 by nawangwe (closed): Shader libraries compile with -fwrapv: Ocarina of Time's mesh-shader models no longer take their ambient light from the wrong probe texels
Ocarina of Time can freeze when an attack, enemy or piece of foliage first needs a native task/mesh pipeline. The regular render prewarm did not cover these pipelines. Record successful native pipelines as
Mrows and prepare them through the existing workers before gameplay. An unprepared state still builds synchronously; geometry is never skipped to hide a stall.The change uses the same descriptor path for prewarm and live draws, validates serialized keys and shader stages, and claims warmed pipelines across equivalent shader-library loads while keeping different depth entries separate. It adds 73 observed Ocarina states and an optional
scripts/prewarm_native_mesh.pytool that expands coverage from the player's own packaged BNSH programs and compatible observed render states. Generated game data are not committed.Validation
Current base: official main
d8b2b64a1fc5. Its CI repairs are retained; the branch now contains only the native-prewarm feature and its duplicate-load correction.On the rebased sources, Apple M3 Max:
Earlier combined-host gameplay on base
028a263, chain3f35b514643e, used a copy of the player's v131072 save at Hyrule Castle. After expanded preparation, the player reported no further freezes during attacks and rapid movement; the log recorded zero native mesh demand builds and zero renderer red errors. This is bounded gameplay coverage, not a pristine-current-main benchmark or a promise of zero stutter everywhere.The expansion reproduced 1,286 source triples and 7,716 prospective mesh states. Preparing this broad set took about 151 seconds. One immediate warm restart took 5.08 seconds, but later launches again took about 152–164 seconds and reported driver compiled-variant footprint pressure. Persistent native-mesh archive reuse remains a separate open issue: the broad list is optional and no consistently fast restart is claimed.
Regression impact includes Breath of the Wild, Tears of the Kingdom and Pokémon Scarlet through shared NVN callers. The requested multi-game harness cannot run because only packaged apps remain locally, with no standalone Mac build folders. No cross-game runtime or iOS execution validation is claimed. The feature-specific GPU fixtures exercise both native and ordinary render first-use behavior.
Front-ends: existing launch preparation reads
Mrows automatically. Broader coverage is generated explicitly with the optional tool; no new default setting is required. No game assets, keys or saves are included.