# The Legend of Zelda: Tears of the Kingdom (`0100F2C0115B6000`) Update 1.4.3 (v720896) over the base game, SDK 20.5.22. Nintendo EPD's engine (sead / agl / gsys, NintendoWare G3d2 / Ui2d / Vfx2, Havok) on NVN. Modules `main`, `subsdk0` (the movie library) and `sdk`; `subsdk0` and `sdk` are the same builds as Breath of the Wild 1.9.0's ([01007EF00011E000](../01007EF00011E000/README.md)). Plays on the iPhone; 60 fps (30 on the Switch) through the host's frame step. ## What it needs | Setting | Where | Why | |---|---|---| | Frame step, `fps_target 60` | [`patches.py`](patches.py) `FRAME_STEP`, [`game.tsv`](game.tsv) | 60 fps at normal speed; see [Frame rate](#frame-rate) | | Node area cut 1 GB → 62 MB | `dm/tools/sdk_patches.py` SDK-wide rules, `sdk` build `574284b4…` | the resource heaps ran out of alias region (issue #70); see [Memory](#memory) | | 5 GB guest layout: `mem_reserve 0x140000000`, `mem_alias 0x98000000`, `mem_stack 0x10000000`, `app_pool 0xCD500000` | `game.tsv` | 256 MB in front + 2.375 GB alias + 256 MB stack + 2.125 GB heap region. 5 GB is the total proven on a phone (one reservation of at most 6 GB without the extended virtual addressing entitlement) | | `render_cond on` | `game.tsv` | the 3D scene was black: the game skips clears with conditional rendering | | `tex_flush_upload on` | `game.tsv` | streamed textures are written by the CPU into pool memory in GPU layout and published with `nvnMemoryPoolFlushMappedRange` | | `tex_dirty_upload on` | `game.tsv` | textures filled from the CPU with no flush at all (the magenta cave, the unlit stone blocks) | | Integer output rows | [`shader_facts_manual.tsv`](shader_facts_manual.tsv) | no PC version, so the translator has no output types: agl's BC4 encoder and the Ultrahand mask (`e3fb0bb58a691e10`, R8Uint, from PR #11; the Mac route does not reach it) | | `pad_layout full` | `game.tsv` | the 3D gamepad layout: the right stick turns the camera | ## Frame rate - **Current:** the game picks a present interval each frame (`main+0x2db174`: 2 = 30 fps, 3 under load) and steps its game time by 60 / fps (int fps at timing +0x50, read at `main+0x2daa54` and `main+0x3e562c`). Stubs in `patches.py` (sites from masagrator's FPSLocker config for this build) replace that logic with the host's frame step in whole vsyncs, as in Breath of the Wild: int fps = 60 / step, and the float fps at timing +0x24 the same. Prerendered movies hold 30, by the host's movie decoder since its own movie start and end stubs were removed ([Movies hold 30 fps under the frame step](../../../docs/reference/frame-rate.md#movies-hold-30-fps-under-the-frame-step)). `DM_FPS_TARGET=30` saves power, `0` gives the game's own step back (every stub then runs the original instructions). - **Current:** before the host has decided a step (the first frames), the stub steps by the measured frame time, capped at the target. Game time that ran ahead after a short frame is paid back by the next frames (the idea from OJZen/totk-mobile); frames longer than 1/15 s are not caught up. - Measured on the Mac (M4 Pro): the opening cave holds 60 at 1.000 of real time; with 12 ms added to every frame it drops to 30 after three late frames and stays at 1.000. - **Render scale:** `DM_RENDER_SCALE=0.5`–`1.0` multiplies the size of the 3D views (1600x896 docked) and fixes it there; the game's own dynamic resolution runs only at 1.0. The HUD keeps its resolution. The stub multiplies in the view size function (`main+0xd5c24`), unlike Breath of the Wild's, which sets the scale at the dynamic-resolution block. - **Resolved:** the yield back-off used to start after 200 µs, which caught the main thread waiting for its workers on the frame's critical path: frames ran past 33 ms and the game dropped itself to 20 fps (9 times in 300 s on the Mac; on the iPhone the threads also stayed on efficiency cores). From 2 ms on it never backs off ([development.md, Power](../../../docs/development.md#power)). - The spin-wait rewrite finds 843 loops in `main`; 701 of them are one inlined atomic decrement (a compare-and-swap retried after another thread changed the count), which yields only on a second retry in a row. ## 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). ## Rendering Game-specific findings. The general host changes they led to are listed under [Found on this game](#found-on-this-game). - **Resolved: the 3D scene was black.** The game wraps nearly every `ClearColor` / `ClearDepthStencil` in `SetRenderEnableConditional(RENDER_IF_NOT_EQUAL, rec)` … `SetRenderEnable(true)`, each clear followed by `ReportCounter(TIMESTAMP_TOP, rec)`. The CPU sets `rec` to 1 when a target needs a clear, and `rec + 16` is never written. A timestamp report puts 0 in the counter field, so after one clear the two counters are equal and later conditional clears of that target are skipped. The host ignored the condition, so every clear ran: the first tile-lighting round, the half-resolution scene depth the light volumes test against, and the light accumulation were all cleared before the composite read them. Fixed by `render_cond`. With it, the game's scissored colour clears (50×50 tiles of a 500×400 target, about five a frame) are all skipped. - **Resolved: the cave was magenta.** The terrain samples two 121-layer ASTC 8×8 arrays (42 MB each), created on zeroed memory and filled from the CPU with no `nvnMemoryPoolFlushMappedRange` or `FlushTexels` (its cache maintenance runs natively). They stayed GPU-only with content 0, and Metal decodes an all-zero ASTC block as (1, 0, 1). Fixed by `tex_dirty_upload`. - **Resolved: the stone blocks and steps of the opening cave got no torch light (Mac and iPhone).** Their fragment shader `54e8c08998050e79` takes its roughness from a 5120×5120 BC4 atlas (roughness = the square root of its red, packed into the upper six bits of blue in colour target 3, which the tile-light shaders read). The game fills 1024×1024 BC4 material textures on the CPU with no flush, reads them back with `nvnTextureReadTexels` on its own threads before any draw uses them, and copies the blocks into the atlas, which it fills after first binding it. `ReadTexels` returned the never-uploaded host texture (zeros). Found by running MacNativeGames' build on the same save (their atlas held data). Traced with `DM_NVN_TEXDUMP` (roughness bits in colour target 3), the shader's MSL, `DM_NVN_TEXRAW` on the atlas and `DM_NVN_TEXINFO`, then lldb reading the atlas in their process. - **Resolved: draws into a 32×32×32 BC4 3D texture were lost.** agl's BC4 block encoder (`0544282c162305db`, the same shader Mario Wonder ships) encodes it one depth plane per pass through an `RGBA16UI` view. It draws through the compressed-target shadow (Breath of the Wild's), with its output declared `uint` in `shader_facts_manual.tsv`. A raw dump at frame 1500 of the new-game route: all 32 planes hold encoded blocks. - **Resolved: a draw with no render target.** An agl fragment shader that only stores to a storage buffer draws one triangle into a 1×1 viewport with no target (it samples a 64×64 cube map; the game reads the buffer back). With the attachment-less pass, the cave's rock and stone blocks get ambient light they lacked, and Zelda's bloom halo in the descent cutscene is gone. - **Resolved: meadows lost their grass and went dark within half a minute of loading (Mac).** The terrain tiles' normal maps (260×260 RG8, 9 levels) are drawn on the GPU into textures a flush had made CPU-written; the resource defragmentation (`main+0x5bc988`) then moved them with `memcpy`, whose source held zeros on the host, and a zero normal gives every grass blade length 0. Traced from the grass vertex shader (`d351876c331ebd20`, its blade length is scaled by the ground's flatness from slot 1, the tile's normal map), host logs of the tiles' creation call chains (drawn tiles from `main+0x6dc0f4`, never-drawn ones from the defragmentation through `main+0x5bcd78`) and Ghidra. See [Render passes into textures uploaded from their storage](../../../docs/reference/nvn-objects.md#render-passes-into-textures-uploaded-from-their-storage). - **How the tile lighting was traced:** the G-buffer class byte selects per-class half-resolution passes through a depth buffer of class values (`gl_FragDepth = mix(0.5, 1, nibble-swapped class / 255)`, then full-screen or per-tile quads with depth `EQUAL`), so `DM_NVN_DEPTHOVR` (depth test forced to `ALWAYS`) with `HILITE` tells "rejected by depth" from "never rasterized". - **Current (issue #183): the Depths' terrain stretched into huge walls and ceilings, and its rock smeared.** Two host causes are fixed. Two 320×320 RGB5A1 / RGB565 textures with `MINIMAL_LAYOUT` sit before mesh data in one resource and take 204,800 bytes each; the host laid them out in 245,760, and `WriteTexels` overwrote the mesh ([Minimal texture layouts](../../../docs/reference/nvn-objects.md#minimal-texture-layouts)). Initial-fill RGB565-family textures were sampled with red and blue exchanged ([RGB565-family textures in Metal's channel order](../../../docs/reference/rendering.md#rgb565-family-textures-in-metals-channel-order); the host now keeps these formats in Metal's order in every host texture, which also fixed buffer ↔ texture copies, `ReadTexels` and clears into packaged textures, checked by the tests only). AntonZubritski found both on an M1 with 1.2.1 (replaying the wrong writes reproduced all 373,957 changed bytes of the resource); Culacco checked the same two changes on an M4 with 1.4.3 on one Depths save at frame 1800: with the layout fix the stretched surface is gone, with both the rock has its detail. Here: the unit and Metal tests only, no Depths run and no iPhone. Still open in the Depths: black patches around vegetation (the reporters' early-fragment-test candidate), flowers that sink into the ground after a few seconds (their pool-invalidation readback candidate: 260×260 RG8 terrain normal maps; that shape also has `MINIMAL_LAYOUT` and was laid out 118 KB too large, so recheck it with this fix first), and five pixel shaders whose pipelines fail on 1.4.3 with float / integer colour outputs against `R8Uint` or float targets (mekongluca's log). - **Current: Ultrahand and Recall highlight validation pending.** The [Depth16 load-clear correction](../../../docs/reference/rendering.md#depth16-load-clears-match-fragment-writes), ported from MacNativeGames, addresses its reported tile grid. The depth conversion mismatch is reproduced in synthetic Mac GPU tests; this game's highlights and the iPhone have not been rechecked here. - **Resolved in the host: packaged block dimensions and linear compressed storage sizing**, from the driver probes linked under [Found on this game](#found-on-this-game). CPU layout and CPU / GPU packaged 3D deswizzle tests cover the correction; no new gameplay validation of these cases or iPhone run here. - **Resolved: grass flattened along Link's path and the meadow around him went bare as he walked (Mac).** The grass bend map, a 256×256 RG8 window that follows Link (0.5 = upright), is advanced each frame by `ff9def5b3c418851` (GrassShader BAHS), which samples the previous map with wrap 5 (clamp-to-border) and border colour (0.5, 0.5, 0.5, 0.5). Metal has no such border colour, and the host gave the sampler transparent black, so every row and column that scrolled in read "bent all the way". Fixed in the chain and host: [Border colours Metal has no sampler state for](../../../docs/reference/rendering.md#border-colours-metal-has-no-sampler-state-for). Measured on the Mac (M5 Max, chain `44109fcd961e`, with the storage write-back of the terrain normal maps applied), from a copy of the player's meadow save outside the Lookout Landing palisade, by dumping the map (`DM_CTL` `texdump`) three times while Link walks (`LDown~6`): with the correction cut out of the same host, 29–64 % of the map's texels were more than 8 away from 128, 47–69 % in its 16-texel edge band; with it, 2.2–2.7 % (Link's own trail near the centre) and 0.4–0.9 % in the edge band. The grass stays upright along the walk. - The game issues a depth clear scissored to 8×8 of a 64×64 target outside a pass, which the host still clears whole (`depth-stencil clear with a scissor or partial stencil mask, cleared whole`). - About one draw per 8-bit index widening, up to a dozen widenings a frame on the title and load screens, no pass split (log line `8-bit index GPU expansion`). - Its 14,766 vertex shaders have no transform feedback. - Attachment loads and stores per frame on the Mac went from 1,100 to 700 MB once an inline uniform update inside a render pass stopped ending the pass ([development.md, Power](../../../docs/development.md#power)). ## Command memory - **Resolved (issue #61): `CRASH sig=10` in `mtl_exec` after minutes of play**, the fault address equal to `x19` and shaped like `0x1000000003`. The game gives each model's prerecorded lists fixed slots of the size a recording of that list measured (`GetCommandMemoryUsed`), slot k at base + size × k, and passes `AddCommandMemory` max(size, 512) (`main+0xbb120`); its memory callback is empty. A JUMP the host wrote after a 496-byte list reached 8 bytes into the next slot. The host now never writes past what `GetCommandMemoryUsed` reported (`OP_RESERVE`, [Prerecorded lists in slots of their measured size](../../../docs/reference/nvn-objects.md#prerecorded-lists-in-slots-of-their-measured-size)). ## Services - SDK 20 calls it needed (each aborted in `sm::Initialize` or read a null applet proxy, one per boot): `oe::GetPreviousProgramIndex`, the hardware Opus decoder's C interface, cache storage, `fs::IsSaveDataExisting` for another title (it asks for Breath of the Wild's save: none), `MountSaveDataReadOnly`, `time::ClockSnapshot::CreateWithStandardSystemClock` ([Applet resource user ID, launch parameters and VR mode](../../../docs/reference/services.md#applet-resource-user-id-launch-parameters-and-vr-mode), [Hardware Opus decoders](../../../docs/reference/audio.md#hardware-opus-decoders-built-on-the-sdks-software-decoders), [Cache storage and other titles' save data](../../../docs/reference/services.md#cache-storage-and-other-titles-save-data), [Steady clock, clock snapshots and user clocks](../../../docs/reference/services.md#steady-clock-clock-snapshots-and-user-clocks)). - **Resolved: clock snapshot types** ([PR #385](https://github.com/seedds/nxnative/pull/385), static SDK check). SDK build `574284b40c06cf1821a44857939083bee5716820` passes type 1 for standard snapshots (`sdk+0x441890`) and 2 for adjustable snapshots (`sdk+0x441924`); both entries first read the time-service session through `sdk+0xb6b280`. The host now sets the standard type and takes over the adjustable entry as described in [Steady clock, clock snapshots and user clocks](../../../docs/reference/services.md#steady-clock-clock-snapshots-and-user-clocks). This verifies the ABI; gameplay was not rerun for this check. - `main` imports `nn::ro` (it loads NRO modules at run time). - Focus handling mode 2 (focus notifications are sent). ## Files and shaders - **Resolved in the shader builder (#283): BAHS pipeline interfaces.** The local 1.4.3 libraries reproduce all 11 reported pairs: four vertex shaders omit `locn1` or `locn6`, which their pixel partners read. Every failing pair is in the split's 4,159 BAHS pairs; none of the profile's 20,016 other pairs has a missing output. The shared fix makes padding read both tables; see [Pixel shader inputs the vertex shader does not write](../../../docs/reference/shaders.md#pixel-shader-inputs-the-vertex-shader-does-not-write). Targeted validation: the affected vertex sources compile for Mac and iOS, and every affected pair builds into `g13s` and `g16s` Metal archives with both depth entry points. This uses Metal 32023.921; the original TotK sources reproduce the reported rejection on that toolchain too. Full Mac rebuild: 28,669 of 28,669 shaders successful, no binding or pulling-library failures, no regressions, and no interface mismatches across all 24,175 pairs. The Mac host also rebuilt with the regenerated uniform tables. The complete `g16s` archive also succeeds: all 24,153 eligible bases, 1,306 MiB, Metal 32023.921 (2,494 s in the compiler with other builds running). The compiler peaked around 36 GB; a late sample was releasing `AIRNTDispose` / `LLVMContext` contexts. No new gameplay or iPhone run. - **Current: prewarm capture reported in [PR #261](https://github.com/seedds/nxnative/pull/261).** The seed in `pso_manifest.tsv` contains 1,537 shader, 2,512 render-pipeline and 43 compute-pipeline rows, recorded on an M2 iPad Pro with update 1.4.3 on 2026-10-25 over about 33 minutes: boot, title, a save load and overworld exploration. The author reports no pipeline compilations in the second session's long frames with this list. This covers the recorded route, not the whole game; no new gameplay or cold-install validation here. The capture is separate from the shared deswizzle and symbol-index optimizations. - Most RomFS files are zstd with dictionaries (`*.zs`); the dictionaries are `Pack/ZsDic.pack.zs`, which is also the profile's `romfs_marker`. - **Reported in [PR #369](https://github.com/seedds/nxnative/pull/369):** copying the 17 GB, 304,000-file RomFS folder with `devicectl` failed with `EMFILE`; synchronous deletion of a previous copy hit the iOS launch watchdog. Its author reports a 39 s image pack, about one minute to transfer, and gameplay on an iPhone. No new timing or gameplay check of this title is claimed here. The general image implementation and validation are described in [RomFS images](../../../docs/reference/packing.md#romfs-folder-transfers-fail-or-leave-stale-game-files). - Shaders: `Shader/*.bfsha.zs` (BNSH; `material.bfsha` holds most) and the layout shaders in `Shader/ApplicationPackage.Nin_NX_NVN.release.sarc.zs`. - **Resolved in the host: duplicate pipeline keys from unused colour state.** MacNativeGames commit `f3e2f66`, reported in [PR #196](https://github.com/seedds/nxnative/pull/196), found 8,479 of 24,146 recorded render pipelines (35%) differed only in unused state. The general normalization and prewarm deduplication are ported; this is the source project's measurement, with no new gameplay or prewarm-count measurement on this game here. ## 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. - `regress.py capture` records frame 2400 of [`smoke.tsv`](smoke.tsv) (Link in the cave, after the banner) for `regress.py replay`: every replay equalled the live frame (noise 0, 2026-10-29, chain `a31235713eee`). Since the early fragment tests ([Open](#open)) its replays vary: the capture of 2026-10-30 (chain `f3ceca86cac5`) gives 7 digests in 8 replays, none the live frame's, 122 to 163 pixels off (largest byte difference 12). - Grass (2026-10-28, a save in the meadow outside the Lookout Landing palisade, Mac M5 Max): with `DM_CTL`, `A` on the title once the 3D background shows, then `A` twice to load the newest save; shots 25 s and 70 s after loading, then a walk (`LUp~3`, `LRight~3`, … ). Before the fix the grass was gone and the ground dark by the second shot. ## Found on this game General host changes first needed here; each applies to every game: - **Resolved in the host: render passes into textures uploaded from their storage** write the storage, and storage-backed textures get render-target use when attached: [Render passes into textures uploaded from their storage](../../../docs/reference/nvn-objects.md#render-passes-into-textures-uploaded-from-their-storage). Covered by `t_readback`; checked on the Mac along the grass route. - [A capture refused after a change to the reflection structs](../../../docs/reference/nvn-objects.md#a-capture-refused-after-a-change-to-the-reflection-structs). - **Early fragment tests from control +0x718 (chain a76212ee4af0):** [Early fragment tests from the control section](../../../docs/reference/shaders.md#early-fragment-tests-from-the-control-section). 1,677 of the 1.4.3 pixel shaders set the flag, none of them writes depth. The Great Sky Island lattice dots that MacNativeGames reported were not reproduced or checked here. - **Display link at frame latency 2 in fullscreen (#347, a workaround; why the system misses at 16 ms is open):** [Frame latency 2 for the display link in fullscreen](../../../docs/reference/frame-rate.md#frame-latency-2-for-the-display-link-in-fullscreen). Measured from the issue #70 save on an M4 Pro's built-in ProMotion screen: a window held 60; fullscreen at latency 1 stepped to 20 fps on cheap frames in one run of three. - **RomFS folder transfer and startup deletion failures:** [RomFS images](../../../docs/reference/packing.md#romfs-folder-transfers-fail-or-leave-stale-game-files). - **Resolved in the host (#531): `DM_NVN_GPUPROF` abort when an upload flush lands in a profiled draw pass:** [GPU profiles stamp only the encoder they began](../../../docs/reference/rendering.md#gpu-profiles-stamp-only-the-encoder-they-began). Covered by `t_gpuprof`; not rerun in the game. - **Resolved in the host (#342): recurring startup crash during archive compaction**, with a workaround for Metal's serializer defect: [Pipeline archive compaction crashes in Metal's serializer](../../../docs/reference/shaders.md#a-compaction-flush-that-crashes-then-crashes-every-start). Confirmed with local manifest replays; no new gameplay or iOS validation. - **Border colours Metal has no sampler state for** (the grass bend map, see [Rendering](#rendering)): [Border colours Metal has no sampler state for](../../../docs/reference/rendering.md#border-colours-metal-has-no-sampler-state-for). Covered by `t_border` and `test_dmsh_border.py`; measured on the Mac. - **BAHS pairs omitted from vertex padding:** [Pixel shader inputs the vertex shader does not write](../../../docs/reference/shaders.md#pixel-shader-inputs-the-vertex-shader-does-not-write). - **Resolved in the host: frame-step recovery after a 30 fps movie cap**: [The frame step after a 30 fps cap ends](../../../docs/reference/frame-rate.md#the-frame-step-after-a-30-fps-cap-ends). Modelled with the movie flag; no new gameplay recovery observation is claimed. - **Minimal texture layouts (issue #183):** [Minimal texture layouts](../../../docs/reference/nvn-objects.md#minimal-texture-layouts). - **RGB565-family textures in Metal's channel order (issue #183):** [RGB565-family textures in Metal's channel order](../../../docs/reference/rendering.md#rgb565-family-textures-in-metals-channel-order). - **Packaged texture block dimensions and linear storage rows:** [Packaged texture block dimensions and linear storage rows](../../../docs/reference/nvn-objects.md#packaged-texture-block-dimensions-and-linear-storage-rows). - **Resolved in the host: dirty-page writes missed during upload**, with both unprotect paths covered by regression tests; the glyph-cache symptom remains unconfirmed here: [Dirty-page writes missed during upload](../../../docs/reference/nvn-objects.md#dirty-page-writes-missed-during-upload). - **Depth16 load-clears match fragment writes:** [Depth16 load-clears match fragment writes](../../../docs/reference/rendering.md#depth16-load-clears-match-fragment-writes). - **Pipeline keys omit absent-target blend and mask state**, and old prewarm rows are normalized and deduplicated: [Pipeline keys omit unused colour state](../../../docs/reference/shaders.md#pipeline-keys-omit-unused-colour-state). - **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). - **Resolved: registry lock priority inversion** (`g_rmu`): [Registry lock priority inheritance](../../../docs/reference/frame-rate.md#registry-lock-priority-inheritance). Ported from MacNativeGames; checked here through the Metal registry view tests, without a new gameplay contention measurement. - **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). - **Resolved in the host (#471): abort in `up_begin` from `ReadTexels` after the app comes back from the background (iPad Pro M5)**, on a texture of a sparse pool: [`ReadTexels` on a texture of a sparse pool](../../../docs/reference/nvn-objects.md#readtexels-on-a-texture-of-a-sparse-pool). Covered by `t_readback`; not rerun on an iPad. - **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). - **Resolved: black screen at boot since `9a56ecf` (issue #247), handoffs that waited for the whole core:** [Same-core wake handoffs](../../../docs/reference/threads.md#same-core-wake-handoffs). Each wake's handoff waited for every runnable higher-priority thread pinned to the caller's core. `BootupBackgroundWorkThread` (priority 58) then waited 200–290 ms at a time for `ARes Loading 1`, `Presentation Thread` and `BaseProcExecutor`, threads its wake had not made runnable. Checked on the Mac with update 1.4.3 and no shader libraries for chain `8393d85a4eae` (draws skipped), the issue #70 route for 180 s. On `82ab25b` the scene stayed empty (`84 functions 771 calls` a frame, no texture uploaded), and handoffs waited 250,008 ms in total. With handoffs limited to the threads the wake made runnable, they waited 1,221 ms, and the run matched `9feac2f` (before the change) frame by frame: 11 first uploads in both, 14,500–20,500 calls a frame. Gameplay with shaders has not been rechecked. - **Slotted command lists** (`OP_RESERVE`, `t_nvn` "slotted lists"): [Prerecorded lists in slots of their measured size](../../../docs/reference/nvn-objects.md#prerecorded-lists-in-slots-of-their-measured-size). - **Resolved in the NSP script's extractor: a cartridge dump with the update on it** (1G+1U XCI, [PR #311](https://github.com/seedds/nxnative/pull/311)): [A cartridge dump with its update on it extracts the update as the base game](../../../docs/reference/packing.md#a-cartridge-dump-with-its-update-on-it-extracts-the-update-as-the-base-game). - **Resolved in the NSP script: a base NSP without a ticket or a title ID in its name** ([LNPANDY/NX2Apple#177](https://github.com/LNPANDY/NX2Apple/issues/177)) is identified by its meta NCA: [An NSP without a ticket or a title ID in its name](../../../docs/reference/packing.md#an-nsp-without-a-ticket-or-a-title-id-in-its-name-stops-with-no-nsp-with-a-readable-title-id). ## Open - Early fragment tests make a frame vary from run to run (2026-10-30, M4 Pro; [early fragment tests from the control section](../../../docs/reference/shaders.md#early-fragment-tests-from-the-control-section)). Replayed with the libraries of chain `2fcec1622a5f`, which differ from `f3ceca86cac5` only by the `[[ early_fragment_tests ]]` attribute of 1,677 pixel shaders, the capture of frame 2400 gives one digest in 8 replays (58,633 pixels off the live frame, which had the attribute); with the attribute, 3 to 7 digests in 8. Mixing the two libraries narrowed it to one of the 42 attributed shaders the frame draws with, `8f470f5ce5864df7` (a G-buffer material shader of `material.Product.140`): with the attribute on it alone, 3 digests in 16. It writes `1` into a storage buffer at an index it computes per fragment (`fp_s0._m0[idx] = 1u`, a visibility flag), and nothing else of it writes memory. Suspected, not shown: with early tests Apple's GPU may skip the fragments a later draw in the same tile hides, so which flags get set depends on how the GPU shades the pass, where NVN sets one for every fragment that passed the test when it was drawn. Which way to go (the attribute kept, dropped for shaders that write memory, or the flag write made another way) is open. - Ground textures drawn as a checkerboard of blocks at different levels of detail that fill in over a few seconds (iPad Pro M5, GitHub issue #471, second part); the only red line is `texture type mismatch: shader 9808aabbd3219e97_b (stage 1) declares slot 1 as Metal type 2, texture ID … is type 7`. Not investigated. - Texture layout: NVN's automatic block height now truncates for every game (`pick_tile(ah * 3 / 16)`). That changes layouts at 6–10, 17–21, 38–42 and 81–85 block rows, which matters for this game's flushed textures. Not re-checked here. - `game.tsv` still describes the game as "In bring-up", and some memory values as "Breath of the Wild's", not measured for this game.