Files
seedds 9bdef355ab Port Xenoblade Chronicles 3 2.2.1
Add Monolith archive and shader extraction, a build-gated compact memory layout, vertex storage writes under rasterizer discard, primitive ordering and interleaved geometry feedback. Correct native decoder/audio wait accounting and the oe calls used after movies.

Validated opening combat and movement on Mac with real audio, the full Mac/iOS shader build, GPU regressions, and the unsigned IPA archive. iOS runtime, later areas and DLC gameplay remain untested.
2026-10-27 07:58:05 +08:00

42 KiB

1nameclassmeaning
2DM_ABdiagnostic`=<frames>` splits the run into phases of that many frames and alternates every switch set to `ab` (on in the odd phases); logs an `[ab]` line per phase with GPU and frame time and attachment traffic
3DM_ALIAS_WINDOWSdiagnostic`=<MB>` logs every 30 s how much of each window of that size in the alias region is mapped (windows aligned to their size in absolute addresses)
4DM_AOC_DIRpathFolder of add-on content: one numbered subfolder per DLC index holding that DLC's RomFS, reported by `aoc` and mounted read-only; the app, the Mac launcher and the NSP script set it when the build has DLC
5DM_AOC_OWNEDswitch`0` reports no add-on content even when `DM_AOC_DIR` has some, for runs without the DLC
6DM_APP_VERSIONswitchOverrides the IPA's version in `build_ipa.sh`; by default it is the packed game's display version from its control data (the update's when one is packed)
7DM_AUDIOswitch`1` plays audio through Core Audio, `0` uses the silent sink; real output is the default on iOS, the silent sink on the Mac (the Mac launcher sets `1`)
8DM_AUDIO_DUMPdiagnostic`=<file>` writes every PCM block the game appends as is (16-bit, 48 kHz, channel count as in the OpenAudioOut log), to judge whether a sound played
9DM_AUDIO_MUTEswitch`=1` runs the real Core Audio output path (callback pacing, background take-over) with the output silenced, for lifecycle tests on the Mac without noise
10DM_AUDREN_TRACEdiagnosticWhen set, the CPU audio renderer logs every update with the number of frames rendered since the previous one
11DM_BOOTPROFdiagnosticWhen set, logs boot timing: the loader's breakdown (mapping, relocation, probes), Metal library loading, pipeline creation, texture uploads and the first present
12DM_BUNDLE_IDswitchOverrides the iOS app's bundle ID in `build_ipa.sh` (default `org.nxnative.<title ID in lowercase>`)
13DM_COPY_GAME_RESOURCESswitch`NO` skips the Xcode build phase that copies the game's resources into the app (`stage_resources.sh`, on by default); `build_ipa.sh` sets it for its unsigned build, which packs them itself
14DM_CTLdiagnostic`=<file>` (Mac): the host polls the file every 100 ms and runs each appended line: button presses, `shot`, `passdump`, `texdump`, `env KEY=VALUE`, `peek`, `memdump`, `drag` and more
15DM_DBGdiagnosticWhen set, prints the guest's `svcOutputDebugString` text to stderr as `[guest]` lines
16DM_DBG_AU_FRAMESdiagnostic`=<frames>` asks the Mac's Core Audio output for that many frames per callback instead of about 5 ms (1024 reproduces the iOS default that caused crackling)
17DM_DETCLOCKswitch`=<step ns>`: from the first present on, the guest clock advances a fixed step per present instead of following the wall clock, and the random source becomes a fixed-seed stream (replay and test runs)
18DM_DETCLOCK_PACEswitch`=1` with `DM_DETCLOCK`: each frame takes at least one clock step of wall time, so background loading keeps up with the fixed clock (used by the screenshot gate)
19DM_DISPLAY_NAMEswitchOverrides the iOS app's name in `build_ipa.sh` (default the game name in the base NSP's control data)
20DM_ENTITLEMENTSpath`=<plist>` gives a prepared Xcode project another entitlements file instead of the Increased Memory Limit one; empty means no entitlements
21DM_ENV_FILEpath`=<file>` makes `build_ipa.sh` bake its `KEY=VALUE` lines into the app as `dm/env.txt`, applied at boot; `Documents/env.txt` overrides them
22DM_ENV_FILE_KEYSswitchSet by the iOS app at launch to the space-separated names an env file set; the launcher keeps those values and shows them greyed out
23DM_FD_LOGdiagnostic`=<seconds>` logs, every that many seconds, the number and kinds of file descriptors the process has open
24DM_FIXED_TIMEswitch`=<seconds>`: the user clock always returns that time and the host time zone is pinned to UTC, for deterministic comparison
25DM_FONT_DIRpathFolder of the shared-font stand-ins (`standard.ttf`, `nintendo_ext.ttf` with the button icons); the app, the Mac launcher and the NSP script set it
26DM_FORCE_STRICTdiagnostic`=1` makes the loader fail on forced-hook entries no module references, instead of only noting them (for checking a mistyped list)
27DM_FPSswitch`30` or `60` pins the frame rate the display link and frame pacing aim for; otherwise it follows the game's present interval (60, or 30 when the game asks for 30)
28DM_FPS_HOLDplayer`on` / `off` overrides the profile's `fps_hold`: whether late frames may raise the hold above the frame cap's vsyncs (on by default)
29DM_FPS_TARGETplayerFrame-rate cap: `30` or `60`, or `0` for the game's own limit; overrides the profile's `fps_target`
30DM_FSdiagnosticWhen set, logs file opens, paths not found or not mounted, and a read summary every 64 MiB or 1000 reads
31DM_FSLOGdiagnostic`=<file>` writes one TSV line per ReadFile: seconds since boot, guest path, offset, length and guest buffer address
32DM_FSLOG_HASHdiagnosticWith `DM_FSLOG`, adds a column with the FNV-1a 64 hash of the bytes read
33DM_FULLSCREENswitchWhen set, the Mac window starts in fullscreen
34DM_GAMEswitchSelects the game profile (a title ID under `dm/games` or `DM_GAMES_DIR`) for the Python tools and the rewriter; there is no default
35DM_GAMES_DIRpathProfile folders outside the repository, separated by `:`, searched after `dm/games`; the NSP script points it at a provisional or derived profile
36DM_GAMES_FIRSTswitch`=1` searches `DM_GAMES_DIR` before `dm/games`, so a provisional or derived profile wins over the game's own (the NSP script's `--provisional`)
37DM_GAME_ENVswitch`KEY=VALUE` pairs, separated by spaces, that the game's own `getenv` returns, in place of the profile's `game_env` (`hle_os.c`); any other name goes to the SDK's empty environment
38DM_GFX_FIXTURE_OUTtest`=<dir>`: graphics tests write their raw result textures and buffers there
39DM_GLSLC_CAPTUREpath`=<dir>` saves every GLSLC output the game compiles at run time; `shader_split.py` reads it (default `<version dir>/glslc_capture`)
40DM_GL_CAPTUREpath`=<dir>`: the GL layer writes every shader source the game compiles (`<key>.vert` / `<key>.frag`) for `gl_shaders.py`; the NSP script uses it to capture run-time shaders
41DM_GL_LOGdiagnostic`=1` makes the GL layer log object creation
42DM_GL_STUBSdiagnostic`=1` gives every GL function the layer lacks a stub that reports its first call and returns 0, instead of a null pointer (bring-up)
43DM_GPU_CAPTUREdiagnostic`=<frame>[:<frames>]` or `gpu:<ms>[:<after frame>]` writes a Metal GPU trace of those frames for Xcode's Metal debugger; can be set while running through `DM_CTL`
44DM_GPU_CAPTURE_DIRpathFolder for `DM_GPU_CAPTURE`'s traces (default `gpu_captures/` in the working directory)
45DM_GPU_CAPTURE_KEEPdiagnosticBefore each GPU capture, prunes the capture folder's `dm_*.gputrace` entries so that the newest `KEEP - 1` stay (default 2)
46DM_GUEST_SPAWN_TESTdiagnostic`=1` runs a self-test before `nnMain`: a host-started guest thread does SDK malloc / free and locks an `nn::os` mutex, and the result is logged; `=2` also keeps a resident thread
47DM_HITCH_DUMPdiagnostic`=<ms>[:<s>]`: when no frame has been presented for that long (from s seconds on), logs every guest thread once per stall: wait, last SVC, pc, lr, frames and registers
48DM_HLECOUNTdiagnostic`=<file>` (`%d` = process ID) writes at exit a TSV of how many times the guest called each HLE function, zero counts included
49DM_ICONpath`=<image>` gives `build_ipa.sh` another app icon (default the `icon.jpg` beside the RomFS)
50DM_IMPORTSdiagnosticWhen set, logs each import the loader binds to a host function and each forced takeover
51DM_KBDswitch`=<text>`: the system keyboard returns that text as OK without showing an input box; unset with no window, it returns cancel
52DM_KBD_PLAYERswitch`own` makes the Mac keyboard player 1 on its own, with controllers from player 2 on (by default the first controller shares player 1 with the keyboard)
53DM_KEYSswitchScripted input: `<seconds or f<frame>>:<key>[+key][~hold][*count/interval],…` presses buttons, sticks and `Shake` at those times
54DM_LANGplayerGame language as a language code (default `en-US`; the iOS app sets the one the IPA was packed with)
55DM_LAUNCHERswitch`0` skips the iOS settings screen and starts the game at once
56DM_LINK_VTICKswitch`0` keeps the system's display-link rate on 144 or 165 Hz Mac screens; by default the link counts only the refreshes nearest a steady 1/60 s clock
57DM_LOADHASHdiagnostic`=1` logs an address-independent SHA-256 per module after loading
58DM_LONGFRAMEdiagnostic`0` turns off the long-frame log (on by default), a line for a frame over 20 ms or with GPU time over 16.7 ms that is clearly above recent frames
59DM_MEASURE_LOCKpath`=<file>`: `scripts/regress.py`'s default `--lock`, the measuring lock `scripts/bench.py --lock` shares: held only while a game runs, and the harness's shader builds pause while another process holds it
60DM_MEMSTATdiagnostic`=<tsv>` writes one line per second of memory accounting: footprint, Metal allocation and resident and charged memory by region class (guest, code, malloc, gpu, …)
61DM_MEMSTAT_DUMPdiagnostic`=<seconds>`: with `DM_MEMSTAT`, at that second writes every VM region of 1 MiB or more to `<tsv>.regions`
62DM_MEM_CAP_GBswitch`=<GB>`: the memory watchdog exits when resident memory exceeds that many GB (default 24 on the Mac, none on iOS; `0` turns it off)
63DM_METAL_CAPTUREdiagnostic`=1` makes `build_ipa.sh` produce a build that can write GPU frame captures (`MetalCaptureEnabled` in `Info.plist`), for `DM_GPU_CAPTURE`
64DM_METAL_HUDplayer`1` shows Apple's Metal performance HUD over the game (frame rate, frame and GPU time, memory)
65DM_MOVIE_TRACEdiagnosticWhen set, the movie decoder logs every call with its thread and decoder (by default the first 12 calls, then every 2^k-th)
66DM_MSL_DIRpathParent folder of the shader libraries: NVN loads from `b-<chain version>/` beneath it, Vulkan from `vk/`, GL from `gl/`; the app and the Mac launcher set it
67DM_NICKswitchThe account nickname the game sees (default `Player`)
68DM_NROswitch`0` turns off loading of the NRO modules the game's NRR files register (on by default): every `nn::ro::LoadModule` then fails
69DM_NVN_ALLOCPROFdiagnostic`=1` charges Metal allocation growth to each replayed op type and function, and logs command allocator sizes and each new texture (serial, size, format, storage)
70DM_NVN_APIswitch`=<major>.<minor>` overrides the NVN API version `nvnDeviceGetInteger` reports (by default decided by the SDK version or the profile's `device_api`: 55.15 for SDK 11 and later, 53.313 before)
71DM_NVN_BARRIERswitchHow draw passes are ordered: `full` (default) waits for all earlier GPU work, `game` only for the previous pass's fragment stage unless the game set a barrier, `ab` alternates with the `DM_AB` phases
72DM_NVN_BF_WANTpath`=<file>`: appends the key of each fragment shader whose passes could not be merged for lack of a readable-tile version to that file, once per key
73DM_NVN_BLIT_ORDERdiagnostic`0` drops the barriers between dependent operations in the copy encoder, which reproduces the fountain's vertical stripes in Mario Wonder
74DM_NVN_CBDUMPdiagnostic`=<dir>`: saves each draw's whole uniform blocks as `F<frame>_p<pass>_st<stage>_cb<slot>_<address>.bin`, and the source bytes of buffer-to-3D-texture copies, with `DM_NVN_PASSDUMP`
75DM_NVN_CBDUMP_KEYdiagnostic`=<shader key>`: limits `DM_NVN_CBDUMP` to draws using that shader; for a vertex shader key also saves the draw's vertex streams and index buffer
76DM_NVN_CBLOGdiagnostic`=1` logs the command memory the game adds to command buffers (`AddCommandMemory`: the first 60, then every 500th) and the out-of-memory callbacks
77DM_NVN_CLEARLOGdiagnostic`=1` logs the first 40 colour clears drawn as a triangle (inside a pass, with a partial channel mask or a partial scissor)
78DM_NVN_CMDSTATdiagnostic`=1` logs every 300 frames the command recording usage: bytes and records per frame, command memory segment sizes, out-of-memory callbacks, host segments, count and bytes per command type
79DM_NVN_CS_HOISTswitch`0` makes a compute dispatch between the draws of a pass end it (on by default: the dispatch runs ahead of the pass when that changes nothing the draws before it read)
80DM_NVN_CUTswitch`=<draws>`: the replay commits its command buffer every that many draws, between passes (default 64; `0` one command buffer per submission, except the cut after a buffer-to-texture copy)
81DM_NVN_DEFERswitch`0` turns off the deferred pass merging of the TBDR optimizations (which run only with `DM_NVN_TBDR=1`)
82DM_NVN_DEFER_ABdiagnostic`=1` keeps the deferred pass merging (with `DM_NVN_TBDR=1`) off until the second screenshot has been written, then turns it on, to compare the pictures with and without it
83DM_NVN_DIRTYCHECKdiagnostic`=1` fully hashes pool content on every use to find changes the dirty-page tracking missed
84DM_NVN_DISPATCH_OWNswitch`=1` gives every compute dispatch a compute encoder of its own with full barriers, as before (by default dispatches share the copy encoder); `DM_NVN_PASSGPU` does the same
85DM_NVN_ENC_LABELdiagnostic`=1` labels every render encoder `p<pass in frame> <width>x<height> <first 8 digits of the first draw's fragment key> d<draws>` for Instruments traces
86DM_NVN_ENC_THREADplayer`1` runs the replay's Metal encoding on a thread of its own while the submit thread goes on translating; on by default on iOS (`0` turns it off), off on macOS
87DM_NVN_FAST_WAKEswitch`0` makes the game's `SyncWait`s wake on the commit feedback handler instead of the GPU's own signal of the fence (on by default)
88DM_NVN_FB_SNAPswitchWhich fragment shaders sampling a colour attachment of their own pass read a snapshot of it: `0` none, `all` every shader (slow), `<keys,…>` that list instead of the profile's `feedback_snap`
89DM_NVN_FLUSH_FILLswitch`0` starts a new GPU texture in a CPU-writable pool as zeros; by default one whose storage the game flushed before its first use is filled from that storage once
90DM_NVN_FRAMESdiagnostic`=<N>` prints the NVN call table frame by frame for the first N frames (default 3)
91DM_NVN_FUSE_CHECKdiagnostic`=1` checks pass merging in the same frame: renders the merged passes again apart and logs the comparison of the attachments every time
92DM_NVN_GPUPROFdiagnostic`=<f>`, `<f1>-<f2>` or `every:<n>`: logs the GPU start and duration of every encoder of those frames (`[gpuprof]` lines from Metal 4 counter heap timestamps)
93DM_NVN_GPU_TSswitch`segment` or `submission`: what timestamp reports record (GPU start / end of the segment holding each report, or one time for the whole submission), instead of the profile's `gpu_timestamps`
94DM_NVN_HILITEdiagnostic`=<fragment shader key>,…`: those draws use a solid colour instead (magenta, green, cyan, yellow, blue, white in order), to tell wrong geometry from wrong shading
95DM_NVN_IXCLOGdiagnostic`=<n>` logs the first n indirect draw and dispatch conversions (record to arguments) once the GPU has run them
96DM_NVN_KEYDUMPdiagnostic`=<fs key>[:n[:every]]`: for up to n draws of that fragment shader (default 6), logs the pass dump binding lines plus vertex formats, vertex streams and uniform values; meant for devices
97DM_NVN_LAZY_CLEARswitch`0` makes clears with no draw after them open a pass of their own, as before; by default they wait to become the load action of the next pass on that target
98DM_NVN_LOADPROBEdiagnostic`=1`, `2` or `3`: attachments whose load is skipped are cleared to a sentinel colour (`3` NaN; `1` NaN for float formats) and the sentinel pixels left at pass end are counted (should be 0)
99DM_NVN_LOGdiagnostic`=1` logs the creation of NVN objects
100DM_NVN_MAGSCANdiagnostic`=<fs key>[:every[:phase]]`: device self-check that reads each pass's colour attachments every `every` frames (default 30) and logs `[mag]` lines for solid magenta 16×16 blocks or non-finite pixels
101DM_NVN_PASSDUMPdiagnostic`=<f>`, `<f1>-<f2>` or `every:<n>`: logs every render pass of those frames (attachments, clears, shader keys, bindings, draw state, presents) for the `tbdr_*.py` tools
102DM_NVN_PASSDUMP_ALLdiagnostic`=1` makes `DM_NVN_PASSDUMP` record every draw and binding change, not only the first per pass and stage, including copies and inline uniform updates
103DM_NVN_PASSGPUdiagnostic`=<file>` writes the GPU time of each render and compute pass from stage-boundary timestamp counters (off under Metal 4); also gives each dispatch its own encoder
104DM_NVN_PASSGPU_SERIALdiagnostic`=1` makes each encoder on the main command buffer wait until all earlier work has finished, so `DM_NVN_PASSGPU` times read each pass's exclusive time (totals read high)
105DM_NVN_PREDICTswitch`0` turns off the parallel precompile look-ahead: a pipeline miss compiles only the pipeline it needs
106DM_NVN_PROFdiagnostic`=1` wraps the implemented NVN functions in a timing wrapper and collects the time each takes during recording
107DM_NVN_PROGTRACEdiagnostic`=<vertex keys,...>` logs matching ProgramSetShaders calls and their guest backtraces
108DM_NVN_REGLUMdiagnostic`=x0,y0,x1,y1:<file>` (normalized coordinates): on every present records the present number, time, mean luminance and a grayscale thumbnail of that region, to check animation speed against frame rate
109DM_NVN_RT_RANGEswitch`=1` (experimental, off by default; with `DM_NVN_TBDR=1`) keeps the pass open when the game sets the same colour and depth target again with a view that differs only in its level count
110DM_NVN_RT_RANGE_CHECKdiagnosticWith `DM_NVN_RT_RANGE=1` and `DM_NVN_PASSDUMP`, renders a candidate pass both ways in the same frame and logs and writes the comparison (`CHECK_RESULTS.tsv`, `[RED]` on a difference)
111DM_NVN_SHDUMPdiagnostic`=<dir>` saves programs missing from the shader map as `<key>.ctl` (control section) and `<key>.code`, to find the files that hold them
112DM_NVN_SHMAPpathThe shader map (`shader_map.tsv`); `c1_full.tsv` and `pso_manifest.tsv` are taken from the same folder. Default: the game profile's folder on the Mac; the iOS app sets it
113DM_NVN_SHOTdiagnostic`=<frame>[,<frame>…]:<path>` saves the swapchain texture as an image at those frames (`%d` in the path = frame number)
114DM_NVN_SHOT_OUTdiagnostic`=<W>x<H>` makes `DM_NVN_SHOT` capture the picture as the present pass upscales it to that size, the crop included, instead of the raw swapchain texture
115DM_NVN_SKIP_FSdiagnostic`=<fragment key>[,…]` (up to 16) drops all draws of those fragment shaders, to measure their GPU cost or bisect a wrong draw; the picture is wrong
116DM_NVN_SKIP_SMALLdiagnostic`=<width>` drops all draws whose target width is at most that, to measure the cost of tiny render passes; the picture is wrong
117DM_NVN_SLICE_MERGEswitch`0` keeps passes into other layers of one array or cube texture level apart (on by default: they run as one layered pass)
118DM_NVN_SNAPRAWdiagnostic`=1` makes `DM_NVN_TEXDUMP` also save each target's raw bytes, with a text header line, since converting an HDR target to an 8-bit image truncates
119DM_NVN_T2T_FROMdiagnostic`=<frame>`: `DM_NVN_T2T_TRACE` records copies only from that frame on (default 0)
120DM_NVN_T2T_TRACEdiagnostic`=<W>x<H>:<file>`: after each copy into an RGBA16F texture of that size, copies the result into a trace buffer on the GPU timeline; 240 entries are written to the file
121DM_NVN_TBDRswitch`=1` turns on the replay's TBDR pass optimizations (store / load elision, pass merging, same-target continuation); off by default since bindless textures defeat their read inference
122DM_NVN_TEXCPUdiagnostic`=1` logs non-packaged (non-swizzled) textures in CPU-visible pools
123DM_NVN_TEXDUMPdiagnostic`=<frame>:<path>`, `size=<W>x<H>:<path>` or `layers=<n>:<path>`: saves every colour render target of that frame as PNG (`%d` = serial × 100 + layer × 10 + level)
124DM_NVN_TEXINFOdiagnostic`=<W>x<H>` logs storage and description of every texture of that size on first use, registration and initialization (pool, flags, packaged, non-zero bytes, swizzles)
125DM_NVN_TEXRAWdiagnostic`=<serial>,…` or `info` (the textures `DM_NVN_TEXINFO` picked out): saves those textures' raw bytes at the `DM_NVN_TEXDUMP` frame, with a text header line
126DM_NVN_TEXSNAPdiagnostic`=<in-frame pass index>,…`: with `DM_NVN_TEXDUMP`, copies those passes' colour attachments as they end and saves them with the end-of-frame dump
127DM_NVN_TREG_IDdiagnostic`=<n>` logs every registration of texture ID n: what it holds from then on, and the frame being recorded
128DM_NVN_TSVdiagnostic`=<path>` writes the per-frame NVN call table and timing rows (frame, metric, value) to a TSV, read by `scripts/bench.py`
129DM_NVN_TSV_CALLSdiagnostic`0` makes `DM_NVN_TSV` write only the timing rows, without the call counts (about two thirds of the file)
130DM_NVN_UBP_CHECKdiagnostic`=1` checks every uniform shadow made from memory: the pass ends, the updates land, the replay waits for the GPU and compares (a difference is a red line; slow)
131DM_NVN_UB_COPY_THREADswitch`0` copies uniform shadows of 512 bytes or more on the submit thread, as before (by default a worker copies them)
132DM_NVN_UB_DEFERswitch`0` ends the render pass at every inline uniform update, as before; by default an update inside an open pass is deferred to the pass end and later draws read a shadow (off in TBDR mode)
133DM_NVN_UB_LAZYswitch`=<n>`: the most deferred inline uniform updates kept across a render pass end (default 160); they land before the next copy, a conflicting draw or dispatch, or the submission end; `0` lands them at every pass end
134DM_NVN_UB_Ndiagnostic`=<frames>`: the length of each phase of the same-process alternating measurement `DM_NVN_UB` (default 180, minimum 60)
135DM_NVN_UB_PARTIALswitch`0`: a uniform block the deferred updates cover only in part ends the pass, as before; by default its shadow starts from memory and takes the submission's queued updates (on by default)
136DM_NVN_UDC_ABdiagnostic`=1` starts with the DontCare store for unwritten attachments off and turns it on after the second screenshot, for an on/off picture comparison in one run
137DM_NVN_UNWRITTEN_DCswitch`0` turns off storing attachments a render pass did not write as DontCare (on by default; part of the TBDR store lookahead), for equivalence comparisons
138DM_NVN_VBUF_CACHEswitch`0` turns off the cache of resolved vertex stream addresses and vertex argument table writes across draws (on by default), for A/B runs
139DM_NVN_VCONV_CHECKdiagnostic`=1` scans the indices again at every reuse of a cached vertex conversion range (`vconv_range`) and reports differences
140DM_NVN_VCONV_CPUswitch`=1` converts integer vertex inputs fed formats of another class on the CPU, as before, instead of through the shader's shadow inputs (`<key>_bv`)
141DM_NVN_VCONV_RANGEswitch`0` / `1` overrides the profile's `vconv_range`: CPU vertex conversion only over the vertices each draw reads instead of the whole bound range
142DM_NVN_VLOGdiagnosticSet: logs each NVN memory pool as it is created (address, memory, size, flags) with a backtrace
143DM_NVN_VSDUMPpathOutput file for post-vertex captures; used with DM_NVN_VSDUMP_KEY and the frame/count bounds
144DM_NVN_VSDUMP_FROMdiagnosticFirst presented frame eligible for a post-vertex capture (default 0)
145DM_NVN_VSDUMP_KEYdiagnosticVertex key to capture, or `*` for all eligible vertex shaders; storage-writing shaders are excluded
146DM_NVN_VSDUMP_MAXdiagnosticMaximum post-vertex captures (default 1, or 256 for the wildcard key)
147DM_NVN_WAITSdiagnostic`=1` turns on the wait ledger: every place a host or game thread waits on the CPU for the GPU or the encode thread, counted per frame
148DM_NVN_XVswitch`0` turns off the cross-submission attachment validity ledger, which skips write-backs of colour attachments cleared before their next use (on by default, only with `DM_NVN_TBDR` on)
149DM_NVN_ZBLOCKdiagnostic`=1` logs (`[zb]`) the all-zero blocks per level of each ASTC texture uploaded on the CPU (magenta when drawn); `=<folder>` also writes the raw storage of the first one per format and size
150DM_NVN_ZSKIPswitch`0` turns off the zero-source skip, which drops a draw whose fragment shader is proven to write 0 over targets already 0 (on by default, only with `DM_NVN_TBDR` on)
151DM_OE_SCRIPTdiagnosticScripted applet state changes at given seconds, `key=value@seconds,…` with keys `focus`, `opmode` and `bg` (`bg=1` / `bg=0` run the whole background round trip), e.g. `bg=1@20,bg=0@25`
152DM_OODLE_HOSTpathThe Mac host binary that `shader_split.py` runs in its Oodle tool mode to decode Trinity packs (`ONEPACK` files); set by the NSP script
153DM_OODLE_JOBpath`=<job file>`: the host runs the game's own Oodle decoder on every record of the job file right before `nnMain`, writes `<job file>.out` and exits (Unreal shader archives)
154DM_OODLE_MODULESpathThe rewritten modules the Mac host's Oodle tool mode loads when `shader_split.py` decodes Trinity packs; set by the NSP script
155DM_OODLE_SERVEswitch`=1`: the host answers decode requests on stdin / stdout with the game's own Oodle (or LZ5) decoder from the guest main thread before the SDK starts, until stdin ends
156DM_OPMODEplayerThe operation mode the game sees: `0` handheld, `1` console (default: the profile's `op_mode`, console unless set); read once at startup
157DM_PAD_MERGEswitch`=1` on the Mac merges every controller into player 1, as before, instead of giving each controller a player of its own
158DM_PATCH_FRONTswitch`=<bytes>`: the size of the patch area right before the module base for a long text (`BIG_TEXT`); set only by the rewriter's own rerun with the size it needs
159DM_PREEMPTswitch`0` / `1` overrides the profile's `core_preempt`: also check already-runnable higher-priority peers on the caller's core after every thread SVC
160DM_PRELOADdiagnosticSet: on the Mac, runs the host's early background loading (`dm_host_preload_start`) as the iOS app does, to exercise that path
161DM_PRESENT_FIFOswitch`0` makes the display link take the newest queued frame each tick, as before; by default it shows frames in order, at most one tick behind
162DM_PRESENT_HZswitch`=<N>`: the frequency of presentation pacing (default 60); `0` means no frame limit and is for performance profiling only
163DM_PRESENT_INTERVALswitch`display` presents one frame per display-link tick whatever interval the game sets; `game` follows the game's present interval (default: the profile's `present_interval`)
164DM_PRESENT_LATENCYswitch`=<n>` (above 0): the display link's preferred frame latency (default 1)
165DM_PRESENT_LINKswitchPresent pacing: `0` acquires the drawable itself, `1` (the default) presents on a 60 Hz display link, `2` uses a 120 Hz display link with a frame every other tick
166DM_PRESENT_SNAPplayer`=<n>`: present snapshots, a ring of n host textures (2 to 4; `1` = 2) the presents are copied to so the game's swapchain texture is free at once; `0` off (default: the profile's `present_snap`)
167DM_PRESENT_UPSCALEplayer`metalfx` scales a picture smaller than its rectangle on the screen through MetalFX's spatial scaler; `off` (the default) scales it bilinearly
168DM_PROBEdiagnostic`=module:offset,…` (Mac only): puts a `brk` at each guest address and on every hit prints the thread, registers, strings they point to and a backtrace, then runs the original instruction
169DM_PROBE_ALLdiagnosticSet: probe hits (`DM_PROBE`) also print x9–x18
170DM_PROBE_DUMPdiagnostic`=module:offset:length[:file]`: on the first hit of any probe, writes that range of guest memory to a file (default `run/<platform>/probe_dump.bin`)
171DM_PROBE_FRAMESdiagnosticPresented frame or inclusive `start-end` range in which guest probes print observations
172DM_PROBE_HEAPdiagnostic`=<name>,<start>,<size>,<free list>,<used list>`: hex offsets of the sead heap layout the probes' `!xN` heap walk uses (default Mario's `0,28,30,b0,c8`)
173DM_PROBE_HEAPFRAMEdiagnostic`=<vtable offset in main>` (hex): the probes' heap walk treats heaps of that class as frame heaps (head +0xe0, tail +0xe8)
174DM_PROBE_HEAPNAMEdiagnostic`=<text>`: the probes' `!xN` heap walk reports only hits on heaps whose name contains the text
175DM_PROBE_HEAPRAWdiagnosticSet: the probes' heap walk also prints the heap object's first 0x130 bytes
176DM_PROBE_HEAPWORDSdiagnosticSet: the probes' heap walk also prints each used block's first two words
177DM_PROBE_LIMITdiagnosticMaximum printed hits per guest probe; 0 or absent leaves the count unlimited
178DM_PROBE_POLLdiagnostic`=<address>[+<length>]` (hex, 4 bytes by default, up to 8): a host thread spins on the bytes and on each change snapshots every thread's pc, lr and frames, for writes the watch misses
179DM_PROBE_WATCHdiagnostic`=<address>[+<length>]` (hex, 8 bytes by default): write-protects that host page and reports who writes these bytes, without a debugger
180DM_PROBE_X2diagnostic`=<bytes>` (hex): probe hits also dump that many bytes of the memory x2 points to
181DM_PROGRAM_IDswitch`=<hex>`: the program ID the host reports from `svcGetInfo(ProgramId)` (default: the profile's `program_id`)
182DM_PSO_ARCHIVEpathThe folder of the per-game Metal 4 pipeline archive of pipeline bases (default `pso_archive/` beside `pso_user.tsv`); `off` keeps no archive
183DM_PSO_BUNDLEpathThe pipeline archive made offline (`<GPU architecture>.mtl4a`, `prebuilt.tsv`), read only; the iOS app and Mac launcher set it to their `pso/` folder; `off` ignores it
184DM_PSO_GPUSswitch`build_ipa.sh`: the GPU architectures, comma-separated, to build the offline pipeline archive for (`none` builds none); unset, `g18p` for a profile with `pso_mtl4 on`, else none
185DM_PSO_HYBRIDswitch`0`: a draw whose pipeline is not built yet waits for it instead of drawing with its shader pair's pulling pipeline meanwhile (on by default with the Metal 4 path)
186DM_PSO_IOS_MINswitch`build_ipa.sh`: the minimum iOS version of the offline pipeline archives (default the SDK's major version); an older system cannot open them and builds the bases itself
187DM_PSO_MANIFESTpathThe prewarm manifest to use instead of the profile's `pso_manifest.tsv`; `off` turns the prewarm off
188DM_PSO_MTL4player`0` builds render pipelines through the `MTLDevice` with no bases and no archive; `1` uses MTL4Compiler with the archive, hybrid pipelines and prebuild (default on on the Mac, the profile's `pso_mtl4` on iOS)
189DM_PSO_PAIRSpathThe prebuild's second shader pair table (default: `pso_pairs.tsv` beside the shader map)
190DM_PSO_PREBUILDplayer`0` turns off the prebuild of every known shader pair's pulling base into the pipeline archive (on by default); `tool` runs the prebuild alone on the Mac and exits
191DM_PSO_PREBUILD_DEPTHswitch`zero`: the prebuild tool (`DM_PSO_PREBUILD=tool`) builds bases for the near = 0 depth mode; the NSP script sets it from the profile's `depth_mode`
192DM_PSO_PREBUILD_THREADSswitch`=<n>`: the workers of the prebuild tool (`DM_PSO_PREBUILD=tool`; default: the performance cores less one)
193DM_PSO_PREPAREswitch`0` runs the prewarm in the background while the game starts, as without a window; `1` makes the first submission wait for the prewarm lists also without a window
194DM_PSO_PREPARE_THREADSswitch`=<n>`: the workers of the prepare step that builds the prewarm lists before the first frame (default: the device's active cores)
195DM_PSO_PULL_ALLdiagnostic`=1`: every draw that has a pulling pipeline draws with it, never with the pipeline for its vertex layout
196DM_PSO_RECORDpath`=<file>`: appends the shaders and pipelines used in the run to that file, for re-recording the prewarm manifest
197DM_PSO_USERpathThe per-device list of shaders and pipelines built on the spot (default: `pso_user.tsv` in the parent of `DM_SAVE`)
198DM_PSO_WAITLOGdiagnostic`=1` logs each draw that waited more than 20 ms for its pipeline, with its shader pair and why no stand-in served it
199DM_QOS_EDGESswitch`=e1,e2`: the Switch priority edges of `DM_QOS_MAP` (default `44,59`)
200DM_QOS_MAPswitch`=1` maps guest thread priority to QoS class: ≤ 44 user-interactive, 45–59 user-initiated, the rest utility (off by default: every guest thread runs user-interactive)
201DM_RENDER_SCALEplayer`0.5` to `1.0`: fixes the game's 3D views at that fraction of their size and turns its dynamic resolution off, for builds with a render scale stub; `1.0` (the default) keeps it
202DM_RESOURCE_AOCpathThe add-on content folder the iOS build copies into the app's `aoc/` (empty for none); written by `gen_resources.py`, read by `stage_resources.sh`
203DM_RESOURCE_CHAIN_HpathPath of `dm/gfx/nvn/dmsh_chain.h`, written to `Gen/resources.env` by `build_ipa.sh`; the Xcode copy phase (`stage_resources.sh`) stops when the prepared shaders are not of its chain version
204DM_RESOURCE_MARKERpathA file under the RomFS, written to `Gen/resources.env` by `build_ipa.sh`, that the Xcode copy phase (`stage_resources.sh`) checks for before copying the game files
205DM_RESOURCE_MSLDIRpathName of the shader library folder (`b-<chain>`), written to `Gen/resources.env` by `build_ipa.sh`; the Xcode copy phase copies the shaders to `msl/<name>` in the app
206DM_RESOURCE_PSOpathFolder of the offline Metal pipeline archive (empty for none), written to `Gen/resources.env` by `build_ipa.sh`; the Xcode copy phase copies it to `<App>/pso`
207DM_RESOURCE_ROMFSpathRomFS folder, written to `Gen/resources.env` by `build_ipa.sh`; the Xcode copy phase (`stage_resources.sh`) copies it into the app's `romfs`
208DM_RESOURCE_SHADERSpathiOS shader library folder, written to `Gen/resources.env` by `build_ipa.sh`; the Xcode copy phase (`stage_resources.sh`) copies it into the app's `msl/b-<chain>`
209DM_RES_CHECKdiagnostic`=1` prints the first 40 textures or buffers a shader reaches through its argument block that are not in the residency set (textures attributed to their parent allocation)
210DM_ROMFSpathThe game's RomFS folder, mounted read-only as `rom` (default `$DM_ROOT/romfs`); the Mac launcher, the iOS app and the NSP script set it
211DM_ROMFS_OVERLAYpath`=<dir>[:<dir>…]`: RomFS reads look in these folders first, in order, and fall back to `DM_ROMFS` (for a modified copy of some files)
212DM_ROOTpathWorkspace root (default `~/dm-work`): the host's and tools' default paths (RomFS, temporary storage, shader libraries under `build/cache/metal_shader_cache`, probe dumps) are under it
213DM_RTdiagnostic`0` leaves the thread that acquires the window on its QoS only, with no Mach time-constraint policy declaring the frame deadline (on by default; for power A/B)
214DM_RT_COMPswitch`=<ms>` fixes the computation the present thread's time-constraint policy declares; default `auto` re-declares it every 120 frames from that thread's per-frame CPU time (p90 and peak)
215DM_RUMBLEplayer`0` turns game rumble off (on by default); launcher setting
216DM_RUMBLE_GAINplayer`=0..3` scales the rumble strength (default 1, `0` is silent); launcher setting
217DM_RUMBLE_LOGdiagnostic`=1` logs the game's vibration handle requests and, once a second, the values it sent, how many had no routed output and the peak amplitude
218DM_SAVEpathThis run's save folder (must be set); the device save is `<DM_SAVE>_device`, and `pso_user.tsv` goes in its parent folder; the Mac launcher, the iOS app and the NSP script set it
219DM_SCHEME_NAMEswitchSet by `build_ipa.sh` itself for xcodegen's `project.yml`: the Xcode scheme name, `DmIOS`, or `<display name> (<title ID>)` for a project prepared with `--prepare-xcode`
220DM_SCREEN_MATCHswitch`0` keeps the screen's refresh rate in fullscreen; by default a Mac screen whose rate is not a multiple of the game's frame rate switches to one that is (144 → 120 Hz)
221DM_SF_TRACEdiagnostic`=1` logs every request on the game's own HIPC client sessions that the host answers (`hle_sf.c`)
222DM_SHAKE_Gswitch`=<G>`: on iOS, the acceleration beyond gravity above which a flick of the phone shakes the controller's six-axis sensor (default 1.5)
223DM_SHARED_FONTpathFont file served for every shared-font type except the Nintendo extension (default `$DM_FONT_DIR/standard.ttf`, then macOS's Arial Unicode)
224DM_SHARED_FONT_EXTpathFont file served for shared-font type 5, the Nintendo extension with the button icons (default `$DM_FONT_DIR/nintendo_ext.ttf`, made by `make_ext_font.py`)
225DM_SHOW_FPSplayer`1` shows the frame-rate counter on the iPhone (frames put on screen per second, top left); at IPA build it sets `DMShowFPS` in `Info.plist`, which `Documents/env.txt` overrides
226DM_SLOWFRAMEdiagnostic`=1` writes the per-frame timing breakdown to the log only for dropped frames (kept in a ring of the last 16 frames, judged 8 frames late)
227DM_SPINswitch`0` makes the rewriter's spin gate return at once, so guest poll loops spin with no sleep; the gate stays (on by default)
228DM_SPIN_LISTdiagnostic`=1` makes `patch_nso.py` print every guest poll loop it found and sends through a spin gate
229DM_SPIN_POLLswitch`=<µs>`: how long a spin-gate wait polls before it sleeps with the yield back-off (default 2000; `0` yields on every pass)
230DM_SVCdiagnostic`=1` logs memory SVCs (`SetHeapSize`, `MapMemory`, `Map`/`UnmapPhysicalMemory`) with their addresses and sizes
231DM_SYMCHECKdiagnostic`=1` checks every hashed module symbol lookup against a linear search and logs a red line for each mismatch
232DM_TEAM_IDswitchApple team ID for the per-game Xcode project, used when `--team-id` / `TEAM_ID` is not given; `build_ipa.sh` uses the placeholder `0000000000` (unsigned) when unset
233DM_TEMPpathTemporary storage folder (default `$DM_ROOT/run/platform/temp`); stand-in system data goes in `<DM_TEMP>_sysdata`; the Mac launcher, the iOS app and the NSP script set it
234DM_TEST_FS_FAILdiagnostic`=write:<n>[:<errno>]` makes the nth save write fail with that errno (default ENOSPC), which refuses the save transaction's commit
235DM_TEST_FS_FAILATdiagnostic`=<point>[:<count>][,…]` makes steps of the save transaction (`mountclone`, `reclone`, `guestname`, `renameback`) fail with ENOSPC
236DM_TEST_GEOMETRYtestPath of the native `t_geometry` executable; `test_dmsh_geometry.py` runs its native geometry emitter checks only when it is set
237DM_TEST_KEYRACEdiagnostic`=<n>` creates up to n (at most 512) pthread keys on a thread of its own while the host starts up
238DM_TEST_KILL_ATdiagnostic`=write:<n>` exits the process (`_exit(9)`) at the nth save write, imitating a kill mid-write
239DM_TEST_LEAK_GPUdiagnostic`=1` allocates and keeps a 1 MB shared Metal buffer every 100 ticks: a GPU memory leak on demand
240DM_TEST_LINK_STALLdiagnostic`=<start s>,<duration s>`: counting from the first present, pauses the display link at that point for that long, to check the present fallback
241DM_TEST_NO_METAL4diagnostic`=1` treats the GPU as one without Metal 4, as on a virtual Mac: the NVN layer starts only its classic part and drops every present
242DM_TEST_PRESENT_LAGdiagnostic`=<every n>,<ms>[,<in a row>][;…]` sleeps that long before every nth present (and the ones after it in the run): a slow frame on demand
243DM_TEST_SWKBD_HOLD_MSdiagnostic`=<ms>` (with `DM_KBD`) keeps the system keyboard up that long before `DM_KBD`'s text is returned, as a player typing would
244DM_TEST_SWKBD_LAG_MSdiagnostic`=<ms>` sleeps that long between the keyboard handing back its text and the game's thread getting the result, to check that auto-accept does not act early
245DM_TEST_TRANSFORM_FEEDBACKtestPath to the native t_transform_feedback executable used by the Python feedback tests
246DM_TEST_UP_LEAKdiagnostic`=1` keeps the old upload staging block instead of retiring it, as before the fix, to measure the leak
247DM_TEST_UP_LOSTdiagnostic`=<batch index>` treats that batch of uploads as dropped, to exercise the re-upload path
248DM_THERMAL_CAPswitch`0` turns off the thermal cap, which holds the frame step at 30 fps while iOS reports a serious or critical thermal state (on by default)
249DM_THRdiagnostic`=1` logs each SVC (except `SleepThread`) with its first four arguments, and each `CreateThread` with entry, stack, priority and core
250DM_THRCPUdiagnostic`=<tsv path>[,<seconds>]` writes each thread's CPU time (100% = one core) and the total every interval (default 10 s); on iOS a relative path is under `Documents`
251DM_TOUCH_HAPTICSplayer`0` turns off the light haptic tap when a touch control is pressed (on by default); launcher setting
252DM_TOUCH_LOGdiagnostic`=1` logs each touch-screen read with touch points (sample, finger, position, attributes) and each gesture entry, up to 500 lines
253DM_UDC_SELFTESTdiagnostic`=1` runs a start-up check of DontCare load and store on private depth-stencil and RGBA8 textures (clear, Load + DontCare, read back) and logs one result line
254DM_UE_SHADERSpathFolder of the Unreal shader code archives decoded by `uepak.py`, for `shader_split.py` (default `ue_shaders` beside the RomFS); needed when the RomFS has Unreal paks
255DM_VK_CAPTUREpath`=<dir>` (Mac) writes every SPIR-V module the game creates to `<dir>/<key>.spv`; the NSP script's Vulkan shader capture stage sets it
256DM_VK_LOGdiagnostic`=1` logs Vulkan object creation in the Vulkan-on-Metal layer
257DM_VSYNC_HZswitch`=<Hz>`: rate at which a host thread fires the vi vsync event when the display link does not drive it (default 60)
258DM_WATCHdiagnostic`=<s>` dumps all threads after that many seconds (SIGALRM) and turns on the stall watchdog; off unless set
259DM_WATCH_SAMPLEdiagnostic`=<path>` (Mac): when the stall watchdog fires, samples the process for 1 s with `/usr/bin/sample` and writes the thread stacks to that path
260DM_WATCH_STALLdiagnostic`=<s>`: when the frame loop makes no progress for that long (default 15 with `DM_WATCH`), logs a red line, dumps the threads and exits
261DM_WINDOWswitchWhen set (to any value, `0` included) opens a Mac window with keyboard and controller input; unset runs headless with the guest on the current thread; the Mac launcher sets it
262DM_XCODE_DERIVED_DATApathXcode derived data folder for `build_ipa.sh` (default `$W/build/ios/xcode-dd`); the NSP script points it into the game's build folder
263DM_XCODE_PROJECT_DIRpathFolder of the per-game Xcode project that `build_ipa.sh --prepare-xcode` makes (default `$W/xcode`); the NSP script sets it
264DM_XV_FILEpathFile where the attachment validity ledger keeps the keys it disabled after a violation, read at the next launch
265DM_YIELD_BACKOFFswitch`0` turns off the yield back-off; `=<cap µs>[:<start µs>]` sets its sleep cap and the run of yields after which it starts (default 250:2000)