Turn the Game tab's Testing settings on by default for 0.10.2, as the user asked: CPU helper threads Automatic (replay_workers = auto, which gives none on four cores or fewer and none on AMD's driver for RX 6000 and older), Helpers work ahead 4 (replay_pipe), Helpers take small jobs 16 (replay_small) and Start next frame early On (tail_early). A value a player set in the menu or nx2navi.ini stays; the notes say how to go back to 0.10.1's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
chrg6
2026-11-14 03:20:37 -05:00
parent 87b4e2607e
commit 69ab33d1f1
5 changed files with 37 additions and 24 deletions

View File

@@ -12,6 +12,18 @@
game and 1.5 GB for the launcher; a GPU with Vulkan 1.3 and `VK_EXT_external_memory_host` (current NVIDIA and AMD
cards).
## Changed
- **The Game tab's Testing settings are on by default:**
- *CPU helper threads*: Automatic (`replay_workers = auto`): half the CPU's cores less one, none on four cores or
fewer and none on AMD's driver for Radeon RX 6000 and older;
- *Helpers work ahead*: 4 (`replay_pipe = 4`);
- *Helpers take small jobs*: 16 (`replay_small = 16`);
- *Start next frame early*: On (`tail_early = 1`).
They are still experimental. A value you chose yourself, in the settings menu or in nx2navi.ini, stays as you set
it: to keep 0.10.1's behaviour, set them back to 0 and Off.
## Fixed
- **See-through ground** (issues #569 and #824). 0.10.0 and 0.10.1 shipped an older shader translator, whose shaders

View File

@@ -102,31 +102,31 @@
# 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
# submitting one: auto or 0 to 16; 0 records everything on the submitting thread. Default: auto (0 in 0.10.1 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
# replay_workers = auto
# 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
# results it reads are there. A frame whose end hands the game anything else runs as before. Default: 1 (0 in 0.10.1
# 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
# tail_early = 1
# EXPERIMENTAL, with replay_workers. replay_pipe = N (0 to 4, default 4): the submitting thread goes on past up to N
# groups its workers still record. replay_small = N (0 to 63, default 16, 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
# take small jobs (replay_small). Neither does anything without replay workers.
# replay_pipe = 4
# replay_small = 16
# 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.

View File

@@ -328,11 +328,11 @@ static const CfgMeta metas[] = {
{"DISCORD_IMAGE", NX2NAVI_DISCORD_IMAGE_DEFAULT, NULL, LIVE},
// Advanced: scheduling
{"ASYNC_PREEMPT", "1", "0|1|2", RESTART}, {"REPLAY_ASYNC", "0", "0|1", RESTART},
{"REPLAY_PIPE", "0", "0..4", RESTART},
{"REPLAY_WORKERS", "0", "auto|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16", RESTART}, // vk_exec.c rw_init, vk_exec_replay_workers_auto
// vk_exec.c "the early tail"; off by default (on in 0.10.0 only)
{"TAIL_EARLY", "0", "0|1", RESTART},
{"REPLAY_SMALL", "0", "0..63", RESTART}, // vk_exec.c group_start
{"REPLAY_PIPE", "4", "0..4", RESTART},
{"REPLAY_WORKERS", "auto", "auto|0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16", RESTART}, // vk_exec.c rw_init, vk_exec_replay_workers_auto
// vk_exec.c "the early tail"; on by default (off in 0.10.1 only)
{"TAIL_EARLY", "1", "0|1", RESTART},
{"REPLAY_SMALL", "16", "0..63", RESTART}, // vk_exec.c group_start
{"FREE_CORES", "0", "0|1", RESTART}, {"TIMER_1MS", "1", "0|1", RESTART},
// dynamic resolution (dynres.c): the scene follows the GPU time toward DYN_RES_TARGET milliseconds (under 1: the
// frame limit's frame time), holding each step DYN_RES_STEP 60 Hz frames of the clock

View File

@@ -1476,7 +1476,7 @@ static void tab_game(float scale) {
opt_group_text("Testing");
// vk_exec.c rw_init and tail_enabled read these at start: each row notes the restart and the bar's Restart does
// it. A row whose setting does nothing without another one (rw_init) is greyed out until that one is set.
// Automatic first (vk_exec.c vk_exec_replay_workers_auto), named with the count it gives on this PC; 0 is the default
// Automatic first, the default (vk_exec.c vk_exec_replay_workers_auto), named with the count it gives on this PC
{
static const char *const vals[] = {"auto", "0", "1", "2", "3", "4", "5", "6", "7", "8"};
static char auto_name[64];

View File

@@ -1138,7 +1138,7 @@ static int split_n = -1, split_idle, split_in_pass, split_draws, split_at, part_
static uint64_t split_ns, part_t0;
static uint64_t n_parts, n_subs, n_idle_parts, n_pass_splits, n_cuts;
// ---- the early tail (NX2NAVI_TAIL_EARLY, default 0; on by default in 0.10.0 only)
// ---- the early tail (NX2NAVI_TAIL_EARLY, default 1; off by default in 0.10.1 only)
// Standing in Hyrule Field with FSR 4 (RX 7900 XT, 2026-11-13) a frame's main submission ends with one part of 4.7 ms
// of GPU time, the temporal upscaler and the interface drawn after it, and one of 1.4 ms, the write-backs of what the
// shaders wrote into VRAM mirrors. The game waits for all of it before it writes the next frame's data (the wait after
@@ -1890,16 +1890,17 @@ static void op_one(VkExec *ex, const op_hdr *h) {
}
}
// ---- replay workers (NX2NAVI_REPLAY_WORKERS, default 0: the replay records every op on the submitting thread; auto:
// as many as the CPU's cores make worth it, vk_exec_replay_workers_auto, the default in 0.10.0 only; the Game tab's CPU
// helper threads row sets it)
// ---- replay workers (NX2NAVI_REPLAY_WORKERS, default auto: as many as the CPU's cores make worth it,
// vk_exec_replay_workers_auto; 0, the default in 0.10.1 only: the replay records every op on the submitting thread;
// the Game tab's CPU helper threads row sets it)
// 3 workers: on an RX 7900 XT with a Ryzen 7 5800X3D, Hyrule Field standing went from 41.2 to 50.4 fps (2026-11-12, one
// batch), with the same pictures there and in Kokiri Forest, Kakariko, Goron City, a graveyard house and Gerudo
// Valley; 5 or 7 workers measured the same as 3. Default 0 again after players' games crashed with 3 on by default
// Valley; 5 or 7 workers measured the same as 3. Players' games crashed with 3 on by default
// (0.9.1, 0.9.2): an RX 6700 XT lost its device after about 18,000 frames, its last mark the game's own compute
// dispatch (op_dispatch: 20x1x1 groups of cs d7566eb1, a depth probe) and nothing after it marked, since the group of
// draws that followed was recorded by the workers, whose passes have no marks; an occlusion query slot was found
// unavailable after its fence just before. An RX 6600 lost it the same way twice (0.9.2). The cause is not known.
// unavailable after its fence just before. An RX 6600 lost it the same way twice (0.9.2). The cause is not known;
// auto gives that driver no workers (vk_exec_replay_workers_auto), and auto is the default again since 0.10.2.
// A submission's draws come in runs between ops that have to stay in the replay's order on its own thread (dispatches,
// copies, texture and buffer clears, events, the game's barriers, calls). Hyrule Field, standing (NX2NAVI_REPLAY_RUNS,
// 2026-11-11): about 3,500 draws a frame in 82 runs, 96% of them in runs of 16 draws or more and 67% in runs of 256 or
@@ -1922,7 +1923,7 @@ static void op_one(VkExec *ex, const op_hdr *h) {
// replays the op again once in turn, and so do the contact shadows' pass and the HDR pass's source. Per-object motion
// lists its draws under a lock (vk_exec_draw.c mvobj_draw), and the occlusion queries' slots and segments follow the
// stream (vk_exec_xfer.c vk_exec_xfer_slots, vk_exec_xfer_group_merge).
// NX2NAVI_REPLAY_PIPE=N (1-4, default 0): the submitting thread hands the group to the workers, takes chunks of it as
// NX2NAVI_REPLAY_PIPE=N (0-4, default 4): the submitting thread hands the group to the workers, takes chunks of it as
// they do until none is left to take, and goes on with the ops after it, in a new command buffer after the chunks'
// places in the part (vk_sync_append_later), while the last chunks are recorded; also into the front pass of the next
// group: up to N (at most LIVE_GROUPS) groups are handed out and not in their part yet, their chunks taken from one
@@ -2471,7 +2472,7 @@ static const op_hdr *group_start(VkExec *ex, const op_hdr *h, int depth) {
int n = (int)(draws / CHUNK_DRAWS);
if (n > RW.n + 1) n = RW.n + 1;
if (n > GROUP_CHUNKS) n = GROUP_CHUNKS;
// NX2NAVI_REPLAY_SMALL=N (default 0, with NX2NAVI_REPLAY_PIPE): a group of N draws or more that is too small to cut
// NX2NAVI_REPLAY_SMALL=N (default 16, with NX2NAVI_REPLAY_PIPE): a group of N draws or more that is too small to cut
// goes whole to one worker, and the submitting thread goes on with what follows it without taking the chunk
// itself. Kokiri Forest standing, 5 workers, 4 groups out, the early tail on (2026-11-13): about 700 draws a frame
// were in such groups, 3.6 ms of the submitting thread; with 16 the replay took 10.2 instead of 11.0 ms a frame