Skip to content

Pools that hold shader code are no longer made resident to key their shaders (Ocarina of Time: 222 pools, 334 MB the GPU never reads) - #1484

Closed
aksmith-git wants to merge 1 commit into
seedds:mainfrom
aksmith-git:pr/shader-pool-residency
Closed

aksmith-git wants to merge 1 commit into
seedds:mainfrom
aksmith-git:pr/shader-pool-residency

Conversation

@aksmith-git

Copy link
Copy Markdown
Contributor

What and why

keys_hash (hle_nvn.c) checks that a shader's code lies in a memory pool before it hashes the code into the shader's key. It asked mtl_addr, which also makes the pool resident (pool_res). The GPU never reads that code, since the shaders run translated. So every pool a program's code lies in stayed in the residency set: in Ocarina of Time, 222 pools and 334 MB, read from the residency line's additions by source line, where mtl_addr had added them as the game set its programs. On an iPad, Metal's working set is 8,192 MB, and this game goes past it (#1436).

mtl_pool_holds is the same lookup as mtl_addr (pool_find), without the residency. Keys are unchanged: a shader is keyed exactly when it was before. A pool the GPU does read, through a binding or an address, is still made resident on that path.

Reference entry: docs/reference/memory.md, "Pools that hold shader code made resident to key the shaders", with its line in the symptom index and Ocarina of Time's note.

Checked

  • Tests: check_t_pool_holds (new, 8 checks: the lookup, a range past the end, no pool made resident, mtl_addr still making it resident, a removed pool), t_nvn (236 checks), test_docs.py.
  • make -C dm/host GAME=0400486024DEC000 dmhost builds on main 0f510fd.
  • Games run: the change ran in our Ocarina of Time (0400486024DEC000 v131072) builds on the Mac (M4 Pro) and an iPad Pro (M5, iOS 27). It was on a stack of other changes there, so there is no separate before/after run of this one. The 334 MB figure comes from that stack's residency line.
  • regress.py not run: we have no --platform mac builds of other games on this machine. Keys are unchanged, and the only behaviour change is that a pool is not made resident at program set time.

Docs

  • The finding is in docs/reference/memory.md, and python3 dm/tools/docs_symptoms.py was run
  • No game files, keys or data extracted from a game in the change

…shaders: Ocarina of Time's 222 such pools, 334 MB, which the GPU never reads

keys_hash (hle_nvn.c) checks that a shader's code lies in a memory pool before it
hashes it, and asked mtl_addr, which also puts the pool into the residency set.
The shaders run translated, so the GPU never reads that code. mtl_pool_holds is
the same pool lookup without the residency; a pool the GPU reads through a
binding or an address is still made resident there.

t_pool_holds checks the lookup and that asking makes no pool resident. The
reference entry is in docs/reference/memory.md, with its line in the symptom
index and Ocarina of Time's note.
@github-actions github-actions Bot added nvn NVN on Metal and its tests (dm/gfx/nvn, dm/gfx/tests) docs Documentation game: 0400486024DEC000 A game labels Nov 6, 2026
gnosticgeek pushed a commit to gnosticgeek/nxforge that referenced this pull request Nov 6, 2026
john62036203-ops added a commit to john62036203-ops/NXNativeWindows that referenced this pull request Nov 6, 2026
…ina's 9 shaders build, encode-thread mesh draws, storage takeover lookups) into switch2

seedds#1484 stays reverted while Ocarina's white foliage is tested.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013SzykpcKm2eZPvPjGPKx1C
john62036203-ops added a commit to john62036203-ops/NXNativeWindows that referenced this pull request Nov 6, 2026
…revert undone): main's 339d9f2 fixes raw reads of pools made mid-submission, a likely cause of Ocarina's white foliage; seedds#1484 stays reverted

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013SzykpcKm2eZPvPjGPKx1C
john62036203-ops added a commit to john62036203-ops/NXNativeWindows that referenced this pull request Nov 6, 2026
…Ocarina's 334 MB): it was not the white foliage, and an iPhone run ended on a residency set of 5,070 of 5,461 MB

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013SzykpcKm2eZPvPjGPKx1C
@nafields

