Repository navigation
Sync with upstream seedds/nxnative (48 commits, to 2026-10-28) - #2
Merged
Merged
Conversation
Size module tables from the NRO manifest, snapshot initialized data on first load, and synchronize NRO-backed stack lifetimes. Preserve NRO headers during rewriting and isolate NVN bindings by queue across launcher/game handoffs. Read Phyre effects from Virtuos VBF archives, add integer sampler border setters, and register the game profile and 5,752 shaders. Brief Mac validation covers the FFX opening and X-2's first battle; iOS is built but untested. The game note records tests, the Wonder route mismatch and remaining findings. Refs seedds#372 Co-authored-by: Naced28 <105175582+Naced28@users.noreply.github.com>
…e failures by kind The StandardAllocator cap was checked with main rewritten without its cut on Paper Mario: The Thousand-Year Door 1.0.1 (62 GB -> 4.06 GB, frame 1,800 in 75 s) and Absolum 1.1.1. Absolum's .NET garbage collector takes 1.5 GB after malloc, more than the 256 MB the default leaves: the default 4.06 GB aborts at sdk+0x13a684, so its profile gets stdalloc_cap 0xa0000000 (2.5 GB, its cut's size), with which it ran to frame 3,900; the region check computes 2.72 GB from a 64 GB boot. Registered builds are unchanged. regress.py matched a smoke failure the baseline had too as new when the number in its parentheses differed by run (Pikmin 4's reach, "(max 4797)" against "(max 4774)"). It now matches by kind: those numbers are dropped, words and exit statuses kept, so a crash with another signal or another exit status is still new. regress.py check --root /Volumes/S790/harness --games-dir /Volumes/S790/nsp, baseline 3283fee (before stage 1), candidate stage 1, headless, full routes: Pikmin 4 (2 runs each), Super Mario Bros. Wonder, Super Mario Odyssey, Kirby and the Forgotten Land and Xenoblade Chronicles 2 PASS, with the same shaders, interface and [RED] kinds and fps within noise (Pikmin 4's route misses its reach on both revisions). The iOS app builds and links (dm/ios/tools/build_smoke.py).
The test imports image and RET from test_nso_match, which is on the path only when the tests folder is; python -m unittest <file>, as CI runs each test file, failed at the import (since 3e77816). Its own folder goes on sys.path first.
Add the game profile, build-gated allocator cuts, recorded pipelines, and a Mac gameplay screenshot. Read legacy and nested Snowdrop shader records, ignore GLSL-only preambles, and follow checked jump-table index copies to the function boundary. Fold absent secondary blend sources to the host's zero choice so both Metal pipeline paths accept the first level. Validation: full Python tool and graphics checks, native Metal suite, brief World 1-1 movement and coin collection, and five-game quick regressions (Three Houses, Sparks of Hope, Luigi's Mansion 3, Odyssey, and Xenoblade Chronicles 2). Unsigned IPA built; iOS remains unvalidated. Co-authored-by: seedds <seedds@gmail.com>
Pass the platform's Metal target from the NSP builder and skip the other platform's base, fetch, pulling, integer-input and geometry libraries. Keep MSL and reflection in every shader cache entry because cache hits, paired vertex padding and profile tables still need those analysis files. Apply target selection to side libraries, Metal cache prefill and reuse keys. Regenerate the shared chain header and document the cache invariant. Validated with 100 unit/documentation tests, the Python lint/type ratchet, five-game shader/interface and quick-boot regression checks, byte-identical Mac/iOS library comparisons, and platform-switch cache round trips. Co-authored-by: JMRBDev <josemrb99@gmail.com>
Add a standalone diagnostic ZIP collector for logs, versions, device details and settings without game assets. Read packaged-app provenance and shader folder names instead of attributing the collector checkout to the app, and include the bundle's environment settings alongside the player's overrides. Count report.md and truncation markers within the byte limits, and refuse explicit .keys inputs before opening them. App commits remain unknown when the package has no stamp; adding producer stamps remains a follow-up. Verified on a packaged Breath of the Wild 1.9.0 app and a freshly compiled and packaged fixture. The focused collector and documentation tests pass, with no new Python lint or type findings. The standalone collector does not change game execution or the shader chain. Based on PR seedds#465. Co-authored-by: v0lumehi <aljic.zijad@gmail.com>
t_sparse_layout, t_timestamp, t_rt_depth_ro, t_rt_range_shape, t_ub, t_pso_pending and t_vk_desc were compiled by the build check but never run. None goes through mtl_init; each runs in under a second.
Register Absolum 1.1.2 alongside 1.1.1 and update the package and shader version metadata. The SDK and movie modules keep their existing build IDs. Use the existing StandardAllocator symbol gate and stdalloc_cap for the new main build instead of adding another fixed-address cut. Preserve the original 1.1.1 cut, distinguish both builds' addresses, and record the contributor's gameplay evidence and the open cap-only gameplay rerun. Validation: all 414 local Python tool tests (the 7 initially skipped translator cases passed separately with the committed compiler configured), 35 focused documentation/patch/profile tests, symptom-index and diff checks, and four passing GitHub CI checks (lint, host/CPU graphics, sanitizers and the unsigned iOS app). The tool and build-check jobs remained queued in GitHub's Mac runner backlog at merge. No shared runtime behavior changes. Co-authored-by: Hanns Adrian Böhme <me@hannsadrian.de>
…#478) Apply DM_COPY_ROMFS=NO to unsigned IPA packing as well as the Xcode resource phase. Keep add-on content bundled. Carry the requested entitlements in an ad-hoc executable signature for the sideloader to read; an empty DM_ENTITLEMENTS opts out. Validated 43 focused iOS packing, Xcode workflow, documentation and environment tests. No on-device install or startup claim. Co-authored-by: v0lumehi <aljic.zijad@gmail.com>
…s#493) Add --romfs separate to unsigned IPA and prepared Xcode builds. Keep the extracted image available for one-time transfer and compare its size and header/index identity before using Documents/romfs.img. Keep bundle as the default and keep add-on content bundled. Reject separate deployment with extraction cleanup before building, since cleanup otherwise deletes the image the printed push command needs. Reject mismatching images while retaining the existing validated folder fallback; regression tests reproduce both original failures. Validate 451 tool tests (8 optional skips), 38 iOS tests, the actual prepared-project settings in both modes, 178 iOS compilation units, and the lint ratchet. Game regression and build results are recorded in the PR reply. Device startup and sideloader entitlement preservation are not claimed. Co-authored-by: v0lumehi <aljic.zijad@gmail.com>
Hash the parsed Python code for CODE_FP so comments, docstrings and formatting preserve per-shader keys while executable changes invalidate them. Keep the target-selective builds from seedds#275 and regenerate the shared chain header for the integrated source. Checked 111 Python tests, the pinned lint/type ratchet, the Mac host and the full Metal graphics suite. The five-game static comparison built all 66,126 shaders on both revisions with no MSL, base-reflection or interface regressions; 18 geometry JSON changes were chain stamps only. The original PR's paired BotW comment-edit build fell from 246.230 s to 96.259 s, with all 19,592 shader-cache hits and zero retranslations. Co-authored-by: v0lumehi <aljic.zijad@gmail.com>
Reconcile the current seedds#336 geometry, upload and resolution work with seedds#416's lean passthrough and mesh paths on main. Preserve buffer dependencies, query ordering, target selection and chain/cache validation. Keep mesh primitive IDs draw-wide and rebase only local capture reads. Snapshot recursive split descriptors before child draws reuse the shared geometry job, fixing the Octopath first-attack index-range corruption. Retain emitted-vertex feedback, pause/resume ordering and raster discard through the new jobs without recapturing the synthetic raster reader. Co-authored-by: JioChoi <jiochoi7@gmail.com> Co-authored-by: ThrecL <91959522+ThrecL@users.noreply.github.com>
How to play now opens the page, above the games gallery: community Mac apps (NX2Apple, NX Play, NxNative Launcher), then a three-step command-line build and the install step. Known issues is gone (each is in its game note), and the playing details moved to docs/playing.md. The text below the gallery is small print, and the gallery's captions are too (docs_gallery.py), since GitHub keeps its own line height in a README.
…p replaces The host's StandardAllocator cap (stage 1) now does what three games' main cuts did, for every build: Pokémon Legends: Z-A (12 GB -> 3.94 GB; its cut and its function-matched rule go, and with them the profile's patches.py), Paper Mario: The Thousand-Year Door (62 GB -> 4.06 GB; its other cuts and frame-step stubs stay) and Absolum (40 GB -> 2.5 GB with its stdalloc_cap; its patches.py goes). Pokémon Scarlet keeps its cut: no game files here to check it on. Checked with Mac builds from this tree (Mac shaders for the current chain): each game's route from a fresh save into play, headless, on the same build with and without the cut. Z-A 380 s into Lumiose City and a walk (frame 11,100 both), Paper Mario 480 s into Rogueport (28,500 both), Absolum 320 s into the first level, walking and striking (18,300 / 18,600): the same [RED] kinds, alias region use and memory mapped, and screenshots of the same scenes (only animation and fade timing differ). Z-A's 4 GB cut had already been lowered to 3.94 GB by the cap since stage 1.
When a window has no explicit crop, use the recorded VI layer crop for its queued present. Link's Awakening requests this crop for its 1280x720 handheld picture inside 1920x1080 textures. Preserve explicit window crops and check the fallback layer rectangle against the presented texture. Keep regression coverage through the real QueuePresent path and document the general mechanism and the author's iPhone gameplay result. Validation on f838995 plus this change: crop 88/88, NVN 159/159, full Metal graphics suite and 419 Python tool tests pass (16 skipped). Restoring the original present call fails exactly the new layer-crop queue assertion. Five-game comparison: Wonder and ANIMAL WELL pass. BotW's Zora save is missing; a documented Great Plateau route passes the fixed-camera direct presentation control. Scarlet has a prebuild timing flag and an isolated runtime tail that did not reproduce. TotK reaches no frame on either revision, so it has no runtime coverage. All 94,717 shader entries match with no new build or interface failures. Full results are recorded on seedds#499. The target game's 11-minute iPhone run remains author-reported. Co-authored-by: Gabs <40191213+GabZoFar@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Every encoder end goes through m4_end, which called gp_end for any encoder, including the upload, diagnostics and present encoders that are never profiled. gp_end closed whichever main command buffer encoder gp_begin had opened last and wrote its end timestamp through the encoder it was given. An upload flush inside a profiled draw pass sent the render encoder's timestamp selector to the upload compute encoder, and the host aborted on an unrecognized selector (Tears of the Kingdom, DM_NVN_GPUPROF=every:300, one run in four). Where the kinds matched, the pass lost its own end stamp and its GPU time was wrong. gp_begin now records the encoder it stamped, and gp_end ignores any other, so the open pass keeps its label until its own end. General: no profile key or build gate; nothing changes with the profiler off. t_gpuprof ends an upload encoder inside a profiled pass with fakes that, like Metal 4's encoders, answer only their own timestamp selector: 3 checks fail with the exception before the change, 0 of 31 after. Docs checks pass. No regress.py run: its runs do not enable the profiler, so they do not reach the change. Not rerun in the game. Co-authored-by: Rob Young <210684206+QID-Rob@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Carry primitive offsets through recursive range splits and preserve each instance's own numbering. Pass the base in the geometry-info ABI and add it only to the translated guest PrimitiveID; capture and output indices remain local. Rebuild the translator, chain stamp and profile shader libraries together. Cover actual Maxwell PrimitiveID loads with 40 native GPU cases and a failing old-translator control, plus 160 nested CPU splitter cases. Keep current main and the earlier reviewed NieR integration together for the main update. Co-authored-by: JioChoi <jiochoi7@gmail.com> Co-authored-by: ThrecL <91959522+ThrecL@users.noreply.github.com>
…s#530) Every --romfs separate build printed a red line saying the extraction held a RomFS folder and the build carried no image identity, with recovery steps that did not apply. say_push_romfs asked rfs.source()'s romfs.Path whether it was a directory, and romfs.Path shows an image's root as a folder by design, so a real RomFS.img always matched. The check now asks the filesystem whether the image is a regular file, the same test build_ipa.sh uses before it writes romfs.id, so the warning means what it says. romfs.Path is unchanged: bench.py, regress.py and pack_app.py use its is_dir() to mean "a usable RomFS", which an image is. General: no profile key or build gate. test_nsp_romfs now passes a real packed image through rfs.source(), as main does (the old test used an empty file, which romfs.Path does not treat as an image): it prints the issue's red line before the change and passes after. 159 NSP and RomFS tool tests pass. No full NSP build run; no regress.py run, since only a closing message of the script changes. Co-authored-by: Ishtiaq Ul Haq Syed <25985759+ishtiaq156@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
A derived build (a version the profile was not brought up on) has none of the registered builds' fixed-address cuts, only the function-matched ones, so a region those cuts shrank now shows at pack time rather than as an abort on the iPhone (GitHub issue seedds#375). The stamp names the rewrite it measured, so other rewritten modules (a new cut) check again. Tried on Pokémon Legends: Z-A 1.0.0 packed alone: its 12 GB StandardAllocator region, which the host gives 3.94 GB. Smash 1.0.0 does not reach the check (smash_arc.py's table format, a jump table in its main): recorded as open in its note.
Preserve main's allocator cleanup and VI layer crop handling alongside the NieR integration and generalized compute primitive-ID correction. Recheck the merged NVN/presentation paths (169/88 native checks), the 40-case compute-ID GPU replay, Mac host build, 178 iOS source compilation checks, and 25 documentation/patch-table tests. Co-authored-by: JioChoi <jiochoi7@gmail.com> Co-authored-by: ThrecL <91959522+ThrecL@users.noreply.github.com>
Keep the GPU-profiler encoder ownership and RomFS warning fixes from main. Their focused checks pass (31 native profiler checks, 14 Python tests), as do the Mac host build and 178-source iOS compilation check after merging. The compute primitive-ID follow-up compares 86,058 shaders against 2c31212: NieR for mesh eligibility, Octopath II for its large compute split, Xenoblade 2 for another geometry engine, Odyssey for shared NVN state, and Kirby for geometry/upload integration. No shader or interface failures, MSL or reflection changes; all variant differences are chain metadata. The full Octopath first-attack gameplay comparison also passes. The other four gameplay routes retain the earlier integration's validation. Co-authored-by: JioChoi <jiochoi7@gmail.com> Co-authored-by: ThrecL <91959522+ThrecL@users.noreply.github.com>
Preserve c00b81c while completing the reviewed geometry update to main. The incremental NSP, RomFS and documentation tests pass after merging. This packaging-only update does not change the host or shader chain. Co-authored-by: JioChoi <jiochoi7@gmail.com> Co-authored-by: ThrecL <91959522+ThrecL@users.noreply.github.com>
…dds#347, seedds#348) In fullscreen the system shows the layer directly, and at frame latency 1 the display link calls back only one 60 Hz period (16 ms) before the target display time. On ProMotion built-in screens (an M4 Pro here, the reporter's M5 Max) it then shows some presents one 120 Hz refresh late and skips the link's next tick, though the callbacks run on time (16.2-16.6 ms ahead), the present takes about 0.1 ms and the misses do not follow GPU load. Frames that wait for the skipped tick start late, and the frame step read three in a row as load: 1 -> 2 -> 3 vsyncs on frames costing 0.1-0.6 vsyncs, 15 presents a second (TotK here, MK8DX in seedds#348). link_latency asks for latency 2 (33 ms) while front_mac.m's front_fullscreen is set and 1 in a window; a new link takes the current one and logs it, and link_sync sets it again only when the window has entered or left fullscreen. DM_PRESENT_LATENCY=<n> still sets one latency for both. It is a workaround: why the system misses at 16 ms is open (docs/reference/frame-rate.md). One frame more input lag, in fullscreen only; iOS keeps latency 1. Measured (TotK 1.4.3, 180 s fullscreen runs, about 9,600 presents each): latency 1, 68 / 100 presents a refresh late, 70 / 93 skipped ticks, one run with 4 cheap step-ups; latency 2, 17-19 late, no cheap step-ups outside an unrelated game stall; the final code started in fullscreen, 1 late present and 1 skipped tick in 3,724 frames. Reporter's M5 Max: 49 skipped ticks in 2,306 frames at latency 1, 4 in 5,328 at latency 2. A 120 Hz link (DM_PRESENT_LINK=2) avoided the cheap step-ups but showed 102-209 presents a refresh late. Checked: t_present_rescue (6 new checks: window, enter, leave, a link created in fullscreen, DM_PRESENT_LATENCY in both; 49/49, 53/53 with --metal), t_link_ticks, t_present_alloc, t_present_crop, t_present_snap suspend/pacing/copy, test_docs; the Mac host builds. Not checked: entering and leaving fullscreen while a game runs (macOS refused scripted keystrokes); scripts/regress.py (another session's harness held the games, and this session's sandbox cannot signal the harness's process groups).
can_clone found its test file with os.walk, which yields nothing for a file, so since the RomFS became one image (e09ff95) every Mac app pack decided it could not clone: the free-space check asked for a full copy of the game files (40.3 GB for Metroid Prime 4: Beyond on a volume with 26 GB free) although cp -c would have cloned them. A file source is now tested as itself (seedds#518). The RomFS probe also decided for the rewritten modules, the shader libraries and the DLC, while the pipeline archive had its own. As cp -c copies whatever it cannot clone, the probes decide only the free-space check: each source now gets its own, and the check counts only what will be copied (the modules were never counted). Tests: a real-clonefile probe of an image, a folder and an empty folder, and a pack whose RomFS clones while the rest is on another volume; both fail on the old code. test_nsp_mac_app, test_bug_report, test_nsp_incremental and test_docs pass. No real game packed. Co-authored-by: Lilun Xu <173143200+lx7720@users.noreply.github.com>
PR seedds#397 correctly identifies instruction-like bytes in NRO metadata. Its linear-scan cutoff still lets per-function analysis reenter the header when code precedes the first unwind entry, failing with "jump table 44". Keep the shared data-block exclusion already on main and extend the real rewriter regression to cover this path. Document that both scans and function analysis must exclude metadata. The new test fails against the original PR and passes with the existing implementation; 108 related and documentation tests pass. Production code is unchanged. Refs seedds#397 Co-authored-by: v0lumehi <aljic.zijad@gmail.com>
The session used AVAudioSessionCategorySoloAmbient, which iOS silences with the ring / silent switch: every game was mute whenever the phone was set to silent, though the volume was up (seedds#155's commenter has to toggle the switch). front_ios_audio_session now sets Playback, the category for sound central to an app: the switch no longer mutes it, other apps' audio is still interrupted, and the host still suspends its output in the background (no background audio mode is declared). The volume buttons still silence the game. General: the session is the app's, so this holds for every game; the Mac has no audio session. docs/reference/audio.md has the entry, with the symptom index regenerated, seedds#155 linked and a line in Breath of the Wild's note. The iOS compile check (178 files) and the documentation tests pass; not yet heard on a device with the switch on silent. Refs seedds#155 (seedds#414) Co-authored-by: Max Davidson <davidsonmax@gmail.com>
The idle-release test assumed dispatch_after had delivered its callback after sleeping for 1.1 seconds. A delayed callback on CI left the fake player's stop count at zero even though the adapter stopped it correctly once delivered. Advance a virtual monotonic clock and deliver scheduled callbacks on the real serial queue. Cover the idle deadline explicitly and retain pulse renewal, stale callbacks, failure recovery and routing checks. Validated with the complete host unit suite, ASan/UBSan and TSan for the Apple haptics test, 100 repeated adapter runs, and documentation/NRO tests. Mutation checks catch missing, early and stale idle stops. No game runs are needed for this test-only scheduling change.
Add opt-in quick/full validation records and show them in regress.py list, without treating validation metadata as a profile input. Require successful boot runs as well as PASS/CHANGED: an unchanged baseline crash is not proof that the candidate booted. Derived build profiles cannot validate repository profiles, and completed reports survive a validation metadata write failure. Exercise a full ANIMAL WELL check --record on Apple M4 Pro / macOS 27.2: 46 shaders unchanged, 60 fps, no new RED lines and screenshots in tolerance. Record the tested chain and document the result. Python tools (478 tests, 16 skipped), Metal graphics, docs and the lint ratchet pass. Co-authored-by: v0lumehi <aljic.zijad@gmail.com>
…ale one The tests' rule for game_profile.h had no prerequisites, so a header from an older game.py was kept once it existed: after game.py added DM_GAME_STDALLOC_CAP, t_heap_size failed on the missing define until the header was deleted by hand (CI starts clean and never saw it). The rule now runs on every make (FORCE) and defers to the host Makefile's game_profile target, as the host build does; game.py writes the header only when its content changes, so an unchanged header rebuilds no test. The libvpx rule's FORCE_VPX is folded into the same FORCE target. Closes seedds#466 Co-authored-by: v0lumehi <aljic.zijad@gmail.com>
Patch libraries can reference unchanged shader groups in base containers. Resolve chunk IDs across the ordered container set and extract only the winning library, including unnumbered and lowercase patch suffixes. Check encryption when selected data is read: refuse group-only encrypted containers without a key, while leaving fully replaced encrypted libraries unread. Add ten synthetic archive-resolution tests and document the fix. FINAL FANTASY RESONANCE's two decoded archives remain byte-identical: 74,244 entries and 73,496 distinct shader keys. Focused tests, Python tool tests, GPU tests and lint/type checks passed during review. The full regression harness remains incomplete (cold shader rebuild); gameplay was not rerun. Co-authored-by: Favour Okwara <favourprogrammer@gmail.com>
When the regions made after a StandardAllocator region need more room than the 256 MB the host's cap leaves them, the check now sets stdalloc_cap in the provisional or derived profile instead of only naming the value: the alias region less the regions before it, those after it and the same 256 MB for regions made later in play. A value set by hand is checked, not replaced; one an earlier check set is worked out again. Absolum 1.1.1: 2.5 GB and 2.72 GB both play its 320 s route to frame 18,600 with no red line; a provisional pack (with its game_env) sets 0xa2000000, 2.53 GB, between them.
…thread (seedds#471) mtl_read_texels decided on its own which textures take their content from guest storage, and that copy had drifted from tex_mtl_'s: it left out sampled textures of a sparse virtual pool. Those went through tex_mtl, which uploaded them on the caller's thread, and up_owner_check aborted (Tears of the Kingdom on an iPad Pro M5, thread bake::ModuleMgr, a few seconds after the app came back from the background). The storage path also read a sparse texture at its virtual address, which faults where nothing is mapped. One predicate, tex_from_storage, now serves both, and mtl_read_texels gathers a sparse texture through its page table (nvn_sparse_copy, unmapped pages as 0) before deswizzling. The up_owner_check abort stays. t_readback reads sparse textures over mapped and unmapped pages on another thread and on the submit thread. Co-authored-by: Ink <347642667+Inksdx@users.noreply.github.com>
A provisional split of Pokémon Legends: Arceus 1.0.2 counted all 678 GFPAKs
under bin/archive as unreadable ("entry 0 has compression 3 (Oodle), which
this reader does not decode") and left their shaders out: every entry of
Arceus's GFPAKs is Oodle Kraken, where every entry of Sword's is LZ4.
gfpak_members now decodes compression 3 with the game's own decoder through
oodle(), as Trinity packs and PKZ archives are. profile_guess.py
build_sources counts the GFPAKs that hold an Oodle entry (oodle_gfpak), so
oodle_packs is set from the files and the NSP script provides
DM_OODLE_HOST / DM_OODLE_MODULES for the split. Nothing is keyed to a title
or build: any GFPAK with Oodle entries takes this path; LZ4-only games count
none and read as before.
Checked: on Arceus (reporter, Linux emulator of the game's decoder) the split
reads all 678 GFPAKs and finds 12,851 shaders, 69 more. On the Mac, a GFPAK
of 300 real Kraken streams from Pokémon Scarlet's packs (28 MB raw) decodes
through gfpak_members and the Mac host byte-identically with Scarlet's and
Z-A's OodleLZ_Decompress, and build_sources sets oodle_packs for it but not
for an LZ4-only GFPAK. dm/gfx/tests/test_gfpak.py covers each compression.
Arceus itself was not run on the Mac.
Co-authored-by: Aman Singh <40149189+amansingh909@users.noreply.github.com>
Persona 4 Golden 1.0.2 (010062B01525C000), SDK 14.3.0, on NVN with CRIWARE: 26 shaders, 8 vertex and 18 pixel, all BNSH entries under sysdat.cpk, and no shader pairs and no compute shaders. On the Mac it runs from boot through the opening movie, the title screen, a new game and the in-game notices into the first Velvet Room scene: 60 fps (frame time p50 16.66 / p95 17.01 ms), 243 render passes a frame in the busiest part of the route, and no [RED] line over a 9,900-frame run. Resident memory 1370 MB with 1672 MB of Metal allocations. The RomFS is 12 files: eleven CPKs at the root plus data_cri/sound, which the packer extracts as a 9.7 GB image that the host mounts directly. main carries 471 MB of bss and declares no system resource, so the profile keeps sys_resource 0x0 and the 3.5 GB layout. The 26 shaders are grouped by their CPK (shader_groups /sysdat.cpk/=sysdat) rather than left in "other". pso_manifest.tsv holds 44 recorded lines (21 shaders, 23 render pipelines) from an empty save over the smoke route. dm/gfx/tests on this Mac: every binary passes except t_pso_bundle, which fails the same 10 of its 52 checks on main with the same profile, so the failures come from this machine's Metal 32023.883 on an M5, not from this profile. The touch layout is untested and no IPA was built. Co-authored-by: Ian Franklin <ian.franklin@outlook.com>
…nd survives their removal (seedds#476) exFAT and FAT have no extended attributes, so macOS keeps a file's (a download's quarantine flag) in an AppleDouble `._<name>` beside it and deletes it with the file. Two things went wrong on such a drive: - scan_nsps listed `._Update [<title ID>800].nsp`, 4 KB of metadata whose name carries the title ID, as a second update; an untagged update then read as two and was left out. Names starting with `._` are skipped. - Deleting `x` takes `._x` with it, so shutil.rmtree's later unlink of the listed `._x` raised FileNotFoundError, which before Python 3.13 ended the removal and left a half-deleted folder. The script's rmtree passes ENOENT through an onexc hook (Python 3.12 is the floor) and raises every other error. Nothing is keyed to a game. On top of the PR: the pre-3.12 onerror branch is dropped, the test's stand-in unlink joins the partner's directory (it was correct only for the dir_fd walk), and docs/reference/packing.md has the entry, linked from docs/development.md and the symptom index. Checked: on an exFAT disk image (hdiutil -fs ExFAT) main's scan_nsps listed the `._` copy as an update and deleting `a` removed `._a`; the patched scan finds one update and rmtree removes a tree holding 55 `._` files. test_nsp_external_drive.py passes on Python 3.14 and 3.15, all 148 test_nsp_* and test_docs.py pass, and the pinned lint ratchet reports 0 new findings. Python 3.12 was not available here; the author ran the tests on 3.12, where the rmtree and scan tests fail without the change. Co-authored-by: v0lumehi <aljic.zijad@gmail.com>
title_of falls back to the [title ID] in a file's name when the file holds no ticket, so scan_nsps took any file with a game's extension and tag for one of its packages: an AppleDouble `._` copy on an exFAT drive (seedds#476), a failed download saved under the game's name, a file cut off before its header. One such file beside an untagged update made it one of two and left it out. is_package checks what nx_extract's OpenNsp opens: an XCI / XCZ by the card header's HEAD at 0x100, else a PFS0 (NSP, NSZ). scan_nsps skips any other file with a line saying why; `._` files are still skipped without one. Nothing is keyed to a game. Checked: dm/tools/tests/test_nsp_scan.py (an XCI base without a ticket, a tagged HTML page and a truncated XCI beside a real update, a quiet `._` skip) fails without the change and passes with it; all 150 test_nsp_*, test_docs.py and test_bug_report.py pass; the pinned lint ratchet reports 0 new findings. is_package accepts all 339 packages on the T7 drive (336 NSPs, 3 XCIs); no NSZ / XCZ there, those are covered by the tests only.
dm/tools/docs_patches.py lists, per game, the rewriter's patches of its builds (CUTS, OBS, FRAME_STEP sites, MATCH_CUTS, CAPABILITIES), the host rows keyed by its build IDs, the SDK cuts by sdk build, translator rules keyed by one shader, and the profile keys that switch host behaviour. Each patches.py gets a GENERALIZE note on whether a general rule could replace it. test_docs.py checks the page is current.
docs_patches.py walked dm/host with rglob, so the git-ignored build output in dm/host/gen (game_profile.h's build check) entered the page wherever the host had been built: the committed page carried a TOTK row a clean checkout cannot produce, and test_docs.py failed on any machine with a different build. It now lists the host files with git ls-files, as env_switches.py does, and the page is regenerated. The 4 findings lint-python reported on 68fbe84 are fixed: load() checks the spec and its loader before using them (as regress.py does), and page() drops the unused by_id.
…ript 68fbe84 reached main with 4 new ruff/pyright findings: the guide's pre-PR list never named lint_python.py, and the system Python has neither tool, so the check stops at a [RED] line unless it runs from a venv with lint.txt. The list now names it, where the venv goes, and that a generated page must not read git-ignored files (CI compares it on a clean checkout).
…e path components (PR seedds#513) On Horizon a FileHandle is a pointer to the SDK's FileAccessor, so its low bits are clear, and Metroid Prime 4: Beyond's file device masks them off (handle & ~7) before ReadFile. The host's RomFS image handle kept the entry index in its low bits, so entry 7 was read as entry 0: a 10-byte read of another file, then a null pointer at boot. The guest now gets the host's handle shifted left by 4 (FH_OUT), and each call that takes one shifts it back (FH_IN); the image flag moved from bit 62 to bit 58, so the guest still sees it at bit 62. Horizon's file system accessor replaces every backslash in a path with a slash before it normalizes the path (FileSystemAccessor::SetUpPath), on every mount but the PC host's; Metroid Prime 4 names its files rom:\StartupUI.pak. Each guest path resolver (img_path, host_path_ex, set_guest_name, dir_snapshot) converts them first, so overlay folders, ".." and guest names see the same path. PR seedds#513 taught two of the parsers instead. t_fs: 10 new checks (masked handle on an image entry, backslash paths on a folder with an overlay, an image, an image with an overlay, directory listings, a save's create, rename and guest name): all fail before, all pass now. t_fs_commit_list decoded a handle as an fd and hung with any shift; it now uses FH_IN. All host tests and tsan-threads pass. Reference entry in docs/reference/services.md. regress.py check on 5 games (Mac, M4 Pro, shared with three other harness runs): ANIMAL WELL PASS; Pokemon Scarlet reached the end at 29.9 fps as before (its "new" red lines are shader libraries missing in both runs); Tears of the Kingdom and Breath of the Wild did not run (the baseline's shader build stopped); Super Mario Bros. Wonder frame p99 16.9 -> 47.6 ms under that load, unexplained, to re-run on an idle machine. Co-authored-by: Lilun Xu <173143200+lx7720@users.noreply.github.com>
The tools read NSO and NRO modules through ten copies of the same loader, and each trusted the header: a 256-byte file could make it allocate 8 GiB, and a segment shorter than its size shrank the image (python-lz4 returns fewer bytes without an error, and the slice assignment then shifted the later segments), with no error. dm/tools/nso.py is now the one loader (load, read, cli_read; nso.Error is a ValueError), and patch_nso, nso_code, insn_census, nso2elf, loader_census, nso_syms, shader_split, uepak, gl_shaders and profile_guess use it. It accepts what Horizon accepts and checks it the same way, from Atmosphere's loader (ldr_process_creation.cpp) and nn::ro (ValidateNro): NSO offsets on pages, text at 0, ro and data in order without overlap; an uncompressed segment read at its size; a compressed one decompressing to exactly its size; a segment's SHA-256 checked when its flag is set (every retail module: 93 of 93 surveyed, 279 of 279 hashes matching), so damaged bytes of the right size are caught too; an NRO in whole pages, contiguous to its size. Beyond Horizon, so a small file cannot claim gigabytes, a compressed segment is no more than LZ4 produces from its stored bytes (255 per byte) and the image, gaps included, no more than that of the file. A zstd main and a compressed NRO are an error naming the format. bss is never allocated (nso.py's own output gets it as a sparse tail). Each tool's command line, and the NSP script for the modules it reads itself, stops on a damaged module with a [RED] line. nso.py joins the rewrite and shader-stage cache keys, regress.py's rewriter files and build_src.sha256. Checked: 121 real modules (93 NSOs of 26 games, 28 Portal NROs) load into images byte-identical to the old loader's, none refused; patch_nso on Metroid Dread's, Wonder's and Monster Hunter Rise's mains and a Portal NRO differs from before only in build_src.sha256. The issue's huge-segment.nso is refused with nothing allocated; its short-segment.nso now loads its full image, as Horizon would. test_nso.py covers each rule; 71 of 71 tool and gfx test files pass; the lint ratchet has no new finding. regress.py check and dm/ios/tests were not run.
Consolidate seedds#126, seedds#289 and seedds#304 for title 0100B8A026F14000 and main b7f965b9d7227db8e29f04e84ea7331b. Keep one profile with build-gated allocator and frame-rate registrations, the complete shader map, merged manual facts and recorded prewarm seeds. Preserve each contributor's Mac/iPhone testing and its limitations in the game note. Normalize update 1.0.1 to v65536 and use the registered rhi.SyncInterval write rather than a display-interval override. Keep independent translator work separate from the profile. Validation: rebased Python tools (509 tests, 16 skipped), 78 focused profile/docs tests, FPS build-gate/override/startup tests and complete shader-key verification. The initial base also passed host unit and Metal graphics tests, the regional Mac host build and 178 iOS source compiles. Full Mac/iOS shader validation and the ANIMAL WELL regression control are queued behind the shared compile window; regional gameplay was not rerun. Co-authored-by: huangzhuangchao <95277145+huangzhuangchao@users.noreply.github.com> Co-authored-by: willreg <47594112+willreg@users.noreply.github.com> Co-authored-by: 4202217 <208370207+4202217@users.noreply.github.com>
…ds#487) An Intel Python under Rosetta, a shader translator without a .NET runtime of its slice, a missing iOS SDK or a missing glslang each stopped the build late, the translator ones as an empty `xlate_source` at the shader step. - check_native_python stops under Rosetta (sysctl.proc_translated): the universal translator it starts runs as x86_64 and finds no x86_64 .NET (reproduced with arch -x86_64: exit 131, empty stdout). - check_prereqs starts the translator once with --source-sha (check_translator), asks for glslangValidator, and for an iPhone build checks the iOS SDK before the Metal check (check_ios_sdk; the Command Line Tools case named apart). - own_compilers.py does not ask a Mac-only shader build (DMSH_TARGETS=mac) for the iOS Metal compiler, so a Mac build needs no iOS platform. - Open: dmsh_chain.py tools_now still drops the translator's exit code and stderr; fixing it changes the chain version (docs/reference/packing.md). Tests: test_nsp_env_checks.py (new), test_own_compilers.py, test_nsp_mac, test_nsp_progress, test_nsp_dotnet, test_nsp_incremental, test_nsp_romfs, test_xcode_workflow, test_docs; lint_python.py 0 new. Raging Loop --platform mac through the script: green. regress.py check --quick: ANIMAL WELL PASS (46/46 shaders, 0 changed MSL, 59.7 -> 59.6 fps, 0 new RED). Co-authored-by: v0lumehi <aljic.zijad@gmail.com>
Add the game profile, shader inventory, title smoke route, Mac gameplay screenshot and port notes. Decode loose Monolith HCPS, XBC1, DRSM and compressed effect containers through the existing recursive reader. Retire cached descriptor views when their texture is finalized, while preserving copied NVN metadata and fence-safe late command replay. This removes the streamed texture retention found during the opening battle. Validation: full Metal graphics suite, Python graphics/tool/docs checks, 15,129 Mac and iOS shaders, all 10,681 Mac pipeline pairs, brief gameplay through the opening boss and Colony 9 combat, and a CRC-verified unsigned 13.2 GiB IPA. Five-game regression details are in the game note; Xenoblade 2's timed-route screenshots and footprint compare different scenes and remain inconclusive. No iPhone or save/reload validation is claimed. Co-authored-by: seedds <seedds@gmail.com>
… address space (GitHub issue seedds#483) Shaking the overalls bush in the opening quest wrote to 0x78 at main+0x2c534a8: a UI node context (Moria::Services::UI::Shared::Nodes:: Context, main+0x2c4a228) reserves 576 KB and 256 KB of address space, never checks the reservation, and pushed its first entry onto a NULL array. Measured with a 64 GB alias region and DM_REGIONS, the opening quest's regions end at +4.515 GB, past the profile's 4.375 GB alias region; on the profile's layout only 110 of 147 contexts got their range. The largest region besides Snowdrop's 3 GB is a 1.06 GB pool of 4,194,304 272-byte slots built by the memory system's startup (main+0x94364). Nothing allocates from it: only that startup and its teardown name the pool or the default-pool slot it fills, and nothing was ever committed in it. A build-gated cut (+0x94354) gives it 65,536 slots (17 MB). The regions then end at +3.455 GB, every context gets its range, and the overalls route picks them up without a crash (Mac, headless, past frame 5100). The save-loading crash in the issue is likely the same cause but was not tested (no such save); docked coin colours are listed as open in the game note. Tests: test_docs and test_patches (26 tests) pass.
DM_NVN_CAPTURE=<frame>:<file> writes one frame of an NVN game to a file: the memory pools and the regions records point to, the objects and registries, textures whose content lives only in Metal, each submission's command segments, the present, and the live run's pool block hashes and presented pixels. Pointers are stored as region offsets and object indices (cap_rec_fields), so dm/gfx/tests/nvn_replay.m replays the frame in a process of its own, without the game, and compares the result with the live run: memory hashes, the presented frame's SHA-256 and, with the new LPIX chunk, its pixels. --repeat n runs n fresh replays; --max-pixels n accepts a frame that differs from the live one in at most n pixels and prints the count, the largest byte difference and the box. tex_fit made a compatible view of a view taken from the view cache; Metal's shader validation reports such a view as not resident (BotW: a 64x64 cube read through a 2D-array view). The view is now made from the root texture, with the level and slice offsets added up (t_tex_fit_root fails before and passes after; rendering.md "Compatible views made from the texture under a view"). Open (BotW note): fresh replays of one BotW outdoors frame differ from the live frame and from each other in 3 to 124 pixels of colour targets 1 and 3 of the G-buffer pass, with segmented submission on or off; textures, depth and per-draw dumps are identical. The cause is not found. t_capture 77/77, t_tex_fit_root 9/9, t_capture_live 2/2, test_docs, test_env_switches, docs_symptoms --check, iOS compile check (179 files). regress.py check --runs 2 (impact: BotW, TotK, Scarlet; plus ANIMAL WELL, Wonder): ANIMAL WELL and Wonder pass; no shader, MSL or interface change in any game. The flags on the other three are the test Mac's, not the change's: one Scarlet candidate run fell to 14 fps after its window's display link stalled for 1 s twice (an occluded window, frame-rate.md; GPU 3-7 ms a frame); BotW's outdoors route misses frame 2200 at 20 fps on both sides, with screenshot differences below the baseline's own; TotK's new red lines are missing-library names that differ from run to run, as in the baseline, and its p99 rose in one of two runs. Co-authored-by: v0lumehi <aljic.zijad@gmail.com>
…edds#307) Every new graphics test edited the same lines: the run: line in dm/gfx/tests/Makefile, its recipe and two lines in dm/gfx/tests/.gitignore, so any two branches that each added a test conflicted there. make run now runs every t_*.c / t_*.m but those NOT_RUN names, each with its reason (helpers linked into other tests, fixtures other tests build, t_gpuprof from CI's CPU subset). It builds them first, in parallel with -j, then runs them one at a time through check_t_<name>: ./t_<name> by default, with the environment a RUN_ENV beside the build rule gives it, or a check_ recipe of its own for a test that runs several ways. The Python tests become check_test_dmsh_pull and check_test_tbdr_budget. .gitignore ignores t_* without an extension and every .dSYM, plus nvn_replay, the one tool built there. t_dirty_slots and t_dirty_race now depend on the profile header dm.h includes; a parallel build from a clean dm/host/gen could compile them before it existed. dm/tools/tests/test_gfx_tests_makefile.py (no compiler or GPU) checks that every test source has a build rule, NOT_RUN names existing sources, no hand-kept run: list comes back, every binary the Makefile compiles and its .dSYM are ignored, and no tracked file is. Rebased on d9c2d5e: t_capture, t_capture_live and t_tex_fit_root (seedds#473) keep their check_ recipes without run: lines; nvn_replay gets its .gitignore line and the ignore check covers every compiled binary, not only t_* (it fails without that line). make -n -B run executes the same 104 test commands as before (sorted sets); make -C dm/gfx/tests GAME=010015100B514000 -j8 run from a clean dm/host/gen passes (1:47); test_gfx_tests_makefile, test_lint_python, test_docs. No runtime code changes, so no regress.py run. Co-authored-by: v0lumehi <aljic.zijad@gmail.com>
…nd iOS (seedds#541) macOS and iOS take both buttons as system gestures: Home on a Pro Controller opens the Games app (macOS) or the Games overlay (iOS) over the game, and Capture takes a screenshot on iOS. The host gives them no function, so both front ends now set their preferredSystemGestureState to disabled on every controller they attach: front_mac.m in the merged mode and per player, DmGamepad.m for iOS's single player. Co-authored-by: Peter Kmet <55005408+peterkmet@users.noreply.github.com>
…f fixed 50 ms (seedds#445) SwiftUI reports the grouped Form's scroll geometry on a later pass, an estimate first and the measured rows a few ms after it. On a slow runner the fixed 50 ms wait could read the estimate (CI: height 1282 = 660 + the estimate), so the resize to that height did not fit. Each step now runs the loop until the report meets the step's expectation and has held for 0.2 s, at most 5 s; the checks are as strict as before (a 16 pt misfit still fails all four). Each measurement also runs in its own autorelease pool, so earlier hosting views no longer stay alive and lay out their Forms again on every change of window.advanced.
Conflicts: README.md keeps the fork's; front_ios.m keeps the data help screen; main.m keeps both the split-build data roots and upstream's romfs.id check; dmsh_chain.h is recomputed for the merged tree (same sha256 recipe as dmsh_chain.py version()).
… version Upstream's committed dmsh_xlate.dll is an arm64 PE (machine 0xaa64), which dotnet on Windows x64 refuses to load (the assembly architecture is not compatible with the current process architecture). Rebuilt from the in-repo source with dotnet build (machine 0x14c, as before the sync); Ryujinx DLLs stay upstream's. The lock's dmsh_xlate.dll line and DMSH_CHAIN (4e91e9103b44) follow. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
KillingStalking
pushed a commit
to KillingStalking/NXNativeWindows
that referenced
this pull request
Nov 13, 2026
The walk from the load back to the bounds check noticed copies and masks but no other write: cmp w18,zenvyzenshiro#4; b.hi; add w18,w18,#1; ldrsw x18,[x4,x18,lsl zenvyzenshiro#2] read entries 0 to 4 while the code uses 1 to 5, so one case's target was missing with no sign of it. A site with a write of the index after its check, or a call with a caller-saved index, is now refused, as jump_adr_offsets and half_count already refuse a write. A refusal goes on to the other recognizers and ends in the jump table assertion. Writes before the check do not count, which keeps the sites check_before_copy takes. A write that keeps the value, such as sxtw x0,w0, is refused too; no module on the drive has one. Checked: test_jump_copies.py (the new cases fail on the previous rewriter). Of the 345 unique modules on the drive, old and new recognition are the same on 281, and 60 more mains were scanned on the previous code with no site this refuses. That includes Smash 13.0.5, EA SPORTS FC 27 and Well Dweller. Four could not be checked: New Super Mario Bros. U Deluxe's main, sdk and rtld fail alike (no profile), and Smash 1.0.0's main stops at a table the game's note already lists. No regress.py run: nothing changes in the modules checked.
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.
Merges seedds/nxnative main (48 commits after the 2026-10-27 sync in #1), plus a Windows fix that #1 needs.
Conflicts resolved:
README.md(the fork's),front_ios.m(the fork's data help screen),main.m(both the split-build data roots and upstream'sromfs.idcheck).Fix for main as of #1: upstream's committed
dmsh_xlate.dllis an arm64 PE (machine0xaa64).dotneton Windows x64 refuses it ("assembly architecture is not compatible with the current process architecture"), so the shader translator did not run. Rebuilt from the in-repo source withdotnet build(machine0x14c, like the DLL before the sync). The Ryujinx DLLs stay upstream's. The lock'sdmsh_xlate.dllline andDMSH_CHAIN(4e91e9103b44) follow.Checked on Windows 11 x64 (.NET 10.0.403, Vulkan SDK spirv-cross):
dmsh_chain.pyprints4e91e9103b44, matching the header.dmsh_chain.py --check-tools: DLL fingerprints,xlate_sourceand spirv-cross match the lock. Only the two Metal compiler lines differ, because Metal Developer Tools for Windows are not installed on this PC (the lock's Metal lines are carried over, not re-measured).win/tests/test_win.py: 11 tests OK.🤖 Generated with Claude Code