Repository navigation
Raw global memory's pool table lists only the pools the game took a buffer address in: every pool was wired for it, which slowed Ocarina of Time's frames to 60-65 ms - #1394
Open
david-on-spring wants to merge 1 commit into
Conversation
…uffer address in: every pool was wired for it, which slowed Ocarina of Time's frames to 60-65 ms A shader with raw global memory reaches any address it loads from memory, so its pool table (gmem_map_gpu) listed every memory pool and made each one resident, and a zero-copy buffer in the residency set is wired whole. Ocarina of Time (0400486024DEC000, profile in seedds#1299) makes over 4,500 pools, most of them holding only textures. In Link's house the residency set reached 11.7 GB on a 16 GB Mac, against Metal's 12.1 GB working set, and frames took 60-65 ms. The pool walk's storage check (tex_storage_live) also went through mtl_addr, which puts the pool it finds into the residency set, for every registered texture. A shader can only reach an address the game wrote into memory, and the game gets a GPU address only from nvnMemoryPoolGetBufferAddress, nvnBufferInitialize or nvnTextureGetTextureAddress. Those now mark the pool's range (mtl_pool_buffer_addr), and the table lists and makes resident only the pools that meet a mark; a large pool is taken whole only then. Other pools still come into the residency set when a binding addresses them. The storage check only asks whether a pool maps the storage (mtl_addr_mapped), and a texture upload from an unlisted pool reads it through a buffer of its own that the upload batch retires (up_big_src), as for a large pool. nvn_replay marks every captured pool. A full mark table lists every pool, with a red line, and DM_NVN_GMEM_ALL=1 lists every pool, as before. On our stack: Link's house from 60-65 ms to about 26 ms a frame, and the residency set from 11.7 to 9.5 GB. t_gmem_marks covers the table, the residency set, the storage check, the upload and DM_NVN_GMEM_ALL; t_pool_chunks takes a large pool whole only once it is marked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
gnosticgeek
pushed a commit
to gnosticgeek/nxforge
that referenced
this pull request
Nov 6, 2026
…nly the pools the game took a buffer address in: every pool was wired for it, which slowed Ocarina of Time's frames to 60-65 ms Its marks go into the pool table that seedds#1360 sized to the pools (gmem_map here); t_pool_chunks checks the mark, then the chunk hints. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016qteK29T18U8p1c9LsVY8g
3 tasks done
3 tasks done
fpedrolucas95
pushed a commit
to fpedrolucas95/nxnative
that referenced
this pull request
Nov 6, 2026
…ists only the pools the game took a buffer address in: every pool was wired for it, which slowed Ocarina of Time's frames to 60-65 ms # Conflicts: # dm/gfx/nvn/nvn_mtl.m # dm/gfx/tests/t_pool_chunks.m # docs/env_switches.tsv # docs/reference/shaders.md
fpedrolucas95
pushed a commit
to fpedrolucas95/nxnative
that referenced
this pull request
Nov 6, 2026
…mark the pools a buffer address was taken in seedds#1394's table lists only the pools the game took a buffer address in, so the tests that make pools for the raw table (t_pool_chunks's 5,000 pools, t_gmem_raw's, seedds#1417's t_pool_retire) mark them as nvnMemoryPoolGetBufferAddress would; seedds#1394's and seedds#1417's tests call gmem_map(), which replaced gmem_map_gpu() here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
david-on-spring
marked this pull request as ready for review
November 6, 2026 02:29
1 task done
gnosticgeek
added a commit
to gnosticgeek/nxforge
that referenced
this pull request
Nov 6, 2026
…mtl_tex_gpu_written), tests follow pool_skip_retired, the buffer-address pool table and the new present / DM_CTL calls - nvn_mtl.m ndve_scale called mtl_pool_gpu_written, which seedds#1390 replaced with mtl_tex_gpu_written (a range): it did not compile - t_cpu_tex pins pool_skip_retired off: Ocarina of Time's profile turns it on, and its retired-descriptor checks want textures made again (t_pool_retired covers on) - t_pool_chunks: the 5,000-pool table check takes a buffer address in each pool, since seedds#1394 puts only those in the table - host tests: stubs for mtl_present_layer (t_vi_display), mtl_present_screen (t_nro, t_symbols) and DM_CTL poolstat / texstat (t_hid) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016qteK29T18U8p1c9LsVY8g
gnosticgeek
pushed a commit
to gnosticgeek/nxforge
that referenced
this pull request
Nov 6, 2026
) 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
Aeonitis
pushed a commit
to Aeonitis/nxnative
that referenced
this pull request
Nov 6, 2026
…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.
3 tasks done
m-gnr
pushed a commit
to m-gnr/kid-with-sword-remake
that referenced
this pull request
Nov 7, 2026
- Reconcile upstream PRs (seedds#1455, seedds#1447, seedds#1394, seedds#1439, seedds#1489, seedds#1590, seedds#1663) and commits (ffebfd5, e5f1ade) against local fork - Confirm PRs seedds#1455, seedds#1447, seedds#1394, and seedds#1439 are already implemented in ad99858 - Establish that host-only renderer optimizations require zero shader rebuilds and reuse the 42,854-entry b-dc815e0f38ca.img library - Establish that native subword stores (ffebfd5) affect only 515 shaders and leverage cas.db compilation caching - Rank candidates for base M3 Normal + Handheld (>=40 FPS target, ideal 60 FPS) and identify the top three candidates - Recommend the smallest independently verifiable first optimization (host-only PSO archive epoch separation from PR seedds#1590) - Update documentation index, plan, changelog, and known issues
cfryerdev
pushed a commit
to cfryerdev/nxnative
that referenced
this pull request
Nov 8, 2026
…took a buffer address in (seedds#1394)" Superseded by seedds#1404, whose exposed-address marking (pool_raw / mtl_pool_expose) covers the same fix without the buffer-address bitmap: the pool table keeps every pool, and only GPU-exposed pools become resident, so CPU-only texture storage is not pinned just to list its address.
cfryerdev
pushed a commit
to cfryerdev/nxnative
that referenced
this pull request
Nov 8, 2026
…ures (seedds#1404)" and "Retire obsolete NVN chunks after whole-pool mapping (seedds#1417)" They tank Ocarina of Time's submit thread: on the same route and save, the host with them ran 12.4 fps with the submit thread at 56-78 ms CPU (73-78 ms wall), and without them 58.6-59.1 fps with the GPU at 12 ms. seedds#1393's pool_skip_retired stays (it is not implicated, and it fixes the scene-change OOM); seedds#1394's bitmap stays reverted in favour of upstream's address table.
2 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
Ocarina of Time (Switch 2,
0400486024DEC000, v131072; profile in #1299) runs at 60–65 ms a frame in Link's house on a 16 GB Mac. The residency set is at 11.7 GB, against Metal's 12.1 GB working set. Romen-Adama-Dev's report on #1299 shows the same thing on an 18 GB M3 Pro:memory pools 4553, all resident for the raw global memory table.Cause: a shader with raw global memory can reach any address it loads from memory. So its pool table (
gmem_map_gpu) listed every memory pool and made each one resident. A zero-copy buffer in the residency set is wired whole. The game makes over 4,500 pools, and most of them hold only textures. There was a second path to the same result: the pool walk's storage check (tex_storage_live) went throughmtl_addr, which also puts the pool it finds into the residency set, for every registered texture.Fix: general, in
nvn_mtl.m. A shader can only reach an address the game wrote into memory, and the game only gets a GPU address from three calls:nvnMemoryPoolGetBufferAddressnvnBufferInitialize(thennvnBufferGetAddress)nvnTextureGetTextureAddressEach of these now marks the pool's range (
mtl_pool_buffer_addr). The table lists, and makes resident, only the pools that meet a mark, and takes a large pool whole only then (big_full). A pool without a mark still comes into the residency set when a binding addresses it.Supporting changes:
tex_storage_liveonly asks whether a pool maps the storage (mtl_addr_mapped).up_big_src), as large pools already do.g_mu, so a table built while a mark arrives is rebuilt.nvn_replaymarks every captured pool, since a capture doesn't record the marks.DM_NVN_GMEM_ALL=1lists every pool, as before.Relation to #1360, which rewrites the same table to grow with the pools: this PR only filters which pools go in. It doesn't change the table's size or layout. It merges with #1360 without conflicts (
git merge-tree). After the merge, #1360's new 5,000-pool cases int_pool_chunksandt_gmem_rawadd pools without marking them, so 3 and 4 of their checks fail. Addingmtl_pool_buffer_addrbeside theirmtl_pool_addcalls (3 lines) makes both pass: 89 and 61 checks, 0 failed. Whichever of the two lands second should carry those lines, and I can add them here once #1360 is in.#1360's entry says every pool has to stay in the table, because a zero read through a missing pool can become a hang. That still holds for every pool the game could hold an address in. This PR only leaves out pools the game never got an address from.
Reference entry: Pools the game took no buffer address in, out of the raw pool table. The symptom index is regenerated.
Checked
make -C dm/gfx/tests GAME=0400380020056000 check_t_gmem_marks(new, 28 checks) covers:DM_NVN_GMEM_ALLlists every pool.check_t_pool_chunks(79 checks; it now marks its large pool before the table takes it whole).check_t_nvn(234),check_t_cpu_tex(56),check_t_readback(154 cases) andcheck_t_capture_live(the replay matches the live frame) pass.make -C dm/host/tests GAME=0400380020056000): 143 checks passed.test_env_switches.pyandtest_docs.pypass.lint_c.py tidyonnvn_mtl.m,hle_nvn.cand the new test: no finding above the baseline. My clang-tidy is LLVM 21, and the baseline was made with 23.make -C dm/host GAME=0400380020056000 dmhostbuilds.make -C dm/gfx/tests run).mainhas no profile for the game.588e242a52f5f7aa). Their record pools come fromnvnMemoryPoolGetBufferAddress/nvnBufferInitialize, so they should still be listed. Donkey Kong Bananza's tunnel is the run that would show a miss: walls and floor missing.Docs
docs/reference/nvn-objects.mdentry (with a link from the raw global memory entry inshaders.md), andpython3 dm/tools/docs_symptoms.pywas run (the symptom index)DM_NVN_GMEM_ALLis indocs/env_switches.tsvDrafted with Claude; reviewed by me.
🤖 Generated with Claude Code