From 5ae55db41c7d11c4e997d2676019939a936e560b Mon Sep 17 00:00:00 2001 From: epicmeme546 <178368684+epicmeme546@users.noreply.github.com> Date: Fri, 13 Nov 2026 11:57:11 -0500 Subject: [PATCH] Keep CPU helper threads on Automatic and Start next frame early on by default in 0.10.1, as in 0.10.0, and give 0.10.1's notes the video memory fix. The release commit for 0.10.1 had turned both off by default (replay_workers = 0, tail_early = 0). They stay as 0.10.0 has them: replay_workers = auto, half the processor's physical cores less one (3 on 8 cores), and tail_early = 1. A player's session with all four Testing settings at 0 filled the video memory as before (bug capture 7: 15.5 GiB in use, 20.7 frames a second); what filled it were the images of moved render targets, which the two commits before this one fix. runtime/cfg.c, runtime/ui/menu.cpp, runtime/vk_exec.c and nx2navi.ini.example are back as they were at 0.10.0. The notes of 0.10.1 lose the entry about the defaults and take the fix's entry from the draft for 0.10.2, which goes. Co-Authored-By: Claude Fable 5.2 --- docs/releases/v0.10.1.md | 22 ++++++++++++++-------- docs/releases/v0.10.2.md | 16 ---------------- nx2navi.ini.example | 18 +++++++++--------- runtime/cfg.c | 6 +++--- runtime/ui/menu.cpp | 2 +- runtime/vk_exec.c | 8 ++++---- 6 files changed, 31 insertions(+), 41 deletions(-) delete mode 100644 docs/releases/v0.10.2.md diff --git a/docs/releases/v0.10.1.md b/docs/releases/v0.10.1.md index 3ff9df59..d70046ad 100644 --- a/docs/releases/v0.10.1.md +++ b/docs/releases/v0.10.1.md @@ -12,13 +12,19 @@ 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 +## Fixed -- **Every setting under the Game tab's Testing heading is off by default again:** - - *CPU helper threads* (`replay_workers = 0`; it was Automatic in 0.10.0); - - *Start next frame early* (`tail_early = 0`; it was on in 0.10.0); - - *Helpers work ahead* and *Helpers take small jobs* (`replay_pipe` and `replay_small`, off as before). +- **Video memory no longer fills up while you walk or turn the camera** (by epicmeme546). In 0.10.0 the video memory + in use climbed by several gigabytes within seconds of moving, in any area, until the card was full: the frame rate + fell to 2 to 4 frames a second and the game could end. The game lays its render targets out anew in every frame, one + behind the other. One of them, a shadow map, changes its size with the view, and every target behind it then lies at + a new address in each frame. A moved target should take over the image of the one it replaces, but that image counted + as in use until the game recycled the old target's texture object, so every frame got about a dozen new images and + each old one stayed for 120 frames or more: 6.7 GiB of them at 3416x1440 and 12.2 GiB at 3840x2160, on top of the + 10 GiB an area needs at those sizes. Such an image now goes to the next target of its size once nothing has drawn + with it or sampled it for 16 frames, and sooner once the card is past 80 % of its memory. Walking through Kokiri + Forest at 3416x1440 on a 20 GiB card: 15.9 GiB in use before, 9.7 to 10.7 GiB now. The same walk at 3840x2160 with + the memory budget of a 16 GiB card: 10.9 to 11.4 GiB, where a player's 16 GiB card had 22.2 GiB asked of it. - They are experimental and were measured on few cards. A value you chose yourself, in the settings menu or in - nx2navi.ini, stays as you set it: to keep 0.10.0's behaviour, set *CPU helper threads* to Automatic and *Start next - frame early* to On. Everything else is as in 0.10.0; see its notes. +Everything else is as in 0.10.0, the settings under the Game tab's Testing heading included: *CPU helper threads* is +Automatic (half the processor's cores less one: 3 on 8 cores) and *Start next frame early* is on. See 0.10.0's notes. diff --git a/docs/releases/v0.10.2.md b/docs/releases/v0.10.2.md deleted file mode 100644 index dc1fbe47..00000000 --- a/docs/releases/v0.10.2.md +++ /dev/null @@ -1,16 +0,0 @@ -## Fixed - -- **Video memory no longer fills up while the camera moves** (by epicmeme546). The game lays its render targets out anew - in every frame, one behind the other in one block of memory. One of them, a shadow map, changes its size with the view - (1141x1141 to 1917x1917 in Kokiri Forest, a texel or two a frame), and every target behind it then lies at a new - address in each frame. A moved target should take over the image of the one it replaces, but that image counted as in - use for as long as the game had not recycled the old target's texture object, so every frame got about a dozen new - images and each old one stayed for 120 frames or more: 6.7 GiB of them at 3416x1440 and 12.2 GiB at 3840x2160, on top - of the 10 GiB the area needs. A 20 GiB card ran full twice in five minutes of Kokiri Forest (images that could not be - made, 4 frames a second, then the game ended) and a 16 GiB card in Castle Town (images in system memory, 2 frames a - second). An image that another target was drawn over now goes to the next target of its size once nothing has drawn - with it or sampled it for 16 frames, or for 8 once the card is past 80 % of its memory, where such images are also - freed after 32 frames instead of ten seconds. Walking 28 metres from a save in Kokiri Forest and then around it at - 3416x1440: 15.9 GiB of video memory in use before and 14 GiB again on each lap; 9.7 to 10.7 GiB now, with at most 2.2 - GiB of released targets where there were 6.9 GiB, and 3,609 images made in the run where there were 6,970. The same - walk at 3840x2160 with the memory budget of a 16 GiB card: 10.9 to 11.4 GiB, at most 1.6 GiB of them released. diff --git a/nx2navi.ini.example b/nx2navi.ini.example index e107edb2..374b5d06 100644 --- a/nx2navi.ini.example +++ b/nx2navi.ini.example @@ -86,23 +86,23 @@ # 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 +# submitting one: auto or 0 to 16. Default: auto, 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. +# 0: the replay records everything on one thread. 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 +# replay_workers = auto +# 1, the default, 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 +# results it reads are there. A frame whose end hands the game anything else runs as before. Default: 1 (0 up to +# 0.9.2); 0 turns it off. 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 +# tail_early = 1 # 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 diff --git a/runtime/cfg.c b/runtime/cfg.c index e655d99d..aef5b0b8 100644 --- a/runtime/cfg.c +++ b/runtime/cfg.c @@ -296,9 +296,9 @@ static const CfgMeta metas[] = { // 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_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 since 0.10.0 + {"TAIL_EARLY", "1", "0|1", RESTART}, {"REPLAY_SMALL", "0", "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 diff --git a/runtime/ui/menu.cpp b/runtime/ui/menu.cpp index cf4760ed..abf4603e 100644 --- a/runtime/ui/menu.cpp +++ b/runtime/ui/menu.cpp @@ -1475,7 +1475,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]; diff --git a/runtime/vk_exec.c b/runtime/vk_exec.c index 62e37966..7f59ddbe 100644 --- a/runtime/vk_exec.c +++ b/runtime/vk_exec.c @@ -1135,7 +1135,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 since 0.10.0; 0 turns it off) // 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 @@ -1849,9 +1849,9 @@ 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 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