Repository navigation
NVN: avoid pinning CPU-only pools and recreating retired textures - #1404
Open
givethesourceplox wants to merge 1 commit into
Open
givethesourceplox wants to merge 1 commit into
givethesourceplox wants to merge 1 commit into
Conversation
Track GPU address exposure without changing the raw-address table ABI. Keep descriptor storage checks non-pinning and avoid rebuilding lost GPU backing for retired descriptors while preserving CPU uploads and storage twins. Keep cube faces eligible for 2D-array tables and compressed images read-only. Include focused GPU coverage and an older-SDK declaration for the existing guarded temporal-scaler setters.
This was referenced Nov 5, 2026
3 tasks done
|
This overlaps two drafts of mine, opened at about the same time from the same Ocarina of Time measurements:
If reviewers would rather take this one, I'm happy to close mine. Data points from ours, on Ocarina of Time on a 16 GB M4:
Drafted with Claude; reviewed by me. |
2 of 3 tasks
2 tasks done
3 tasks done
seedds
added a commit
that referenced
this pull request
Nov 6, 2026
…ed texture in one lookup instead of walking the serial table: Ocarina of Time's long frames in Kokiri Forest fall from 332 to 212 (PR #1439) For each sharing-table entry a takeover could remove, alias_take_over called serial_holds(&g_by_serial, ...), a walk over the serial table's whole capacity. With thousands of serials and shared textures, every new shared texture walked the table once per overlapping entry, and in Ocarina of Time, where the texture pool's walks make hundreds of textures in a submission, that walk was the submit thread's hottest function while frames took up to a second. A count per object of the serial-table entries holding it (g_by_serial_held) is now kept by every writer of the serial table (serial_put, serial_del, tex_put and the upgrade's in-place replacement), and alias_take_over asks it in one lookup. An entry holds its object, so a counted address is not reused while counted. The reference entry notes that a change letting objects hold shared textures another way (PR #1404's views and packaged members) must count those holds too. t_alias_takeover: live-held entries stay, unheld ones go after ALIAS_IDLE submissions, two serials keep an object held until both go, and a takeover past 1,000 held entries with 20,000 serials takes 0.03 ms instead of 4.3 ms. Ocarina of Time on an M4 Pro, loading a Kokiri Forest save through Saria's dialogue and a walk: a host asking both the count and the walk compared them 393,216 times with no difference; [longframe] lines 332 -> 212, frame p99 72.8 -> 38.8 ms (one run each, hosts on the build's chain at 88c7e03). Measured by the author on an M5 Max and by a commenter on an M3 Max (frames over 100 ms 85 -> 2). Regress: Breath of the Wild's build is in the packed layout regress.py does not read, so Ocarina ran instead. Co-authored-by: enjoyerofslop <281774948+enjoyerofslop@users.noreply.github.com>
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.
2 tasks done
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.
Know-It-All-Brother
pushed a commit
to Know-It-All-Brother/nxnative
that referenced
this pull request
Nov 9, 2026
…ed texture in one lookup instead of walking the serial table: Ocarina of Time's long frames in Kokiri Forest fall from 332 to 212 (PR seedds#1439) For each sharing-table entry a takeover could remove, alias_take_over called serial_holds(&g_by_serial, ...), a walk over the serial table's whole capacity. With thousands of serials and shared textures, every new shared texture walked the table once per overlapping entry, and in Ocarina of Time, where the texture pool's walks make hundreds of textures in a submission, that walk was the submit thread's hottest function while frames took up to a second. A count per object of the serial-table entries holding it (g_by_serial_held) is now kept by every writer of the serial table (serial_put, serial_del, tex_put and the upgrade's in-place replacement), and alias_take_over asks it in one lookup. An entry holds its object, so a counted address is not reused while counted. The reference entry notes that a change letting objects hold shared textures another way (PR seedds#1404's views and packaged members) must count those holds too. t_alias_takeover: live-held entries stay, unheld ones go after ALIAS_IDLE submissions, two serials keep an object held until both go, and a takeover past 1,000 held entries with 20,000 serials takes 0.03 ms instead of 4.3 ms. Ocarina of Time on an M4 Pro, loading a Kokiri Forest save through Saria's dialogue and a walk: a host asking both the count and the walk compared them 393,216 times with no difference; [longframe] lines 332 -> 212, frame p99 72.8 -> 38.8 ms (one run each, hosts on the build's chain at a4b9b0f). Measured by the author on an M5 Max and by a commenter on an M3 Max (frames over 100 ms 85 -> 2). Regress: Breath of the Wild's build is in the packed layout regress.py does not read, so Ocarina ran instead. Co-authored-by: enjoyerofslop <281774948+enjoyerofslop@users.noreply.github.com>
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's first 3D load makes CPU-only tiled texture storage GPU-resident alongside private Metal textures. Scanning registered descriptors can also recreate zero-filled GPU textures for finalized objects whose storage has already been reused.
This keeps the existing raw-address table and shader ABI, but makes residency follow NVN address exposure and actual GPU buffer bindings. Late exposure invalidates the table generation; virtual mappings and capture replay remain conservative. Storage validation no longer calls the pinning address resolver. Retired descriptors preserve existing backing, CPU uploads and linear/sRGB aliases, but do not recreate lost GPU storage.
The same allocation preflight rejects incompatible texture classes while preserving cube faces' 2D-array backing. Compressed
IMAGEtextures retain read-only usage, allowing the separate mip-reduction work to apply. A setter-only declaration for the existing OS-27-guarded MetalFX offsets allows the host to compile with Xcode 26.5 headers; its runtime selectors are unchanged.Reference finding. Related: #1281, #1326, #1299. This does not replace #1360's pool-table capacity fix or duplicate #923, #1225, #1308 and #1319.
Checked
On Apple M1 Pro, 16 GiB, macOS 26.5.2, Xcode 26.5:
t_raw_residency, 1,079 checks, andt_cpu_tex --metal, 56 checks, pass with Metal API validation. These cover 1,024 retired GPU descriptors over reused storage, late pool/buffer/texture address exposure, CPU uploads and command snapshots, cube-array compatibility, compressed image usage and retired linear/sRGB aliases.0400486024DEC000v131072, short loads into Link's house on the existing integration stack, including [WIP] The Legend of Zelda: Ocarina of Time (Switch 2, 0400486024DEC000, v0, SDK 22.2.8) runs on the Mac through the title movie into Kokiri Forest #1299/Raw global memory's pool table grows with the pools: pools past 4,095 were left out and hung the GPU in Ocarina of Time #1360 and other open Ocarina fixes. This exact upstream-base branch has fixture validation, not standalone gameplay validation.Residency-set inventory, MiB (different short runs; not an isolated FPS benchmark):
The after-run still reports about 9,080 MiB Metal allocations and 9,635–9,785 MiB process resident memory. These are different accounting measures: 5,881 MiB is the residency-set inventory, not total app RAM. Gameplay remains below 30 FPS, with roughly 37–40 ms median frame time in the sampled gameplay windows. No FPS, thermal or iPhone fix is claimed.
Limits: the existing 4,095-pool capacity remains on this base (#1360 addresses it); private texture copies and already pinned pools are not removed. No five-game
regress.py checkreport or iPhone run is available. Cross-game address reachability and long-session behavior still need runtime coverage.Docs
docs/reference/nvn-objects.mdanddocs/reference/shaders.md; symptom index regenerated.