nafields commented Nov 7, 2026

Copy link
Copy Markdown
Contributor

Data from Ocarina of Time (Switch 2, 0400486024DEC000, v131072), M2 Pro 16 GB, with this PR ported onto a tree with #1417, #1391/#1482, the render-target reclaim (#1588) and #1607:

  • Estimated saving, read off the residency log (not an A/B of footprint): 222 pools holding shader code stay out of the residency set, about 334 MB.
  • Stability: runs to f7,750 with it have no crash or regression we could attribute to it.
  • Ruled out as the cause of a deterministic GPU page fault near f780 (the Kokiri load spike). A run with the pre-PR mtl_addr (shader code pools made resident again) still faults there, so that fault has another cause.

seedds added a commit that referenced this pull request Nov 7, 2026
…aders: keys_hash asks mtl_addr_known, which makes no pool resident and no chunk (The Great Ace Attorney Chronicles: three chunks, about 5 MB; PR #1484)

keys_hash (hle_nvn.c) checks that a shader's code lies in a memory pool before it
hashes it, and asked mtl_addr, which also puts the pool into the residency set and,
in a pool in chunks, makes the chunk that holds the code. The shaders run translated
and their c1 constants are copied into host buffers, so the GPU never reads that
code. It now asks mtl_addr_known, the side-effect-free lookup texture uploads already
used, made public; for a pool in chunks it now checks the whole range lies in the
pool. Keys are unchanged.

Measured with hosts built from main with and without the change:
- The Great Ace Attorney Chronicles (DM_CTL restop): shared buffers in the
  residency set 19 / 241 MB -> 16 / 236 MB at 30 s, 22 / 353 MB -> 19 / 348 MB at 60 s.
- Ocarina of Time: no change (4,276 resident pools before, 4,277 after on the
  village walk; 2,324 on both at the title). Its shaders read raw global memory,
  and the raw pool table (gmem_map) makes every pool it took an address in
  resident. The PR's 222 pools / 334 MB came from a build with other changes.

t_addr_known checks the lookup, ranges past a pool's end, that asking makes no pool
resident and, in a large pool, no chunk.

Co-authored-by: aksmith-git <242086076+aksmith-git@users.noreply.github.com>
@seedds

seedds commented Nov 7, 2026

Copy link
Copy Markdown
Owner

Thanks, landed as f25fa95 with you as co-author. The diagnosis, the test and the reference entry are kept.

What changed:

  • keys_hash now asks mtl_addr_known, the side-effect-free pool lookup texture uploads already used on main, made public, instead of a new mtl_pool_holds. mtl_pool_holds went through pool_find, and for a pool in chunks (512 MB or more) that makes the chunk holding the code, so it still had a side effect there. mtl_addr_known answers from the pool's range, and now checks that the whole range lies in it.
  • The test is now t_addr_known, with a large-pool case (no chunk made, nothing resident).

Measured on main, with hosts built with and without the change:

  • The Great Ace Attorney Chronicles (DM_CTL restop): shared buffers in the residency set 19 / 241 MB -> 16 / 236 MB at 30 s, 22 / 353 MB -> 19 / 348 MB at 60 s (three chunks of its 1,000 MB pool).
  • Ocarina of Time: no change, 4,276 resident pools before and 4,277 after on the village walk, 2,324 on both at the title. Its shaders read raw global memory, and on main the raw pool table (gmem_map) makes every pool the game took an address in resident, shader code pools included. The 222 pools / 334 MB came from your build with other changes. The reference entry says so.

@seedds seedds closed this Nov 7, 2026
gnosticgeek pushed a commit to gnosticgeek/nxforge that referenced this pull request Nov 7, 2026
…heck; seedds#1520 / seedds#1484 landed versions left for the next full merge (NXForge carries their heads)

The pick of seedds#1644 kept NXForge's alias_let_go (used at two call sites) with upstream's rule (always a release; residency follows g_retire_held), its newest-first defer_drain order, and the GPU-by-kind memory line with upstream's held count added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016qteK3qWJVi2jG3Gz4i1eY
thomasruegsegger pushed a commit to thomasruegsegger/nxnative that referenced this pull request Nov 7, 2026
…mmits on top of main, without seedds#1484 and seedds#1644, which main landed as f25fa95 and fa9cfb8 (this merge keeps the earlier branch history reachable, so the push needs no force)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Aax1HnchwCweUDRNWjhHx9
cheemu21 added a commit to cheemu21/kid-with-sword-remake that referenced this pull request Nov 7, 2026
…d level, the readout's peak

- Pools that hold shader code are no longer made resident to key their shaders
  (upstream seedds#1484, via kid-with-sword-remake 2191f7a): keys_hash asks mtl_pool_holds.
  Ocarina of Time: 222 pools, 334 MB the GPU never reads.
- DM_NVN_RES_EVICT_MB=<MB>: the GPU memory guard lets go of what it can from that
  size and never stops the game by itself (the Potato preset).
- The memory readout logs the residency set's size and peak (the GPU memory a phone's
  footprint follows); DM_NVN_RES_TOP=1 logs what the set holds with every readout.
- DM_NVN_TEX_SOFT's rule applies beside DM_NVN_TEX_MIP_SKIP's: a texture the game reads
  back is made whole again.

Mac, Kokiri Forest with v3's env.txt: peak 5,608 MB (the v3 author's iPhone: 5,728 MB).
DM_NVN_TEX_MIP_SKIP=512 froze the game right after the save loaded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Aznracer pushed a commit to Aznracer/Mighty-Green-Kokiri-Kid that referenced this pull request Nov 8, 2026
…aders: keys_hash asks mtl_addr_known, which makes no pool resident and no chunk (The Great Ace Attorney Chronicles: three chunks, about 5 MB; PR seedds#1484)
Know-It-All-Brother pushed a commit to Know-It-All-Brother/nxnative that referenced this pull request Nov 9, 2026
…aders: keys_hash asks mtl_addr_known, which makes no pool resident and no chunk (The Great Ace Attorney Chronicles: three chunks, about 5 MB; PR seedds#1484)

keys_hash (hle_nvn.c) checks that a shader's code lies in a memory pool before it
hashes it, and asked mtl_addr, which also puts the pool into the residency set and,
in a pool in chunks, makes the chunk that holds the code. The shaders run translated
and their c1 constants are copied into host buffers, so the GPU never reads that
code. It now asks mtl_addr_known, the side-effect-free lookup texture uploads already
used, made public; for a pool in chunks it now checks the whole range lies in the
pool. Keys are unchanged.

Measured with hosts built from main with and without the change:
- The Great Ace Attorney Chronicles (DM_CTL restop): shared buffers in the
  residency set 19 / 241 MB -> 16 / 236 MB at 30 s, 22 / 353 MB -> 19 / 348 MB at 60 s.
- Ocarina of Time: no change (4,276 resident pools before, 4,277 after on the
  village walk; 2,324 on both at the title). Its shaders read raw global memory,
  and the raw pool table (gmem_map) makes every pool it took an address in
  resident. The PR's 222 pools / 334 MB came from a build with other changes.

t_addr_known checks the lookup, ranges past a pool's end, that asking makes no pool
resident and, in a large pool, no chunk.

Co-authored-by: aksmith-git <242086076+aksmith-git@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Documentation game: 0400486024DEC000 A game nvn NVN on Metal and its tests (dm/gfx/nvn, dm/gfx/tests)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants