Bound NVN upload staging and retire it on upload completion

Split GPU upload batches at 128 MiB and retire overflow and CPU staging when the upload completes, rather than retaining it until the main rendering fence. Scope weak-reference diagnostics to avoid temporary staging retention.

Add a real-Metal regression covering memory bounds, upload pixels and an open render pass in direct and deferred encoding modes. Both modes pass 261 checks; documentation checks and the TotK host build pass.

Refs #147. Reporter-device validation and the full-device reboot investigation remain open.
This commit is contained in:
seedds committed 2026-10-26 01:05:44 +08:00
1 parent be5b197640
commit 7dc250e2f1
7 files changed
+122 -6

No files matched your search

+3
View File
@@ -26,6 +26,7 @@ Update 1.4.3 (v720896) over the base game, SDK 20.5.22. Nintendo EPD's engine (s
## Memory
- **Current (issue #147): confirmed transient upload-memory bug on the Mac; iOS validation pending.** With update 1.4.3, the corrected issue #70 SDK module, shader chain `dec5ee141a9f` and 30 fps, walking from the Great Sky Island save produced 10.70 GiB peak footprint after about 474 s; a shorter repeat reached 12.81 GiB after about 150 s. Live staging peaked at 4.48 / 5.82 GiB and the open batch at 4.41 / 5.75 GiB, then memory fell back near 4 GiB. The shorter burst logged 3,084.2 MB of uploads in one frame. A temporary 50 ms sampler and the kernel footprint-peak ledger caught peaks missed by the periodic reports and the 8 GiB sampled watchdog. With [bounded batches and upload-completion retirement](../../../docs/reference/memory.md#upload-staging-grows-within-one-rendering-submission), the 220 s shortened route with deferred encoding enabled peaked at 4.24 GiB footprint and 216 MiB live staging, without GPU errors. A 520 s replay of the original input timings peaked at 4.23 GiB / 200 MiB, but landed differently and reached Game Over earlier, so it is not an equivalent traversal comparison. These local results do not establish the cause of the reporter's full-device reboot or rule out longer-term cache growth; the requested save/route, full logs and Jetsam/panic reports are still needed for that comparison.
- The NPDM declares 24 MB of system resource, so `IsVirtualAddressMemoryEnabled` is true and the game's memory lives in the alias region. `nninitStartup` also calls `SetHeapSize(0x86000000)` (2.1 GB of the pool as its heap; a 2 GB heap region aborts there with 0xd401). What it can map is bounded by the pool less the heap (1.1 GB).
- **Resolved (issue #70):** the resource heaps are address regions in the alias region (2.375 GB here, 64 GB on the Switch). With the SDK's ~1 GB node area at its start, the alias region was used up to +2.25 GB at the first descent from the Great Sky Island with 1.00 GB mapped. The game then took a memory shortage: its frame check (`main+0x1fd32ec`) logs `MSF`, then `R` and `Rf` (reason bits of one resource heap's object), and plays the memory-shortage Blood Moon, which puts Link back at the start. With the node area cut to 62 MB (as Fire Emblem Engage's, Hollow Knight: Silksong's and other builds have it) the high-water mark is +1.75 GB, and no shortage came in 3.7 minutes on the island (it came within a minute in 7 of 8 runs without it).
@@ -62,12 +63,14 @@ Game-specific findings. The general host changes they led to are listed under [F
## Mac routes
- The issue #70 save: `DM_KEYS="20:A*6/4,f2480:LUp~5"` (title, load, jump, steer into the pond).
- The issue #147 short streaming route uses a fresh copy of the issue #70 save and its corrected SDK module: `DM_FPS_TARGET=30 DM_KEYS="20:A*6/4,f2480:LUp~9,f4000:LUp~20,f4700:LRight~5,f5000:LUp~20"`, run for at least 220 s. This is a fall/respawn stress route, ending at Game Over in both short comparison runs; it is not a long surviving traversal test. The movement timings are repeatable, but the upload burst varies with streaming and CPU/GPU timing, so the deterministic staging regression complements it.
- The in-cave autosave (`run/save`): keys `f2500:A,f2800:A,f3100:A,f3600:A`, shot at frame 4500. `DM_DETCLOCK` cannot be used: the game stops at frame 1 waiting for guest time.
## Found on this game
General host changes first needed here; each applies to every game:
- **Bounded upload staging and retirement on upload completion:** [Upload staging grows within one rendering submission](../../../docs/reference/memory.md#upload-staging-grows-within-one-rendering-submission).
- **Conditional rendering** evaluated at replay (`OP_RENDER_COND`, profile key `render_cond`) and **CPU-written textures with no flush** (`tex_dirty_upload`, `ft_add`): [Conditional rendering evaluated at replay](../../../docs/reference/rendering.md#conditional-rendering-evaluated-at-replay), [CPU writes with no flush, caught by page protection](../../../docs/reference/nvn-objects.md#cpu-writes-with-no-flush-caught-by-page-protection-tex_dirty_upload).
- **Mid-pass, partial-mask and partial-scissor clears** drawn as a triangle (`clear_color_tri` / `clear_ds_tri`), **8-bit indices widened on the GPU** when written in the same submission (`wide_run`), **`ReadTexels` from guest memory on any thread** with `nvn_ft_poll` marking textures written after first use, **attachment-less passes** (`bare_dims`): same section.
- **Rewriter:** out-of-line atomic retry blocks (`retry_block` / `site_retry_window`, 8 sites) and jump tables relative to an `adr` (`jump_adr_offsets`, `main+0x393bb0`): [Out-of-line retry blocks of atomic updates](../../../docs/reference/rewriter.md#out-of-line-retry-blocks-of-atomic-updates), [Offset tables relative to an adr](../../../docs/reference/rewriter.md#offset-tables-relative-to-an-adr).