nxnative review: what Napple can take (review only, 2026-10-25)¶
Branch claude/nxnative-review-2026-10-25-titles, session nxnative-review (Mac). Nothing was implemented, built or run. No code was copied from nxnative; every claim below cites a file I read, with line numbers where I have them. Paths: NX: = /Users/neto/Documents/Napple/nxnative/ (read-only, commit 1a93086, MIT, NX:LICENSE, Copyright 2026 seedds). Unprefixed paths are in Napple/ of this repo at main 9ac63a8. ACR: / PERF: / MK8: = other batch branches read through git show origin/<branch>.
Status words: read (I read both sides), inferred (reasoned from one side, not confirmed on the other), verify (needs a run before acting).
0. Context that decides how to read everything¶
- Same lineage, different HLE level. nxnative and Napple descend from the same idea (MacNativeGames / d2r-mobile: run the game's A64 natively, rewrite what macOS forbids, NVN on Metal). They differ below it. nxnative hooks SDK functions by symbol (
NX:dm/host/hle_*.c,HLE_FORCE(...), e.g.NX:dm/host/hle_sf.c:33) and runs the SDK's own audio renderer and movie decoder on the CPU. Napple answers IPC as the real services would (docs/runtime-services.md,runtime/src/services/). So nxnative's service and audio fixes are findings about what games do, not transplantable code. Their GPU layer is a closer analogue ofgfx/, but their shaders are translated offline by Ryujinx's translator (SPIR-V, SPIRV-Cross, metallib;NX:dm/gfx/tools/dmsh_build.py,NX:dm/third_party/ryujinx/), ours by an own Maxwell-to-MSL translator (gfx/src/shader/maxwell_translate.c, 2044 lines) at run time. Shader findings therefore map by behaviour, not by patch. - Nothing from nxnative is in Napple's pipeline yet.
git grep -il nxnativeon main and on the three batch branches only hitsMacNativeGames/(a separate snapshot:MacNativeGames/README.md:258,docs/how-it-works.md:84: its NSP common-ticket import follows nxnative's approach) and my own orchestration file.git log --all --grep=nxnativefinds only my orchestrate commit. No integrator file or change note cites it. The batch sessions found several of the same bugs independently (marked overlap below). So "already in progress" below means same fix landing from another route, never "being ingested from nxnative". - MK8D is two different programs. Evidence from our own logs (session notes,
ios-sim-mk8d-base-a32.logvsios-sim-mk8d-latest-update.log): base v0 (b5c39b5b…) is AArch32 (a32:loader lines), but the Testing Material UPDATE v1376256 (fe941ed5…) loads as ordinary 64-bit modules (loader: mapped main … relocs=149788, noa32). nxnative has no AArch32 support (no hit for aarch32/armv7/elf32/thumb inNX:dm/tools,NX:dm/host) and only ever runs the merged 4.0.0 update (NX:dm/games/0100152000022000/game.tsvbuild v1441792 4.0.0 main=2c336a9b…, "only the merged 4.0.0 copy is extracted"). Consequence: base+update+DLC MK8D needs no A32 recompiler; the A32 work only matters for a base-only build. The update path's first blocker in our runtime isFAIL: IPC command time:u:300 not implemented(last line of the update log; see S1).
(a) Summary and ranked top 15¶
Short answers to the five questions:
- ACNH black frame. nxnative's AC (3.0.3, same build line) is black unless the profile key
render_cond onis set: AC wraps clears inSetRenderEnableConditional, and "four clear-only passes wiped the composite before the window copy" (NX:dm/games/01006F8002326000/README.md, "What it needs"). We record the condition and then draw as if always enabled (gfx/src/api_cmd.c:435-437,gfx/src/mtl_replay.m:1557). Our timestamp reports already write counter 0 plus time (gfx/src/mtl_replay.m:225-229), which is the semantic their evaluation relies on. This is the first thing to try. It may not be the whole story: ac-render's symptom is a culled final quad (ACRchange note, "Next blocker"), whose cause nxnative does not explain (upper-left origin, winding code is equal on both sides:NX:dm/gfx/nvn/nvn_mtl.m:7366vsgfx/src/mtl_replay.m:747-748). Second suspect from their docs: the quad's data comes from an SSBO and a UBO (driver table wordsc0), see G6/G12. - SMO visual bugs. nxnative has no note on exploded skinned geometry or the cap brim. Their SMO fixes that touch us:
c0+0x610largest point size (fog; G6), position invariance (we already have it,gfx/src/mtl_shader.m:121),nvnTextureComparechannel-mapping fix (HUD). Our integer-vertex-input handling is ahead (attr kind keyed per runtime format:gfx/src/shader/maxwell_translate.c:245,1900), so the repacked R8_UINT bone-index stream in PERF's finding (fa3fa316…) is not explained by their "integer vertex inputs" entry. Best use of nxnative here is as a reference translator oracle (E1). - First-use stutter. They avoid it with (i) shaders compiled offline into metallibs, (ii) a shipped/recorded prewarm manifest of pipeline keys (
pso_manifest.tsv,pso_user.tsv:NX:docs/development.md:281-293), (iii) Metal 4 base pipelines specialized in microseconds instead of 3-5 ms builds, with an on-disk archive (NX:docs/development.md:296-308), (iv) a look-ahead that compiles the next pipelines of the submission in the background (pso_predict_rest,NX:docs/reference/shaders.md"The precompile look-ahead restores the scissor"), (v) normalized keys so duplicates collapse (NX:dm/gfx/nvn/nvn_pso_skey.h:22). We already persist keys, prewarm and use a binary archive (gfx/src/mtl_shader.m:1-60); missing are (ii) a seed list for a fresh install, (iv), (iii) and (v). - AArch32. Not handled by nxnative; see section 0.3.
- Where they are more correct / where we are ahead: see (c) and the "ahead" table in (d).
Top 15, "take this first" (ranked by benefit to the four titles per effort)¶
| # | Item (row id) | Titles | Effort |
|---|---|---|---|
| 1 | Evaluate conditional rendering, key render_cond (G1) |
ACNH, MK8D, TOTK | S-M |
| 2 | time:u command 300 and the rest of the MK8D 64-bit boot path; decide base-only A32 is optional (S1, section 0.3) |
MK8D | S |
| 3 | Graphics driver-segment words c0+0x610 (max point size 2047), +0x644 (base instance) (G6) |
SMO, instanced draws everywhere | S |
| 4 | Per-pass dump diagnostics (PASSDUMP/TEXDUMP/HILITE/DEPTHOVR style) to pin the AC culled quad and SMO skin bug (T4) |
ACNH, SMO | M |
| 5 | Vertex outputs start at (0,0,0,1), not only pos (G7) |
all | S |
| 6 | Same colour texture at two slots: leave the duplicate unattached (G3) | agl titles (SMO, AC, MK8D use agl G-buffers) | S |
| 7 | Attachment larger than the pass: clear in its own pass first (G2) | all | S |
| 8 | Compressed render target through an uncompressed shadow (G4; queued as backlog "copy-back for compressed RTs") | MK8D | M |
| 9 | SignalToAddress type 2 with count <= 0 must write value-2 (K1, our bug) |
all | S |
| 10 | Seed prewarm manifest + key normalization + background look-ahead (G11) | all | M-L |
| 11 | Cross-check rewriter jump-table shapes and exclusive-window cases against their list (R1, R2) | ACNH (63 MB text), updates | M |
| 12 | Present path hardening: commit residency before present, QueueFinish does not wait for display, present rescue (G10) |
windowed Mac, iOS | M |
| 13 | MK8D service stand-ins: six default Miis with valid CharInfo, MiiModel system-data mount, device vs account save as two saves (S2, S4) | MK8D | M |
| 14 | Symptom-indexed reference docs and per-subsystem entries (T1) | process | S-M |
| 15 | CI workflow for host + CPU graphics + tool tests + iOS compile smoke (T2) | all | M |
(b) Full table¶
Licence codes: NX nxnative's own MIT; D2R d2r-mobile MIT (per NX:README.md Acknowledgements); RYU Ryujinx MIT (NX:dm/third_party/ryujinx/LICENSE.txt); DEKO deko3d zlib (ported in NX:dm/gfx/nvn/nvn_tex.c:1-8); ATM Atmosphere GPLv2, YUZU GPLv2: reference only, never copy; MNG MacNativeGames MIT (NX:dm/third_party/macnativegames/LICENSE); LH LibHac (version 0.19.0 in NX:dm/tools/nx_extract/nx_extract.csproj:10; licence not stated in nxnative's tree, believed MIT upstream, verify before any reuse); SPV/GLS SPIRV-Cross, glslang (pinned by tool fingerprint NX:dm/gfx/tools/dmsh_chain.lock, not vendored, licences not verified here). Rule for every row: take the finding and design, write our own code, cite the nxnative doc in the commit. If any nxnative text or code is ever copied, add it to THIRD_PARTY_NOTICES.md (today it lists Ryujinx.Audio, MacNativeGames, LASRecomp, libopus, libvpx; no nxnative).
Owners: ac-render owns runtime/src/services, kernel waits in runtime/src, gfx/src/api_*.c, gfx/src/tex/; mk8d-recompiler owns runtime/src/a32jit, crates/napple-rewrite A32; ios-sim owns frontend/src/ios, runtime/src/ios_*, tools/build_ios*; backlog smo-gfx owns gfx/src/mtl_*.m, gfx/src/shader/. Proposed owners below say which new session, so that none touches another's files; rows whose files an active session owns say "after
GPU: passes, clears, state¶
| Id | nxnative (file) | Ours (file) | Benefit | Eff / risk | Lic | In progress | Owner |
|---|---|---|---|---|---|---|---|
| G1 | Conditional render evaluated at replay: NX:docs/reference/rendering.md:551-560; code NX:dm/gfx/nvn/nvn_mtl.m:539-575 (counter at rec vs rec+16, timestamp report = counter 0, samples-passed condition keeps drawing), :1299, skips at :8228,8245; key in NX:dm/games/01006F8002326000/game.tsv, 0100152000022000/game.tsv, TOTK |
recorded gfx/src/api_cmd.c:435-437; ignored gfx/src/mtl_replay.m:1557; timestamp reports right :225-229 |
ACNH black frames, MK8D race clears, TOTK | S-M / SMO: their note says evaluating hurt SMO (NX:dm/games/0100000000010000/README.md, "Rendering"), so gate per profile or only evaluate deterministic timestamp conditions |
NX (design only) | no | new gfx-cond session after smo-gfx (same files mtl_replay.m, api_cmd.c) |
| G2 | Clear of attachment larger than pass: own pass first: NX:docs/reference/rendering.md:206-213, rp_begin_ex_ NX:dm/gfx/nvn/nvn_mtl.m:2707 |
load-action clears folded when clear_covers_target() gfx/src/mtl_replay.m:328-350,504 (size mismatch handling verify) |
stale depth/colour outside small passes (agl small targets) | S / low | NX | no | smo-gfx |
| G3 | Same texture at two colour slots: unattach duplicate: NX:docs/reference/rendering.md:185-191, rt_dup_slot NX:dm/gfx/nvn/nvn_mtl.m:2673,2725 |
no equivalent found (grep for dup/same texture in mtl_replay.m: none) |
G-buffer corruption on TBDR (scattered squares); agl titles bind such slots | S / low | NX | no | smo-gfx |
| G4 | Compressed RT via shadow: NX:docs/reference/rendering.md:170-177, bcrt_attach/bcrt_flush NX:dm/gfx/nvn/nvn_mtl.m:2571-2603; depth-via-colour shadow shrt_block :2603 |
backlog item "copy-back for compressed render targets (MK8D)" orchestrations/backlog.md |
MK8D | M / medium | NX | queued, not started | smo-gfx |
| G5 | Layered passes for layer-writing VS: NX:docs/reference/rendering.md:199-205 |
no renderTargetArrayLength/layered path found in gfx/src/mtl_replay.m |
LUT/cube passes (not seen on our 4 titles) | M / low | NX | no | backlog |
| G6 | Driver segment c0+0x610 = 2047 (max point size, SMO alPointSpriteShader), +0x644 base instance: NX:docs/reference/shaders.md:505-519, NX:dm/gfx/nvn/nvn_mtl.m:5234-5238, :4990; layout table NX:docs/agents/04-graphics.md section 3 |
graphics c0 carries only SSBO tables at 0x110/0x510 gfx/src/mtl_replay.m:790-796; compute words 0x200/0x210/0x310 are present :801-806 (same layout as theirs) |
SMO Cap fog never parts; any shader using gl_BaseInstance |
S / low | NX | no | smo-gfx |
| G7 | Vertex outputs init (0,0,0,1): NX:docs/reference/shaders.md:323-329, vs_init NX:dm/gfx/tools/dmsh_build.py:580 |
only out.pos set, varyings zero: gfx/src/shader/maxwell_translate.c:1956 |
LAS sun shadows were wrong without it; unwritten w=0 divides | S / low | NX | no | smo-gfx |
| G8 | (diagnostics are listed as T4) | ||||||
| G9 | Lower-left origin by negative viewport + reversed winding + flip at present NX:dm/gfx/nvn/nvn_mtl.m:3529,7349,7366,8391 |
rows stored bottom-up, flipped at present gfx/src/internal.h:40, mtl_replay.m:370,483,723-759, mtl_present.m:363; LAS title text reads correctly in ios-sim-las-title.png (session notes) |
none now | n/a | equivalent, keep | none | |
| G10 | Present hardening: residency committed before present NX:docs/reference/rendering.md:279-286; QueueFinish waits GPU only NX:docs/reference/nvn-objects.md:165-172; present rescue NX:docs/reference/frame-rate.md:50-57; present snapshots :70-82; dynamic interval holds :59-69 |
gfx/src/mtl_present.m (not read in full: verify each) |
windowed Mac, iPhone smoothness | M / low | NX / D2R | no | gfx-present |
| G11 | Pipelines: Metal 4 base + specialization + archive files NX:docs/development.md:296-308; seed manifest + user manifest :281-293; look-ahead NX:docs/reference/shaders.md "precompile look-ahead"; key normalization NX:dm/gfx/nvn/nvn_pso_skey.h:22 |
persisted keys, background prewarm, binary archive, wait-or-build gfx/src/mtl_shader.m:1-60,610; archive off on iOS Simulator :52 |
first-visit stutter (mtl_pipe_get), cold-start |
M-L / medium (Metal 4 path is Mac-only in theirs; iOS stays off) | NX | no | smo-gfx (same file) |
| G12 | Inline uniform updates replayed as ordered GPU copies, barriers inside encoders, alias visibility: NX:docs/reference/rendering.md:459-482 |
CPU memcpy at replay gfx/src/mtl_replay.m:1577, ring copy per draw :830- (ordered on the CPU timeline; wrong only if the buffer is also GPU-written earlier) |
AC final pass reads UBO+SSBO; verify with a pass dump | M / low | NX/MNG | no | gfx-cond |
| G13 | fp math: precise:: min/max/clamp, iOS relaxed math: NX:docs/reference/shaders.md:338-350 |
our FMNMX uses fmin/fmax maxwell_translate.c:1057-1059, fastMathEnabled = NO mtl_shader.m:122, no iOS math-mode flag verify |
NaN lighting (white half on Mario in Galaxy 2) | S / low | NX | no | smo-gfx / ios-sim |
| G14 | SR_Y_DIRECTION: open on their side (NX:docs/reference/shaders.md:385, Ryujinx returns +1) |
we return -1 always maxwell_translate.c:1423 |
LAS-like shaders under upper-left origin | S, verify | no | smo-gfx | |
| G15 | Geometry shaders as compute + capture: NX:docs/geometry-metal-research.md, NX:dm/gfx/tools/dmsh_geometry.py, NX:dm/gfx/tests/t_geometry.m (498 checks); tessellation not drawn (NX:docs/reference/shaders.md:464); ACNH keyboard has 8 GS, SMO 3 (thunder), MK8D 1: none translated there either |
none; backlog gfx-features (L) |
low for the 4 titles | L / medium; their path rests on Ryujinx's GS lowering, ours has none: design only | RYU (design) | backlog | later |
| G16 | Image atomics contract NX:docs/image-atomic-binding-contract.md, bounded MSL 2.3 emulation NX:docs/reference/shaders.md:615-676 |
the brief says we have docs/image-atomic-binding-contract.md and docs/geometry-metal-research.md: neither file exists in this checkout or on any branch (git log --all --name-only); backlog shader-surface |
SULD/SUST titles (not our 4) | L | NX | backlog | later |
| G17 | Texture details: new textures zero NX:docs/reference/rendering.md:15, cube array = layer-faces :65 (overlap: ACR commit 22752de), block-height truncation :108, sparse :117, 1D as 2D :51, buffer-texture row wrap :93, stencil carried in depth-stencil copies :542, copy_t2t_draw for RG11B10F to RGBA16F :529 |
gfx/src/tex/napple_layout.c (same packaged-layout byte as theirs :4), sparse getters are stubs gfx/src/api_texture.c:72,147 |
per-title bugs not yet seen | S each | NX/DEKO (layout origin: both cite deko3d zlib NX:dm/gfx/nvn/nvn_tex.c:1-8; check our file header) |
partly | gfx-tex after ac-render |
| G18 | Depth16 clear rounding NX:dm/gfx/nvn/nvn_depth_clear.h:8, partial colour/depth clears as triangles NX:dm/gfx/nvn/nvn_mtl.m:8105 |
clear quads gfx/src/mtl_replay.m:512-606; index != 0 falls back to a pass restart :547 |
partial clears on MRT | S-M | NX/MNG | no | smo-gfx |
| G19 | Same-pass feedback via snapshot for listed shaders NX:docs/reference/rendering.md:260-270, fb_prepare NX:dm/gfx/nvn/nvn_mtl.m:4939 |
none | magenta 16x16 blocks on A-series GPUs (iPhone) | M / perf cost, per-profile list | NX | no | ios later |
Kernel and threads¶
| Id | nxnative | Ours | Benefit | Eff / risk | Lic | In progress | Owner |
|---|---|---|---|---|---|---|---|
| K1 | SignalToAddress type 2, count <= 0 with waiters: value-2 (NX:docs/reference/threads.md:61-66, mesosphere KAddressArbiter; Ryujinx and yuzu agree) |
writes value-1: runtime/src/threads.c:566-570 (cnt <= 0 ... val - 1); count>0 branch matches |
condition variables / mutexes in every title | S / low | ATM (reference only; implement from the documented semantics) | no | after ac-render (owns kernel waits) |
| K2 | WaitForAddress type 3 (64-bit wait-if-equal, SDK 19+) NX:docs/reference/threads.md:67-73 |
types 0-2 only, type 3 returns invalid enum threads.c:546-552 |
none of our 4 | S | ATM | no | later |
| K3 | Same-core handoff when a higher-priority thread wakes/starts on the caller's core: NX:docs/reference/threads.md:7-14,43-51, dm_yield_to_core_peers in NX:dm/host/hle_thread.c |
we model three virtual cores explicitly (runtime/src/threads.c:16,253, NAPPLE_FREE_CORES); may already give this: verify with an equivalent test (NX:dm/host/tests/t_preempt*) |
removes racy guest crashes (LAS physics, ACNH loaders) | M / medium | ATM semantics | no | after ac-render |
| K4 | Yields that make progress return at once (thr_yield NX:dm/host/hle_thread.c:660, NX:docs/reference/threads.md:101-109): ACNH shows a black plane-icon screen for 77 s without it |
our yield hands the core to an equal-priority waiter, else sched_yield runtime/src/threads.c:367-373; no back-off to remove |
ACNH loading time: probably not affected (no back-off), verify once it renders | S | NX | no | none |
| K5 | sleep_precise (3/4 of remaining per step) NX:docs/reference/threads.md:86-100 |
our SleepThread implementation not read | 30 Hz title pacing (27 Hz measured on their side) | S, verify | NX | no | later |
| K6 | svcGetInfo FreeThreadCount = 96 minus live NX:docs/reference/threads.md:28-35 |
constant 0x100 runtime/src/kernel.c:208 |
Unity only | S | ATM | no | none |
| K7 | Thread pause + context for GCs NX:docs/reference/threads.md:36-42 |
implemented runtime/src/threads.c:414,449; docs/runtime-services.md still says "existence check only" (doc stale) |
none | docs only | |||
| K8 | SetThreadCoreMask: ideal core moved into the new mask NX:docs/reference/threads.md:15-20 |
returns InvalidCombination if ideal not in mask, ideal -3 checks current threads.c:390-405 |
cannot tell which matches Horizon; Atmosphere reference needed | S, open question | ATM | no | see (e) |
Services, input, storage, audio, movies (findings, not code)¶
| Id | nxnative | Ours | Benefit | Eff / risk | Lic | In progress | Owner |
|---|---|---|---|---|---|---|---|
| S1 | (their time:: hooks, NX:docs/reference/services.md:508-535: steady clock, snapshots, user clocks) |
time:u table ends at cmds 0-5,20,100-102,200,400,401,500,501 runtime/src/services/time.c:185-199: no 300 (CalculateMonotonicSystemClockBaseTimePoint per switchbrew; confirm) |
MK8D update boots until here (ios-sim log) | S | none | no (found in our logs, not from nxnative) | ac-render's area (services): after merge, or tiny mk8d-boot session |
| S2 | MK8D Mii: six default Miis with valid CharInfo, random for BuildRandom, Mii editor cancelled; MiiModel system data 0100000000000802 mounted as MiiResource: with a stand-in archive (layout in NX:dm/games/0100152000022000/README.md "Miis"; NX:dm/host/hle_mii.c:137) |
runtime/src/services/mii_core.c:21-42 has default Miis; system-data mount: only OpenDataStorageByDataId for DLC fs.c:553-572 (verify MiiModel) |
MK8D crashes at boot without both | M / low | NX | no | MK8D follow-up |
| S3 | Device and account save as two saves when a game mounts both NX:docs/reference/services.md:163-169, NX:dm/host/hle_fs.c:81; MK8D deletes CommonSave:/userdata.dat at boot |
save types are separate directories by type docs/runtime-services.md "Save data"; verify MK8D |
MK8D re-asks Mii every boot if shared | S | NX | no | MK8D follow-up |
| S4 | AOC mount cache size = RomFS working memory NX:docs/reference/services.md:186-192, romfs_work_size NX:dm/host/hle_fs.c:347 |
arises from SDK-level hooks; at IPC level likely N/A | MK8D DLC | S, verify | NX | no | MK8D follow-up |
| S5 | Game's own HIPC clients (olsc:u, npns) answered NX:docs/reference/services.md:50-56, NX:dm/host/hle_sf.c:33 (ACNH aborts without) |
olsc exists (services/olsc.c), npns not in runtime/src/services/; manager enforces the NPDM access list |
ACNH after first frames | S, verify with NAPPLE_IPC_LENIENT=1 |
NX | no | ac-render |
| S6 | History reads fill all 16 entries with consecutive numbers (SMO sticks dead otherwise) NX:docs/reference/services.md:200-209; six-axis sensors per controller and shake :217-224 |
input/src/hid_shm.c:148 count capped to 16; outer=2n, inner=n fix (overlap: ACR); six-axis rings exist :44,87; shake verify |
SMO sticks/motion, cap throw | S | NX | partly | ac-render / input |
| S7 | Audio renderer details (SDK 4/6/8 DeviceSink ids, update lock) NX:docs/reference/audio.md:38-100 |
N/A at IPC level (audio/, services/audio.c) |
none | none | |||
| S8 | Movies: 16 video output slots NX:docs/reference/movies.md:109-115; VP9 via libvpx, Vorbis via stb_vorbis, H.264 via VideoToolbox; vendored in NX:dm/third_party/ (BSD-3 / MIT-or-PD) |
ours uses runtime/src/movie.c, vt_h264.c, Homebrew libvpx (THIRD_PARTY_NOTICES.md); ios-sim added libvpx for the Simulator (commit 5fb4673) |
ACNH opening movie (VP9 1080p + Vorbis) | M | NX/third-party | ios-sim (libvpx) | ios-sim |
| S9 | Frame pacing / present interval handling NX:docs/reference/frame-rate.md |
runtime/src/timescale.c etc. not compared |
smoothness | M | later |
Loader, rewriter, ingest, memory¶
| Id | nxnative | Ours | Benefit | Eff / risk | Lic | In progress | Owner |
|---|---|---|---|---|---|---|---|
| R1 | Jump-table shapes (7+): NX:docs/reference/rewriter.md:23-100; halfword tables padded to the largest entry, patch area 42 MB to 7.9 MB for ACNH :134-143, ACNH note NX:dm/games/01006F8002326000/README.md "Rewriter" |
crates/napple-rewrite/src/jumptab.rs:18-24 (3 shapes + function-span fallback), rewrite.rs:198 "landing pads too far"; ACNH data builds today |
ACNH-size modules (63 MB text), game updates | M / low | NX | no | rewrite-xcheck (disjoint from mk8d-recompiler's A32) |
| R2 | Exclusive windows: exit order, out-of-line retry blocks, adrp in window NX:docs/reference/rewriter.md:103-132 |
crates/napple-rewrite/src/windows.rs, check.rs |
atomics correctness (job systems hang) | M, mostly tests | NX | no | rewrite-xcheck |
| R3 | Spin-wait rewrite for power NX:docs/development.md:310-320; NX:dm/tools/patch_nso.py |
none | battery/thermals (iOS) | L / medium | NX | no | ios later |
| R4 | Per-build workarounds keyed by build id, MATCH_CUTS function fingerprints NX:docs/reference/rewriter.md:7-22, NX:dm/tools/nso_match.py |
per-build signatures knownSignatures/ |
updates keep a workaround | M | NX | no | later |
| R5 | Extraction: LibHac nx_extract NX:dm/tools/nx_extract/Program.cs (231 lines) |
own Rust: crates/napple-core, napple-build/src/bktr.rs, NCZ support; nothing to take (ours is ahead: NSZ, no .NET) |
none | none | LH | ||
| R6 | Survey + provisional profile for unknown titles (NX:dm/games/profile_guess.py, NX:scripts/build_ipa_from_nsp.py, NX:docs/agents/02-survey.md) |
Studio/CLI napple build, no survey step read-only check |
generality, coverage | M-L | NX | no | later |
| R7 | Guest memory layout (4 GB layout, sys_resource, heap from pool minus used) NX:docs/reference/memory.md:7-50, ACNH values in its game.tsv (mem_reserve 0x100000000, app_pool 0xCD500000, mem_used 0x7a00000) |
runtime/src/memory.c layout; iOS budget is backlog ios-memory |
iOS budget | M | NX | backlog | ios-memory |
Tooling, tests, docs¶
| Id | nxnative | Ours | Benefit | Eff / risk | Lic | In progress | Owner |
|---|---|---|---|---|---|---|---|
| T1 | Symptom index + entries "Symptom, Cause, Fix, Found on" per subsystem; NX:docs/agents/symptoms.md, NX:docs/reference/*.md, NX:dm/tools/docs_symptoms.py, NX:dm/tools/tests/test_docs.py (links, anchors, length limits) |
docs/changes/* dated notes; no symptom index |
faster bring-up of the next title | S-M | NX | no | docs session |
| T2 | CI NX:.github/workflows/tests.yml (host + CPU graphics tests, TSAN targets for audio/memory, iOS compile smoke NX:dm/ios/tools/build_smoke.py) |
.github/workflows/ has pages.yml and release.yml only |
regression safety | M | NX | no | ci session |
| T3 | ~40 GPU regression tests NX:dm/gfx/tests/t_*.m (clear_ds, clear_tex, depth16, feedback, present_snap, pso_archive, geometry, copy_alias ...) |
make -C gfx test |
test ideas for G1-G4, G18 | S each | NX | no | with each gfx row |
| T4 | Diagnostics: DM_NVN_PASSDUMP, TEXDUMP, CBDUMP, HILITE, DEPTHOVR, KEYDUMP, MAGSCAN, GPUPROF NX:docs/agents/04-graphics.md section 7 |
NAPPLE_DRAWLOG*, NAPPLE_SHADER_PROBE, NAPPLE_DEBUG_SOLID_FS, NAPPLE_DEBUG_SKIP_VS (gfx/src/mtl_shader.m:470-500, PERF note) |
pass-level dump with clears and per-pass render-condition state would have shown the AC final pass | M | NX (design) | no | smo-gfx |
| T5 | iOS build and launcher settings table NX:dm/ios/tools/*, NX:dm/games/settings.tsv model, ios_metal.py relaxed math |
tools/build_ios*.sh, docs/ios.md |
M | NX | ios-sim | ios-sim | |
| T6 | Per-title notes with "what it needs / open" (NX:dm/games/<id>/README.md, 65 titles; ours under compat/, knownSignatures/) |
S |
(c) Discrepancies: our behaviour contradicts theirs (candidate bugs on our side)¶
| # | Ours | Theirs | Evidence | Confidence |
|---|---|---|---|---|
| c1 | Conditional render always drawn, warning "treated as always enabled" | Evaluated; AC and MK8D require it, SMO wants it off | gfx/src/mtl_replay.m:1557 vs NX:dm/gfx/nvn/nvn_mtl.m:539-575, AC/MK8D game.tsv |
high for AC/MK8D semantics; whether it explains our culled quad: unknown |
| c2 | SignalToAddress type 2, count <= 0, waiters: value-1 |
value-2 | runtime/src/threads.c:568 vs NX:docs/reference/threads.md:61-66 |
high (documented kernel behaviour) |
| c3 | Graphics c0 words 0x610 and 0x644 left 0 |
2047 and base instance | gfx/src/mtl_replay.m:790-796 vs NX:dm/gfx/nvn/nvn_mtl.m:5234-5238 |
high |
| c4 | Varyings start at 0 | (0,0,0,1) | gfx/src/shader/maxwell_translate.c:1956 vs NX:dm/gfx/tools/dmsh_build.py:580 |
high |
| c5 | time:u has no cmd 300 |
their host answers the SDK time:: calls |
runtime/src/services/time.c:185-199, ios-sim update log |
high |
| c6 | docs/runtime-services.md says SetThreadActivity is an "existence check only" |
implemented | doc vs runtime/src/threads.c:414 |
docs stale |
| c7 | Window origin lower-left: our targets stored bottom-up, flipped at present | viewport flipped, rows top-down | gfx/src/internal.h:40 vs NX:dm/gfx/nvn/nvn_mtl.m:3529 |
both work for LAS; keep, watch MIRROR_Y copies |
| c8 | SR_Y_DIRECTION = -1 |
their open question (Ryujinx +1) | maxwell_translate.c:1423 vs NX:docs/reference/shaders.md:385 |
unknown |
| c9 | No unattach of duplicate colour slot | unattached | none vs NX:dm/gfx/nvn/nvn_mtl.m:2673 |
medium |
(d) Do NOT take, and where we are ahead¶
Do not take:
- Any Atmosphere / yuzu code: GPLv2, reference only (K1-K3). Implement from documented semantics.
- Ryujinx translator and dotnet toolchain as a runtime dependency: wrong architecture (offline SPIR-V chain vs our run-time translator), .NET at build, large per-game library sets (up to 344 MB on iOS for MH Rise per their note). Use it only as an offline oracle (E1).
- SDK-symbol HLE (HLE_FORCE, in-process audio renderer, movie decoder hooks, hle_sf.c): we answer IPC; copying hooks would fork our model.
- Per-game profile TSV system and per-build rewriter cuts as a first move: our rule is data-only per-game knowledge via knownSignatures; adopt only the findings.
- LibHac nx_extract: ours is native Rust and ahead (NSZ, no .NET).
- iOS-only items now (power QoS, spin-wait rewrite, present snapshots): out of scope until iOS device work (backlog says iOS out of scope).
- Geometry/tessellation implementation: depends on the Ryujinx GS lowering; none of the 4 titles needs it to reach gameplay (SMO thunder only).
- Their vendored copies: keep our own provenance. Anything adapted needs a THIRD_PARTY_NOTICES.md entry.
Where we are ahead (nobody copy backwards):
- Vertex integer inputs keyed per runtime attribute format, no offline guess and no shadow libraries (gfx/src/shader/maxwell_translate.c:245,1900); stride-not-multiple-of-4 repack, fans/quads/8-bit indices exist (mtl_replay.m:721,1050,1108,1179).
- Depth mode and origin resolved per draw in the pipeline key, no second entry point per vertex library (mtl_replay.m:724, mtl_shader.m:463).
- Compute c0 dispatch size and UBO/SSBO tables already match their layout (mtl_replay.m:801-806), as does preserveInvariance (mtl_shader.m:121).
- Own AArch32 route in flight (A32 interpreter + lifter; they have none). Own NSZ/BKTR ingest in Rust. Transactional save data with crash-safe commit (docs/runtime-services.md "Save data"). SetThreadActivity/GetThreadContext3 implemented.
- IPC-level services with an NPDM access list: SDK-version differences do not matter, which is why their SDK 4/6/8/20 audio-command fixes do not apply.
(e) Open questions¶
- Does evaluating
render_condfix the ACNH black image, or only the culled-quad bug remains? Run ac-render's build withNAPPLE_DRAWLOGand a pass dump of the last pass (conditional state, clears) before changing code. AC (their note) needs it by frame 900; ours draws ~1200 frames in 45 s. - Why is our final-pass quad culled when upper-left winding code is equal? Candidates: vertex data from the SSBO (c0 table,
gpu_va), UBO projection, front-face sense afterSR_Y_DIRECTION,depth_modeclip. Needs a CPU evaluation of one vertex. - SMO skinned geometry: is our translation of fa3fa316 numerically equal to Ryujinx's? Proposed oracle: build
NX:dm/third_party/ryujinxoffline (MIT) on the same shader bytes, compare outputs for random inputs. Is that within what the user wants (their repo,Do not run builds of nxnativeapplied to this review only)? - MK8D: confirm with a run that update v1376256 + base + DLC reaches the title through the 64-bit path after
time:u:300; if so, deprioritise the A32 lifter for the user's goal. (All MK8D evidence here comes from logs, not from a run of mine.) - Brief says we have
docs/image-atomic-binding-contract.mdanddocs/geometry-metal-research.md; they are not in this checkout or any branch. Are they on an unmerged local branch? SetThreadCoreMaskwhen ideal core -3 and the current ideal is outside the new mask: Horizon result vs ours (K8)? Needs the Atmosphere source, not read here.- LibHac / SPIRV-Cross / glslang licences are not in nxnative's tree; confirm upstream before any reuse.
Method and limits¶
Read in full: NX:dm/games/{01006F8002326000,0100000000010000,01006BB00C6F0000,0100152000022000}/README.md, NX:AGENTS.md, NX:docs/agents/04-graphics.md, NX:docs/reference/{threads,rendering(137-290,329-560),shaders(1-20,301-520,697-741),rewriter(1-135)}.md parts, NX:docs/development.md (52-73, 281-334), NX:dm/third_party/README.md, game.tsv of MK8D. Headings only: remaining reference docs. Spot-read code: NX:dm/gfx/nvn/nvn_mtl.m at the cited lines. Ours: cited files at cited lines only; large files (mtl_present.m, tex/, a32jit) not audited. No builds, no game runs. Sibling notes used: ac-render-progress.md, ac-303-stall-findings.md, smo-title-screen-visual-bugs.md, mk8d-is-aarch32.md, ios-sim logs (all in the shared notes folder), ACR/MK8/PERF change notes via git show.