# nx2navi.ini: settings for nx2navi.exe. Copy this file to nx2navi.ini next to nx2navi.exe and remove the '#' of a line to change it. # Each line shows the default; on a Steam Deck the device profile ([display]) changes a few of them. A NX2NAVI_* # environment variable of the same name (NX2NAVI_FPS_LIMIT for fps_limit) overrides the file. Keys are case-insensitive; # '#' and ';' start a comment; [sections] only group lines. # Only the keys in this file are settings. A line with any other key does nothing: the game's log names it at the # start ("no setting of this version") and the settings menu (F1) shows it in its bottom row. # Updates and rebuilds of the game never rewrite nx2navi.ini; the settings menu changes only the lines of the settings # it changes and keeps every other line as it is. [frame rate] # Frame rate limit: 30, 40, 45, 60, 90, 120, 144, any whole rate from 30 to 240, display (the refresh rate of the # window's monitor, at most 240) or unlimited (as fast as the PC goes, at most 240 frames of the game a second). A # higher rate gives 240: far above it the game's own code fails (its quick menu crashed at 700 fps). Above 60 # is experimental and needs realtime = 1. Changes while the game runs take effect at once. # With mailbox or fifo presentation (vk_present, the default) a frame reaches the screen at a vertical blank, so a limit # that does not divide the monitor's refresh rate keeps each frame on screen for a different number of refreshes. On a # 320 Hz monitor 80, 64, 40 and 32 divide it and 90 does not: 90 fps alternates 3 and 4 refreshes per frame, which reads # as judder while the frame counter still shows 90. Likewise on 240 Hz 60, 48 and 40 divide it and on 144 Hz 72, 48 and # 36 do, while 60 does not. vk_present = immediate shows a frame as soon as it is presented, without this quantisation, # at the cost of tearing. A monitor running with variable refresh (FreeSync, G-Sync) follows the frames instead, so # there any limit inside its range is even. # With frame generation on (framegen, [display]) the limit still counts the frames the game draws, and the generated # frames come on top: 60 at 4x is 60 drawn and 240 on screen. Only display counts the frames on screen, so there the # game draws the monitor's rate divided by the multiplier. # fps_limit = 60 # Where RivaTuner Statistics Server is installed and running, the limit goes into its profile for the game's # executable and RTSS does the limiting instead of the game, once RTSS is seen holding the game to it; closing the game # puts back what the profile held, and after a crash or a kill the next start does, unless it has rtss = 0 # (rtss-profile.txt next to the game keeps what it held). Changing that profile needs the game run as administrator # (RTSS keeps its profiles under Program Files). Without it the game limits by itself, as it does with frame generation # on (RTSS would count the generated frames), while the window is minimised, and for the rest of the run when RTSS's # own frame counter shows the game past the limit (RTSS then hooks the game without holding it back) or RTSS is not # seen holding the game within 30 s; the game paces movies itself. With low latency on, the driver holds the limit. # rtss = 0 always leaves it to the game. With rtss = 0, # frame generation or low latency, a limit set in RTSS itself (its global profile or the game's, a frame time limit or # scanline sync) limits the game a second time: the log and the settings menu say so, and setting it to 0 in RTSS # leaves one limiter. # rtss = 1 # 1: asks RTSS's EnumProfiles whether the game's profile exists, instead of looking for its file. EnumProfiles crashes # the game (RTSS keeps a pointer of the game's in 32 bits); only for testing an RTSS that fixed it. # rtss_enum = 0 # Older key, read only while fps_limit is unset: fps60 = 0 means a limit of 30. # fps60 = 1 # Real-time frame step: game speed follows the clock instead of the frame count. # realtime = 1 # Cloth simulation on the real-time clock. Needs realtime = 1. # cloth_realtime = 1 # Fix for physics that bounce at high frame rates. # highfps_fix = 1 # Above 60 fps the game's physics solved contacts and friction in fewer steps a second than at 60, and in none at all # in a frame shorter than 1/240 s, so things standing on moving platforms were left behind. 1 rounds the step count # up instead; 0 is the game's own count. 2 also gives every frame at least the 4 steps of a 60 fps frame, which costs # more physics time above 60 fps (576 steps a second at 144 fps, 960 at 240, against about 288 and 240 with 1) and is # a candidate fix for Link left behind on the Deku Tree's floating platform. Read at start. # physics_steps = 1 # The number in the window that shows a pick-up (a rupee) counts up by whole steps a frame, and above 60 fps the game # rounded that step down to nothing: the window stayed until the area was left and its counting sound went on. 1 lets # it count at least one a frame; 0 is the game's own count. # pickup_count = 1 # Water surfaces and the springy floors (the Deku Tree's webs) are simulated in fixed steps of 1/60 s, as many as the # frame's time holds, and the game dropped the rest: above 60 fps every frame ran none, so they stood still under Link. # 1 keeps the rest for the next frame, 60 steps a second at any frame rate; 0 is the game's own count. Read at start. # water_steps = 1 # Above 60 fps the game handed its sound system a fraction of a frame each frame, which was reported to keep sounds # held after an area unloaded until new sounds and then the music went silent. 1 runs the sound system 60 times a # second with whole frames while the frame rate is above 60; 0 is the game's own step. Read at start. # sound_steps = 1 # Above 100 fps the game kept only a tenth of a moving floor's speed for whoever stood on it, so Link was left behind # on moving platforms (the Deku Tree's floating one). 1 makes the floor carry him as at 60 fps at any frame rate; 0 is # the game's own cut. Read at start; needs game code generated with this release. # floor_carry = 1 # The ocarina's recorder counts how long each note and rest lasts in 60 Hz frames, and the game cut each frame's step # to a whole number: above 60 fps that was 0, so a recorded performance lost its rests and the recorder's time limits # never came, and at the 40 and 45 fps limits it counted slow. 1 keeps the fraction for the next frame, 60 a second at # any frame rate; 0 is the game's own count. Read at start; needs game code generated with this release. # ocarina_timing = 1 # A movie's narration and fades follow the picture on screen: 1 counts their time from the shown picture's # timestamp, so they stay with it at any frame rate (with movie_fps = 0 too) and wait when the picture stalls; 0 counts # the game's redraws, as before, which keeps them with the music when the picture stalls. Read at start; needs game # code generated with this release. # movie_pts = 1 # The step the game is given each frame: 1 keeps it steady (the same value from frame to frame while the frame rate # holds, exactly one 60 Hz frame at a 60 fps limit) and makes up for a late frame over the next second; 0 is the mean # of the last five frame times, which changes with every frame. # step_steady = 1 [performance] # The keys of this section and of [diagnostics] are for testing and troubleshooting, and take effect at the next start. # The Advanced tab of the settings menu (F1) shows all of them except zstd_native and zstd_check. # Scheduling. # A thread waiting for a virtual core interrupts the owner when it runs game code: 1 = on, 2 = priority inheritance # without the interrupt, 0 = off (the old scheduling). # async_preempt = 1 # Replay NVN submissions on their own thread, at most one frame behind the game, 0 or 1. Default: off. Helps where the # game waits for the GPU and in heavy scenes (15 to 18 percent more frames per second in a village); adds up to a frame # of latency, and can show a dark or flickering frame now and then: the other thread reads vertex and buffer memory # the game has sometimes rewritten by then. # replay_async = 0 # EXPERIMENTAL. Record the large groups of draws of a submission on this many replay worker threads beside the # submitting one: auto or 0 to 16. Default: 0, the replay records everything on one thread. auto (the default in # 0.10.0 only): half the CPU's physical cores less one (2 on 6 cores, 3 on 8, 5 on 12, at most 6), none on four cores or # fewer and none on AMD's driver for RX 6000 and older Radeon cards, where a player's game lost its graphics device with # workers on; the log's "replay workers automatic" line says how many. 3 gave 51.7 instead of 43.6 fps standing in Hyrule Field on an RX # 7900 XT, and more than 3 gave nothing more there. Also in the menu: Game, Testing, CPU helper threads. # With 1 a worker records each long run of draws while the submitting thread waits for it: no faster, it checks that # the pictures stay the same. # replay_workers = 0 # EXPERIMENTAL. 1 lets the game start on its next frame while the graphics card still runs the end of the last one: the # upscaler (FSR 4, FSR 3.1 or DLSS) and the interface drawn after it. The graphics card runs the same work, with the # copies of what it wrote for the game moved before that end, and the game's waits end once those copies and the # results it reads are there. A frame whose end hands the game anything else runs as before. Default: 0 (1 in 0.10.0 # only). Standing in Hyrule Field on an RX 7900 XT with FSR 4: 50.7 instead of 42.5 fps, and 63.5 # instead of 49.4 with replay_workers = 3. # Does nothing without one of those upscalers, nor with the lazy write-back (the default on NVIDIA and Intel cards). # Also in the menu: Game, Testing, Start next frame early. # tail_early = 0 # EXPERIMENTAL, with replay_workers. replay_pipe = N (1 to 4, default 0): the submitting thread goes on past up to N # groups its workers still record. replay_small = N (0 to 63, default 0, needs replay_pipe): a group of N draws or more # that is too small to share out (fewer than 64 draws) goes whole to one worker; 64 or more reads as 63. Kokiri Forest # standing on an RX 7900 XT with FSR 4, tail_early = 1, replay_workers = 5, replay_pipe = 4 and replay_small = 16: 63 # instead of 45 fps with all of them off. Also in the menu: Game, Testing, Helpers work ahead (replay_pipe) and Helpers # take small jobs (replay_small). # replay_pipe = 0 # replay_small = 0 # EXPERIMENTAL, THE GAME CRASHES WITH 1. 1 lifts the virtual core gate: guest threads run without the console's limit # of one thread per core, and the game keeps per-core data without locks. With 1 the game crashes or hangs, # usually at start. Keep 0 to play. # free_cores = 0 # Windows timer resolution of 1 ms for steadier frame pacing (0 = the Windows default). # timer_1ms = 1 # The thread that records the GPU work (the first to spend half a second doing it, not the one that submits first) keeps # the highest scheduling priority (recorder_prio), and can get a core of its own that the process's other threads stay # off (recorder_core: 0 = never, the default; auto = with 12 or more logical processors, unless the game runs on the # cache die below; 1 always). That is a fast core, with both of its logical processors: on Windows the highest-numbered # core of the fastest efficiency class; on Linux the performance core that clocks highest on a hybrid CPU (else the core # of the highest capacity or clock), and none when fewer than four cores are that fast. The log names the thread and # its logical processors. Default 0: on an i9-14900KF the reserved core left the woken replay thread unscheduled for # about 200 ms roughly once a second. # recorder_prio = 1 # recorder_core = 0 # Submissions handed to the GPU queue together in one call, 1 to 16 (1 = each one at once). # submit_batch = 4 # Mesa's Vulkan drivers (RADV, ANV, NVK): every submission to the GPU queue goes to a thread of the queue's own, so its # kernel call leaves the thread that prepares the frames, 0 or 1. Default: on (Linux), off (Windows). 0 leaves the # driver's own choice. Unused when MESA_VK_ENABLE_SUBMIT_THREAD is set. # submit_thread = 1 # Occlusion query results are read back from the video card in batches, 0 or 1. Default: on. 0 reads each query with a # call of its own, as before, which on AMD's Windows driver held every frame's "GPU done" back by about 4 ms. # oq_batch = 1 # The game clears small ranges of its buffers on the video card. Where such a range holds a counter the video card # also reports into (a timestamp or an occlusion count), the clear and the reports reach the game's memory in the # order the game issued them, 0 or 1. Default: on. 0 leaves the clear to the video card alone, as before, and a # report issued before the clear can then be written after it. # clear_small_cpu = 1 # Occlusion counts the replay could not take, 0 or 1. Default: off. When the GPU or the thread that reads the results # falls behind (a hitch at a high frame rate), some draws find no free occlusion query and go uncounted, and the # game's report after them says only what the rest counted, at least 1: the object it tested looks all but hidden for # that frame, and whatever the game scales by that count drops for one frame. 1 makes such a report repeat the last # full count of the same object (or what was counted, if that is more). The log says how often it happens either way # ("samples-passed reports so far missed draws", at the 1st, 10th, 100th...). Read at start. # oq_hold = 0 # Indexed quads and line loops, 0 or 1. Default: off. Vulkan has no quad or line-loop topology: draws without indices # are rewritten already, and 1 does the same for indexed ones (two triangles per quad, a closing line for a loop), which # otherwise are drawn with the game's indices as triangles and an open line, joining corners of neighbouring quads. # The log names the first such draw either way ("an indexed quad list"); without that line the game has drawn none. # Read at start. # quad_index = 0 # EXPERIMENT, 0 or 1. Default: off. The game asks the video card how much of an object would show behind what is # already drawn (an occlusion query) and leaves hidden objects out. With 1 it asks nothing and draws them all: more # draws in a frame, and no queries to issue or results to wait for and read back. Whether that gains or loses frames # has not been measured, and it differs from place to place. The log's "patches:" line at the start says # "occlusion_off on" when the game was built with the patch set and the setting took effect. # patch_occlusion_off = 0 # How many milliseconds a submit call waits for the game's own signal that the frame's data is written, when the # frame's commands begin with a wait for that signal (0 to 100; 0: the frame is set aside at once and drawn at its # present, as before). # gate_wait_ms = 10 # Dynamic resolution, 0 or 1, applied at once: with a DLSS upscaling mode, the scene resolution follows the GPU time # per frame toward dyn_res_target milliseconds (1 to 100), one DLSS step at a time, each held for dyn_res_step frames # (8 to 600), from the DLSS mode set down to performance. Default: off. # dyn_res = 0 # dyn_res_target = 16.7 # dyn_res_step = 45 # Processors. On a processor whose dies have L3 caches of different sizes (AMD's two-die X3D processors, with 3D # V-Cache on one die) the game runs on the die with the larger cache when that die has 8 cores or more: 1 = on, # 0 = Windows places the threads. # cache_die = 1 # One logical processor of each physical core, so no two busy threads share a core: 1 = on, 0 = all of them. # one_per_core = 0 # Shaders and pipelines. # Draws whose pipeline is still building: default waits on a reserved worker; draw is the previous scheduling. # pipe_wait = default # Which draws are dropped instead of waiting for their pipeline: strict (only draws into per-frame passes), any (also # draws into passes whose target a recent frame rendered; full-screen draws wait, from pipe_frame_wait_ms) or fullscreen # (those and full-screen draws: no wait, but a lighting or fog pass that is dropped shows as a black or unlit frame). # pipe_skip = any # How many milliseconds one frame may wait, in all, for the shaders and pipelines of its full-screen draws and of # draws into pictures drawn for the first time (0 to 500). What is not ready by then is left out of that frame and # built in the background. # pipe_frame_wait_ms = 50 # A picture the game has drawn in many frames counts as drawn every frame after a pause too (a loading screen, a # menu), so the first frame of an area leaves a draw out while its pipeline is built instead of stopping for it. # 0: as up to 0.7.1, such a frame waits for each new pipeline in turn. # pipe_skip_steady = 1 # How many milliseconds the draws of one frame may wait, in all, for a missing pipeline to be linked from the shader # libraries in the graphics driver's cache before they are dropped (0 to 100; 0: dropped at once, as before). # pipe_link_ms = 6 # How many milliseconds one missing pipeline is waited for, counted from the first draw that needed it (1 to 50). # With its shader libraries in the driver's cache a pipeline takes 2 to 8 ms; what is not ready by then is left out # of the frames until it is. A longer wait leaves fewer draws out and makes those frames longer. # pipe_link_draw_ms = 3 # When a draw finds its pipeline missing, the rest of the commands the game submitted with it are read ahead and the # shader libraries of every other pipeline they will need are built at once on background threads, so the later draws # find theirs ready instead of waiting one after another or being left out of a frame. 0: off, as before. # pipe_ahead = 1 # A pipeline whose fragment shader reads the picture it draws into (soft particles, water, some full-screen passes) is # linked from the shader libraries like any other. 0: as before, such a draw waits for the whole compile. # gpl_feedback = 1 # The threads that build shader libraries also link the pipelines of draws that were left out of a frame, several at # once, instead of one thread linking them one after another while the others build optimised pipelines. 0: as before. # pipe_fast_workers = 1 # The graphics driver's cache of shader libraries is checked at every start and, when it lost them (a driver update, # a cache the driver emptied), filled again in the background while the game runs. 0: no check; force: at every start. # After two cold starts in a row warming stops being tried on that driver; once its cache can hold the libraries (on # NVIDIA under Windows, Shader Cache Size Unlimited in the NVIDIA app), start once with force, or delete # shader-warm.txt, to warm again. # lib_warm = 1 # Draws into a picture drawn for the first time (a lookup table, a new area's target) wait for a pipeline built for # the first time from pipe_frame_wait_ms; one left over is drawn the next frame its picture is drawn. 0: as up to # 0.7.1, each such draw waits up to oneshot_wait_ms milliseconds, which stops the game for as long as the pipelines # of a new area take to build. # oneshot_budget = 1 # oneshot_wait_ms = 30000 # A draw whose shaders also write memory (a storage buffer, or an image they store into) waits for its pipeline in # the same way, also when it draws into a picture the game draws every frame: left out of a frame, it would be drawn # again the next frame, but what it was to write would be missing for everything that reads it until then. 0: such a # draw is left out like any other while its pipeline is built. # draw_writers_wait = 1 # Build shader stage libraries in the background ahead of time, and the threads for it (1 to 16; default 2). More # threads mostly wait on the graphics driver's lock: 16 on NVIDIA spent about 8 cores spinning in the driver. # lib_prebuild = 1 # lib_prebuild_threads = 2 # How many compute pipelines the start builds and keeps: those of the compute shaders the game used most recently. # Every other known one is built into the pipeline cache and released again, and made from the cache when the game # first uses it (well under a millisecond). Very large compute shaders the game has never used are not built at all. # all: the start builds and keeps the pipeline of every known compute shader, as versions up to 0.6.1 did, which held # more than 2 GB of video memory. 0: none are kept. # compute_keep = 512 # 1: very large compute shaders that no cache holds are built on one background thread after the start. 0: each is # built when the game first uses it, which can hold that frame for a second or two. # lib_prebuild_big_bg = 1 # The commit headroom in MB those background builds wait for (0: no check). On Linux the headroom is the smaller of # the room left under the cgroup's memory limit (memory.max, memory.high) and the memory available on the machine. # big_build_free_mb = 8192 # How far those background builds may raise the process commit in MB before the rest wait for their first use instead # (0: no limit). Each large shader costs the driver 1-4 GB; on a 31 GB machine four of them took the process from 15 to # 29 GB and the game stuttered, so raise this only on a machine with room to spare. # big_build_max_mb = 4096 # Memory kept free of pipelines built ahead of their first use (at the start and in the background during play), in MB # of commit headroom: RAM plus page file not yet promised to a program. Such a build starts only while this much stays # free beyond what the builds already running are counted for; otherwise it waits or is left to the moment the game # first needs the pipeline, which can hold a frame once but does not push a full machine into paging. A pipeline a # draw is waiting for is always built. 0: no check. Default: 4096. # build_free_mb = 4096 # What each such build is counted for while it runs, in MB: the working memory of the video driver's shader compiler. # A very large compute shader is counted for 4096. Default: 64. # build_reserve_mb = 64 # 1: the log says how many pipelines came from pipeline-cache.bin; 2 also logs every compute pipeline built. 0: off. # pipe_feedback = 1 # The limit of pipeline-cache.bin and of pipeline-cache-play.bin, each, in MB (0: no limit). A file larger than # this starts empty, so the game never writes one past it: once a cache reaches the limit, pipelines compiled after # that are compiled again at the next start. With the pipeline list of 0.9.1 and later a full cache is about 550 MB # on an NVIDIA card, so the limit has to stay well above that. Default: your RAM / 32, between 1024 and 4096 (2048 # with 64 GB). # pipeline_cache_max_mb = 2048 # 1: the pipelines a run compiles go into pipeline-cache-play.bin, a small file of its own, so pipeline-cache.bin # (hundreds of MB) is not written again while you play; the small file is folded into the large one at a start once # it has grown. 0: one file, written whole whenever a run made a new pipeline. # pipeline_cache_play = 1 # The size (MB) at which pipeline-cache-play.bin is folded into pipeline-cache.bin at a start. # pipeline_cache_play_mb = 64 # 1: the pipelines FSR 3.1 makes for upscaling and frame generation are kept in the pipeline cache files, so a later # start does not compile them again. 0: FSR 3.1 creates them without those files, as the graphics driver alone keeps # them. # ffx_pipe_cache = 1 # 1: where the driver has VK_KHR_pipeline_binary, compiled pipelines are kept in pipeline-binaries.bin under the # runtime's own keys, so a renamed or updated exe starts without compiling them again (pipeline-cache.bin is then # not used). Default 0 (pipeline-cache.bin only) while it is being tested. # pipe_binaries = 0 # pipeline-binaries.bin larger than this (MB) starts empty and is rewritten (0: no limit). # pipe_binaries_max_mb = 1024 # Build known pipelines ahead of time. # pipe_prebuild = 1 # Count the shared pipeline list that comes with the release (seed-pipeline-keys.bin) as known pipelines, so a new # install builds them at the start instead of at their first draw. 0: only the pipelines this install drew. # pipe_seed = 1 # Whether the start builds the pipelines of that list which this install has never drawn. They take 2 to 4 GB of # memory (commit) on an NVIDIA card and about 1.5 GB on an AMD one for the whole run, drawn or not. # auto (default): built at the start, except on a PC that starts with less memory free than the game takes in play # (the start's "this machine has ... MB of memory left for the game" warning): there each is made at its first # draw, from the pipeline cache, and built at the start from then on. # 1: always built at the start. 0: never; a first visit to an area can then hold a frame for a moment. # pipe_seed_boot = auto # How long the start waits for known pipelines on the "Preparing shaders" screen. # auto (default): with the graphics pipeline library the start builds them for at most 20 seconds and the rest in the # background while you play. The first start after a graphics driver update (or with another GPU) waits for # everything instead, because nothing is built then and the game would crawl while it all compiles beside it: every # known pipeline, the compute pipelines and the driver's own shader cache. That takes minutes, once per driver; a # start closed during it goes on with it the next time (three starts at most). # 1: every start waits until every known pipeline is built. # 0: never more than the 20 seconds, also after a driver update. # prewarm_full = auto # The most seconds that first start after a driver update waits (0: no limit). When they are up the game starts and # the rest is built in the background while you play, as on any other start. Closing the window while it waits is # safe: the next start goes on with it. # prewarm_full_s = 600 # Threads that translate known shaders at start (1 to 64; default: half the CPU threads, at most 16). # prewarm_xlate = 8 # After an update that brings a new shader translator, 1 keeps using the shader cache's translations from the earlier # translator, so the update adds no shader translation at start or in play: while you play, a background pass at the # lowest priority translates them again with the new translator for the next start, then deletes the old ones. A shader # the new translator cannot translate keeps its old translation. 0: shaders the new translator has not translated yet # are translated before they are used (at start or when the game first draws them), as earlier versions did. # shader_carry = 1 # 1 keeps a shader's translation (its SPIR-V) compressed in memory once no pipeline was made of it for # shader_compress_idle_s seconds (1 to 3600), and decompresses it when one is made again (about 0.06 ms for most # shaders): about 570 MiB less memory with 7,000 shaders in memory, the picture unchanged. 0 keeps every translation # as it is. # shader_compress = 1 # shader_compress_idle_s = 30 # Vulkan graphics pipeline library, 0 or 1. Default: on, except with AMD's Windows driver for RX 6000 and older cards # (RX 400 to RX 6000), where the game ended at every enemy killed with it on. There it is off: a pipeline needed for # the first time is built whole while its draw is left out for some frames, and the start waits until every pipeline # of earlier sessions is built. gpl = 1 turns it on again. # gpl = 1 # The pipelines of the foliage, the grass and the terrain (mesh shaders) are linked from shader libraries like the # others, where the graphics pipeline library is on: foliage of a kind seen for the first time is drawn after a short # link, and its optimised pipeline is built behind it. 0: as before, each such pipeline is built whole (0.2 to 1.1 s) # while its foliage waits or is left out of the picture. The log's line "mesh pipelines are ..." says which is in use. # gpl_mesh = 1 # Textures and memory. # ASTC texture decoding: native (the GPU's own ASTC support), gpu (a compute shader), cpu, or auto (native when the GPU # has it, gpu otherwise). # astc = auto # With GPU ASTC decoding, 1 requests BC3 compression. Slight blocking is possible. 0 keeps RGBA8, which uses about # four times as much memory for these textures and can exhaust memory while loading. # Leave this setting commented for automatic selection. The renderer requests BC3 when the largest device-local GPU # heap is under 20 GiB or the system reports less than 47 GiB of RAM (allowing for a nominal 48 GiB PC). If the RAM # size is unknown, only the GPU heap decides. Look for "NX2NAVI_ASTC_BC unset" in the game log to see the decision. # astc_bc = 1 # With BC3 on: a texture none of whose texels is see-through is BC1, half the size of BC3 with the same texels (each # upload checks the blocks as it copies them). 0: every ASTC texture BC3. # astc_bc1 = 1 # Game memory shared with the GPU: auto (mirror on a discrete GPU, import on an integrated one), import (host memory # imported into Vulkan), mirror (pools used as buffers get a copy in video memory) or verify (mirror plus a check of # every copy; slow). On a discrete GPU import can be far slower than mirror, not slightly slower: the GPU reads the # game's pools over PCIe. A 5070 Ti Laptop went from 6 ms to 135-230 ms of GPU time per frame with import (5 fps on the # title screen, bound: gpu, every line of the perf window waiting on a fence). The log names the mode in use: "mem: # mode import" or "mem: mode mirror". # memory = auto # A new texture created over a live texture's memory starts with that content instead of empty. # tex_alias = 1 # A new depth image is cleared at the place in the frame where the game makes it (1, default), not ahead of the # frame's other work: made ahead, the clear could wipe depth that draws of the same frame still read, and the sun's # shadow went fully dark for one frame a few times a minute where the game resizes its shadow maps (a town gate). # 0: cleared ahead, as before. depth_alias_log = 1 logs each new depth image made over a live texture, with its frame. # depth_init_inline = 1 # Small texture uploads stage in ranges of a few kept buffers instead of a new buffer each (0 = a buffer each). # stg_arena = 1 # With astc = gpu: the compute shader reads the blocks in the game's tiled layout, so the CPU only copies the # texture (0 = the CPU untiles the blocks first). # astc_gpu_deswizzle = 1 # With astc = gpu: 1 keeps the decoder's scratch buffer from one upload batch to the next instead of making it again for # each, to shorten the hitches when an area loads (0 = one per batch). # astc_scratch_keep = 1 # With astc_scratch_keep = 1: 1 gives back a scratch grown for a large texture 5 s after the last one needed it (up to # 192 MiB of video memory after an area load); 0 keeps it until the next ASTC upload, as in 0.10.1. # astc_scratch_trim = 1 # With astc = gpu: 1 stages a texture's ASTC blocks in the shared staging ranges instead of a buffer of their own # (0 = a buffer each). # astc_arena = 1 # A render target that needs an image of its own takes the image of a released one of the same size and format # instead of making a new one (0 = always a new image). # tex_reuse = 1 # A texture the game does not fill from the CPU itself, made over memory the CPU writes (a second description of a # texture's bytes), starts with those bytes and takes the game's later writes to them until something is drawn into # it (1, default). 0: it starts empty, as before, and what is drawn with it can come out flat and pale. 2: it gets # the bytes once and no later write. Costs an upload for each such texture; a render target the game makes over # CPU memory starts with the last picture left there instead of an empty one. # tex_split_fill = 1 # 1: shaders mark the textures they sample, so that while video memory or the system's memory runs low, textures no # shader sampled for a while go, even those the game keeps registered (the areas it has loaded); one sampled again is # made again within a few frames. The first start after changing it builds the pipelines again. 0: such textures stay. # 2 (diagnosis): the same marks, and such textures give way to stand-ins in the texture pool, but none is freed. # tex_disuse = 1 # Whether such textures really go under pressure. Off by default: after such evictions the ground of some areas was # drawn flat and see-through and stayed so. 1 turns it on (it frees more memory when memory runs short). # tex_disuse_evict = 0 # Percent of the video memory in use above which textures give way: first those the game released, then those no # shader sampled for a while (tex_disuse); each is made again when used. The default lies under the 87 percent past # which game memory gets no copy in video memory (memory = mirror), which costs far more frame time than a texture # uploaded again. 0: textures never give way for video memory. 70 frees more on a card short of memory, and more # textures are made again (the low of the 0.10 previews set it). # tex_vram_pressure = 80 # Seconds a texture the game released is kept once nothing uses it (0 to 900); then it goes, however much room is # left. In play the game took released textures back within a minute or not at all; one taken back after its drop is # made again and shows its stand-in for a frame. A texture whose content only the GPU made waits twice as long, and one # the GPU drew into since its last copy back to game memory stays. 0: released textures stay up to tex_released_mb for # the whole session (as before 0.10). Default: 180. Read at start. # tex_released_hold = 180 # Megabytes the released textures may hold (0: no bound). Past it the oldest go even when young; while tex_released_hold # is on, young ones may stay past it, up to twice it, as long as video memory and the system's commit have room. # Default: a quarter of the video memory budget where the PC has an eighth of its memory to match, at least a # thirty-second of the PC's memory (512 to 2048), at most 8192. 1024 (the low of the 0.10 previews) holds less, but # textures the game takes back after their drop are made again and show their stand-in for a frame. Read at start. # tex_released_mb = 4096 # Texture compaction (experimental). Video memory is taken in blocks (vma_block_mb), and a block goes back to the # driver only once everything in it is freed: after a long session the blocks hold textures scattered between holes, # and the game holds a gigabyte or two of video memory it does not use. 1: textures no shader sampled for ten seconds # are copied on the GPU out of the emptiest blocks into the holes of fuller ones, a few per frame and only in frames # with time to spare, so those blocks go back. Nothing on screen moves and nothing is loaded again. The log's # "mem: holes" line says how much there is to gain, a "texture compaction: pass" line what each pass gave back. # 0, the default: off. Read at start. # tex_compact = 0 # The free space inside the blocks, in MiB (64 to 65536), from which a compaction pass starts; one block's worth while # video memory is above tex_vram_pressure. Default: 256. Read at start. # tex_compact_min_mb = 256 # The texture memory a compaction moves per frame at most, in MiB (1 to 32); a texture larger than this never moves. # Default: 8. Read at start. # tex_compact_frame_mb = 8 # A texture of 1 MiB or more is copied out of the game's memory by several threads at once when it is first drawn, # instead of by the thread that draws alone (the same bytes, 2 to 3 times sooner). 0: one thread, as before 0.10. # Read at start. # par_jobs = 1 # While the video memory in use is over tex_vram_pressure percent of the budget, the pipelines the game built ahead # of play and no draw has used yet are given back, a few hundred every 5 seconds: on a card short of video memory they # are what costs least to lose, and a draw that needs one later builds it again from the pipeline cache. 0: every # pipeline stays for the run, as before 0.10; tex_vram_pressure = 0 turns this off too. Read at start. # pipe_release = 1 # Low-end GPU mode (experimental; also in the settings menu's Game tab). For older graphics cards, and ones short of # video memory: 1 turns on the settings written for them and measured on a Radeon RX 580, for every key below that # this file does not set itself. Mesh shaders run as compute where the card has none (mesh_emulation), video memory # stays within what the driver reports free (vram_heap_limit = auto, vram_reserve_mb = 512), large texture upload # batches go to the GPU early (upload_batch_mb = 256; every batch goes at 64 MiB of staging at the latest with or # without it, so only a value below 64 acts), game memory is copied for the GPU while a frame is recorded and # the game waits less for the GPU (mirror_stage = 1, submit_finish_gpu = 0), pools the game refills every frame stay # in system memory (mirror_hot = 25), and a texture read after another image was drawn over its memory gets memory of # its own (tex_clobber = 1). Frames prepared on a thread of their own (replay_async) stay off in this mode too, as they # can show a dark or flickering frame now and then; its row under the mode's switch turns them on. 0, the default: each of these stays as it was in 0.9.1, and none of these keys # is read. Read at start. # low_end_gpu = 0 # Textures the game released that are kept as they are (1 to 16384); past this count only those that lose nothing # when dropped go. Default: one per 2 MB of the video memory budget, 2048 to 8192. Read at start. # tex_released_max = 4096 # Past 16384 kept textures some go whatever they cost. 1: the cheapest first: those drawn over, then those that come # back unchanged from the game's memory (the oldest first), and only then those whose content only the GPU made, which # would come back empty. 0: the first one in release order that nothing showed for 2 seconds, of any kind (0.10.1). # tex_hard_order = 1 # Megabytes of this process's commit above which the log says so. Windows counts video memory against the commit; # with a discrete GPU the video memory in use is left out of the comparison, since it is not in RAM. Textures no longer # give way at this bound: dropping one lowers both sides of the comparison alike, so nothing they could do brought the # process under it, and the ground flickered white while the system had commit to spare. They give way only while the # system's commit runs low. Default: the installed memory, at least 24576. 0: no bound. On Linux it counts the # process's resident anonymous memory, which stays under the installed memory, so there only a smaller value holds. # tex_proc_commit_mb = 32768 # 1: a texture the game releases or takes back, with nothing else changed at its address, puts the texture table's # slots there back in a state they were in before, and they are not all looked up again (large towns release and take # back thousands a second). 0: every release and take-back counts as a new state. # tex_gen_undo = 1 # Host zstd decoder in place of the game's (0 = the game's), and a check that decodes every call both ways and logs # the differences (1 = on; slow). Ocarina of Time 1.1.1 decodes on the host too since a check run over a village and a # field found no difference in 3,072 files; zstd_native = 0 keeps the game's own decoder there. # zstd_native = 1 # zstd_check = 0 # Render fixes. # Wait for the game to finish rewriting level-of-detail data before the GPU reads it: stops objects flashing in the # wrong place and a flat far field for a frame. # lod_guard = 1 # Fill the driver-reserved constant bank c0 (storage sizes, dispatch size, point size, base instance) instead of zeros. # fix_c0 = 1 # New GPU memory pools start zero-filled, as Switch memory does. # fix_zero = 1 # Build the water's screen coordinates per pixel and keep its absorption distance at 0 or more: without it water is # drawn as a rectangle over solid ground at the Hyrule Castle moat and the Castle Town canal from some camera # positions, and can turn into a red beam there. 0: the water's shaders as they are. # water_projective = 1 # Lines are drawn as wide as the game sets them (it draws two a frame 4.5 pixels wide into a small mask). 0: every # line 1 pixel wide, as up to 0.9.1. # line_width = 1 # Optimisations, 0 turns each off: skip bindings that did not change, remember shader lookups, reuse the previous # draw's pipeline when its state repeats, remember texture descriptors between draws, update descriptors in bulk, # skip push constants that did not change. # bind_skip = 1 # shader_memo = 1 # 1 flushes every shader cache file to the disk before it is used, as earlier versions did; 0 (default) flushes only # the stored game code, which makes shader preparation about twice as fast (a torn file is translated again). # shader_cache_flush = 0 # pipe_memo = 1 # tex_memo = 1 # desc_template = 1 # push_skip = 1 # More optimisations, 0 turns each off: a draw resolves again only the descriptors whose bindings changed, and records # only the dynamic states whose values changed since the last pipeline. # bind_reuse = 1 # dyn_delta = 1 # Submit GPU work in parts every N draws so the GPU starts earlier (0 to 1000; 0 = off), each part at least split_us # microseconds long (0 to 20000). split_in_pass = 1 also splits inside a long pass (it ends there and begins again in the # next part); 0 splits between passes only. split_idle = 1 sends a submission's first part at the first pass boundary # while the GPU has nothing else to run; it made the foliage flicker in Kokiri Forest, so it is off by default. # split_draws = 64 # split_us = 1000 # split_in_pass = 1 # split_idle = 0 # Vulkan. # Vulkan validation layer: checks every call and slows the game down a lot. Needs the layer installed (Vulkan SDK). # vk_validation = 0 # A thread of its own makes the Vulkan calls of each frame, 0 or 1. Default: on, except on AMD GPUs. # vk_recorder = 1 # Dynamic vertex input, 0 or 1. Default: on, except on Intel's older integrated GPU drivers (Vulkan 1.3.215 and older). # vk_dyn_vertex = 1 # Dynamic alpha to coverage, 0 or 1. Default: on, except on AMD's driver for RDNA 2 and older (RX 400 to RX 6000), # which applies alpha to coverage while the dynamic state says off and draws the characters black. # vk_dyn_a2c = 1 # Pin the shader subgroup size to 32 when the GPU allows it. # vk_subgroup_pin = 1 # Keep a shader's threads together after divergent code where the game's shaders expect it (maximal reconvergence, # when the driver supports it). 0 turns it off; leaves then go missing from the foliage's colour pass. # vk_reconverge = 1 # Ask the GPU driver to keep NaN, infinity and signed zero in the game's shader maths as the Switch does, 0 or 1. # Without it a driver may assume they never occur. The AMD symptoms it is for: Navi drawn without her orb (only her # sparkles), black and white blocks on her and on Link, shadows blown up. Default: on, except on NVIDIA's driver, # which keeps them anyway; 1 also asks NVIDIA's driver. The first start after a change compiles the pipelines again. # vk_nan_preserve = 1 # Test for NaN in the game's shaders on the bits of the number instead of as a float, 0 or 1, so that no shader # compiler can leave a test out. Default: on with AMD's driver for RX 5000 and RX 6000 cards (the one whose shader # compiler reads "AMD proprietary shader compiler" in the log), where the black and white blocks were reported; off # elsewhere. The first start after a change compiles the pipelines again. # vk_nan_bits = 1 [display] # Device profile: auto (the Steam Deck when this is one), desktop or deck. On a Steam Deck the keys this file does not # set default to fullscreen = 1, window_size = 1280x800, output_res = 1280x800, render_scale = game, vk_present = fifo, # fps_limit = 40, cores = 4 (the game's six cores share the Deck's four), astc_bc = 1 and spin_handoff_us = 30 # (starting points, not measured yet). Read at start. # device_profile = auto # Presentation mode: mailbox (default when the driver offers it, vsync otherwise), fifo (vsync) or immediate. The menu's # VSync switch sets mailbox when on and immediate when off. # vk_present = mailbox # Window client area in screen pixels (640x360 to 7680x4320), and borderless fullscreen. Windows display scaling does # not apply: at 150% scale, 1920x1080 covers the area 1280x720 covers at 100%. F11 switches fullscreen and saves it # here. Changes while the game runs take effect at once. # window_size = 1920x1080 # fullscreen = 0 # Which monitor the game window opens on, centred in its work area; fullscreen covers that monitor. auto (default): the # system places the window. primary; a number, counting from 1 in the order `nx2navi.exe --list-monitors` prints; or part # of the monitor's name, ignoring case (on Windows also of a GDI device name, display3; on Linux the name carries the # connector, such as dp-2). For a virtual display that may not exist yet, use its name: when nothing matches, the log # lists the monitors and the window is placed as with auto. The command line `--monitor ` overrides this for one # run. Read at start. On Wayland a window cannot place itself: only fullscreen opens on the chosen monitor, and a # windowed window opens where the compositor puts it. # monitor = auto # 1, the default: the game keeps running while you are in another window; the keyboard stays quiet until the window is # in front again. 0: it pauses when its window loses focus, as it does on the Switch when Home is pressed; a load # interrupted that way can stop for good. Read at each focus change. # assume_focus = 1 # Performance overlay in the top right corner: off, fps, or full (frame rate, mean and longest frame time). F10 # cycles the modes in game, as do both stick clicks (L3 + R3) on a controller. # perf_overlay = off # Which GPU to use: its index in the log, or part of its name. Default: the first discrete GPU with Vulkan 1.3. # gpu_index = 0 # gpu_name = NVIDIA # Game resolution: the size the game draws its picture and interface in (1280x720 to 7680x4320). Above 1920x1080 the # game's texture heap and memory pool grow with it. Another shape than 16:9, such as 3440x1440 on a 21:9 monitor or # the Steam Deck's 1280x800 (16:10), gives the camera's view that shape and lays the HUD out for it. The installer # prepares the UI layout for fifteen sizes: 2560x1080, 3440x1440, 3840x1600, 5120x2160 (21:9), 3840x1080, 5120x1440 # (32:9), 1280x800, 1680x1050, 1920x1200, 2560x1600 (16:10), 1920x1280, 2160x1440, 2256x1504, 2880x1920 and 3000x2000 # (3:2). Any other size # gets the camera's view but a 16:9 HUD, stretched over the picture, unless you build its layout with # tools/make_romfs_patches.py --aspect WxH. Read at start. # output_res = 1920x1080 # Ocarina of Time sizes its picture with these two instead (output_res and render_scale do nothing there). The shape: # 16:9, window (the window's shape, or the monitor's in fullscreen), 21:9 or 32:9. The height: 1080 (lighter than the # game's own), 1440 (the game's own), 1800, 2160, 2880 or window (the window's height, at least 1440). The DLSS and # FSR 3.1 modes render their share of this picture. Read at start. # game_aspect = 16:9 # game_res = 1440 # 3D render scale: the scene's size relative to the game resolution, game (5/6, the game's own 1600x900 at 1080p) or # a percentage (25 to 400, at most 4096 pixels a side); above 100 supersamples the scene (anti-aliasing). Read at start. # render_scale = game # Discrete GPUs: a game memory pool whose copies to and from video memory each frame reach this percentage of its size # is read and written by the GPU in system memory instead (0: every pool keeps its video memory copy). For GPUs and # buses short of bandwidth; on an RX 580 the pools the game refills every frame cost about 8 ms a frame in copies. # mirror_hot = 0 # 2: the next Rebuild the Game compiles the game's code at -O2 instead of -O1 (faster game threads on a slower CPU, a # build several times longer). Read by tools/make_game.py; the environment variable NX2NAVI_GUEST_OPT wins. # guest_opt = 1 # GPUs without mesh shaders (VK_EXT_mesh_shader: AMD before RDNA 2, NVIDIA before Turing): 1 runs the game's mesh # and task shaders (grass and other foliage) as compute shaders and draws what they make; 0 skips those draws. The # arena for their vertices and triangles is mesh_emu_mb MiB of video memory, with mesh_emu_tasks task records (3 KiB # each) per submission; with trace = perf the log says how much a submission used. Read at start. # mesh_emulation = 0 # mesh_emu_mb = 256 # mesh_emu_tasks = 16384 # Scaling to the window when it is larger than the game resolution: fsr (AMD FSR 1) or bilinear, and FSR's sharpening # from 0 (off) to 100. Changes while the game runs take effect at once. # upscaler = fsr # sharpness = 80 # Scaling of the 3D scene to the game resolution. The game draws its scene smaller than the picture and enlarges it; # the console does that with an upscaler of its own, which the port replaces: easu enlarges with an edge-adaptive # filter (the one FSR 1 scales with), which keeps edges sharp, and bilinear with the plain filter used before, which # is softer and costs a little less GPU time. DLSS and FSR 3.1 (dlaa = 1) scale the scene themselves, so this changes # nothing there, and it does not touch the movies. Changes while the game runs take effect at once. # standin_filter = easu # The 3D scene's share of the game resolution without DLSS or FSR 3.1 (dlaa = 0), Ocarina of Time: 0.75, the default, # is the game's own most (1920x1080 in its 2560x1440 picture), which the scaling above enlarges; 1 draws the scene at # the picture's full size and nothing enlarges it (the menu's Upscaling row calls it Native (100%)); 0 leaves the size # to the game's dynamic resolution, down to a third of the picture under load. A larger scene needs more of the # memory the game keeps for its render targets, which is set aside at the start: 1 takes 238 MiB more than 0.75 at # 2560x1440, 533 MiB more at 3840x2160 and 712 MiB more at 5120x2160, as dlss = dlaa does. Changes while the game runs # take effect at once up to the share the game started with, a larger one at the next start. # scene_share = 0.75 # Picture shape when the window's shape differs from the game resolution's (a 16:9 picture in a 21:9 fullscreen # window): fit, the default, keeps the shape, with black bars at the sides or above and below, so a 16:9 game in a wider # window is no longer stretched as it used to be; stretch fills the window. Changes while the game runs take effect at # once. # aspect = fit # Anisotropic filtering of surface textures: game (the level the game asks for, as on the Switch, 1x or 2x) or 2, 4, # 8, 16. Default: 16. Keeps ground, roads and walls seen at a shallow angle sharp into the distance. Only filtered, # mipmapped textures that tile are raised; shadow maps, data maps and screen-sized buffers keep the game's setting. # Changes while the game runs take effect at once. # aniso = 16 # Texture detail: auto, full, reduced or low. The textures of a loaded area are what fills a card with little video # memory, and three quarters of a texture is its largest mip level. reduced makes the large surface textures (256x256 and # more, with smaller levels) without that level, low without the two largest when they are 1024x1024 or more. Surfaces # seen up close look softer; interface art, small textures, shadow maps and everything the game draws itself keep their # size. auto picks by the video memory Windows grants the game: full from 8192 MiB (cards of 10 GB and more), low under # 6144 MiB (cards of 6 GB and less), reduced between (8 GB cards). Where the ASTC textures stay uncompressed (astc = # cpu or astc_bc = 0) and the budget is under 20480 MiB, auto goes one step lower, as they take four times the memory. # The log says what was picked ("texture detail:"). Read at start. # texture_detail = auto # Sun shadow map size: game (the game's own, which changes with the view and drops to about 400 near the ground, so # leaf shadows look blocky and jump) or a fixed 256, 512, 768, 1024, 1536 or 2048. Above 960 the texture heap grows with # it. 256 is coarser than the game's own and is for integrated GPUs short of memory bandwidth. Read at start. # shadow_res = game # Shadow map resolution: the game's sun cascades are 960x960 (and its static shadow maps 1440 and 720) whatever the game # resolution; 2 to 4 draws them that many times larger on each side, for sharper shadows. 1 = the game's. The game's # shadow edge filter is narrowed by the same factor (translator patch 0011), so close shadow edges don't look doubled, # and the game's slope-scaled depth bias grows by it, so the larger maps don't shadow the surfaces they are cast on. # Read at start. # shadow_scale = 1 # Sun shadow cascade range in percent of the game's (its cascades end at 20, 40, 80 and 160 m), 50 to 400: higher moves # the steps where shadows turn softer further away, and spreads the shadow map over more ground. Read at start. # shadow_range = 100 # Screen-space contact shadows, strength in percent (0 = off): after the game lights its scene, each pixel traces a # short way toward the sun through the depth buffer and darkens where something close blocks it, adding the small # shadows at feet, under stones and in grass that the shadow maps miss. Read at start. # contact_shadows = 0 # Soft sun shadows (PCSS), percent of the default penumbra width (0 to 200; 0 = the game's own four-tap filter): sharp # where an object meets the ground and softer the further its shadow falls. Done in the translated shaders (translator # patch 0010), so the shader cache is rebuilt once after an update. Read at start. # pcss = 0 # Shadow edge filtering, 0 or 1. Default: off. 1 makes every shadow-map test blend the 2x2 shadow map texels around # it (hardware percentage-closer filtering) instead of testing one texel where the game's sampler asks for nearest # filtering: shadow edges turn from stair steps of shadow-map texels into soft ramps, and crawl less on the ground as the # camera moves. Costs a little GPU time. With shadow_scale above 1 it is on anyway. The log lists the filters of the # game's shadow samplers ("depth-compare sampler:"); where they are already linear this changes nothing. Read at start. # shadow_pcf = 0 # NVIDIA DLSS / DLAA for the 3D scene, on NVIDIA RTX GPUs with the DLSS model from NVIDIA's DLSS SDK next to the # executable (Windows: nvngx_dlss.dll next to nx2navi.exe; Linux: libnvidia-ngx-dlss.so. next to nx2navi, with the # NVIDIA driver's libnvidia-ngx.so.1 installed); elsewhere the setting does nothing. The HUD is drawn after it and is not touched. # Read at start. # dlaa = 0 # What DLSS works from: dlaa (the 3D scene at full size), quality, balanced, performance or ultra_performance (the # scene at 67, 58, 50 or 33 % of the output, scaled up by DLSS; these replace render_scale and sharpen texture filtering # to match). They apply only with dlaa = 1 and the DLSS model next to the executable; otherwise the scene follows # render_scale. Changes while the game runs take effect at once, with one limit: the game's memory for render targets # is sized at the start for the mode set then, so dlaa chosen in the menu of a run that started with a smaller mode # (or with dlaa = 0) renders at 75 % until the next start. # dlss = dlaa # AMD FSR in DLSS's place, on any GPU (Windows): with taa = fsr3 and dlaa = 1 the scene is scaled by AMD FSR 3.1 in the # mode dlss names (dlaa is FSR's Native AA). The menu's Upscaling row sets all of these. Changes while the game runs # take effect at once. # taa = dlss # AMD FSR 4 in FSR 3.1's place (taa = fsr3, dlaa = 1): the machine-learned upscaler, a sharper and steadier picture # that costs more GPU time (on an RX 7900 XT at 3440x1440, Quality: 47 fps where FSR 3.1 gives 51) and about 220 MB of # video memory. It runs where AMD's amd_fidelityfx_loader_vk.dll and amd_fidelityfx_upscaler_vk.dll are next to the # executable (the setup puts them there) and that library lists FSR 4 for the GPU: Radeon RX 6000, RX 7000 and RX 9000 # cards with AMD's driver 26.10.1 or newer. Elsewhere, or when it fails, FSR 3.1 runs and the log says why. Changes # while the game runs take effect at once. # fsr4 = 0 # The menu's Frame generation row lists it as "AMD FSR 4 library". With fsr4 = 1 and framegen = fsr3: 1 takes the # frame generation of the same AMD library # (amd_fidelityfx_framegeneration_vk.dll next to the executable) instead of the FSR 3.1 library's. The library picks # the version for the GPU: the machine-learned FSR Frame Generation 4 on Radeon RX 9000 cards with Windows 11, which # has not been tested, and 3.1.6 on every other, where it runs at the same frame rate as the FSR 3.1 library's. When # it fails, the FSR 3.1 library takes over and the log says why (fg4:). Changes while the game runs take effect at once. # fsr4_fg = 0 # The debug menu, a tool for testing (Ocarina of Time 1.1.1): with 1, F9 opens a window with the game's on/off flags # by name (the names found in your own game's event files), a teleport to every area's start positions (the warp # songs' pads and both sides of the loading zones among them), the game's cutscenes and other events to start by name, # the game's speed, Link's position, a free camera flown with the sticks, and a search of the game's memory with # values to set and to hold. Changing flags or memory, teleporting and starting events can break a save, and the game # saves by itself after a change of area: keep a copy of the save first. Do not bind F9 to a game button while it is on. The menu's Game tab has the switch. Takes effect at once. # debug_menu = 0 # The DLSS model: default (NVIDIA's advice per mode: K for dlaa, quality and balanced, M for performance, L for # ultra_performance), k (K in every mode) or j (the other transformer model: slightly less ghosting behind moving # characters, a little more flicker). Any other model by its letter, a to m: on slower RTX cards the older model e is # cheaper. Changes while the game runs take effect at once (DLSS starts a new history). # dlss_preset = default # DLSS keeps one network per picture size (gameplay, the pause screen). 1: one unused for 3,600 frames is freed, and # ten seconds after the upscaler or frame generation is switched off in the menu, the networks and pictures they held # are freed too (switched on again later, they are made again, which the first frame waits for). # 0: none is ever freed (about 0.5 GB more video memory after the first pause). 2: as 1, and the networks that stay # are not made again when another is made (shows striped pause screens; for tests). # dlss_idle_free = 1 # When DLSS or FSR lets go of a network, an FSR context or a picture (a new picture size, the pause screen, a mode # change). 0: it is freed once the graphics card has finished the frames that used it, and the game does not wait. # 1: the game waits for the graphics card to finish all its work at each such change, as up to 0.10.1 (what was let # go of still goes once the card is past it): a hitch of a frame or more at each change. For comparison, or if 0 shows # a fault. Read at start. # upscaler_idle_wait = 0 # One DLSS network for the render sizes of a DLSS mode. 1: the network made for the mode's own render size also takes # the smaller render sizes DLSS allows on it (dynamic resolution's steps with dyn_res = 1, a screen that renders # smaller than play), so a change of size makes no new network and keeps the picture DLSS has built up. 0: every # render size has its own network and starts its picture anew. The log says for each network which render sizes it # takes, and counts the changes of size that kept the picture against those that made a network. 0 is the default: # the shared network has been compiled and not yet run on a graphics card. Read at start. # dlss_range = 0 # Where DLSS or FSR 3.1 works in the frame (a test, off by default). 0: on the finished picture, after the game has # added its bloom, applied its exposure and tonemapped it. 1: on the scene's own light, before the bloom chain and the # tonemap, as these upscalers are made for; the bloom, the lens flares and the tonemap then work on the upscaler's # picture, drawn at the picture's size when the scene is smaller. Frames without the bloom (menus) stay as with 0. # The log says where it ran (lines starting with "dlaa: prebloom"). Changes apply at the next frame. # dlss_prebloom = 0 # Per-object motion vectors for DLSS: characters, animals and moving objects get their own motion instead of the # camera's, so DLSS keeps their history instead of smearing or rejecting it. Costs some CPU time each frame (about 1-2 ms # on a laptop CPU); 0 leaves camera-only motion. Read at start. # dlaa_objmv = 1 # Motion vectors of Link's own for DLSS, FSR 3.1 and frame generation (game 1.1.1): Link and the equipment attached to him are # drawn a second time with last frame's pose, so fast turns, attacks and jumps move by their real motion instead of an # estimate from colour and depth. 1, the default; 0: the estimate, as before 0.10.0. It reads the player's equipment # from the game's memory at every submission. Read at start. # motion_guard_degrees (35, 45 or 60, the default): a part that turns more than this in one frame is checked against # last frame's depth before its vector is written. # selective_motion = 1 # Motion vectors of their own for every other skinned character (game 1.1.1): people, animals and enemies are drawn a # second time with last frame's pose too, so DLSS, FSR 3.1 and frame generation follow them as they move instead of # smearing them along the camera's motion. A character's draw is matched with last frame's by its mesh and shaders; # where the match is in doubt (it just appeared, another one of the same model appeared or left) it keeps the camera's # motion for a few frames. 1, the default; 0: the camera's motion for all of them, as before. Nothing runs without # DLSS or FSR 3.1. The "selective motion" log line counts the skinned draws and why some kept the camera's motion. # Read at start. # skin_motion = 1 # Characters' trails: where a character, animal or held item moves without motion vectors of its own (all of them with # dlaa_objmv = 0), DLSS can drag a faint copy of it. The G-buffer marks those objects; on them and where they were the # frame before, DLSS is told to favour the current frame by this percentage (0, 35, 65 or 100; 0 off). Higher removes # more of the trails and leaves those edges a little less smooth. Changes while the game runs take effect at once. # dlss_char_mask = 65 # Anti-aliasing of the 3D picture: game (the game's own SMAA, as on the console), off, fxaa, smaa (SMAA at its Ultra # preset in the game's place) or taa (DLSS or FSR at full size: dlaa = 1 with dlss = dlaa, which the menu's # Anti-aliasing row sets with it, and the game's SMAA). With DLSS or FSR on (dlaa = 1, any mode) their TAA always runs, # and game, off, fxaa or smaa runs along with it: off leaves the edges to the TAA alone. Changes while the game runs # take effect at once. # aa = game # The FXAA switch of the game this runtime was first written for; Ocarina has no such pass, so it changes nothing here # (aa above is the setting). # fxaa = 1 # Frame generation: off, fsr3 (AMD FSR 3.1 on any GPU where amd_fidelityfx_vk.dll loads, so not on Linux: one generated # frame between every two the game draws, the HUD kept out of it) or dlss (NVIDIA DLSS Frame Generation on GeForce RTX # 40 and 50 GPUs, paced with Reflex; it needs nx2navi_dlssg.dll and NVIDIA Streamline's files next to the executable, # which the setup puts there). Both run with any upscaling: with DLSS or FSR 3.1 (dlaa = 1) they take its depth and # motion vectors, and without one (dlaa = 0) the same ones made for them alone, with no jitter (the log's "dlaa: frame # generation runs" line says which). While frame generation runs, fps_limit # counts the frames the game draws and the screen shows that times the multiplier (2 for fsr3); fps_limit = display # alone holds the screen to the monitor's rate and the game to that rate divided by the multiplier. # fsr3 takes effect at once, dlss (on or off) at the next start. # framegen = off # On Linux dlss runs through NVIDIA's NGX itself, without Streamline: it needs dlaa = 1 with DLSS when the game starts # (it keeps running when dlaa is switched off later) and NVIDIA's libnvidia-ngx-dlssg.so. (from NVIDIA's DLSS SDK repository) beside the game, then switches at # once, and its multiplier is fg_mult: 2 to 6 (above 2 needs an RTX 50 GPU) or dynamic, which generates only the frames # needed to reach the display's refresh rate at the rate the game draws. framegen_multiplier is not used there. # fg_mult = 2 # DLSS frame generation's multiplier: the frames on screen for each frame the game draws, 2, 3 or 4 (one, two or three # generated). 2 needs an RTX 40 GPU or newer, 3 and 4 an RTX 50 and a current driver. A value above what the GPU and # driver allow (Streamline reports it) is lowered to that, with a line in the log; the menu offers only what they allow. # Each step adds a little latency, and a display shows no more than its refresh rate. Changes while the game runs # take effect at once. # framegen_multiplier = 2 # With framegen = dlss, Reflex holds fps_limit where each frame starts, before the controller is read, and the game's # own limiter keeps only its ceiling of 240 frames a second: a finished picture no longer waits for its turn, which # takes up to a frame of the game's off the delay from the controller to the screen. The game's own limiter takes the # limit back while a movie plays, while the window is minimised, and for the rest of the run when the frames show that # Reflex does not hold it; the log's "frame rate:" lines say which one holds it. 0 leaves the limit to the game's own # limiter, as before 0.10.2. Needs the nx2navi_dlssg.dll of 0.10.2 or later (an older one leaves the limit to the # game). Changes while the game runs take effect at once. # reflex_limit = 1 # Low latency without frame generation: 0 off, 1 on, 2 on with boost (NVIDIA's: the GPU keeps a high clock; on AMD 2 # is 1). The graphics driver holds each frame's start, so the game reads the controller as late as the picture allows # and no finished picture waits for its turn: NVIDIA's low-latency mode (VK_NV_low_latency2) or AMD's Anti-Lag # (VK_AMD_anti_lag), whichever the driver has. On a driver with neither the setting does nothing. While it is on the # driver holds the game to fps_limit, in place of the game's own limiter and of RivaTuner Statistics Server (rtss). # With framegen = dlss on Windows, DLSS Frame Generation's own low latency is used and this setting is not; with # framegen = fsr3 it runs on AMD GPUs and is off on NVIDIA ones while frames are generated. Turning it on takes effect # at the next start: a run that starts with 0 leaves the driver's mode off the graphics device altogether. In a run # that started with it on, changes take effect at once. # low_latency = 0 # HDR output, two kinds (both need HDR on in Windows, "Use HDR", or a Wayland compositor with colour management; # without it the picture stays SDR, the game's own): hdr = 1 sends the game's scene tone mapped to your display, one # fixed look, and applies at once; hdr = native shows the game's own HDR mode, which the game takes up at the next # start. hdr_peak_nits is your display's peak, hdr_game_nits the picture's white (paper white, 203 is the HDR # reference) and hdr_ui_nits the HUD's and the menu's. The settings of the look of earlier versions # (hdr_tonemap, hdr_exposure, hdr_gamma and the rest) are read by nothing now and do no harm. # hdr = 0 # hdr_live = 0 leaves the HDR path out of a run that starts with hdr = 0, as before hdr followed the menu: switching # HDR on then takes a restart. Only worth setting if the picture differs with it at 1. # hdr_live = 1 # hdr_peak_nits = 1000 # hdr_game_nits = 203 # hdr_ui_nits = 203 [language] # Language: a Windows locale such as de-DE, or a Switch code (en-US, ja, zh-Hant, ...). Default: the Windows locale. # locale = en-US # lang = en-US # System mode reported to the game: docked or handheld. # operation_mode = docked # Speed of the game's message windows (game 1.1.1; live): normal (the game's), fast (three times as fast; the # pauses the text holds stay as long) or instant (each page shows at once, as the game shows it when you press the # button that turns the page while it types). # Messages the game does not let you hurry, such as text timed against a cutscene or a voice, keep their speed. # Needs a game built with this version (the launcher's Rebuild the Game); the menu row shows once it is. # text_speed = normal # Language of the settings menu and the overlay: en, ru, pt-BR or zh-Hans. Default: the Windows display language, English if # it is none of them. # menu_lang = en [discord] # Rich Presence: "Playing NX2navi" with the play time in your Discord status while the game runs, through the # local IPC of a running Discord client; without one it does nothing. 0 = off. The Game tab of the settings menu (F1) # and the launcher's Settings switch it too, and a change in the menu reaches the presence thread at once. # discord_rpc = 1 # The Discord application whose name ("Playing ") and artwork the status shows: its Application ID from # discord.com/developers/applications (General Information), digits only. Default: the NX2navi application, built # in from runtime/discord_app.h (NX2NAVI_DISCORD_APP_ID_DEFAULT). Register your own application to choose another # name and art. # discord_app_id = 1568862362969309275 # The key of the application's uploaded art asset (Rich Presence > Art Assets) shown as the status's large image. # discord_image = nx2navi_512x512 [audio] # none mixes without opening an audio device. # audio = default # Audio the output queues before it starts, in ms (0 to 500; above about 170, half the output ring, it is held there). # audio_prefill_ms = 20 # Log where gaps in the sound come from (1 = on): output underruns, late passes of the audio render thread, late # audio updates from the game and voices that ran out of queued sound, with the game frame of each. # audio_stats = 0 # Host priority of the game's audio thread: 0 leaves it alone, 1 raises it to the highest while its audio update is # read (the audio render thread waits for that), 2 also keeps it above normal. Takes effect at the next start. # audio_game_prio = 0 # When the game changes a sound's volume, go from the old volume to the new one across the 5 ms of sound that follow, # as the console does (1, the default). 0 applies the new volume at once, which clicks when a volume moves quickly (a # fade, a sound passing by). Takes effect at the next start. # audio_ramp = 1 # After the sound was held up (the PC was busy and a gap was heard), skip as much sound as the gap was long, so the # sound keeps its place against the picture as on the console (1, the default). Gaps of more than 3 seconds are not # skipped. 0 plays on from where the sound stopped, which leaves it later than the picture by every gap so far. # Takes effect at the next start. # audio_catchup = 1 # When the game sends an audio value this version cannot use (an effect setting out of range, an id it does not have), # that effect or sound is left out and the log gets one line per kind (0, the default). 1 ends the game there instead, # with the details in the log, as versions before 0.10.2 did for most of them: for bug reports. Takes effect at the # next start. # audio_strict = 0 # Volume in percent (0 to 100), on top of the game's own. Changes while the game runs take effect at once. # volume = 100 # Speakers: stereo, 5.1 or auto (5.1 when the Windows speaker setup has six or more channels, stereo otherwise). The # game is told the same channel count and mixes for it. A change while the game runs takes effect at once: the game is # told its output device changed, as on a console, and mixes for the new count. # audio_channels = stereo # Which output device the sound plays on. default (the default): the system default device, which the game follows when # the Windows default changes. Or a number, counting from 1 in the order `nx2navi.exe --list-audio-devices` prints; or part # of a device's name, ignoring case (`headphones`). When nothing matches, or the device will not open, the log lists the # devices and the game plays on the system default. With audio_channels = auto, the channel count is the chosen device's. # The command line `--audio-device ` overrides this for one run. Takes effect at the next start. # audio_device = default # The game's microphone input (the Ocarina can be played into one): 1 lets it read the default recording device, # 0 refuses it, as earlier versions did. # microphone = 1 [input] # Gamepad motion controls (0 = off) and vibration (0 = off). # motion = 1 # rumble = 1 # Sprint button (game 1.1.1): Link sprints without rolling first. off (the default), l3 (the left stick's click, which # has no other use) or b (the game's B button, the bottom one of the Nintendo layout: it sprints only while Link moves # and puts the weapon away as usual otherwise; with the game's Swap Jump Controls B is the jump, so use l3). sprint_mode: toggle (press to sprint and again to stop; the sprint # also ends when Link stops, attacks, rolls, targets, uses an item, swims or climbs) or hold. The Controls tab's # Sprint rows set both; changes take effect at once. # sprint_button = off # sprint_mode = toggle # Rumble strength in percent (0 to 300; 0 = off) and the exponent on the amplitude (0.2 to 1.5; lower = weak pulses # stronger, 1 = linear). rumble_triggers = 1 also drives the impulse triggers of an Xbox pad. # rumble_strength = 130 # rumble_curve = 0.6 # rumble_triggers = 0 # HD rumble for a Switch Pro Controller, a Joy-Con or a pair of them: 1 sends the game's vibration to the controller as # the game makes it, each side's low and high band with its own frequency and amplitude, in place of two motor # strengths. rumble_strength still scales the amplitude (its default, 130, is exactly the game's; the controller's # safe maximum is never passed) and rumble_curve does not apply. 0 (default), and every other gamepad: the motors, as before. Changes # while the game runs take effect at once. rumble_hd_ms is the shortest time between two rumble reports in # milliseconds (5 to 50, default 15): raise it if a controller on Bluetooth stutters or disconnects with HD rumble on. # rumble_hd = 0 # rumble_hd_ms = 15 # PlayStation 3 controller (DualShock 3), Windows: 1 reads its buttons, sticks and rumble directly from the controller # when no driver presents it to the game as a gamepad; 0 (default) leaves it to SDL and XInput. Changes while the game # runs take effect at once. # ds3 = 0 # Which gamepad button is Switch A: nintendo (the default: the Switch's buttons by position on any pad, east A, # south B, west Y, north X), xbox (south A, east B, west X, north Y, as an Xbox pad labels them; cross A on a # PlayStation pad), playstation (the same as xbox: cross A, circle B, square X, triangle Y) or auto (nintendo for a # pad with Nintendo labels, xbox for the others). The bind_ lines below apply # on top. Changes while the game runs take effect at once. 0.1.9's xbox_prompts is read as nintendo with prompts = xbox. # pad_layout = nintendo # The buttons the game's prompts show: nintendo (the game's own), xbox (LB RB LT RT, Menu, View), playstation (L1 R1 # L2 R2, Options, Create) or steamdeck (the Deck's A B X Y, L1 R1 L2 R2, Menu, View), with A B X Y as the button # pad_layout presses is labelled: with nintendo, A shows as B or circle and X as Y or triangle. pc: the key each # button has (the bind_ lines below when the files are made), WASD # and the mouse. Read at start; their files come from tools/pad_prompts.py (docs/controls.md, "Button prompts"). # prompts = nintendo # Gamepad stick dead zone in percent of full deflection (0 to 50). Raise it for a stick that drifts: inside the circle # the stick reads centred, and the rest of its travel is scaled to start there. # stick_deadzone = 8 # Right-stick camera speed (0.1 to 3): multiplies the game's own camera turn rates, top speed included, at each of the # five camera sensitivities in the game's Options. Keys bound to the right stick follow it; the mouse keeps mouse_sens # for its turn per movement, and in stick mode the fastest turn it can reach rises and falls with this. # A change while the game runs takes effect at once (the first one of a run within a few seconds). # stick_sens = 1 # The dead zone of one stick, in place of stick_deadzone for that stick (0 to 50; unset = stick_deadzone). The Controls # tab shows each stick's deflection now, so a drifting stick's resting value can be read off. # lstick_deadzone = 8 # rstick_deadzone = 8 # Mouse camera mode: direct (default) or stick. Direct turns the camera by the raw mouse motion, the same on both axes, # with no stick dead zone or response curve, at any frame rate and however fast the mouse moves. Stick makes the # mouse a right stick. Neither changes the gamepad. The Controls tab changes this while the game runs. # mouse_mode = direct # Mouse camera sensitivity (0 to 10; 0 = no mouse camera and no cursor capture). In direct mode a count of the mouse # turns the camera about 0.08 degrees at 1; the game's own camera sensitivity (Options) scales it as it scales the # stick. The Controls tab changes this while the game runs. # mouse_sens = 1 # The keyboard's sticks are all or nothing, so the game only sees a full tilt from them; while this key is held the # keyboard-driven stick values shrink and the keyboard can walk instead of run. Key names as in the bind_ lines below, # none turns it off. 0.2 to 0.9, the default holds for anything else. Only the keyboard is scaled: the mouse camera and # the gamepad are unchanged. The Controls tab sets both. The default stops just above half because a keyboard sample of # 32767 times 0.5 is one short of the 16384 the game's stick-direction bits need, and below that the keyboard stick # reads as a partial tilt only. # walk_key = lalt # walk_scale = 0.51 # Write the input of this run to a file that replays as a script (docs/controls.md, "Scripted input"). Default: off. # input_record = input.txt # Remap buttons: the Controls tab of the settings menu (F1) writes these lines. One line per Switch button or stick # direction: bind_ or bind__, or bind_SHAKE (shakes the right stick; no default key, Ocarina has no use for it) = comma separated # pad: and key: entries, key:default / pad:default for that part's defaults, or none. # A line replaces that button's defaults (pad and keyboard); buttons without a line keep them. Stick directions and # SHAKE take keys only. Invalid entries are logged and skipped. Changes while the game runs take effect at once. # pad names: south east west north l r zl zr start back lstick rstick dpad_left dpad_up dpad_right dpad_down # lpaddle1 rpaddle1 lpaddle2 rpaddle2 (the back buttons of an Xbox Elite, DualSense Edge or Steam Controller) # key names: a-z 0-9 f2-f7 f9 f12 num0-num9 space tab enter backspace lshift rshift lctrl rctrl lalt capslock insert # delete home end pageup pagedown up down left right num_add num_sub num_mul num_div num_decimal minus equals # lbracket rbracket semicolon apostrophe comma period slash backslash grave mouse_l mouse_r mouse_m mouse_x1 mouse_x2 # Defaults (pad_layout = nintendo): A = pad:east, key:E, key:lshift (held: dash). B = pad:south, key:lctrl, # key:backspace. X = pad:north, key:space. Y = pad:west, key:mouse_l. A pad that reports A/B and X/Y swapped # (some GuliKit models): set pad_layout = xbox, or swap them back here (keyboard keys stay): # bind_A = pad:south, key:E, key:lshift # bind_B = pad:east, key:lctrl, key:backspace # bind_X = pad:west, key:space # bind_Y = pad:north, key:mouse_l [mods] # Folder with the player's mods, one subfolder per mod (/romfs, /exefs, /cheats). A relative folder # is under the game's folder. Default: mods next to the game's exe. The build takes the ExeFS patches and code cheats # of the mods folder next to the exe only. The launcher's Mods screen adds mods and puts downloads in order. # mods_dir = # Load order, top first, names separated by |; a mod not listed goes below the listed ones, by name. The top mod wins a # file two mods replace. The launcher's Mods screen sets it (Load Order); the in-game menu has no Mods tab. # mods_order = # Mods switched off, names separated by |. The launcher's Mods screen sets it. # mods_disabled = # auto: when an enabled mod has cheats that change the game's code and the game was built without them, the game starts # the setup's rebuild at start (a few minutes) and starts again after it. off: the game starts with the code it has. # A rebuild that failed or was cancelled is not started again for the same cheats. Default: auto. # mods_rebuild = auto [files] # Developer overlay: a folder with RomFS files and a manifest.tsv (tools/make_romfs_patches.py format). Players put # their mods into the mods folder instead ([mods]). Default: none. # romfs_mods = # Folder with the Switch shared fonts (BFTTF files, tools/extract_fonts.py output), for Chinese and Korean text. # Default: shared-fonts next to nx2navi.exe. NX2NAVI_SHARED_FONTS overrides it. # shared_fonts = [cheats] # One line per cheat of the mods' cheat files, mods\\cheats\.txt (docs/cheats.md); the Cheats tab of # the menu writes them. cheat_ = 1 switches a cheat on, the hash being FNV-1a 32 of "/". # Default: every cheat off. # cheat_0123abcd = 1 [diagnostics] # Extra lines in the log, comma separated: svc, host, ipc, fs, gfx, perf, sched, audio, present or all. The menu's # Performance log sets perf (frame timings). Default: none. # trace = perf # A game thread that waits this many seconds for a lock, or for another thread to end, is logged once with the thread # it waits for and what that one is doing (at most 24 lines a run): a game that stops then leaves the chain in its log. # Off by default: its thread takes the game's thread lock every 2 seconds. 10 is a good value for a hang report. # wait_watch_s = 0 # 1: what the game's present closes for the frame (the DLSS state, the motion tables, the frame count conditional # draws go by) is closed between two replays: when another game thread is replaying at the present, the next # submission does it first thing, or the present thread before the picture's blit, and the game's present goes on at # once. 0: at the present, as in 0.10.1, whatever another thread replays (a rare one-frame fault at area changes). # Read at start. # present_order = 1 # A report in the log when nothing moves for this many seconds: no frame shown while the window is in front, or a GPU # submission not finished. It names who holds the present and queue locks and what the game's threads wait for, at # most three times a run; the game goes on. 0 turns it off. Read at start. # hang_watch_s = 20 # Diagnosis: one log line per frame while Link stands near a moving floor (the floating platforms): the frame's step, # how far he moved and how far the floor moved. 1 writes 4000 lines, a larger number that many; 0 is off. # floor_probe = 0 # Diagnosis: while a floor carries Link sideways at 60 fps and the left stick rests, one snapshot of the game's memory # finds the values below him that move with him (the floor's position among them) and logs them once a second from # then on. The snapshot holds the game for about a second once. 1 writes 20000 lines, a larger number that many; 0 is # off. # floor_scan = 0 # Diagnosis (Windows): 1 also runs floor_scan and, once it has found the floor, logs which code of the game reads and # writes it: hardware watchpoints on its addresses for a few seconds at 60 fps, and again at the next stretch at 120 # fps or more with Link on the floor. Each pass slows the game for its few seconds. 0 is off. # floor_watch = 0 # 1: with trace = perf, walks of the process's address space count its private and write-combined memory every 600 # frames (the "mem: process" line; at every 3600th frame, and any other where the commit census walks, that walk # stands in for it) and where its committed memory lies every 3600 frames, and when the process's own commit (without # the video memory Windows charges to it) rose 1 GiB over the highest it was, at most once a minute (the "commit # census" lines). Each walk holds the address-space lock for 100-260 ms and delays the next frame by as much, so they # are off unless asked for: leave it off in a run whose smoothness is judged. # mem_census = 0 # 1: with trace = perf, the process's handles counted by kind (events, sections, threads, files...) at the 600-frame # report when their number grew by 16 or more since the last count (the "mem: handles" line). It reads the system's # whole handle table on a thread of its own, 2-5 ms each time, and keeps a few MB for it. Read at start. # handle_census = 0 # The memory the game is taken to need, in MB of commit (RAM plus page file not yet promised to a program). When less # is free at the start, the log gets a warning line: short of memory the game stutters, loses textures or stops with # an out-of-memory or lost-device error. The default is what the game took in play at 3840x2160 on an RTX 5090; the # video card's memory counts on Windows. 0: no warning. Default: 24576. # mem_need_mb = 24576 # The size in MiB (16 to 256) of the blocks the renderer takes video memory in. A block goes back to the driver only once # everything in it is freed, so smaller blocks hold less free space after area changes; larger ones need fewer # allocations while an area loads. Default: 64. # vma_block_mb = 64 # Flight recorder: keeps the last frames and saves them to a flight folder next to the folder of nx2navi.exe when a frame # takes longer than flight_spike_ms (0 to 60000). # flight = 0 # flight_spike_ms = 100 # The flight recorder also saves them after a one-frame flash: a frame whose picture differs from the frame before and # the frame after while those two are alike (0: not). The three pictures are compared as 16x9 cells of mean # brightness: at least flight_flash_cells cells (1 to 144) must be more than flight_flash_diff (4 to 255, of 255) # brighter or darker than in both other frames. Lower values catch smaller and fainter flashes and take more of the # game's own effects for one. At most one such save every 30 seconds; a flash the game means (lightning) counts # too, and one while the camera turns fast does not. It needs the recorder's thumbnails. Read at start. # flight_flash = 1 # flight_flash_diff = 24 # flight_flash_cells = 3 # Stutter map: the log gets a line for each hitch (a frame over 2.5 times the frames before it and at least 12 ms, or # over 25 ms) with the area, what the frame waited for and the pipelines and shaders its draws met missing; a run of # consecutive long frames counts as one hitch with their summed time. Every 5 minutes of play, when the window loses # the focus in play and at exit, a map of the areas by their hitches and of the pipelines that cost the most. # tools/stutter_map.py reads it. 0: off. Read at start. # stutter_map = 0 # GPU pass marks: after a GPU crash (device lost) the log names the render pass or dispatch the GPU had started and the # last one it finished. Unset: on AMD GPUs (VK_AMD_buffer_marker). 1: also on NVIDIA GPUs # (VK_NV_device_diagnostic_checkpoints), which NVIDIA says costs a little. 0: off. # pass_crumbs = 1 # Pipelines built without the video driver's shader optimiser: the same picture, slower shaders in those pipelines. # mesh: only the pipelines with task and mesh shaders (terrain, foliage). 1: all. 0: none. # Unset (default): mesh on AMD's Windows driver for the RX 5000 and RX 6000 series and older, where the device is lost # ("driver timeout") in render passes that start with such a pipeline; 0 on every other driver. On those cards 0 gives # the optimised pipelines back. # vk_noopt = mesh # GPU draw marks, for a GPU crash (device lost) that comes back in the same place on an AMD GPU: inside each render pass # a mark is written wherever the shaders change, and after the crash the log names the shaders of the draws the GPU had # not finished, not only the pass. It costs a little frame rate, so it is off unless a crash is being tracked down. # Needs the pass marks above (AMD GPUs). Default: 0. # draw_crumbs = 1 # A test of how the game ends when the video card stops answering (device lost): the hand-over to the GPU queue with # this number is not made and is taken as one the driver refused with a lost device. The log then holds one report and # one FATAL line, and the game ends with exit code 72. 0: never. Default: 0. # device_lost_at = 0 # A test of the page write generations (how the renderer tells which game memory changed since it last looked): they # start after this number instead of 0, so a run reaches 4294967296, where the 32-bit generations of versions before # 0.10.2 ran out, within its first seconds (4294966000 does that). Decimal, or hexadecimal with 0x; at most # 4611686018427387904. The log says where they start. Nothing else changes. Read at start. Default: 0. # gen_seed = 0 # Once a second, puts the crash report's exception filter back if a GPU driver or an overlay loaded after the start set # its own in its place, and says so in the log. Without it, a crash in such a DLL can end the game with no FATAL line in # the log. 0: off. # crash_filter_guard = 1 # Render targets up to this size (bytes, 0 to 1073741824) go back to their game memory whenever the game waits for a # GPU fence. A larger target goes back too unless the GPU drew it in each of the last 16 frames. A game that reads a # larger target drawn every frame without invalidating it sees stale bytes at the default. With trace = gfx the log # names each dirty target that stays on the GPU ("fence write-back skipped-drawn-every-frame") and each one over 65536 # bytes that went back ("over-default"). Raising it costs a copy per such target and wait. # wb_fence_limit = 65536 # Log kernel services that block longer than this many ms, with the service number (0: off). A stalled frame shows up as # time in the replay; this says whether the guest was waiting in a service, and which one. # svc_slow_ms = 0 # 1: every signalled event and every thread that ends wakes all the game threads that wait for any event, as before; # each takes one of the game's virtual cores to find that its own event is not the one, often from a thread that was # working. 0 (default): only the threads that wait for that event or thread are woken. With trace = sched the # "sched:" line counts both ("signals woke ..., left ... asleep"). # sync_wake_all = 0 # 1 (default): a thread of its own writes the log lines, to the log file and the console, so a write that stalls (a # busy disk, a virus scanner, a console that scrolls) no longer holds the thread that logged, which is often the one # that draws the frame. It writes the lines of a quarter of a second together, sooner when many are waiting, so the # log file and the console are up to that much behind the game. A crash, a fatal error and the end of the game write # out what is still queued first; a game that is ended from outside (Task Manager) loses those last lines. 0: each # line is written at once by the thread that logs it, as before. Either way a "log: ... writes of the log took over # 2 ms" line counts the slow writes and says whose time they took. # log_async = 1 # 1: the frame-time summary also splits the replay by op kind (draw, bind, transfer), which says where a stalled frame # went. The clock reads cost a fraction of a millisecond a frame, so it is off by default. # replay_time = 0 # A frame whose texture work on the render thread (new textures, uploads, upload submits) takes at least this many ms # gets a "texup:" line in the log that splits it: creation, staging, storage copy, ASTC recording, scratch buffers and # new device memory (up to 400 lines; 0: none; 16 catches the area-change hitches). # texup_log_ms = 0 # 1: the frame-time summary also lists the locks the replay waited for, by the code that asked (addresses; the line's # "ref" is perf_lock_timing_here, which the link map names), the recorder's waits, and the texture lock's holds over # 1 ms. Off by default. # lock_time = 0 # 1: with trace = perf, the "mem: sizes" line also counts the recording copies (the game's recorded command lists, # kept until the game hands their control memory over again) that no submission used for 5 minutes and whose control # memory the game has written over since, or no longer maps: copies the game will not use again. A thread of its own # reads 16 bytes of game memory for each new copy, and for up to 4096 known copies every 5 seconds; nothing is freed. # The count is a lower bound: memory written over with the same bytes is not seen. Read at start. Default: 0. # copy_retire = 0 # Texture entries the bindless texture pool may create in one refresh (images and their uploads); the rest wait for # the next refresh and show their stand-in until then. Lower spreads streaming over more frames (smaller hitches, a # frame or two of pop-in); higher loads sooner. # pool_create_budget = 16 # The refresh runs before every draw that samples the pool, so the budget above holds per draw. Once a frame's # refreshes have taken this many ms, they create nothing more until the next frame (the first refresh of each frame # keeps its budget): an area load then spreads over several frames with stand-ins instead of holding one frame for # 200-400 ms. 0: no limit. # pool_create_ms = 6 # An area load is told from streaming by the number of textures still to make: at this many or more, the two limits # above give way (a frame may take pool_load_ms for them) and the picture before the load stays on screen until the # area's textures are there, instead of showing the ground and the walls black for the first seconds. 0: never. # pool_load_backlog = 512 # pool_load_ms = 50 # Idle 2 MiB regions of game memory are made read-only so that the per-frame checks for CPU writes skip them. Right # after an area load such a freeze can take 4-30 ms instead of microseconds, so after a slow one the freezes wait # (250 ms, doubled for each further slow one up to 2 s) and start the doubling over only after freeze_quiet_ms without # a slow one (0: after any fast freeze, as in 0.10.1). None is made while an area's textures load nor for # freeze_load_hold_ms after that or after an area loads (0: no such hold). The regions wait meanwhile; their checks # cost a few microseconds per MiB each submission until they are frozen. # freeze_quiet_ms = 5000 # freeze_load_hold_ms = 3000 # Written storage-buffer ranges up to this size in MiB (1 to 256) go back to game memory as a merge, in 4 MiB pieces: # copied within video memory and only the words that changed written over PCIe. Larger ones are copied back whole at # the end of every submission. Raising it from 4 to 16 took a 5.5 MiB range off the plain copies (about 46 MiB a frame # in the field), and 32 the 4-15 MiB ranges of Kokiri Forest. # wb_merge_max = 32 # 1: pages a VRAM mirror wrote back to game memory are not copied up into it again, as it already holds them (a write by # the game still is). Outdoors this removed about 57 MiB of copies a frame. 0: they are copied up again. # wb_no_reup = 1 # 1: finds out who reads what the GPU wrote back into guest memory. The 2 MiB regions inside a range just written back # are made inaccessible until their first read or write, which is logged with its instruction ("mem: write-back # probe"). The bytes are there all along; the probe only watches, at the cost of the faults it takes. # wb_probe = 0 # The wait after each frame's first GPU submission. 1 (default): it ends when the video card has run the submission # and the results the game reads next are in its memory (the last frame's visibility counts above all); what the card # wrote besides goes back to the game's memory in a submission of its own, behind the wait. 0: the game waits until # everything before it has reached its memory, about 0.7 ms more of every frame in the open. 3: the wait ends as soon # as the card has run the submission, without the visibility counts: the game then reads counts that may be a frame # old, and lit things near the camera can lose their light for single frames. With shadow storage (Linux, Wine) 1 # and 3 change nothing; 2 forces 1 there as well, for tests. # wb_split = 1 # 1: what the game's shaders write into its memory is copied back from the video card once, and after that only when # the game's CPU code touches it (most of it never is: 66 MiB a frame in Hyrule Field), for about a third more frames # a second in open areas. 0: copied back at the end of every GPU submission, as in 0.7.0. # Default: 1 on Windows, except 0 on AMD graphics cards (AMD's own driver), where two reports had the game end in play # with it on and the cause is not found: set 1 there to try it, and back to 0 if the game ends in a fight (the log's # "mem: lazy write-back" line says which is in effect and why). 0 elsewhere. With shadow storage (Linux, Wine) it # stays off whatever is set. # wb_lazy = 1 # With wb_lazy, off by default: with it on the graphics device was lost shortly after some save loads (about one load # in three of a save in Hyrule Field at night on one card), and not once in 15 loads with it off; the cause is open. # 1: when the game's CPU code touches such memory, only the 64 KiB around the place it touched are copied # back and kept up to date from then on; the rest of that buffer stays on the video card. The game reads a few words # at the start of buffers of several MiB about twice a second. 0: the whole buffer comes back and everything near it # is copied back every frame for up to 32 seconds, as before (a tenth fewer frames a second in a village). # wb_lazy_chunk = 0 # With wb_lazy: 1 (default): when the game's CPU code touches memory the video card wrote, the copy that brings it # back holds up only the threads that touch that memory; the game's other threads, the video card's bookkeeping and # file reads go on meanwhile, and several such copies can run at once. 0: every such copy holds them all up until it # is done and the copies run one at a time, also those made when video memory runs short, as in 0.10.1; only a thread # that touches memory while it is being copied still waits for that copy alone. Set 0 if the game ends or the graphics # device is lost where it did not before, and send the log. # wb_lazy_unlocked = 1 # Barriers between the game's draw passes and compute dispatches. 1: only where the game itself asks for one, or where # the work changes between drawing and compute; this takes about a tenth off the graphics card's time for a frame. # 0: a full barrier before every pass and every dispatch. Default: 1 on NVIDIA graphics cards, 0 on all others, where it # has not been tried: set 1 there to try it, and back to 0 if the picture shows faults. # barrier_game = 1 # Mesh draws whose count the graphics card computes: 1 (default) prepares the counts of a run of such draws at its # first one, so their draw pass is not ended and begun again at each of them (about 40 passes fewer a frame in a # village). 0: each such draw ends its pass and prepares its own count, as before. # mesh_ahead = 1 # Graphics cards without mesh shaders (GTX 10 series, RX 500 and 5000 series, many integrated ones): the game's mesh # draws, most of the world, are computed in compute passes and drawn as ordinary triangles. auto (default) does that # on such a card, and on the RX 6000 series with AMD's Windows driver, where the game drawn with mesh shaders lost the # graphics card in play ("driver timeout", the game ends with code 72); there it costs some frame rate, and a place's # ground, rocks and plants show a moment late the first time they are drawn in a run. 1 does it on every card (for # testing: it is slower than mesh shaders); 0 never: an RX 6000 card then draws with mesh shaders as version 0.10.1 # did, and a card without them draws no world. # mesh_fallback = auto # Video memory in MB for what those compute passes hand to the draws. A draw that needs more loses the geometry that # does not fit, and the log says so. # mesh_fallback_mb = 128 # Threads that prepare those compute passes for the mesh programs a place uses, the first time each is drawn (until # then its draws are left out). auto (default): one for each 4 logical processors, 1 to 4. # mesh_fallback_workers = auto # Windows, 1 (experimental): the game's heap is committed a 64 KiB run at a time where it is first used, instead of # all of it when the game sizes it. Windows counts committed memory against RAM plus the page file whether it is used # or not, and in Castle Town after Hyrule Field about 3.4 of the heap's 6.8 GiB had never been used. 0: committed up # front. Linux commits pages on first use anyway. With 1, a PC whose commit is used up ends the game at the moment a # heap page is first used, in the middle of play, where with 0 it would not have started. # heap_lazy = 0 # Linux, shadow storage: 1 clears the write watch's protection of a range in one call before the GPU's bytes are copied # back into the game's memory, instead of taking a fault at the first store into each page. # shadow_bulk_write = 0 # 1: the game's flushes of mirrored memory are copied into the mirrors even where the write watch already sees every # page the game wrote; 0 (default) copies only the written pages there, which saved 47-57 MiB of copies a frame in # Kokiri Forest. # flush_upload = 0 # For measuring: only mirrors of the game's memory pools up to this many KiB send what shaders write through the # device address table to game memory as well; larger mirrors keep it in video memory and are not evicted. On PCIe 3.0 # those second writes cost about 3 ms of GPU time a frame. 0 (default): every mirror sends them. A pool that needs them # and is left without shows as foliage stretched into columns or flickering. # gpa_twin_max_kb = 0 # 1 (default): shaders that follow the game's pointers read a memory pool's new copy in video memory only once that # copy has been filled; until then they read the game's own memory. 0: they read the new copy at once, as up to 0.9.2, # where a card over its video memory budget could lose the device at an area load (a GPU read fault at the first byte # of the new copy). # gpa_late = 1