Repository navigation
Conversation
Front-ends: DMSH_RAW_LOAD_QUADS=1 is an optional build-time experiment. Use the same setting for chain-header generation, shader libraries and the matching host. It remains disabled by default.
…eedds#1405, opt-in DMSH_RAW_LOAD_QUADS=1), extended to this tree's hinted pool table seedds#1405's matcher knew the fixed table walked by an unrolled binary search and addresses written as base + 4 / 8 / 12; this tree's translator writes the hinted table (DMSH_GMEM_HINT_SHIFT: the 2 MiB chunk's hint, else a search over the count in entry 0) and Ocarina of Time's words as as_type<int>(x) + 16..28 with a carry each, so on the chain built with the option none of the 727 compute shaders with raw loads changed. The pass now verifies the hinted helper line by line, takes addresses as a 64-bit value plus k, k + 4, k + 8, k + 12, and in the hinted form shares the lookup only within one chunk and reads the next entry only below the table's count. A sampled shader gets 59 shared lookups and compiles; not measured in a game. Off by default; the option changes the chain version (dmsh_chain.py, dmsh_build.py passes the shift). Front-ends: DMSH_RAW_LOAD_QUADS=1 must be the same for dmsh_chain.py --header, the shader libraries and the host build; it is not a runtime switch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Some measurements that may be useful for this PR: in Kokiri Forest the raw-memory lookups cost the most in mesh and vertex shaders, which this pass leaves out. A small per-invocation range cache covers every stage. Setup: MacBook Pro M5 Pro, macOS 27.2, Ocarina of Time v131072 built from #1387 (chain 1. The foliage draw dominates the frame when the game's dynamic resolution is active With The foliage reads its per-blade data word by word ( struct dm_gmc { ulong s; ulong e; int i; };
// in the helper (int _N(lo, hi, table, thread dm_gmc& c)), around the binary search:
ulong a = as_type<ulong>(uint2(uint(lo), uint(hi)));
int idx = 0;
if (a - c.s < c.e - c.s) idx = c.i;
else { /* the original do … while search */
int r = idx * 8; c.s = as_type<ulong>(uint2(t._m0[r], t._m0[r + 1])); c.e = as_type<ulong>(uint2(t._m0[r + 2], t._m0[r + 3])); c.i = idx; }
/* the original end check, delta and read, unchanged */It relies on the GMEM map's ranges being disjoint, as With only that shader replaced (the host takes a loose 2. The helper is everywhere Of the 42,853 shaders in this build, 2,234 contain it: 801 vertex, 719 compute, 605 fragment and 98 mesh. Some call it 971 times (the largest foliage mesh shaders) or 759 times (a family of vertex shaders). This PR's pass covers ordinary compute only, and it looks for the unrolled fixed-table form, so it matches none of the shaders in this build. With the cache in all 2,234 helpers (loose metallibs over the
So the game holds 60 fps there. Screenshots from before the player moves (frame 4350) match the stock build: same geometry, foliage and NPCs. Also worth knowing: this game's speed seems to follow its frame rate. At 42 fps the same timed stick input covered noticeably less ground than at 60 fps, so below 60 the game appears to run in slow motion. 3. One more observation
Separately, I have a host change that stops memory pool add/remove, retired IDs at a new submission and storage takeovers from rebuilding the pool tables whole. It brought a six-minute walk from about 9,600 table rebuilds (26 s) to 14 (0.3 s), with a unit test. It builds on #1299 / #1387's patching. I can open it as a PR if that's useful. |
|
@TheekshanaA thanks for the numbers: the per-invocation range cache (10.9 → 2.1 ms on the foliage pass, 23.7 → 16.7 ms p50 over the route) and the host change that cut the pool-table rebuilds from about 9,600 to 14 are both very welcome. Could you open each as a pull request, or push them to a branch and link it here? For the cache, the helper's text (where |
|
@lunks thanks! Both are up now.
|
…ng walked whole: registrations, memory pools added or removed, retired IDs at a new submission and storage takeovers each leave a note pool_gpu walked a table of handles traced to no slot whole at any change of g_reg_gen or g_ser_gen, though each change reaches only a few of its IDs. On main (6121fd7), TheekshanaA measured about 53 s of a seven-minute walk through Ocarina of Time's Kokiri Forest spent on 61,000 such builds of its 33,025-entry texture table (PR seedds#1405, seedds#1464). The game registers something between most of its draws, its streamed textures map and unmap virtual pool runs (vrun_set) dozens of times a second, finalized descriptors stay registered, and textures take over each other's storage (alias_take_over, about 8,400 times in six minutes), which bumped g_ser_gen with no note and so also sent every texture ID down the slow path. This ports TheekshanaA's branch oot-pool-table-notes (9579768, 9d486f8) to main's walk. Those commits sat on the table patching of seedds#1299 / seedds#1387, which main did not take, so the patching comes with them: - A registration records its generation and ID (g_reg_log), a storage change its serial (g_ser_log, beside the notes ser_sync takes). A table built at an earlier generation takes again only the IDs they name, by the walk's own rules (pool_entry), and is kept when no entry changes, else copied and patched. - A memory pool added or removed records REG_POOL and no ID: a table takes again only the IDs it found without storage (pool_snap.dead), and treg_gone notes each ID of a finalized pool. A note's generation is stored last (release) and read first (acquire), as pool changes come from threads that do not hold g_rmu. - A table keeps the IDs whose entries are views of retired registrations (pool_snap.trans and .sub); the next submission takes only those again. - A takeover records a note that names no texture (ser_note(0)). - Past POOL_IDS_MAX IDs on a list, a note the ring has overwritten, a bump without a note, a pool that grew or a sparse mapping, the table is built whole as before. The log line says why tables were built whole and how many were patched or kept; the power lines gain "[nvn] pool tables up to frame ...". What main's walk changes on the way: - A patch makes textures only within what the frame may still make (pool_room, taken out of pool_walk_limit), as a walk does. A texture left out counts in the table's left, and the walk goes on next frame as before. - Patched tables take and give their buffers through pool_table_take / pool_table_give, as walked ones do. - A retired registration's view that the read scan writes in place (pool_seen_scan) is listed as transient too, and a table holding such views from an earlier submission does not stand under POOL_SUB_MS. Before, nothing made a table take those IDs again after the submission whose end drops the views. - alias_sweep, and seedds#1387's exception that kept a retired view of a shared texture past its submission, are not needed: main drops every retired view at the submission's end, so the next submission takes those IDs again. - A sampler table follows registrations alone. Checked: t_pool_notes (new, 67 checks). A pool elsewhere keeps the table, the pool that brings an ID's storage patches it, a finalized pool's ID holds the dummy, a bump without a note builds it whole, a retired ID and a takeover are taken again at the next submission without a build, a registration past the budget is left out by a patch, and a read written in place is taken again; patched tables match tables built whole. Without the takeover note, the retake at a new submission or the in-place record, it fails (2, 4 and 2 checks). make -C dm/gfx/tests GAME=0400486024DEC000 for the 35 tests that reach registrations, pool tables, serial notes and the sharing table (t_pool_chunks, t_feedback, t_sparse_tiles, t_image_alias and t_nvn among them): all pass. The Mac host builds, and the two changed files compile for the iPhone SDK. clang-tidy (LLVM 22, not CI's 23) finds nothing new in them. Ocarina of Time, four scripted runs on an M4 with 24 GB, alternating main (88c7e03) and this change, from the autosave at Link's house (180 s in the house, Saria's greeting, 300 s on the balcony): the table was built whole 44,000 and 24,000 times per run on main (67 s and 72 s), about 100 times with this change (about 0.2 s), while about 86,000 tables were patched and 63,000 kept. The submit thread's CPU time per frame (p50) went from 12-15 ms to 3-5 ms; frame p50 is the GPU's and did not move, p99 in the house went from 34.6 and 41.0 ms to 24.2 and 25.6 ms, and frames over 50 ms walking from 23 and 48 to 3 and 2. Same picture, footprint and red lines. Co-authored-by: TheekshanaA <10327965+TheekshanaA@users.noreply.github.com>
…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.
…ng walked whole: registrations, memory pools added or removed, retired IDs at a new submission and storage takeovers each leave a note pool_gpu walked a table of handles traced to no slot whole at any change of g_reg_gen or g_ser_gen, though each change reaches only a few of its IDs. On main (6121fd7), TheekshanaA measured about 53 s of a seven-minute walk through Ocarina of Time's Kokiri Forest spent on 61,000 such builds of its 33,025-entry texture table (PR seedds#1405, seedds#1464). The game registers something between most of its draws, its streamed textures map and unmap virtual pool runs (vrun_set) dozens of times a second, finalized descriptors stay registered, and textures take over each other's storage (alias_take_over, about 8,400 times in six minutes), which bumped g_ser_gen with no note and so also sent every texture ID down the slow path. This ports TheekshanaA's branch oot-pool-table-notes (9579768, 9d486f8) to main's walk. Those commits sat on the table patching of seedds#1299 / seedds#1387, which main did not take, so the patching comes with them: - A registration records its generation and ID (g_reg_log), a storage change its serial (g_ser_log, beside the notes ser_sync takes). A table built at an earlier generation takes again only the IDs they name, by the walk's own rules (pool_entry), and is kept when no entry changes, else copied and patched. - A memory pool added or removed records REG_POOL and no ID: a table takes again only the IDs it found without storage (pool_snap.dead), and treg_gone notes each ID of a finalized pool. A note's generation is stored last (release) and read first (acquire), as pool changes come from threads that do not hold g_rmu. - A table keeps the IDs whose entries are views of retired registrations (pool_snap.trans and .sub); the next submission takes only those again. - A takeover records a note that names no texture (ser_note(0)). - Past POOL_IDS_MAX IDs on a list, a note the ring has overwritten, a bump without a note, a pool that grew or a sparse mapping, the table is built whole as before. The log line says why tables were built whole and how many were patched or kept; the power lines gain "[nvn] pool tables up to frame ...". What main's walk changes on the way: - A patch makes textures only within what the frame may still make (pool_room, taken out of pool_walk_limit), as a walk does. A texture left out counts in the table's left, and the walk goes on next frame as before. - Patched tables take and give their buffers through pool_table_take / pool_table_give, as walked ones do. - A retired registration's view that the read scan writes in place (pool_seen_scan) is listed as transient too, and a table holding such views from an earlier submission does not stand under POOL_SUB_MS. Before, nothing made a table take those IDs again after the submission whose end drops the views. - alias_sweep, and seedds#1387's exception that kept a retired view of a shared texture past its submission, are not needed: main drops every retired view at the submission's end, so the next submission takes those IDs again. - A sampler table follows registrations alone. Checked: t_pool_notes (new, 67 checks). A pool elsewhere keeps the table, the pool that brings an ID's storage patches it, a finalized pool's ID holds the dummy, a bump without a note builds it whole, a retired ID and a takeover are taken again at the next submission without a build, a registration past the budget is left out by a patch, and a read written in place is taken again; patched tables match tables built whole. Without the takeover note, the retake at a new submission or the in-place record, it fails (2, 4 and 2 checks). make -C dm/gfx/tests GAME=0400486024DEC000 for the 35 tests that reach registrations, pool tables, serial notes and the sharing table (t_pool_chunks, t_feedback, t_sparse_tiles, t_image_alias and t_nvn among them): all pass. The Mac host builds, and the two changed files compile for the iPhone SDK. clang-tidy (LLVM 22, not CI's 23) finds nothing new in them. Ocarina of Time, four scripted runs on an M4 with 24 GB, alternating main (88c7e03) and this change, from the autosave at Link's house (180 s in the house, Saria's greeting, 300 s on the balcony): the table was built whole 44,000 and 24,000 times per run on main (67 s and 72 s), about 100 times with this change (about 0.2 s), while about 86,000 tables were patched and 63,000 kept. The submit thread's CPU time per frame (p50) went from 12-15 ms to 3-5 ms; frame p50 is the GPU's and did not move, p99 in the house went from 34.6 and 41.0 ms to 24.2 and 25.6 ms, and frames over 50 ms walking from 23 and 48 to 3 and 2. Same picture, footprint and red lines. Co-authored-by: TheekshanaA <10327965+TheekshanaA@users.noreply.github.com>
…ng walked whole: registrations, memory pool changes, retired IDs at a new submission and storage takeovers each leave a note; Ocarina of Time's village walk builds its 33,025-entry table 16 times instead of over 4,000 (PR #1489) pool_gpu walked a table of handles traced to no slot whole at any change of g_reg_gen or g_ser_gen, though each change reaches only a few of its IDs. Ocarina of Time registers something between most of its draws, its streamed textures map and unmap virtual pool runs dozens of times a second, finalized descriptors stay registered, and textures take over each other's storage (alias_take_over), which bumped g_ser_gen with no note and so also sent every texture ID down the slow path. TheekshanaA measured about 53 s of a seven-minute walk through Kokiri Forest spent on 61,000 such builds (PR #1405, #1464). This is TheekshanaA's branch oot-pool-table-notes, ported to main's walk by PucaVaz, with the table patching of #1299 / #1387 it sat on: - A registration records its generation and ID (g_reg_log), a storage change its serial (g_ser_log, beside the notes ser_sync takes). A table built at an earlier generation takes again only the IDs they name, by the walk's own rules (pool_entry), and is kept when no entry changes, else copied and patched. - A memory pool added or removed records REG_POOL and no ID: a table takes again only the IDs it found without storage (pool_snap.dead); treg_gone notes each ID of a finalized pool. - A table keeps the IDs whose entries are views of retired registrations, those the read scan writes in place among them (pool_snap.trans); the next submission takes only those again, and such a table does not stand under POOL_SUB_MS. - A takeover records a note that names no texture (ser_note(0)): it changes no serial's texture (an entry a live serial holds is not evicted, serial_table_holds; one a finalized serial holds is only unref'd). A live sRGB / linear twin's view of an evicted texture is found stale by tex_mtl_ and dropped (serial_del), a note naming it. - A patch makes textures only within what the frame may still make (pool_room). Past POOL_IDS_MAX IDs, a note the ring has overwritten, a bump without a note, a resized table or a sparse mapping, the table is built whole as before. The log line says why; the power lines gain "[nvn] pool tables up to frame ...". On landing: the comment and the reference entry name serial_table_holds (#1439 replaced the serial table walk) and describe the sRGB / linear twin case; a registration note is read as a sequence lock (reg_read: its generation is checked before and after its ID, and the writer clears it first), as memory pool changes write notes from threads that do not hold g_rmu and a note the ring overwrote during the read could be taken torn. Checked: t_pool_notes 81 checks (patched tables compared with tables built whole), t_pool_chunks 102, t_alias_takeover 28, t_gmem_words 16, t_feedback 159, t_image_alias 329, t_sparse_tiles 4,253, t_cpu_tex --metal 68, all 0 failed; test_docs; the Mac host builds and the iOS compile check passes (261 files). Ocarina of Time on an M-series Mac, hosts at 51cc8bc with and without this (main's chain has no libraries on disk for it), the village walk from save_ref: tables built whole 4,000+ (5.85 s+) on the base, 12 and 16 (0.11 s, 0.12 s) with this; submit p50 in the village 11-16 ms on the base, about 7-12 ms with this; the same red lines and no GPU error. Vertical stripes in both sides' shots at the same balcony points come from that old-chain setup, not this change. The author measured submit p50 12-15 -> 3-5 ms and frames over 50 ms walking 23 and 48 -> 3 and 2 (M4, two runs per side). No second game: none local has libraries for main's chain, and the one whose regress runs reach these tables (Paper Mario: The Thousand-Year Door) needs 11,861 shaders translated first. Co-authored-by: PucaVaz <65235669+PucaVaz@users.noreply.github.com> Co-authored-by: TheekshanaA <10327965+TheekshanaA@users.noreply.github.com>
|
Closing this experiment because its rewrite no longer applies to the current translator output, rather than resolving only the generated chain-header conflict and presenting it as integration-ready. Rechecked against main d8b2b64: This does not establish that every potential benefit of grouping loads has been exhausted. It means this patch, as written, does not deliver that benefit on current main. Its historical GPU savings were measured on an earlier chain and also came with worse enqueue-to-display latency. Any successor needs a new implementation and a fresh correctness/performance comparison against current main; those older results should not be reused as current validation. The experiment and measurements remain available in this PR and its branch. No installed game or saves were changed during this audit. |
…ng walked whole: registrations, memory pool changes, retired IDs at a new submission and storage takeovers each leave a note; Ocarina of Time's village walk builds its 33,025-entry table 16 times instead of over 4,000 (PR seedds#1489) pool_gpu walked a table of handles traced to no slot whole at any change of g_reg_gen or g_ser_gen, though each change reaches only a few of its IDs. Ocarina of Time registers something between most of its draws, its streamed textures map and unmap virtual pool runs dozens of times a second, finalized descriptors stay registered, and textures take over each other's storage (alias_take_over), which bumped g_ser_gen with no note and so also sent every texture ID down the slow path. TheekshanaA measured about 53 s of a seven-minute walk through Kokiri Forest spent on 61,000 such builds (PR seedds#1405, seedds#1464). This is TheekshanaA's branch oot-pool-table-notes, ported to main's walk by PucaVaz, with the table patching of seedds#1299 / seedds#1387 it sat on: - A registration records its generation and ID (g_reg_log), a storage change its serial (g_ser_log, beside the notes ser_sync takes). A table built at an earlier generation takes again only the IDs they name, by the walk's own rules (pool_entry), and is kept when no entry changes, else copied and patched. - A memory pool added or removed records REG_POOL and no ID: a table takes again only the IDs it found without storage (pool_snap.dead); treg_gone notes each ID of a finalized pool. - A table keeps the IDs whose entries are views of retired registrations, those the read scan writes in place among them (pool_snap.trans); the next submission takes only those again, and such a table does not stand under POOL_SUB_MS. - A takeover records a note that names no texture (ser_note(0)): it changes no serial's texture (an entry a live serial holds is not evicted, serial_table_holds; one a finalized serial holds is only unref'd). A live sRGB / linear twin's view of an evicted texture is found stale by tex_mtl_ and dropped (serial_del), a note naming it. - A patch makes textures only within what the frame may still make (pool_room). Past POOL_IDS_MAX IDs, a note the ring has overwritten, a bump without a note, a resized table or a sparse mapping, the table is built whole as before. The log line says why; the power lines gain "[nvn] pool tables up to frame ...". On landing: the comment and the reference entry name serial_table_holds (seedds#1439 replaced the serial table walk) and describe the sRGB / linear twin case; a registration note is read as a sequence lock (reg_read: its generation is checked before and after its ID, and the writer clears it first), as memory pool changes write notes from threads that do not hold g_rmu and a note the ring overwrote during the read could be taken torn. Checked: t_pool_notes 81 checks (patched tables compared with tables built whole), t_pool_chunks 102, t_alias_takeover 28, t_gmem_words 16, t_feedback 159, t_image_alias 329, t_sparse_tiles 4,253, t_cpu_tex --metal 68, all 0 failed; test_docs; the Mac host builds and the iOS compile check passes (261 files). Ocarina of Time on an M-series Mac, hosts at 66e6e4c with and without this (main's chain has no libraries on disk for it), the village walk from save_ref: tables built whole 4,000+ (5.85 s+) on the base, 12 and 16 (0.11 s, 0.12 s) with this; submit p50 in the village 11-16 ms on the base, about 7-12 ms with this; the same red lines and no GPU error. Vertical stripes in both sides' shots at the same balcony points come from that old-chain setup, not this change. The author measured submit p50 12-15 -> 3-5 ms and frames over 50 ms walking 23 and 48 -> 3 and 2 (M4, two runs per side). No second game: none local has libraries for main's chain, and the one whose regress runs reach these tables (Paper Mario: The Thousand-Year Door) needs 11,861 shaders translated first. Co-authored-by: PucaVaz <65235669+PucaVaz@users.noreply.github.com> Co-authored-by: TheekshanaA <10327965+TheekshanaA@users.noreply.github.com>
Current applicability
Main now uses a private per-invocation cache for raw pool lookups (commit 0f510fd, following #1464). Its scalar helper takes a fourth argument, the private cached entry. This PR still matches the earlier three-argument helper. Running the current PR pass on the post-cache Ocarina of Time leaf compute source (
50d3050cfa7cded5) leaves all 253 calls byte-identical and generates zero four-word groups. This also affects the PR's previous merge basec229bd7, which already contained the private cache.The conflict against main
b2d46b8is limited to the generated shader-chain header. Regenerating it would leave the compatibility gap. The measurements and output validations below document the earlier local integration and pre-cache shader helper. Incremental benefit over main's cache remains unmeasured.Earlier implementation
Ampere wide loads can arrive in Metal as four scalar raw global loads. Each word independently searches the guest pool table before reading the translated address. This change adds an experimental build pass that lets four adjacent reads share one lookup.
Enable it with
DMSH_RAW_LOAD_QUADS=1when generating the shader chain header and building the libraries and matching host. It is off by default. The mode is part of the shader chain and cache fingerprints.The pass is limited to ordinary Ampere compute. It verifies the reflected table binding and the fixed-table scalar helper, then recognizes four ordered 32-bit reads at offsets 0, 4, 8 and 12 with only address copies between the reads. The fast path requires a complete, four-byte-aligned 16-byte span inside the winning interval, before any next start. This preserves the scalar resolver's priority when entries overlap. Other cases call the original scalar resolver four times. Kernels with a raw write-log binding stay on the original path. Writes to ordinary bound resources remain supported.
Historical measurements
Local Ocarina of Time v131072 testing used an Apple M3 Max, macOS 27.0.1 and Xcode 27.2 (main build ID
e0f3ccfaf50065ae4ea01eb5aeb13b1a). With only one compute library replaced, same-frame comparisons saved about 1.16 ms in the initial compute encoder. The forward window showed 28.048 to 29.050 fps, and the reverse run had different visibility.With the full opted-in chain, the initial compute encoder saved about 2.3 ms at the same frame and dispatch signature in both test orders. Whole-frame GPU medians, weighted over matched pass counts and shown frames, improved by 1.98 ms forward and 1.80 ms in reverse. The forward run showed 28.235 to 29.602 fps with all 651 frames displayed. The reverse candidate displayed 647 of 651 frames, with four drops.
At the direct-present 30 fps target, median enqueue-to-display time increased by approximately 61 ms in the forward run and 39 ms in reverse. This interval begins after input and simulation. The pass remains off by default while presentation pacing is investigated. The installed app was left on the stock chain.
These measurements used the earlier local Ocarina integration and its 8,192-entry table. The original PR base
865cc35used a 4,096-entry fixed table. The update onto88c7e03adapts the pass to the official Ocarina profile and its tagged 8,192-entry table. The timings above do not measure that updated base.Historical validation
88c7e03base, the actual Ocarina leaf compute shader50d3050cfa7cded5compiled with and without the pass. The adapted pass preserved the tagged hint, the 13-step fallback search, and the original scalar fallback. It transformed 232 of 253 scalar calls into 58 groups, with identical reflection apart from the chain identifier. Synthetic matcher, chain-header, documentation and pinned Python lint checks passed. The updated base still needs a full opted-in shader build and runtime comparison.670e154b2faaand opted-inef214d417e26found 552 changed compute shaders, with no new compile failures, reflection changes, variant changes or pipeline-interface regressions.Ocarina is the only locally available game that reaches this opt-in Ampere path. Other Switch 2 games have not been run. The functional regression below used the existing installed game modules and two matched local renderer snapshots; its time-window cadence is separate from the controlled measurements above.
CHANGEDis expected for the 552 compute sources; there were no new failures or interface changes.Full local Ocarina regression report
regress.py check (full): CHANGED
Baseline
installed-source655ec95e414e (+ uncommitted changes), candidateraw-load-quads-source655ec95e414e (+ uncommitted changes); Apple M3 Max, macOS 27.0.1, Xcode 27.2; 545.6 s0400486024DEC000Ocarina of Time
0400486024DEC000: CHANGED001f62d77a5447e6,00359b6009aed142,0041cb1d10d87b8c,0193bf98ac2101db,020fdeffc388ba6d,02f639fd402d35ba,0342ab5e045200ee,039de553a54efefc,03a0adf10e22ddc9,03b4b2bd24119d23,03e1d6d1364b6f66,04755edba751a394,049d5dc0ec7c210c,04e1a4df6753b760,050869474dbd21e5,058b08b97630e7db,05c7844dba186699,0628b8488becf892,064e18cd4b24e333,0697f6e16bf526f9,06bcedbac50aaf10,06cfa96f4a317e98,06ed8b50947110fc,06f48465990a41b8,08cc06c7e15267c4,08d0392fe2401bb9,08e6000a09048dcb,091a75326533bbd8,0937361d55942510,0961b791a728035a,09a560381d118cc3,0a18567e6b12210b,0a2d45552b89c293,0a516d3f55e17ebe,0b8a29367c147be5,0c0a96c73c61723f,0c56e04c5ccd88a5,0cb0612e43b1fed9,0e664f4cf7eb6ef2,0e6ab77faa833e34…Link’s Awakening static negative control
regress.py chainpassed on Apple M3 Max, macOS 27.0.1 and Xcode 27.2 in 784.7 s. Baseline865cc35fad70used chain223f10d34f97. Candidate3fe33bc3997aused chain5ba43d2a3f37. The worktree’s only uncommitted change was regeneratingdmsh_chain.hwithDMSH_RAW_LOAD_QUADS=1.01006BB00C6F0000Front-ends: This is an optional build-time experiment. Keep
DMSH_RAW_LOAD_QUADS=1consistent for chain-header generation, shader libraries and the matching host; it is not a runtime-only switch.