Repository navigation
Release 0.9.0: nxnative merge up to 2716f78, upstream's cheat engine - #29
Merged
Merged
Conversation
…the 13 fixed frame-limit rows removed (issue seedds#635) The rewriter finds each TAutoConsoleVariable the host may write from the engine's own registration code: the variable's name (UTF-16 or UTF-32), the adrp + add that loads it into x1, and the first call after it. A bl is UE 4.18's constructor, with the object in x0; a blr is the console manager's register call (UE 4.2x and 5), and the object is the one the returned value pointer is stored into. A name registered at two objects gives none, with a [RED] reason. It writes UE_CVAR:<name> rows into main's fixups for t.MaxFPS, rhi.SyncInterval, nvn.SyncInterval, r.Streaming.PoolSize and Project.FrameRateLimit. The host reads them (loader.c): hle_fpslock.c raises the frame limit and the present interval from them for fps_target, and hle_uecvar.c the texture pool, with its search code gone. This replaces the fixed k_locks rows of OCTOPATH TRAVELER 0 and II, DQ7 Reimagined, FINAL FANTASY RESONANCE (global and Asia), SMT V Vengeance and DQ XI S. The new profile key ue_fps_cvar names the variable to write (default t.MaxFPS; SMT V's Project.FrameRateLimit). Checked offline over 61 mains: the search finds exactly the objects of the 13 removed rows, and nothing in non-Unreal games. The rewrite cache keys (NSP script, regress.py, build_src.sha256) now include ue_cvar.py, ue_malloc.py and loader_census.py. Open: OCTOPATH TRAVELER's inlined registration.
…in the build folder regress.py took any <id>_build/profile/<id>/game.tsv as a derived profile and ran it instead of dm/games/<id>. The NSP script leaves a provisional profile there from a game's first packing, before its profile is added, so 38 of the 57 games on the game drive were tested with their guessed profiles. OCTOPATH TRAVELER 0's had no tex_dyn_slots (three particle shaders refused, with red lines), no fps_target and no depth_mode. A build's profile now runs only when it is derived (the NSP script's <id>.derived.key beside it) or the game has no profile in dm/games. The games line marks such a game with "the build profile". On the game drive that leaves Mario Kart 8 Deluxe (derived) and Atelier Ryza (no profile yet).
… its toolchain (GitHub issue seedds#717) Each Xcode downloads and uses its own Metal toolchain, whatever the macOS version, so with Xcode 27.2 selected -downloadComponent fetched 32023.922 again. The message now names the selected Xcode and says to install 27.1 beside it, select it, then download its toolchain; README links Apple's download page instead of the App Store. The lock stays at the one tested compiler.
…(PR seedds#425) .clang-tidy runs the bugprone checks and clang's static analyzer (core, unix, osx, nullability, two security checks) over dm/host and dm/gfx, with each excluded check's reason on its line. dm/tools/lint_c.py builds a compile database from the Makefiles' dry runs (196 sources) and counts findings per file and check against dm/tools/lint_c_baseline.tsv (273 findings in 140 pairs, LLVM 23.1.4, current main). The lint-c workflow downloads that LLVM release (sha256 pinned) on xcode-27. The ratchet works like lint_python.py's: a new finding fails (fix it, or // NOLINT a false positive with a reason), so does a fixed one still listed (tidy --update only shrinks), and a pull request's baseline may not grow over its base's (--against), unless LLVM_VERSION was raised (--rebaseline). Left out of the PR: the clang-format report. .clang-format cannot state the house style (one statement per line), and a root .clang-format would let editors' format-on-save and git clang-format rewrite dense lines. Co-authored-by: v0lumehi <34629096+v0lumehi@users.noreply.github.com>
…ge per PR (PR seedds#439) make coverage in dm/host/tests and dm/gfx/tex/tests rebuilds the tests with clang's source-based coverage into their own folders (dm/sanitizers/coverage.mk), runs them with continuous-mode profiles (children that end with _exit still count) and exports llvm-cov's lcov. coverage.py measures the tool tests over dm/tools, dm/gfx/tools, dm/games and scripts, subprocesses included. dm/tools/coverage_report.py writes the job summary: totals per area, the largest files and, on a pull request, the changed lines the tests run and those they do not. The coverage job in tests.yml is report only and uploads the raw reports. Changed from the PR: the C line counts are llvm-cov's own (the DA lines of -format=lcov, which llvm-cov show marks) instead of a rebuild of its line logic from the JSON export's segments; both give the same counts on every file of the host and texture tests (42 files, 0 lines differ). Today: host 61.7% of 7,883 lines, CPU textures 85.4% of 240, Python tools 51.9% of 15,023. Co-authored-by: v0lumehi <34629096+v0lumehi@users.noreply.github.com>
…he test binds its loop variable ue_cvar.registered_at decoded add_imm(word(j)) twice, and pyright could not tell the second call was not None; it is decoded once now. test_ue_cvar's lambda bound base_ctor by reference (B023); it takes it as a default now. Neither changed behaviour: the lambda ran within its iteration.
…sue seedds#700) A native-texture GetOutputBuffer returned its slot inside the call, the host decoded the next packet into it at once and announced it, the player's decoder thread acquired it again, and the player's own release of the old picture then freed the new one: a picture one slot cycle (16 frames) ahead, then back. A rendered slot now waits for the client's release; until the decoder has seen its client release a rendered slot, it comes back at the client's next GetOutputBuffer instead (players that never release). Metroid Dread on the Mac, 75 s: 15 jumps of 533 ms before, none after. BotW regress check PASS. Fixes seedds#700 Co-authored-by: wriver0s <37092604+wriver0s@users.noreply.github.com>
… 1.6.0 ran a job twice (issue seedds#251, PR seedds#562) Breath of the Wild 1.6.0 crashed on the Mac 10 to 60 s into its first scene (10 of 10 runs, in h_nvnBufferGetAddress and elsewhere). Its job queue takes its lock with ldxr; cbnz; stxr; cbnz and no barrier after the loop: an exclusive load without acquire ordering. Armv8 lets the queue reads after it be satisfied before the lock is held; Apple cores do it, so two workers popped the same job and built their draw lists into one arena. patch_nso.py (acquire_lock_sites) turns every such acquire into ldaxr, found by its instruction shape in every module, with no address list and no build gate; a loop followed by dmb ish or dmb ishld is already ordered and left alone (Tears of the Kingdom's 32 and Super Mario Bros. Wonder's 33 loops of this shape all are). The statistics line counts the rewritten ones as acquire_lock. docs/reference/threads.md has the entry, the BotW note the finding; test_acquire_lock.py checks the shape on hand-assembled words. Reach over the local games: only Super Mario 3D All-Stars' main (7 sites, no repository profile) rewrites differently: 14 bytes, the 7 sites and their 7 spin-wait copies. Every other local game, BotW 1.9.0 included (no loop of this shape), rewrites byte-identically. 1.6.0 is not on this Mac; the contributor's runs: 10 of 10 crashed before, 0 of 7 after (up to 900 s). Regression (1 game, narrow reach): BotW 1.9.0 full check against e513bfe: PASS (19592/19592 shaders, 0 changed; 110 s route, fps 59.1 → 58.5, no new RED). Co-authored-by: Suraj Mandal <11650177+surajmandalcell@users.noreply.github.com>
…channel has an output (GitHub issue seedds#715) Super Mario Odyssey 1.4.1 crashed entering a Sand Kingdom pipe with rumble on: the SDK's own call opened the hid service, which sm refuses, and read the null service object (sdk+0x24254c). The host now answers it from vib_targets, as GetVibrationDeviceInfo reports the device. Co-authored-by: Wjouter <34310151+Wjouter@users.noreply.github.com>
…e capped at 1080p (PR seedds#367, GitHub issue seedds#705) A TV gets the game's view through an external display scene: 16:9 fills it, the game switches to console mode (operation mode notification, as a Switch on its dock), and the iPhone or iPad keeps the pad. Unplugging moves the view back and restores the earlier mode. An app built with the iOS 27 SDK is offered the TV scene only after it registers a scene accessory (registerSceneAccessory); the manifest entry alone is ignored and iOS mirrors the whole screen, pad included (issue seedds#705). The Info.plist entry stays for iOS 26. The TV picture is at most 1920 pixels across the 16:9 picture (taken from the picture, not the screen, so a display of another shape keeps the full 1080p): the game renders 1080p docked, and a 4K drawable only added an upscale pass and a 4K stream. An Apple TV over AirPlay showed black with it (GPU 15 to 60 ms a frame). Only the external display role gets the TV scene configuration; every other role keeps Default. Tested by the author on an iPhone with a TV by cable and an Apple TV over AirPlay, and in issue seedds#705 on an iPad Air M3 (iPadOS 27.2) with a 4K TV by USB-C: the game fills the TV, the iPad keeps the pad, the game is docked. Open: unplugging and plugging in again on a device, the iOS 26 manifest-only path, and LiveContainer (it connects an unclaimed external display scene; a follow-up was offered in the PR). Co-authored-by: Zorrobyte <7257172+zorrobyte@users.noreply.github.com>
…l profile and the NSZ conversions follow it (PR seedds#475) --work-dir <folder> (WORK_DIR in Spyder) is the game's build folder, used as given. Without -o the IPA (or the Mac app) defaults to the folder holding it. The provisional or derived profile goes to <build folder>/profile unless --profile-out names another place, and the NSZ / XCZ conversions to <build folder>/nsp/. Without the option every path is as before; the survey stays in the NSP folder. A front end that stages the NSPs in a fresh folder for every build (LNPANDY/NX2Apple#132) lost the profile with that folder: it was surveyed again, and its dated heap check line changed its content, which the shader split and the iOS shaders key on, so both ran again (about 3.5 hours on a 73,000-shader game). Converted NSZ files were lost the same way and converted again. A profile in the default <title ID>_build/profile is copied once into a new build folder that has none; the original stays. Co-authored-by: v0lumehi <34629096+v0lumehi@users.noreply.github.com>
…ytes on SDK 10 and older (GitHub issue seedds#708, PR seedds#709) The host zeroed 0x40 bytes of nv::MemoryInfo on every SDK. On SDK 10 and older the record is 0x20 bytes (four 64-bit counters), so the answer overran the caller's record by 32 bytes: Hyrule Warriors: Definitive Edition 1.0.1 (SDK 3.5.1) passes a 32-byte record, and AddressSanitizer reported the write. Every local sdk module from 3.4.0 to 20.5.22 fills four counters; on 3.4.0-10.8.1 the function has no 0x40 path, from 11.4.3 on it zeroes 0x40 when nv is not initialised. That is the DM_SDK_OLD boundary the NVN API version and the shared-font layout already follow, so the size follows dm_sdk_major(). The pool figures lie in the first four counters, so both sizes carry them. t_nv checks both sizes between guard words and in exact allocations under AddressSanitizer. From PR seedds#709 by monoquark; review: the size follows the SDK version instead of recognising the wrapper's instruction sequence (the modern SDKs fill four counters too, so the instruction form did not mark the record's size). Co-authored-by: monoquark <24584001+monoquark@users.noreply.github.com>
…s chunked zlib .gz files read by the shader split Atelier Ryza: Ever Darkness & the Secret Hideout DX (0100199023B2E000), update 1.2.0 (v65536): Gust's engine on Koei Tecmo's KTGL, SDK 18.3.2, NVN. Plays on the Mac at 30 fps, as on the Switch: the opening movie, the title, a new game through the opening story into the field, the menu and the map, and a load of that save. Profile (no cuts, no run-time keys), prewarm list, note, games table row and gallery screenshot. - Shader split (shader_split.py gust_gz): every frame was black, the title included, with 26 shaders missing from the map. They were the post effects' GLSLC outputs in Data/NX/PostEffect/pe_pack.elixir.gz, one of the game's 156 .gz files in Gust's chunked zlib (a u32 stored length and one zlib stream per 16 KB chunk, ended by a zero length); the other 3,956 are CRAE archives stored as they are. The split inflates that form, by its structure, and scans the result as a loose file: 921 -> 1,049 shaders. New test: dm/tools/tests/test_split_gust_gz.py. Regression (very certain, 1 game): the change reaches only the split. Fire Emblem: Three Houses is the only other local game with a .gz file whose fifth byte is 0x78 (one file, which takes kt_gz first); its tables split with and without the change are identical (1,372 shaders). regress.py check on it (chain only, no smoke route): PASS.
Atelier Ryza DX leaves cube textures (NVN target 8) in slots its draws read as 2D: a compute shader of CLC.g1s, the PBB materials' pixel shaders and the river's vertex shader, a different texture each run, so stale bindings. tex_fit had no view for that case and bound the cube as is, a type mismatch whose reads are undefined on Metal (up to five red lines over the opening). Maxwell keeps a cube's faces as six layers and a non-array sample reads layer 0, as for the 2D array -> 2D view tex_fit already makes; the cube now gets a one-face 2D view (valid under the Metal API validation layer). What the Switch reads there was not measured. Ryza, same save-load route with the host before and after: the cube mismatch lines are gone (the river slot's buffer texture and a 3D texture left in slot 20 in one run stay reported, no view bridges them); the field at frames 3000 and 4000 looks the same, 0.3 % of pixels differ, scattered particles and foliage. ROMANCE OF THE THREE KINGDOMS 8 REMAKE has the same case in two vertex shaders (its note updated); not run, its build folder is gone. Regression (narrow reach, 1 game: only Ryza and RTK8R bind a cube in a 2D slot in any run log on disk): Ryza as above. Extra: regress.py check on Xenoblade Chronicles 2 (full route, against origin/main fe6d3df): PASS, 15,572 shaders unchanged, 30.0 -> 30.1 fps, screenshots match.
…ore the game runs are the ones it uses (GitHub issue seedds#614) The game calls nvnDeviceSetDepthMode with near = 0 ([nvn] depth mode near=0 in the Mac report of seedds#614 and in the iPhone logs of seedds#149 and seedds#292), and the profile had no depth_mode, so the NSP script's prebuild made the Mac app's bundled archive (1.2 GB) for near = -w. The host follows the game's mode and found none of those bases ("made for ... depth near=-w ... this run needs ... depth near=0"), so every base compiled while playing (found none 6, bases compiled 3 / 258.6 ms up to frame 1200), one cause of the hitches on new moves. Legends: Arceus, Scarlet and Violet already set it. Only the offline bases change; the shader input digest and libraries do not. The game note records it, what stays open in seedds#614 (shader library loads; the 33/50 ms fullscreen alternation, which matches seedds#347), and the iPhone page faults of seedds#149 / seedds#292 as open: both logs come from builds before native texture atomics. Checked: game.py reads zero; docs, nso_match, patches and NSP script tests pass. Not re-measured with a repacked app.
…e rewriter (ue_region.py); the 7 game_args rows and Pikmin 4's cut removed (issue seedds#635) The rewriter finds, in any Unreal Engine 4 / 5 main without a build ID, the store of the engine region's size right before nninitStartup reserves it with nn::os::AllocateAddressRegion, and puts observation gate OBS_UE_REGION on it. The host (hle_svc.c) sets the size register and x1 to what the alias region has room for, StandardAllocator's formula (now one shared function): 2.81 GB in the 3.75 GB block, 4.06 GB in Engage's 5 GB block. On the 123 mains on the game drives it finds the reservation of the nine Unreal builds with the option and nothing else. -SwitchVirtualAddressSpaceSize= was no general way to size it: Pikmin 4's UE 4.26 nninitStartup reserves the region only while its size variable is 0, the game's own code. The default path takes the gate there, so its patches.py cut goes. Observation gates no longer need x9-x17 dead at their site (scratch_dead removed): the gate frame saves and restores x0-x28 and the flags, and three of the size stores read x10. Not booted yet on any game.
…o two 16-byte literals found in main's code (uepak.py code_keys)
…s carried across game updates (PR seedds#406) hle_cheats.c loads the running build's <build ID>.txt from DM_CHEATS (default <DM_ROOT>/cheats, flat or the atmosphere/contents tree) and runs the dmnt cheat VM, opcodes 0-C4 as Atmosphère 1.12.1 runs them (docs/reference/cheats.md says where the host differs), once per presented frame and from a ~60 Hz thread while the game is not presenting. On top of the plain format: labels and EdiZon sections, on / off pairs as one switch, per-build toggles (<build ID>.enabled), typed values, run-once cheats, a dry run, a master switch and, on the Mac, safe mode after an unclean exit. The Mac window gets a Cheats menu and a floating Cheats panel (⌘⇧C) that never takes the keyboard from the game. scripts/cheat_anchor.py imports a cheat file into a version-independent source anchored to the game's code and data and compiles it for any build. docs/frontends.md has the files as the contract for front ends. Changes to the pull request: - Cheats never write over the rewriter's work. patch_nso.py writes <name>.changed.tsv: the text words it changed (sites, cuts, lock acquires, jump tables) and those whose copies run instead (windows, spin waits); Mac apps carry it. A code write that covers one turns the cheat off with the reason: the Switch's original word there (an "X - off" restore, most often) would run an SVC or a TLS read natively or undo an ldaxr, and a write into a copied instruction never runs. Without the list (an older rewriter's modules) no code write is allowed. Writes past the game's own image (the key page, the frame step page, the patch areas) are refused too. - No thread without cheats: the ~60 Hz apply thread starts with the first file that has a cheat in it, not for every game. - No code writes without the writable alias of main. On the iPhone the code pages are the app's signed pages, and toggling the game's own pages writable on the Mac races with its cores, so the mprotect fallback is gone: the iPhone runs data cheats only. t_cheats covers the refusals (143 checks, also under ASan and UBSan). The clang-tidy findings the new files brought are fixed (a realloc that lost its buffer, a shift by 64 on an untyped value, three nils handed to AppKit, the test's unchecked lookups) or marked: file loads under the cheats lock, which the per-frame pass only trylocks. Regression (normal reach, 3 games), check against fe6d3df: - Super Mario Bros. Wonder: PASS (16268/16268 shaders, fps 59.4 → 59.6, no new RED). - Tears of the Kingdom: the first run never presented. Its window resigned key before the first frame and the game suspended on the out-of-focus notification, as on a Switch. A second run booted (first frame 7.9 s, fps 34.5 → 46.5, p99 51.6 → 17.9 ms, 28669/28669 shaders); only its 90 s screenshot was missing, after a late focus loss. - Breath of the Wild: frame p99 17.5 → 33.4 ms in 3 of 3 runs (fps 60.0 → 58.5, 19592/19592 shaders, no new RED). This baseline's 17.5 ms is the outlier: BotW's other checks today measured 32.8 to 33.5 ms on both sides (e513bfe, 195986f). Without a cheats file the host's only new per-frame work is a timestamp and a flag check. Co-authored-by: Amost <6445689+Amost-@users.noreply.github.com>
…ept in the log (PR seedds#721) Arcade Archives RAINBOW ISLANDS (01004E101D476000, 1.0.2, SDK 19.3.11) crashed with SIGBUS on the Mac (M1, macOS 27.2) at its first nn::audio::StartAudioOut, and the process then hung. The game calls Start on its own thread, and the first AudioOutputUnitStart of the process sets up the Core Audio session (HALC_ProxyIOContext::StartIOProc -> +[AVAudioSession sharedInstance], which connects to the session service over XPC). That ran off the bottom of the game thread's stack: the fault is the top of the page just below the stack, sp in the guest stack block, and the faulting frame varies between runs (CFString formatting under NSXPCInterface, the Swift type demangler under CAReporter). Start now runs on the thread's big host stack (HLE_FORCE_BIG), as the file system take-overs do, and so do Stop (AudioOutputUnitStop) and Close (disposes the AudioUnit), which talk to the same service from the game's thread. Running Start on a helper thread, as Open does, would join that thread while holding g_aos_lock, which can give up the guest core to a thread that then waits for the lock. The big-stack entry now keeps the game's return address beside the saved sp at the top of the host stack, and dm_bigstack_caller (hle.h) gives it back, so the Start / Stop / Close log lines still name the game's call site instead of "host". t_bigstack runs a take-over on a 16 KB fake guest stack and checks the switch, the arguments and the call site on both paths. The audio unit tests link hle_bigstack.c and stub dm_guest_as_contains, as the file system tests do. Co-authored-by: jasonkimball82 <350284318+jasonkimball82@users.noreply.github.com>
…r(type, format) taken over, short timed waits as polls Hyrule Warriors: Definitive Edition (0100AE00096EA000, SDK 3.5.1, KTGL on NVN) plays on the Mac from the first-run questions through the title, Legend Mode's opening movie and the first battle, at the game's own 60 fps with no red line. Two general host changes: - hle_movie.c: SDK 3's movie::Decoder constructor takes only a type and an output format; the host took over the SDK 4 and later forms only, so the SDK built its own decoder and the host's Configure called through a null pointer. It is now taken over as a CPU-mode decoder; SDK 3 numbers its formats one lower (3 = NV12, 2 = ARGB) and reports an alignment of 0x20 as GetOutputBufferSize's second output. - hle_thread.c: a wait with a timeout under 20 µs that times out is a step of the run of yields (poll_wait_begin / poll_wait_end): the game's main and update threads polled their frame events with 30 ns and 500 ns waits, so the back-off never started. Its first battle on the Mac: CPU 102% -> 27% of a core, 4.6 -> 1.5 W, same frame times. Test: t_pollwait. Regression check (regress.py check, baseline 6b0cffb, 5 games): Xenoblade Chronicles 2 (SDK 3.5, imports the same constructor) 29.8 -> 29.8 fps; Breath of the Wild 55.7 -> 59.2; Tears of the Kingdom 54.6 -> 57.3 (--prebuild-limit 3000); FINAL FANTASY X/X-2 28.5 -> 29.3; Catherine: Full Body 29.9 -> 29.9; no new red line, screenshot differences are the same scenes at other moments.
… the shader split, the pixel sample index and GLSLC's sample position table, and image stores kept under rasterizer discard - shader_split.py: Retro's RFRM forms in either byte order (rfrm_order), TOCC resource lists with 52-byte ADIR entries, and GLSLC's extra control data past a control section's own length - Translator: PIXLD.MYINDEX reads the sample index (IoVariable.SampleId, SampleRateShading); the host fills the pixel stage's sample position rows of c0 (0x620, 0x630) and dmsh_build allows the dynamic index into them; nvnProgramSetSampleShading answered - dmsh_build: a vertex shader that writes images, not only storage buffers, keeps its draws under rasterizer discard (the volumetric fog's froxel volume) - Chain d1043b780a74
…fests of the older hashing hashed again nvn_manifest hashed a shader's variant files (<key>_bg0.json, _bgv.json and the others) as bytes, and their reflections carry the chain stamps (chain, chain_metal, chain_compiler), so every chain change reported every shader with variants as changed (2026-10-31: 720 on Donkey Kong Country Tropical Freeze, 5 on Xenoblade Chronicles Definitive Edition, all only the stamps). Variant .json files now drop the same fields refl_hash drops for <key>_b.json (refl_canon); .metal and .metallib variants stay hashed as bytes (pull and vertex-input variants leave only their metallib in the library, and the same MSL compiles to the same bytes). A reused chain manifest made by the older hashing would compare against new ones the same way, so manifests record their hashing (hashes: 2) and one of another number is hashed again from its outputs when they are on disk. Tests: test_variant_hash_ignores_chain_stamps, test_reused_manifest_of_older_hashes_is_hashed_again. No game regression run: the change is in the harness's comparison only.
Bind the current Capstone instruction in the operand helper and assert that a detected engine-region gate has a size register before encoding it. These make the existing invariants explicit without changing valid rewrite behavior or widening the Python lint baseline. Reviewed PR seedds#756. Focused UE-region, lint-ratchet and docs tests pass (28 tests); the pinned lint check has 392 baseline findings, zero new findings and zero stale entries. Regression risk is low: instruction matching and emitted gate encoding are unchanged, so no game regression run was needed. Co-authored-by: Eliran Zach <4012041+thehobbit85@users.noreply.github.com>
Declare the near-zero depth selected by Echoes of Wisdom's NVN calls so its offline pipeline archive uses main0_z and matches the runtime stamp. Compare observed runtime depth with each tested profile in NVN smoke runs, including quick runs without an archive. Detect bundled archive stamp rejections and prevent mismatched runs from recording a green validation. Invalidate cached baselines that predate these observations. Add regression coverage and document the mechanism and validation limits. Both archives built all 7,495 bases with matched historical host/shader artifacts: GL was rejected and zero passed 16/16 coverage probes on the opening route. Castle-entry performance remains unvalidated without a save. Validation: 77 targeted tests passed, one compiler-dependent check skipped; Python lint and diff checks passed. Regression risk is low because only a profile archive input and harness diagnostics change; no multi-game regress.py check was run. Refs seedds#758. Co-authored-by: Marceloalexandregoncalves <62747593+Marceloalexandregoncalves@users.noreply.github.com>
Guest ring allocators update NVNbuffer offset and size directly at +0x18 and +0x20. The host previously read +0x10 and +0x18, so GetAddress kept the initial offset and GetSize returned the allocation offset. Reserve the intervening bytes and assert the guest field offsets. All buffer queries now use the updated fields without a game-specific rule. Add public-entry-point tests for raw stores, ring wraparound, GPU-only pool mapping restrictions, builder independence and neighbouring objects. Fixes seedds#723. Source: seedds#727. Co-authored-by: Eliran Zach <4012041+thehobbit85@users.noreply.github.com>
Record depth_mode zero for SteamWorld Heist II, NieR:Automata, Portal, DRAGON QUEST III HD-2D Remake, Raging Loop, Subnautica and Below Zero. Their registered builds select near-zero NVN depth while the omitted key made offline pipeline builds default to the GL vertex entry. Confirm the recorded routes against registered module build IDs and reproduce each game's actual NVN depth call with an isolated headless boot. Extend the archive-builder regression test to check all eight affected profiles' stamps and vertex entries, including Echoes of Wisdom. Record the evidence and validation limits in each game note and the shared reference. The original 14-profile audit now has no observed depth mismatch. The shader-library input digests are unchanged; archives must be rebuilt and apps repacked. Rebuilt archive acceptance and performance remain unmeasured. Validation: seven isolated depth confirmations passed; 77 targeted tests passed, one compiler-dependent test skipped; Python lint and diff checks passed. Regression risk is low: only profile archive metadata, tests and docs change, so no full multi-game regression run was performed. Refs seedds#758.
The poll-wait test reads pthread storage after registering its guest thread. Assert that setup invariant before dereferencing the nullable result so a setup failure is explicit and the clang-tidy nullability check passes.
Keep default-valued render functions unspecialized while loading and let the existing Metal 4 descriptor carry their values into pipeline compilation. Compute shaders and per-value render variants retain library specialization. Use one stable fallback record per function so overlapping MTLDevice builds share a single specialization without blocking unrelated functions. Preserve the record when the same library entry is registered again. A gated-library regression fails on the original PR and passes with the fix. Metal pipeline tests: 90 passed; pending-pipeline tests: 52 passed; docs: 11 passed. The full clang-tidy ratchet passed with no new findings. Full regressions for Breath of the Wild, Pokemon Scarlet and Tears of the Kingdom stopped before gameplay because the offline Metal compiler is missing. Co-authored-by: KillReal1234 <48804399+KillReal1234@users.noreply.github.com>
…eedds#738) Eight color targets and independent depth/stencil store decisions require ten records. Size the ledger and lookahead buffer from one constant to prevent the tenth record from corrupting cached pipeline formats. Retain both physical planes of combined storage, preserve logical aspect use, normalize live/predicted/historical keys, and reject invalid formats before either Metal pipeline compiler can assert. Add asset-free GPU coverage and make its parsing, readback allocations and format comparisons explicit for the clang-tidy ratchet. Co-authored-by: Ethan Cha <43095500+ripull125@users.noreply.github.com>
Readback and PNG capture stall measured frames and can change adaptive pacing. Request default visual proof after the timing window and parse game speed from the host's current frame-step log format. Preserve explicit screenshot schedules and document their timing cost. Link the finding from the Breath of the Wild and Tears of the Kingdom game notes. The PR's region lint corrections are already on main. Validated with the 24 benchmark, region and documentation tests. Co-authored-by: Leandro Piccione <15013313+ComicBit@users.noreply.github.com>
Run the x18 scan and spin-wait analysis in forked pools while keeping patch emission ordered. Share a worker budget across module rewrites, honor explicit DM_REWRITE_J settings, and reject invalid counts before loading modules. Exit through pool cleanup on SIGTERM so cancelled rewrites reap their workers. Add regression tests, a rewriter reference entry and its symptom index entry, and document the completed game validation. Validation: 173 focused tests, the Python lint/type ratchet and docs checks passed. Breath of the Wild's full regression passed; all 21 binary and TSV outputs of its three modules were byte-identical. No completed full-game regression for other titles in this change. Co-authored-by: Daniel Johnson <41651107+djdev0010@users.noreply.github.com>
Host-owned shader libraries compiled from source at first use, including one clear library per attachment slot and output type. Move their MSL to build inputs, combine the clear variants, and load cached metallibs in the shared graphics paths. Compile Mac libraries for MACOS_MIN and recheck the compiler, SDK, deployment target and sources on every build. Reuse unchanged headers, but regenerate source-only headers when the Metal compiler becomes available. Prepare and fingerprint the generated header in the NSP packer, regression host cache and iOS compile check. Validation: graphics tests, tool tests, focused build/cache tests, Python and C lint, documentation checks and iOS source compilation pass. Full game regression was not completed; gameplay timing remains inconclusive. Co-authored-by: KillReal1234 <48804399+KillReal1234@users.noreply.github.com>
…s#644) The settings screen offered pipeline prebuild even when Metal 4 pipelines were off, although both runtime prebuild paths require them. Add the existing needs metadata to the shared settings row and document when it appears. Preserve the platform defaults and saved choices. Validation: all 17 focused settings and native Swift launcher tests pass. Regression risk is low: only settings metadata and prose change, so no game regression runs were needed. Co-authored-by: v0lumehi <34629096+v0lumehi@users.noreply.github.com>
Emit a shaders_stale event before rebuilding libraries after a chain or profile input change, with the same explanation in human progress modes. Check completion stamps separately for the selected targets so partial current-chain outputs cannot hide old libraries. Count each current shader key once per selected target instead of summing retained historical copies. Document the count as scheduled base libraries, including cache restores, and cover interrupted rebuilds, mixed targets and duplicate old caches. Co-authored-by: v0lumehi <34629096+v0lumehi@users.noreply.github.com>
34 upstream commits since 6d880d2. Conflicts resolved: - Cheats: upstream's engine (hle_cheats.c, PR seedds#406) replaces NXForge's cheats.c / cheats_host.c and their loader, frame and heap-region hooks. The Quick settings sidebar's Cheats section reads upstream's rows (the same as the Cheats menu) through declarations in quick_settings_mac.h, which front_mac.m checks against dm.h. The switches live in <build ID>.enabled, not in the preferences. dm/tools/cheats_md.py now converts the old Markdown files to .txt. - The present filters, FXAA and Sharpen moved from nvn_mtl.m's runtime MSL string into upstream's dm/gfx/msl/present.metal. - Makefile and NSP script: the Swift sidebar object next to upstream's host_msl header, in the build and its fingerprint. - t_hid keeps NXForge's IsVibrationPermitted rule and gains upstream's IsVibrationDeviceMounted checks. - Docs: both sides kept (games table, settings sections, development.md's cleanup and org.nxforge bundle ID), upstream's cheats rows in env_switches.tsv. dmsh_chain.h and the symptom index regenerated. Checked on an M4 Pro (macOS 27.0.1): the Mac host builds for Wonder, Hades and Digimon with no new warnings, host tests and the GPU tests pass, every gfx test and the iOS sources compile, the Python tool tests pass but test_host_msl.py (it fails the same way on upstream's main on this Mac), and the Python lint is clean. clang-tidy was not run locally. No game was played. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The host's compile line passed -Xlinker -rpath -Xlinker /usr/lib/swift. The clang-tidy compile database (dm/tools/lint_c.py compdb) keeps flags and drops non-source arguments, so every host source's entry ended in "-Xlinker -c": clang-tidy got a link job instead of a compile and reported nothing for the host's files, and CI's ratchet failed on 23 findings "fixed" (crash.c's system() call among them). -Wl,-rpath,/usr/lib/swift is the same link flag, and lint_c.py skips it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… count lowered With the host's sources in the compile database again, clang-tidy checked NXForge's own Mac files for the first time. capture_mac.m read the adaptor's nullable pixelBufferPool twice and handed a possibly nil Metal device to CVMetalTextureCacheCreate; front_mac.m's mods_list listed a folder whose path is nil when there is no Application Support folder. Each now checks the value once. t_hid.c has one memcmp of dm_vibration less since the merge kept NXForge's startup check, so its baseline count goes from 2 to 1. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
clang-tidy's next pass found two more nullable values in capture_path: the Pictures or Movies folder URL can be nil (the home folder is used then), and stringByAppendingPathExtension: can return nil (with_ext keeps the name). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Tom
What and why
Release 0.9.0. It merges seedds/nxnative
mainup to2716f78(34 commits since6d880d2): Metroid Prime Remastered, Hyrule Warriors: Definitive Edition, DQ III HD-2D and Atelier Ryza, NVN depth/stencil and ring-buffer fixes, the BotWldaxrlock fix, faster rewriter scans, build-time host shaders, and upstream's cheat engine. The CHANGELOG 0.9.0 entry has the details, and BACKLOG.md is updated.The biggest conflict was cheats. Upstream's
hle_cheats.creplaces NXForge's Markdown engine, and the Quick settings sidebar's Cheats section now reads upstream's rows, the same ones as the new Cheats menu and panel (⇧⌘C). The folder is unchanged. Old.mdfiles convert withdm/tools/cheats_md.py txt, and Tom's Curse of the Moon file is already converted. The present filters, FXAA and Sharpen moved into upstream'sdm/gfx/msl/present.metal.The four upstream contributions are open as seedds#789, seedds#790, seedds#791 and seedds#792.
Checked
host_warnings.pyreports no new warnings. Host tests and GPU tests (make -C dm/gfx/tests run) pass. Every gfx test and the iOS sources compile.test_host_msl.py, which fails the same way on a clean upstreammainon this Mac.lint_python.pyreports 0 new findings, andrelease_check.py check 0.9.0passes.lint-cworkflow; NXForge's own C and Objective-C have not been through it before), and the converter app.Docs
dmsh_chain.py --headerrun;dm/gfx/nvn/dmsh_chain.his part of the change🤖 Generated with Claude Code