From 7a8bbad47ec73ae32abbdfe824910a672bd54e39 Mon Sep 17 00:00:00 2001 From: chrg6 Date: Sat, 14 Nov 2026 06:13:18 -0500 Subject: [PATCH] Remove the low-end GPU mode from the settings. The user asked for it: the mode no longer gains frame rate, and the mesh shader fallback covers the cards it was written for. Its switch in the settings menu's Game tab is gone with the rows under it, and so are their 57 text ids and strings. low_end_gpu itself does nothing any more. It is still a known key, so an older nx2navi.ini gives no unknown-key warning, and while it is on the log says once that the mode was removed in 0.10.2. The preset that gave nine keys other defaults is gone, and so is the rule that read the mode's keys only while it was on: each of them (mesh_emulation, tex_clobber, foliage, vram_heap_limit, vram_reserve_mb, upload_batch_mb, mirror_stage, mirror_hot, submit_finish_gpu and the others) is an ordinary setting with the default of its row or of its reader, so a line a player wrote by hand keeps counting and a file with only the switch runs the game as it runs for everyone else. guest_opt in nx2navi.ini counts for the next rebuild without the switch too (tools/make_game.py). The recorder thread read the switch itself: on an AMD card without mesh shaders the mode turned it on. It is off on every AMD card now unless vk_recorder = 1 is set. nx2navi.ini.example lists the former mode's settings as single settings, the 0.10.2 notes have a Removed entry and name the foliage fix of the commit before this one, and the comments that said what the mode sets say so in the past tense. tests/cfg_parse_check has the new reading of the switch and of the keys without it; the test matrix is at 90 ok with the same two not ok as before (installer_test, worktree_test), and a clean build compiles 169 runtime files and links. Not run in the game. Co-Authored-By: Claude Fable 5.2 --- docs/building.md | 5 +- docs/releases/v0.10.2.md | 17 ++++-- nx2navi.ini.example | 31 ++++++----- runtime/cfg.c | 78 +++++++-------------------- runtime/cfg.h | 1 - runtime/ui/menu.cpp | 85 ------------------------------ runtime/ui_text.c | 111 --------------------------------------- runtime/ui_text.h | 22 +------- runtime/vk_device.c | 21 +++----- runtime/vk_exec_draw.c | 2 +- runtime/vk_memory.c | 12 +++-- runtime/vk_mesh_path.h | 12 ++--- runtime/vk_rec.c | 12 ++--- runtime/vk_sync.c | 2 +- runtime/vk_vma_budget.c | 3 +- tests/cfg_parse_check.c | 10 ++-- tests/cfg_parse_check.py | 33 +++++++----- tests/cfg_rows_check.py | 3 +- tests/launcher_test.py | 22 +++++--- tests/mesh_path_check.c | 7 +-- tools/make_game.py | 13 ++--- 21 files changed, 138 insertions(+), 364 deletions(-) diff --git a/docs/building.md b/docs/building.md index d37eec55..ae74535c 100644 --- a/docs/building.md +++ b/docs/building.md @@ -919,10 +919,11 @@ A change to how nx2navi.ini and the environment are read (`runtime/cfg.c` `cfg_l `cfg_bool`, `check_value`) passes `python tests\cfg_parse_check.py`, which builds `cfg.c` with stand-ins for what it links with and loads scratch files: a comment after a value of a setting with a set of values is cut and logged once with its line, free text, a value in double quotes and the environment keep theirs; switches written as words read as -0 or 1 through every reader, the low-end mode's switch (`lowend_of`, read apart from `cfg_get`) included; values +0 or 1 through every reader; `low_end_gpu`, the switch of the low-end GPU mode that 0.10.2 removed, turns nothing on +and is named once in the log (`lowend_set`), and the mode's keys are read by themselves; values outside their sets are logged with their line, at most 16 lines and a count; a full settings table logs one line at load and one for the menu. The launcher's reader (`launcher/gameini.py`) has the same comment lines in -`tests\launcher_test.py` `PlayerIniTest`, and `tools/make_game.py`'s own reads of `shader_carry` and `low_end_gpu` +`tests\launcher_test.py` `PlayerIniTest`, and `tools/make_game.py`'s own reads of `shader_carry` and `guest_opt` (`shader_carry`, `guest_opt_ini`) theirs in `MakeGameTest`. No game files. The lifter (`recomp/`) and the CPU headers (`runtime/cpu.h`, `runtime/simd.h`) are checked against Unicorn. Every lifter diff --git a/docs/releases/v0.10.2.md b/docs/releases/v0.10.2.md index 03a2b4d5..55a78c30 100644 --- a/docs/releases/v0.10.2.md +++ b/docs/releases/v0.10.2.md @@ -24,6 +24,14 @@ cards). with *Full* and 42.8 with *Reduced* on the same tour, and a handheld that got *Full* closed when a save was loaded. A texture detail you chose yourself stays as you set it. +## Removed + +- **The low-end GPU mode** is gone from the settings menu's Game tab, with the rows under it: it no longer gained + frame rate, and the mesh shader fallback now covers the cards it was written for. `low_end_gpu = 1` in an existing + nx2navi.ini does nothing, and the log says so once; the game then runs as it does for everyone else. The settings + the mode turned on can still be set one by one in nx2navi.ini (`nx2navi.ini.example` lists them); a line for one of + them that is already in your file keeps counting. + ## Fixed - **See-through ground** (issues #569 and #824). 0.10.0 and 0.10.1 shipped an older shader translator, whose shaders @@ -40,10 +48,13 @@ cards). code 70, until nx2navi.ini was edited by hand): with DLSS Frame Generation on and the *Graphics card* setting on the card that is not NVIDIA's, the device could not be made. The game now starts on the NVIDIA card, and where there is none, or frame generation cannot be set up, it starts without frame generation and the log says why. -- **A crash on GeForce GTX 10 cards with the low-end GPU mode on** (the game closing inside NVIDIA's driver at the - first grass or foliage of an area, reported on a GTX 1050 Ti, a GTX 1070 and a Titan X): the mode turned on an +- **A crash on GeForce GTX 10 cards that had the low-end GPU mode on** (the game closing inside NVIDIA's driver at + the first grass or foliage of an area, reported on a GTX 1050 Ti, a GTX 1070 and a Titan X): the mode turned on an older way of drawing the game's mesh shaders that this driver does not survive. NVIDIA cards without mesh shaders - now always take the mesh shader fallback, which ran on the GTX 1050 Ti with the rest of the mode still on. + now always take the mesh shader fallback, and the mode itself is gone (see *Removed*). +- **Flashing or white foliage on cards that take the mesh shader fallback** (reported on a Radeon RX 580): the numbers + each such draw goes by were written in an order the graphics card was free to change, and about half the draws got + the wrong ones. Each is now written exactly once (by Tobim6). - **Crashes and hangs found in a review of the whole runtime**; none was seen in our own play, and each fix has a check of its own: - a crash when the game read memory the lazy write-back was just handing to the GPU (NVIDIA and Intel cards); diff --git a/nx2navi.ini.example b/nx2navi.ini.example index 66cd207f..b3ae2859 100644 --- a/nx2navi.ini.example +++ b/nx2navi.ini.example @@ -447,18 +447,25 @@ # 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 +# The low-end GPU mode of 0.9.2 to 0.10.1 is gone: low_end_gpu = 1 in an older file does nothing, and the log says +# so once. The settings it turned on are ordinary settings now, each off unless this file sets it, and none has a row +# in the settings menu. Read at start. +# mesh_emulation = 1 runs mesh shaders as compute where the card has none, in place of the mesh fallback (never on an +# NVIDIA card). vram_heap_limit = auto and vram_reserve_mb = 512 keep video memory within what the driver reports +# free. upload_batch_mb sends large texture upload batches to the GPU early (every batch goes at 64 MiB of staging at +# the latest, so only a value below 64 acts). mirror_stage = 1 and submit_finish_gpu = 0 copy game memory for the GPU +# while a frame is recorded and let the game wait less for the GPU. mirror_hot = 25 keeps pools the game refills every +# frame in system memory. tex_clobber = 1 gives a texture read after another image was drawn over its memory memory +# of its own. foliage = reduced draws no small grass or moss, off no foliage. +# mesh_emulation = 0 +# vram_heap_limit = 0 +# vram_reserve_mb = 0 +# upload_batch_mb = 0 +# mirror_stage = 0 +# submit_finish_gpu = 1 +# mirror_hot = 0 +# tex_clobber = 0 +# foliage = full # 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 diff --git a/runtime/cfg.c b/runtime/cfg.c index 07c7e0c0..3302ca10 100644 --- a/runtime/cfg.c +++ b/runtime/cfg.c @@ -113,7 +113,7 @@ static const char *const known[] = { // The nx2navi.ini section a key cfg_set may write goes to when the file lacks it (nx2navi.ini.example's sections). static const struct { const char *key, *section; } sections[] = { - // the low-end GPU mode's rows in the menu's Game tab (ui/menu.cpp rows_low_end) + // the settings the low-end GPU mode had rows for up to 0.10.1 (lowend_set, below) {"TEX_RELEASED_MAX", "performance"}, {"MIRROR_HOT", "performance"}, {"FREEZE_IDLE", "performance"}, {"SUBMIT_FINISH_KINDS", "performance"}, {"FOLIAGE", "performance"}, {"ZSTD_NATIVE", "performance"}, {"VRAM_HEAP_LIMIT", "performance"}, {"VRAM_RESERVE_MB", "performance"}, {"UPLOAD_BATCH_MB", "performance"}, {"MESH_EMULATION", "performance"}, @@ -406,7 +406,7 @@ static const CfgMeta metas[] = { // it for the idle seconds; 0 keeps every shader's SPIR-V plain {"SHADER_COMPRESS", "1", "0|1", RESTART}, {"SHADER_COMPRESS_IDLE_S", "30", "1..3600", RESTART}, - // the low-end GPU mode's rows in the menu's Game tab (ui/menu.cpp rows_low_end) + // the settings the low-end GPU mode had rows for up to 0.10.1 (lowend_set, below): each is read by itself now {"TEX_RELEASED_MAX", "", NULL, RESTART}, // vk_texture.c released_max: "" by the video memory budget, else 1..16384 {"MIRROR_HOT", "0", "0..1000", RESTART}, {"FREEZE_IDLE", "1800", "0..100000", RESTART}, {"SUBMIT_FINISH_KINDS", "31", "0..31", RESTART}, // vk_sync.c res_mask @@ -426,7 +426,8 @@ static const CfgMeta metas[] = { // vk_texture.c drop_aged: seconds a released texture is kept unused (vk_tex_release.h) {"TEX_RELEASED_HOLD", "180", "0..900", RESTART}, {"ASTC_BC", "", "0|1", RESTART}, {"ZSTD_NATIVE", "1", "0|1", RESTART}, {"ZSTD_CHECK", "0", "0|1", RESTART}, {"TEX_CLOBBER", "0", "0|1", RESTART}, - {"LOW_END_GPU", "0", "0|1", RESTART}, // LOWEND below + // the switch of the low-end GPU mode, which is gone: still a known key, and it does nothing (lowend_set, below) + {"LOW_END_GPU", "0", "0|1", RESTART}, {"STG_ARENA", "1", "0|1", RESTART}, {"ASTC_GPU_DESWIZZLE", "1", "0|1", RESTART}, {"ASTC_SCRATCH_KEEP", "1", "0|1", RESTART}, {"ASTC_ARENA", "1", "0|1", RESTART}, // vk_astc.c scratch_get, vk_texture.c astc_arena // render fixes @@ -822,54 +823,19 @@ static int on_steam_deck(void) { static const char *raw_get(const char *name); -// low_end_gpu = 1 in nx2navi.ini (NX2NAVI_LOW_END_GPU): defaults for the keys the player does not set, as the device -// profile gives them. They turn on what was written for older graphics cards and ones short of video memory or bus -// bandwidth, and measured on a Radeon RX 580: mesh shaders run as compute where the card has none (vk_pipeline.c -// mesh_emu_on), a texture read after another image drew over its pool memory gets memory of its own (vk_texture.c -// mark_clobbered), game memory is copied for the GPU while the replay records and the game's wait after a frame's -// first submission ends once the replay has submitted it (vk_memory.c stage_on, vk_sync.c vk_sync_recorded_wait), -// texture checks share their write-watch queries (vk_memory.c snap_widen_n), video memory stays within the heaps' -// budgets (vk_device.c vram_heap_limits, vk_vma_budget.c), large upload batches go to the queue early (vk_memory.c -// vk_upload_end) and pools the game refills every frame stay in system memory (vk_memory.c hot_check). Without the -// key each of these keeps what 0.9.1 did. Asynchronous replay (vk_backend.c, NX2NAVI_REPLAY_ASYNC) is not among them: -// it can show a dark or flickering frame now and then, so the mode leaves it off and its row under the mode's switch -// turns it on for a player who wants it. -static const struct { const char *key, *value; } LOWEND[] = { - {"MESH_EMULATION", "1"}, {"TEX_CLOBBER", "1"}, {"MIRROR_STAGE", "1"}, {"SUBMIT_FINISH_GPU", "0"}, {"SNAP_WIDEN", "8"}, - {"VRAM_HEAP_LIMIT", "auto"}, {"VRAM_RESERVE_MB", "512"}, {"UPLOAD_BATCH_MB", "256"}, {"MIRROR_HOT", "25"}, -}; -// The keys that count only while the mode is on (LOWEND_ONLY): without it each reads as unset, whatever the settings -// file or the environment says, so nothing of the mode acts unless a player turned it on. The menu shows their rows -// only then (ui/menu.cpp rows_low_end). Keys the game had before the mode (replay_async, freeze_idle, zstd_native, -// tex_released_max, astc_scratch_keep) are not among them. -static const char *const LOWEND_ONLY[] = { - "MESH_EMULATION", "MESH_EMU_MB", "MESH_EMU_TASKS", "MESH_EMU_BATCH", "TEX_CLOBBER", "MIRROR_STAGE", "MIRROR_HOT", - "SUBMIT_FINISH_GPU", "SUBMIT_FINISH_RESULTS", "SUBMIT_FINISH_KINDS", "SNAP_WIDEN", "VRAM_HEAP_LIMIT", - "VRAM_RESERVE_MB", "UPLOAD_BATCH_MB", "FOLIAGE", "FLUSH_SKIP_CLEAN", "VEC_INDEX_FIX", "GUEST_OPT", "PASS_TIMES", - "DUMP_KEY", "LOG_TEX_NEW", "SVC_WAITS", -}; -static int lowend_only(const char *key) { - for (size_t i = 0; i < sizeof LOWEND_ONLY / sizeof *LOWEND_ONLY; i++) - if (!strcasecmp(LOWEND_ONLY[i], key)) return 1; - return 0; -} -static int lowend = -1; +// low_end_gpu (NX2NAVI_LOW_END_GPU) was the switch of the low-end GPU mode up to 0.10.1. With it on, nine keys got +// other defaults (mesh shaders run as compute where the card has none, a texture read after another image drew over +// its pool memory given memory of its own, game memory copied for the GPU while the replay records, video memory kept +// within the heaps' budgets, large upload batches sent early, pools the game refills every frame kept in system +// memory), and those keys and a dozen more were read only while it was on. The mode is gone. Its switch is still a +// known key, so that an old file's line is no unknown one, and does nothing. Each of its keys is read like any other, +// with the default of its row or of its reader: a value a player set by hand counts, and a file that sets none runs +// the game as it runs for everyone else. cfg_init says so once while the switch is on. // Read through raw_get, which skips switch_word, so the words are taken here as cfg_bool takes them: "low_end_gpu = -// off" is off for the mode as for the menu and cfg_get, and any value that is not 0 or one of the off words is on. -static int lowend_of(void) { - int p = __atomic_load_n(&lowend, __ATOMIC_ACQUIRE); - if (p >= 0) return p; +// off" is off, and any value that is not 0 or one of the off words is on. +static int lowend_set(void) { const char *set = raw_get(PREFIX "LOW_END_GPU"); - p = set && *set && switch_of(set) != 0; - __atomic_store_n(&lowend, p, __ATOMIC_RELEASE); - return p; -} -int cfg_low_end_active(void) { return lowend_of(); } -static const char *lowend_value(const char *key) { - if (lowend_of()) - for (size_t i = 0; i < sizeof LOWEND / sizeof *LOWEND; i++) - if (!strcasecmp(LOWEND[i].key, key)) return LOWEND[i].value; - return NULL; + return set && *set && switch_of(set) != 0; } static int profile_of(void) { @@ -919,12 +885,11 @@ static const char *switch_word(const char *name, const char *v) { static const char *cfg_get_now(const char *name) { const char *v = raw_get(name); if (strncmp(name, PREFIX, PREFIX_LEN)) return v; - if (!lowend_of() && lowend_only(name + PREFIX_LEN)) return NULL; // the mode is off: its settings are not read if (v) return switch_word(name, v); if (profile_of()) for (size_t i = 0; i < sizeof DECK / sizeof *DECK; i++) if (!strcasecmp(DECK[i].key, name + PREFIX_LEN)) return DECK[i].value; - return lowend_value(name + PREFIX_LEN); + return NULL; } // Whether name's value comes from the player (the environment or nx2navi.ini), not a profile or the table. @@ -1029,8 +994,6 @@ const char *cfg_default(const char *key) { if (profile_of()) for (size_t i = 0; i < sizeof DECK / sizeof *DECK; i++) if (!strcasecmp(DECK[i].key, name)) return DECK[i].value; - const char *low = lowend_value(name); - if (low) return low; const CfgMeta *m = cfg_meta(key); return m ? m->def : NULL; } @@ -1461,14 +1424,13 @@ void cfg_init(void) { if (e && *e) check_value(metas[i].key, e, 0); } check_end(); - __atomic_store_n(&lowend, -1, __ATOMIC_RELEASE); // asked before the file was read: decided again (lowend_of) if (profile_of()) rt_log("cfg: device profile Steam Deck: defaults for the keys nx2navi.ini does not set (NX2NAVI_DEVICE_PROFILE=desktop " "turns it off)"); - if (lowend_of()) - rt_log("cfg: low_end_gpu = 1: the settings for older graphics cards are on for the keys nx2navi.ini does not set " - "(mesh shaders as compute, video memory budgets, staged uploads and the shorter wait for the GPU, frames " - "prepared on their own thread)"); + if (lowend_set()) + rt_log("cfg: low_end_gpu is on, and the low-end GPU mode was removed in 0.10.2: the line does nothing, and the game " + "runs as it does without it. The mode's single settings (mesh_emulation, tex_clobber, foliage, " + "vram_reserve_mb and the others) still count where nx2navi.ini or the environment sets them"); start_values(); } diff --git a/runtime/cfg.h b/runtime/cfg.h index 741d625e..de953471 100644 --- a/runtime/cfg.h +++ b/runtime/cfg.h @@ -26,7 +26,6 @@ int cfg_setenv(const char *name, const char *value); int cfg_from_env(const char *name); // 1 when the player set name (the environment or nx2navi.ini), 0 when cfg_get gives a device profile's default or NULL. int cfg_is_set(const char *name); -int cfg_low_end_active(void); // the low-end GPU mode was on when the game started (cfg.c LOWEND) // The keys of the file's lines that are no settings of this version, lower-case with ", " between them ("" when there // are none; a list too long to keep ends early), and how many there are. Such a line does nothing: the log says so at // start and the settings menu shows it (ui/menu.cpp), so that nobody takes one for the cause of what they see. diff --git a/runtime/ui/menu.cpp b/runtime/ui/menu.cpp index 5eedcebc..a6d6795b 100644 --- a/runtime/ui/menu.cpp +++ b/runtime/ui/menu.cpp @@ -91,8 +91,6 @@ int vk_fg4_failed(void); // ... it failed in this run, FSR 3.1's int vk_fg4_active(void); // ... its swapchain is in place const char *vk_fg4_name(void); // ... the version the library runs here ("3.1.6", "4.0.2") int vk_texture_detail_auto(void); // vk_texture.c: the texture detail auto picks on this card, 0 full to 2 low -int vk_mesh_shader_native(void); // vk_device.c: the GPU has mesh shaders (the mesh emulation does nothing) -int vk_low_end_card(void); // vk_device.c: no mesh shaders, or under 8 GiB of video memory int vk_exec_replay_workers_auto(const char **why); // vk_exec.c: replay_workers = auto's count on this PC double frame_step_limit_hz(void); int frame_limit_adjustable(void); @@ -1454,7 +1452,6 @@ static void rows_saves(void) { if (line[0]) opt_text_str(line, warn); } -static void rows_low_end(void); static void tab_game(float scale) { opt_begin("##game", scale); @@ -1502,16 +1499,6 @@ static void tab_game(float scale) { "of area: keep a copy of the save first.", on)) opt_apply("NX2NAVI_DEBUG_MENU", on ? "0" : "1"); } - // Last, as its own settings follow it while it is on (rows_low_end). cfg.c LOWEND: the defaults for older graphics - // cards, read at start. - // Offered on the cards it was written for (vk_low_end_card). On any other the row cannot turn the mode on; while - // the mode is on there (set earlier, or in nx2navi.ini) the row stays usable, to turn it off again. - if (!cfg_bool("NX2NAVI_LOW_END_GPU") && !cfg_low_end_active() && !vk_low_end_card()) - opt_disable_next(UI_MENU_LOWEND_NOT_FOR_CARD); - opt_toggle("NX2NAVI_LOW_END_GPU", UI_MENU_LOW_END_GPU, UI_MENU_LOW_END_GPU_DESC); - // the mode's settings are read only while it is on (cfg.c LOWEND_ONLY), so their rows wait for the restart too - if (cfg_low_end_active()) rows_low_end(); - else if (cfg_bool("NX2NAVI_LOW_END_GPU")) opt_text(UI_MENU_LOWEND_RESTART); opt_end(); } @@ -1722,78 +1709,6 @@ static void tab_controls(float scale) { binds_after_page(); } -// ---- the settings of the low-end GPU mode, under its switch in the Game tab while that is on (tab_game): each is read -// where the code it sets reads it -static void rows_low_end(void) { - opt_text(UI_MENU_LOWEND_INTRO); - opt_group(UI_MENU_LOWEND_MEMORY); - { // vk_texture.c sweep_released - static const char *const values[] = {"", "512", "1024", "2048", "4096", "8192"}; - const char *names[] = {menu_text(UI_MENU_AUTO), "512", "1024", "2048", "4096", "8192"}; - opt_choice_list("NX2NAVI_TEX_RELEASED_MAX", UI_MENU_LOWEND_RELEASED, values, names, 6, UI_MENU_LOWEND_RELEASED_DESC); - } - opt_slider("NX2NAVI_MIRROR_HOT", UI_MENU_LOWEND_MIRROR_HOT, 0, 100, UI_MENU_LOWEND_MIRROR_HOT_DESC, 5, "%.0f %%"); - { // vk_device.c vram_heap_limits - static const char *const values[] = {"auto", "0"}; - const char *names[] = {menu_text(UI_MENU_AUTO), menu_text(UI_MENU_OFF)}; - opt_choice_list("NX2NAVI_VRAM_HEAP_LIMIT", UI_MENU_LOWEND_HEAP_LIMIT, values, names, 2, UI_MENU_LOWEND_HEAP_LIMIT_DESC); - } - { // vk_vma_budget.c reserve_bytes - static const char *const values[] = {"512", "256", "768", "1024", "0"}; - const char *names[] = {"512 MB", "256 MB", "768 MB", "1024 MB", menu_text(UI_MENU_OFF)}; - opt_choice_list("NX2NAVI_VRAM_RESERVE_MB", UI_MENU_LOWEND_RESERVE, values, names, 5, UI_MENU_LOWEND_RESERVE_DESC); - } - { // vk_memory.c upload_batch_cap - static const char *const values[] = {"128", "256", "512", "1024", "0"}; - const char *names[] = {"128 MB", "256 MB", "512 MB", "1024 MB", menu_text(UI_MENU_LOWEND_NO_LIMIT)}; - opt_choice_list("NX2NAVI_UPLOAD_BATCH_MB", UI_MENU_LOWEND_UPLOAD_BATCH, values, names, 5, UI_MENU_LOWEND_UPLOAD_BATCH_DESC); - } - opt_toggle("NX2NAVI_ASTC_SCRATCH_KEEP", UI_MENU_LOWEND_ASTC_KEEP, UI_MENU_LOWEND_ASTC_KEEP_DESC); - { // vk_memory.c freeze_pass: submissions a region stays unwritten before it is frozen - static const char *const values[] = {"1800", "1200", "600", "60", "0"}; - const char *names[] = {"1800", "1200", "600", "60", menu_text(UI_MENU_OFF)}; - opt_choice_list("NX2NAVI_FREEZE_IDLE", UI_MENU_LOWEND_FREEZE, values, names, 5, UI_MENU_LOWEND_FREEZE_DESC); - } - { // vk_sync.c res_mask: the result kinds the submit wait counts (31 all, 30 all but events) - static const char *const values[] = {"31", "30"}; - const char *names[] = {menu_text(UI_MENU_LOWEND_RESULTS_ALL), menu_text(UI_MENU_LOWEND_RESULTS_NO_EVENTS)}; - opt_choice_list("NX2NAVI_SUBMIT_FINISH_KINDS", UI_MENU_LOWEND_RESULTS, values, names, 2, UI_MENU_LOWEND_RESULTS_DESC); - } - opt_toggle("NX2NAVI_ZSTD_NATIVE", UI_MENU_LOWEND_ZSTD, UI_MENU_LOWEND_ZSTD_DESC); // ov_zstd.c trusted - opt_group(UI_MENU_LOWEND_RENDER); - opt_toggle("NX2NAVI_REPLAY_ASYNC", UI_MENU_LOWEND_ASYNC, UI_MENU_LOWEND_ASYNC_DESC); // vk_backend.c - const bool native = vk_mesh_shader_native() != 0; // vk_exec_draw.c: the emulation only where the GPU lacks them - if (native) opt_disable_next(UI_MENU_LOWEND_MESH_NATIVE); - opt_toggle("NX2NAVI_MESH_EMULATION", UI_MENU_LOWEND_MESH_EMU, UI_MENU_LOWEND_MESH_EMU_DESC); - { // vk_exec_draw.c foliage_skip - static const char *const values[] = {"full", "reduced", "off"}; - const char *names[] = {menu_text(UI_MENU_LOWEND_FOLIAGE_FULL), menu_text(UI_MENU_LOWEND_FOLIAGE_REDUCED), menu_text(UI_MENU_OFF)}; - opt_choice_list("NX2NAVI_FOLIAGE", UI_MENU_LOWEND_FOLIAGE, values, names, 3, UI_MENU_LOWEND_FOLIAGE_DESC); - } - if (native) opt_disable_next(UI_MENU_LOWEND_MESH_NATIVE); - opt_slider("NX2NAVI_MESH_EMU_MB", UI_MENU_LOWEND_MESH_MB, 64, 2048, UI_MENU_LOWEND_MESH_MB_DESC, 64, "%.0f MB"); - if (native) opt_disable_next(UI_MENU_LOWEND_MESH_NATIVE); - opt_slider("NX2NAVI_MESH_EMU_TASKS", UI_MENU_LOWEND_MESH_TASKS, 4096, 65536, UI_MENU_LOWEND_MESH_TASKS_DESC, 4096, "%.0f"); - if (native) opt_disable_next(UI_MENU_LOWEND_MESH_NATIVE); - opt_toggle("NX2NAVI_MESH_EMU_BATCH", UI_MENU_LOWEND_MESH_BATCH, UI_MENU_LOWEND_MESH_BATCH_DESC); // vk_exec_draw.c - opt_toggle("NX2NAVI_TEX_CLOBBER", UI_MENU_LOWEND_CLOBBER, UI_MENU_LOWEND_CLOBBER_DESC); - static const UiTextId vec[] = {UI_MENU_OFF, UI_MENU_LOWEND_VEC_AUTO, UI_MENU_ON}; // gfx_shader.c patch_vec_index - opt_choice("NX2NAVI_VEC_INDEX_FIX", UI_MENU_LOWEND_VEC_INDEX, vec, 3, UI_MENU_LOWEND_VEC_INDEX_DESC); - opt_group(UI_MENU_LOWEND_BUILD); - // tools/make_game.py reads it from nx2navi.ini at the next Rebuild the Game (guest_opt_ini) - opt_toggle_value("NX2NAVI_GUEST_OPT", UI_MENU_LOWEND_GUEST_OPT, UI_MENU_LOWEND_GUEST_OPT_DESC, "2", "1", - menu_text(UI_MENU_LOWEND_GUEST_OPT_NOTE)); - opt_group(UI_MENU_LOWEND_DIAG); - opt_toggle("NX2NAVI_PASS_TIMES", UI_MENU_LOWEND_PASS_TIMES, UI_MENU_LOWEND_PASS_TIMES_DESC); // vk_crumbs.c -#ifdef _WIN32 - { // vk_dump.c: the keys it knows - static const char *const values[] = {"", "pause", "scrolllock", "insert", "f12"}; - const char *names[] = {menu_text(UI_MENU_OFF), "Pause", "Scroll Lock", "Insert", "F12"}; - opt_choice_list("NX2NAVI_DUMP_KEY", UI_MENU_LOWEND_DUMP_KEY, values, names, 5, UI_MENU_LOWEND_DUMP_KEY_DESC); - } -#endif -} - static const UiTextId kTabNames[TAB_COUNT] = {UI_MENU_TAB_SCREEN, UI_MENU_TAB_GAME, UI_MENU_TAB_SOUND, UI_MENU_TAB_CONTROLS}; static int g_tab; // the tab shown diff --git a/runtime/ui_text.c b/runtime/ui_text.c index 515dbae9..475e0e5d 100644 --- a/runtime/ui_text.c +++ b/runtime/ui_text.c @@ -99,98 +99,6 @@ static const char *const text_en[UI_TEXT_COUNT] = { [UI_MENU_TEX_DETAIL_DESC] = "Sharpness of large surface textures. Reduced and Low leave out their largest versions, so that an area fits the video memory of 6 and 8 GB cards; only surfaces seen up close look softer. Automatic picks by the card's video memory.", [UI_MENU_TEX_DETAIL_AUTO] = "Automatic: %s", [UI_MENU_TEX_DETAIL_FULL] = "Full", [UI_MENU_TEX_DETAIL_REDUCED] = "Reduced", [UI_MENU_TEX_DETAIL_LOW] = "Low", - [UI_MENU_LOWEND_INTRO] = "The settings of the low-end GPU mode. Each can be changed here; most take effect after a restart.", - [UI_MENU_LOWEND_RESTART] = "The mode turns on after a restart. Its settings are listed here then.", - [UI_MENU_LOWEND_NOT_FOR_CARD] = "Not for this graphics card: it has mesh shaders and 8 GB of video memory or more. " - "The mode is for older cards and can break shadows on this one.", - [UI_MENU_LOWEND_MEMORY] = "Video memory and textures", - [UI_MENU_LOWEND_RENDER] = "Rendering", - [UI_MENU_LOWEND_BUILD] = "Build", - [UI_MENU_LOWEND_DIAG] = "Diagnostics", - [UI_MENU_LOWEND_RELEASED] = "Released textures kept", - [UI_MENU_LOWEND_RELEASED_DESC] = "How many textures the game has released are kept as they are; past it only those that " - "lose nothing when dropped go. Fewer leaves more video memory for the rest; more " - "saves making them again; too few lets some blink black for a moment. Auto: one per 2 MB " - "of the video memory budget, 2048 to 8192.", - [UI_MENU_LOWEND_CLOBBER] = "Fix overwritten textures", - [UI_MENU_LOWEND_CLOBBER_DESC] = "A texture the game reads after another image was drawn over its memory gets memory of " - "its own. Fixes the teal splotches in Kokiri Forest's fog.", - [UI_MENU_LOWEND_MIRROR_HOT] = "Pools copied every frame stay in system memory", - [UI_MENU_LOWEND_MIRROR_HOT_DESC] = "A game memory pool whose copies to and from video memory each frame reach this " - "percentage of its size is read by the GPU from system memory instead, if the " - "CPU does not write it (a pool it refills each frame stays in video memory: read " - "in place, the GPU saw the next frame's data). For GPUs and buses short of " - "bandwidth; 25 suits an RX 580. 0: off.", - [UI_MENU_LOWEND_RESERVE] = "Video memory kept free", - [UI_MENU_LOWEND_RESERVE_DESC] = "Room kept free in each video memory heap for what FidelityFX (FSR 3.1, frame generation) and the " - "driver allocate on their own: a heap with less than this left takes no new allocation while " - "another video memory heap can (an RX 580 has two; cards with one are not affected). Off: video " - "memory can fill up with frame generation on, and the game ends.", - [UI_MENU_LOWEND_HEAP_LIMIT] = "Video memory heap limit", - [UI_MENU_LOWEND_HEAP_LIMIT_DESC] = "Auto: on GPUs with a second video memory heap (an RX 580 shows 6 GB and 2 GB), " - "each heap is filled only to its budget before the next one is used, so the " - "driver does not run out. Off: no limit.", - [UI_MENU_LOWEND_UPLOAD_BATCH] = "Upload batch limit", - [UI_MENU_LOWEND_UPLOAD_BATCH_DESC] = "Texture uploads waiting in staging memory are sent to the GPU early once they " - "hold this much, so an area load cannot run video memory out. Every batch is " - "sent at 64 MB at the latest, so none of these choices changes anything now.", - [UI_MENU_LOWEND_NO_LIMIT] = "64 MB", - [UI_MENU_LOWEND_ASTC_KEEP] = "Keep the ASTC decode buffer", - [UI_MENU_LOWEND_ASTC_KEEP_DESC] = "The buffer that GPU-decodes compressed textures is kept between upload batches " - "instead of being allocated again for each one.", - [UI_MENU_LOWEND_MESH_EMU] = "Mesh shader emulation", - [UI_MENU_LOWEND_MESH_EMU_DESC] = "Draws grass, moss and other foliage on GPUs without mesh shaders (AMD RX 400/500 " - "and Vega, GTX 10-series and older), with compute shaders. GPUs with mesh shaders " - "ignore it.", - [UI_MENU_LOWEND_MESH_NATIVE] = "this GPU has mesh shaders", - [UI_MENU_LOWEND_MESH_MB] = "Mesh emulation memory", - [UI_MENU_LOWEND_MESH_MB_DESC] = "Video memory for the emulated meshes' vertices and indices, in MB.", - [UI_MENU_LOWEND_MESH_BATCH] = "Mesh emulation before the pass", - [UI_MENU_LOWEND_MESH_BATCH_DESC] = "The emulated mesh stages of a render pass run before the pass in a command buffer " - "of their own, instead of splitting the pass at every emulated draw. Off: the " - "split, as before.", - [UI_MENU_LOWEND_MESH_TASKS] = "Mesh emulation task records", - [UI_MENU_LOWEND_MESH_TASKS_DESC] = "Task records per submission for the emulated meshes. Raise it when the log reports " - "that a submission asked for more.", - [UI_MENU_LOWEND_VEC_INDEX] = "Vector index fix", - [UI_MENU_LOWEND_VEC_INDEX_DESC] = "Shaders read uniform vector components at computed indices whole and select the " - "component, for drivers that get such reads wrong. Auto: on AMD's own drivers.", - [UI_MENU_LOWEND_VEC_AUTO] = "Auto (AMD)", - [UI_MENU_LOWEND_GUEST_OPT] = "Optimised game code (-O2)", - [UI_MENU_LOWEND_GUEST_OPT_DESC] = "The next Rebuild the Game in the launcher compiles the game's code at -O2 instead " - "of -O1: the game's own threads run faster on a slower CPU. The build takes " - "several times longer.", - [UI_MENU_LOWEND_GUEST_OPT_NOTE] = "at the next rebuild", - [UI_MENU_LOWEND_FREEZE] = "Freeze idle memory after", - [UI_MENU_LOWEND_FREEZE_DESC] = "Submissions a memory region stays unwritten before it is made read-only, so the write " - "tracking can skip it. 1800 (about 15 s): few thaws and small tracking queries. 60: " - "the game thaws regions all the time and every thaw stalls a frame. Off: no stalls, but " - "the tracking scans all memory every frame.", - [UI_MENU_LOWEND_FOLIAGE] = "Foliage", - [UI_MENU_LOWEND_FOLIAGE_DESC] = "Full: all of it. Reduced: no small grass or moss on the ground; ferns, leaves and " - "other plants stay. Off: no foliage. Terrain, rocks and buildings always stay.", - [UI_MENU_LOWEND_FOLIAGE_FULL] = "Full", - [UI_MENU_LOWEND_FOLIAGE_REDUCED] = "Reduced", - [UI_MENU_LOWEND_RESULTS] = "Wait for GPU results", - [UI_MENU_LOWEND_RESULTS_DESC] = "After a frame's first submission the game waits until the GPU wrote the results it " - "reads back. All: events, counter and occlusion reports, write-backs. Without events: " - "a shorter wait; on an RX 580 nothing flickered.", - [UI_MENU_LOWEND_RESULTS_ALL] = "All", - [UI_MENU_LOWEND_RESULTS_NO_EVENTS] = "Without events", - [UI_MENU_LOWEND_ZSTD] = "Native data decompression", - [UI_MENU_LOWEND_ZSTD_DESC] = "Decompresses the game's zstd data with the PC's libzstd instead of the game's own " - "decoder translated from the console. Lighter streaming while you move.", - [UI_MENU_LOWEND_ASYNC] = "Asynchronous replay", - [UI_MENU_LOWEND_ASYNC_DESC] = "Translates the game's GPU commands on a thread of their own instead of the game's, so " - "the game prepares the next frame meanwhile. Off by default: it can show a dark or " - "flickering frame now and then.", - [UI_MENU_LOWEND_PASS_TIMES] = "Pass times in the log", - [UI_MENU_LOWEND_PASS_TIMES_DESC] = "GPU time of every render pass and dispatch goes to the log, with the largest " - "viewport each kind of pass draws with. Costs a little frame time.", - [UI_MENU_LOWEND_DUMP_KEY] = "Frame dump key", - [UI_MENU_LOWEND_DUMP_KEY_DESC] = "Each press of this key in the game window dumps the next frame (images and the " - "frame's passes) to the dump folder, for a glitch caught while it is on screen. " - "Windows only.", [UI_MENU_SHARPNESS] = "FSR sharpness", [UI_MENU_SHARPNESS_DESC] = "How sharp FSR makes the picture. 0 turns it off.", [UI_MENU_SHARPNESS_NEEDS_FSR] = "only with AMD FSR 1 or FSR 3.1", @@ -503,11 +411,6 @@ static const char *const text_en[UI_TEXT_COUNT] = { [UI_MENU_AMIIBO_STATUS] = "Status: %s", [UI_MENU_MENU_LANG] = "Menu language", [UI_MENU_MENU_LANG_DESC] = "Language of this menu and the overlay.", [UI_MENU_MENU_LANG_AUTO] = "Automatic (from Windows)", - [UI_MENU_LOW_END_GPU] = "Low-end GPU mode (experimental)", - [UI_MENU_LOW_END_GPU_DESC] = "For older graphics cards and cards short of video memory. Runs the game's mesh shaders as compute shaders " - "where the card has none, keeps video memory within what the driver reports free, waits less for the GPU and " - "prepares frames on a thread of their own. Measured on a Radeon RX 580 only: it can show a dark or flickering " - "frame now and then, so leave it off on a newer card.", [UI_MENU_REPLAY_WORKERS] = "CPU helper threads (experimental)", [UI_MENU_REPLAY_WORKERS_DESC] = "Uses more of your CPU's cores to prepare each frame for the graphics card. Automatic " "picks the number for your CPU: half its cores less one, none on four cores or fewer " @@ -1127,11 +1030,6 @@ static const char *const text_ru[UI_TEXT_COUNT] = { [UI_MENU_AMIIBO_STATUS] = "Состояние: %s", [UI_MENU_MENU_LANG] = "Язык меню", [UI_MENU_MENU_LANG_DESC] = "Язык этого меню и индикатора.", [UI_MENU_MENU_LANG_AUTO] = "Автоматически (из Windows)", - [UI_MENU_LOW_END_GPU] = "Режим для слабых видеокарт (экспериментальный)", - [UI_MENU_LOW_END_GPU_DESC] = "Для старых видеокарт и карт с малым объёмом видеопамяти. Меш-шейдеры игры выполняются как вычислительные там, " - "где карта их не поддерживает, видеопамять удерживается в пределах свободного объёма по данным драйвера, игра " - "меньше ждёт видеокарту, а кадры готовятся в отдельном потоке. Проверено только на Radeon RX 580: изредка " - "возможен тёмный или мерцающий кадр, поэтому на новой карте оставьте выключенным.", [UI_MENU_DISCORD_RPC] = "Discord Rich Presence", [UI_MENU_DISCORD_RPC_DESC] = "Пока игра запущена, показывает «Играю в NX2navi» со временем игры в статусе " "Discord. Приложение выбирают discord_app_id и discord_image в nx2navi.ini.", @@ -1559,11 +1457,6 @@ static const char *const text_pt_br[UI_TEXT_COUNT] = { [UI_MENU_AMIIBO_STATUS] = "Estado: %s", [UI_MENU_MENU_LANG] = "Idioma do menu", [UI_MENU_MENU_LANG_DESC] = "Idioma deste menu e do indicador.", [UI_MENU_MENU_LANG_AUTO] = "Automático (do Windows)", - [UI_MENU_LOW_END_GPU] = "Modo para GPUs fracas (experimental)", - [UI_MENU_LOW_END_GPU_DESC] = "Para placas de vídeo antigas ou com pouca memória de vídeo. Executa os mesh shaders do jogo como compute " - "shaders onde a placa não os tem, mantém a memória de vídeo dentro do que o driver informa como livre, espera " - "menos pela GPU e prepara os quadros numa thread própria. Medido apenas numa Radeon RX 580: pode mostrar um " - "quadro escuro ou piscando de vez em quando, então deixe desligado numa placa mais nova.", [UI_MENU_DISCORD_RPC] = "Discord Rich Presence", [UI_MENU_DISCORD_RPC_DESC] = "Mostra \"Jogando NX2navi\" com o tempo de jogo no seu status do Discord " "enquanto o jogo roda. discord_app_id e discord_image no nx2navi.ini escolhem a " @@ -2226,10 +2119,6 @@ static const char *const text_zh_hans[UI_TEXT_COUNT] = { [UI_MENU_MENU_LANG] = "菜单语言", [UI_MENU_MENU_LANG_DESC] = "本菜单和性能浮层的语言。", [UI_MENU_MENU_LANG_AUTO] = "自动(跟随 Windows)", - [UI_MENU_LOW_END_GPU] = "低端显卡模式(实验性)", - [UI_MENU_LOW_END_GPU_DESC] = "适用于较旧的显卡和显存不足的显卡。在显卡不支持网格着色器时以计算着色器运行游戏的网格着色器," - "将显存占用控制在驱动报告的可用范围内,减少等待 GPU 的时间,并在独立线程上准备帧。" - "仅在 Radeon RX 580 上测试过:偶尔可能出现变暗或闪烁的画面,较新的显卡请保持关闭。", [UI_MENU_DISCORD_RPC] = "Discord Rich Presence", [UI_MENU_DISCORD_RPC_DESC] = "游戏运行时在 Discord 状态中显示“正在玩 NX2navi”及游戏时长。nx2navi.ini 中的 " "discord_app_id 和 discord_image 选择应用。", diff --git a/runtime/ui_text.h b/runtime/ui_text.h index 73ccce7c..e23a9345 100644 --- a/runtime/ui_text.h +++ b/runtime/ui_text.h @@ -176,7 +176,7 @@ typedef enum { // Menu tab UI_MENU_MENU_LANG, UI_MENU_MENU_LANG_DESC, UI_MENU_MENU_LANG_AUTO, - UI_MENU_DISCORD_RPC, UI_MENU_DISCORD_RPC_DESC, UI_MENU_LOW_END_GPU, UI_MENU_LOW_END_GPU_DESC, + UI_MENU_DISCORD_RPC, UI_MENU_DISCORD_RPC_DESC, // the Game tab's Testing rows (ui/menu.cpp tab_game), English only UI_MENU_REPLAY_WORKERS, UI_MENU_REPLAY_WORKERS_DESC, UI_MENU_REPLAY_PIPE, UI_MENU_REPLAY_PIPE_DESC, UI_MENU_REPLAY_SMALL, UI_MENU_REPLAY_SMALL_DESC, UI_MENU_TAIL_EARLY, UI_MENU_TAIL_EARLY_DESC, @@ -314,26 +314,6 @@ typedef enum { // frame generation with any Upscaling choice, an upscaler or none (vk_dlaa.c fg_only_frame); through NGX (every // build but the Windows one) NVIDIA's needs DLSS upscaling on at the start, its note and description there UI_MENU_FRAMEGEN_DESC_ANY, UI_MENU_FRAMEGEN_DESC_NGX, UI_MENU_FRAMEGEN_NOTE_NGX, - // the settings of the low-end GPU mode (ui/menu.cpp rows_low_end), English only - UI_MENU_LOWEND_INTRO, UI_MENU_LOWEND_RESTART, UI_MENU_LOWEND_NOT_FOR_CARD, UI_MENU_LOWEND_MEMORY, UI_MENU_LOWEND_RENDER, UI_MENU_LOWEND_BUILD, - UI_MENU_LOWEND_DIAG, - UI_MENU_LOWEND_FREEZE, UI_MENU_LOWEND_FREEZE_DESC, UI_MENU_LOWEND_ZSTD, UI_MENU_LOWEND_ZSTD_DESC, - UI_MENU_LOWEND_FOLIAGE, UI_MENU_LOWEND_FOLIAGE_DESC, UI_MENU_LOWEND_FOLIAGE_FULL, UI_MENU_LOWEND_FOLIAGE_REDUCED, - UI_MENU_LOWEND_RESULTS, UI_MENU_LOWEND_RESULTS_DESC, UI_MENU_LOWEND_RESULTS_ALL, UI_MENU_LOWEND_RESULTS_NO_EVENTS, - UI_MENU_LOWEND_ASYNC, UI_MENU_LOWEND_ASYNC_DESC, - UI_MENU_LOWEND_RELEASED, UI_MENU_LOWEND_RELEASED_DESC, - UI_MENU_LOWEND_CLOBBER, UI_MENU_LOWEND_CLOBBER_DESC, - UI_MENU_LOWEND_MIRROR_HOT, UI_MENU_LOWEND_MIRROR_HOT_DESC, - UI_MENU_LOWEND_HEAP_LIMIT, UI_MENU_LOWEND_HEAP_LIMIT_DESC, UI_MENU_LOWEND_RESERVE, UI_MENU_LOWEND_RESERVE_DESC, - UI_MENU_LOWEND_UPLOAD_BATCH, UI_MENU_LOWEND_UPLOAD_BATCH_DESC, UI_MENU_LOWEND_NO_LIMIT, - UI_MENU_LOWEND_ASTC_KEEP, UI_MENU_LOWEND_ASTC_KEEP_DESC, - UI_MENU_LOWEND_MESH_EMU, UI_MENU_LOWEND_MESH_EMU_DESC, UI_MENU_LOWEND_MESH_NATIVE, - UI_MENU_LOWEND_MESH_MB, UI_MENU_LOWEND_MESH_MB_DESC, UI_MENU_LOWEND_MESH_TASKS, UI_MENU_LOWEND_MESH_TASKS_DESC, - UI_MENU_LOWEND_MESH_BATCH, UI_MENU_LOWEND_MESH_BATCH_DESC, - UI_MENU_LOWEND_VEC_INDEX, UI_MENU_LOWEND_VEC_INDEX_DESC, UI_MENU_LOWEND_VEC_AUTO, - UI_MENU_LOWEND_GUEST_OPT, UI_MENU_LOWEND_GUEST_OPT_DESC, UI_MENU_LOWEND_GUEST_OPT_NOTE, - UI_MENU_LOWEND_PASS_TIMES, UI_MENU_LOWEND_PASS_TIMES_DESC, - UI_MENU_LOWEND_DUMP_KEY, UI_MENU_LOWEND_DUMP_KEY_DESC, UI_TEXT_COUNT } UiTextId; diff --git a/runtime/vk_device.c b/runtime/vk_device.c index 25f8503a..2a118bc3 100644 --- a/runtime/vk_device.c +++ b/runtime/vk_device.c @@ -357,10 +357,11 @@ retry: // the next memory type that allows it (the other device-local heap first), for every allocation: textures, render // targets, VRAM mirrors, pools. The limit is each device-local heap's budget when the device is made (VK_EXT_memory_budget, // what other programs leave) less a margin for memory VMA does not see (swapchain, FidelityFX): a tenth, at least -// 256 MiB. NX2NAVI_VRAM_HEAP_LIMIT: auto (with low_end_gpu = 1), 0 (no limits, the default), or a number of MiB for the largest device-local heap. +// 256 MiB. NX2NAVI_VRAM_HEAP_LIMIT: auto, 0 (no limits, the default) or a number of MiB for the largest device-local +// heap. The low-end GPU mode set auto up to 0.10.1. static int vram_heap_limits(VkDeviceSize *limit) { const char *e = cfg_get("NX2NAVI_VRAM_HEAP_LIMIT"); - long mb = !e || !*e ? 0 : strcmp(e, "auto") ? atol(e) : -1; // unset: no limits, as before (low_end_gpu sets auto) + long mb = !e || !*e ? 0 : strcmp(e, "auto") ? atol(e) : -1; // unset: no limits if (!mb) return 0; VkPhysicalDeviceMemoryBudgetPropertiesEXT b = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT}; VkPhysicalDeviceMemoryProperties2 p2 = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2, @@ -632,8 +633,8 @@ static int create_device(void) { } // vkGetDeviceFaultInfoEXT needs the feature, not just the extension { // mesh_fallback: auto, 1 (on every device) or 0 (vk_mesh_path.h says when auto takes it, and why on AMD's driver // for RDNA 1 and 2). Without mesh shaders the mesh emulation (mesh_emulation = 1) draws them instead. - // has_mesh_shader keeps saying what the hardware has: the recorder thread (vk_rec.c) and the low-end card - // test (vk_low_end_card) go by it, not by how mesh programs are drawn. + // has_mesh_shader keeps saying what the hardware has: the recorder thread (vk_rec.c) goes by it, not by how + // mesh programs are drawn. const char *mf = cfg_value("NX2NAVI_MESH_FALLBACK"), *me = cfg_value("NX2NAVI_MESH_EMULATION"), *why = ""; int path = mesh_path_decide(g_vk.has_mesh_shader, vk_caps.amd_sc, g_vk.props.vendorID == 0x10de, mf, me, &why); g_vk.mesh_fallback = path == MESH_PATH_FALLBACK; @@ -973,16 +974,6 @@ int probe_vkdevice(void) { return g_errors_total ? 1 : 0; } -// The GPU has mesh shaders: the mesh emulation (NX2NAVI_MESH_EMULATION) does nothing there (the low-end GPU rows of the menu's Game tab). +// The GPU has mesh shaders (vk_exec.c vk_exec_tail_begin: the early tail runs only on such a card). int vk_mesh_shader_native(void) { return g_vk.has_mesh_shader; } -// The card the low-end GPU mode (cfg.c LOWEND) was written for: one without mesh shaders, or one whose driver reports -// a video memory budget under 8 GiB. The menu offers the mode only there (ui/menu.cpp tab_game): on a GeForce RTX 5090 -// the mode's own-memory rule for overwritten textures moved the 1600x1600 sun shadow map and the scene depth to memory -// of their own, and the ground's shadow was a dark patch with straight edges that turned with the camera. -int vk_low_end_card(void) { - if (!g_vk.has_mesh_shader) return 1; - uint64_t used = 0, budget = 0; - int exact = 0; - return vk_mem_vram(&used, &budget, &exact) && budget && budget >> 20 < 8192; -} diff --git a/runtime/vk_exec_draw.c b/runtime/vk_exec_draw.c index 1df6c203..ff2e4291 100644 --- a/runtime/vk_exec_draw.c +++ b/runtime/vk_exec_draw.c @@ -6358,7 +6358,7 @@ static int mesh_ring_entry(VkExec *ex, VkCommandBuffer cb, const p_draw_mesh_ind return 1; } -// NX2NAVI_FOLIAGE (full, reduced, off; default full; the low-end GPU rows of the menu's Game tab): Ocarina draws its foliage with +// NX2NAVI_FOLIAGE (full, reduced, off; default full; foliage in nx2navi.ini): Ocarina draws its foliage with // DrawMeshTasksIndirect, the instances its compute passes culled on the GPU. With a task stage: the small grass and moss // that carpet the ground; without one: ferns, leaves, clover and the other plants. Its other mesh draws (DrawMeshTasks // with a count: terrain, rocks, buildings, doors) are not foliage. reduced skips the indirect draws with a task stage, diff --git a/runtime/vk_memory.c b/runtime/vk_memory.c index 423a77c0..20bf11f5 100644 --- a/runtime/vk_memory.c +++ b/runtime/vk_memory.c @@ -1417,7 +1417,8 @@ static uint64_t snap_regions(uint64_t r0, uint64_t r1, uint32_t epoch) { return calls; } -// NX2NAVI_SNAP_WIDEN= (8 with low_end_gpu = 1, else 0, off): a texture check that has to query widens the query to up to this +// NX2NAVI_SNAP_WIDEN= (default 0, off; the low-end GPU mode set 8 up to 0.10.1): a texture check that has to +// query widens the query to up to this // many 2 MiB regions on each side, inside the import pool that holds the texture, so the textures of one pool are // snapped by one query a submission instead of one each. With freezing off (NX2NAVI_FREEZE_IDLE) an RX 580 in Hyrule // Field made about 1,130 texture queries a frame, about 6 MiB each on average incl. repeats, 9.4 ms with the pools'. @@ -4337,7 +4338,8 @@ int vk_mem_mirror_pending(void) { return npend || snl_copied < nsnl || n_gpa_fli // and when its device address table writes reach guest memory as well (a twin: what they write is not recorded); so // does a range with a page that cannot be read without a fault (mem_copy_readable: a lazily armed range). The // whole-pool copy of a mirror's first use is larger than the limit and stays with the GPU. -// Unset or 0 with NX2NAVI_MIRROR_STAGE=1 (what low_end_gpu = 1 sets): CAPTURE_STAGE_KB. A submission whose prologue copied +// Unset or 0 with NX2NAVI_MIRROR_STAGE=1 (which the low-end GPU mode set up to 0.10.1): CAPTURE_STAGE_KB. A submission +// whose prologue copied // everything this way reads nothing of guest memory late, so its submit wait ends once the replay has submitted it // (vk_sync_recorded_wait); one with a range left to the GPU-time copy, or a draw that reads a pool without a mirror, // is noted (vk_mem_note_live) and its submit wait is the GPU's. The first form of this (0.8.0) copied while the replay @@ -5479,11 +5481,13 @@ VkCommandBuffer vk_upload_begin(void) { return open_b.cb; } -// NX2NAVI_UPLOAD_BATCH_MB (256 with low_end_gpu = 1; 0, the default, = no limit of its own): once the open batch's +// NX2NAVI_UPLOAD_BATCH_MB (0, the default, = no limit of its own; the low-end GPU mode set 256 up to 0.10.1): once the +// open batch's // staging buffers hold that much, the outermost vk_upload_end submits it. It does so too once the batch's staging // reaches STG_FLUSH, so that an area load's staging stays inside the staging pool's blocks (the staging pool's // comment): 0 therefore means STG_FLUSH (64 MiB), not "never", and a value above STG_FLUSH changes nothing, the -// low-end mode's 256 and the settings menu's 128 to 1024 included. A save load made thousands of textures between two replay submissions, and every one of them went into +// 256 and the 128 to 1024 its menu row offered included. A save load made thousands of textures between two replay +// submissions, and every one of them went into // one batch: about 1.5 GB of raw ASTC blocks plus the decoder's work in a single submission, // which AMD's 23.10 driver on an RX 580 refused with VK_ERROR_OUT_OF_DEVICE_MEMORY. Submitted early, a batch still // precedes the replay submission that uses its textures (the queue keeps order), and its staging is freed as it retires. diff --git a/runtime/vk_mesh_path.h b/runtime/vk_mesh_path.h index 65e26fb8..909419ce 100644 --- a/runtime/vk_mesh_path.h +++ b/runtime/vk_mesh_path.h @@ -20,12 +20,12 @@ // left out of the picture until their compute passes are built, at their first sight in a run. mesh_fallback = 0 // draws them natively again; 1 takes the fallback on every device. // -// The mesh emulation is the older of the two ways for a card without mesh shaders, and the low-end GPU mode turns it on -// (cfg.c LOWEND). On NVIDIA's cards without mesh shaders (GTX 10 and older) it ended the game inside the driver at the -// first mesh draws of an area: an access violation at nvoglv64.dll+0x10cdffe on a GTX 1050 Ti and on a GTX 1070, both -// on 0.10.1, and a Titan X (Pascal) report of the same mode. The GTX 1050 Ti ran on once mesh_emulation was set to 0, -// through the fallback, with the rest of the low-end mode still on. So an NVIDIA card never takes the emulation: with -// it asked for, the card is drawn for as if it were not. +// The mesh emulation is the older of the two ways for a card without mesh shaders, and the low-end GPU mode turned it +// on up to 0.10.1 (cfg.c lowend_set). On NVIDIA's cards without mesh shaders (GTX 10 and older) it ended the game +// inside the driver at the first mesh draws of an area: an access violation at nvoglv64.dll+0x10cdffe on a GTX 1050 Ti +// and on a GTX 1070, both on 0.10.1, and a Titan X (Pascal) report of the same mode. The GTX 1050 Ti ran on once +// mesh_emulation was set to 0, through the fallback, with the rest of that mode still on. So an NVIDIA card never +// takes the emulation: with it asked for, the card is drawn for as if it were not. #pragma once #include diff --git a/runtime/vk_rec.c b/runtime/vk_rec.c index ab201818..169414d9 100644 --- a/runtime/vk_rec.c +++ b/runtime/vk_rec.c @@ -166,15 +166,15 @@ void rec_begin(VkCommandBuffer cb, uint64_t fence) { // past it). Keeping objects until their submission completed and ending a part from the recorder // (rec_end_cb) fixed the white scene on an RX 6700 XT, but not this: 0.2.8 turned the recorder on for every // GPU and the AMD reports came back the same day. NX2NAVI_VK_RECORDER=1 turns it on for an A/B run. - // On AMD GPUs without mesh shaders (GCN: RX 400/500, Vega; RDNA 1) it is on with low_end_gpu = 1: every report above is from an - // RDNA 2-4 card, and those all have mesh shaders. An RX 580 ran with it and NX2NAVI_REC_CHECK - // (no hazards), the replay's part of the game's wait after a frame's first submission 6.9 ms instead of 12. + // Up to 0.10.1 the low-end GPU mode turned it on for AMD GPUs without mesh shaders (GCN: RX 400/500, Vega; + // RDNA 1): every report above is from an RDNA 2-4 card, and those all have mesh shaders. An RX 580 ran with it + // and NX2NAVI_REC_CHECK (no hazards), the replay's part of the game's wait after a frame's first submission + // 6.9 ms instead of 12. The mode is gone (cfg.c lowend_set): vk_recorder = 1 turns it on there as anywhere. const char *set = cfg_get("NX2NAVI_VK_RECORDER"); - int amd_off = vk_caps.amd && (vk_ctx()->has_mesh_shader || !rt_knob("LOW_END_GPU", "0")); // on only with low_end_gpu = 1 + int amd_off = vk_caps.amd; mode = rt_knob("VK_RECORDER", amd_off ? "0" : "1"); if (!mode && amd_off && !(set && *set)) - rt_log("vk_rec: no recorder thread on AMD GPUs (NX2NAVI_VK_RECORDER=1 turns it on; low_end_gpu = 1 does on " - "cards without mesh shaders)"); + rt_log("vk_rec: no recorder thread on AMD GPUs (NX2NAVI_VK_RECORDER=1 turns it on)"); if (mode) { plat_event_init(&wake_ev, 0, 0); rec_prio = plat_thread_priority_get(); diff --git a/runtime/vk_sync.c b/runtime/vk_sync.c index 5b00b120..ed7e7396 100644 --- a/runtime/vk_sync.c +++ b/runtime/vk_sync.c @@ -1665,7 +1665,7 @@ int vk_sync_recorded_wait(uint64_t value, uint64_t timeout_ns, int (*gpu_wait)(u rt_log("vk: the wait after a frame's first submission also waits for %s (NX2NAVI_SUBMIT_FINISH_RESULTS=%d)", res_mode == 2 ? "every submission before it" : res_mode ? "the newest submission up to it that hands the " "CPU results at its completion (events, counter reports, write-backs)" : "nothing more", res_mode); - gpu = rt_knob("SUBMIT_FINISH_GPU", "1") != 0; // 0 with low_end_gpu = 1 + gpu = rt_knob("SUBMIT_FINISH_GPU", "1") != 0; // the low-end GPU mode set 0 up to 0.10.1 rt_log("vk: the wait after a frame's first submission ends %s (NX2NAVI_SUBMIT_FINISH_GPU=%d)", gpu ? "when the GPU has run it" : "when the replay has submitted it, or the GPU has run it where it reads guest " "memory itself", gpu); diff --git a/runtime/vk_vma_budget.c b/runtime/vk_vma_budget.c index f6970204..c291b0d4 100644 --- a/runtime/vk_vma_budget.c +++ b/runtime/vk_vma_budget.c @@ -16,7 +16,8 @@ // Laptop, 4 GiB) leaving that heap out sent every allocation past the reserve to system memory, more than 4096 of them, // and the process's commit with them: with 16 GiB of RAM the system's commit ran out, host memory imports failed and the // device was lost. Without another device-local heap with room the allocation is made as asked. The reserve -// (NX2NAVI_VRAM_RESERVE_MB, 512 with low_end_gpu = 1, else 0, off) is room left for allocations VMA does not make, which can come at +// (NX2NAVI_VRAM_RESERVE_MB; 0, off, by default; the low-end GPU mode set 512 up to 0.10.1) is room left for allocations +// VMA does not make, which can come at // once: AMD's contexts are made when the upscaler or the frame generation setting changes. An allocation that finds // no room that way is made as asked, as before. Allocations from a VMA pool and those for one memory type alone (the // headroom's anchors, vk_headroom.c) are made as asked. diff --git a/tests/cfg_parse_check.c b/tests/cfg_parse_check.c index 18bddf02..d4ad0013 100644 --- a/tests/cfg_parse_check.c +++ b/tests/cfg_parse_check.c @@ -5,8 +5,8 @@ // full cfg_load on the file, then two cfg_set of keys the file does not have // read cfg_load on the file and cfg_init's check of the environment; then what cfg_get, cfg_bool and cfg_int give // for a list of keys -// lowend cfg_load on the file and cfg_init; then whether the low-end mode is on (cfg.c lowend_of, which reads its -// switch apart from cfg_get), what cfg_bool gives for its switch and what one of the mode's keys reads +// lowend cfg_load on the file and cfg_init; then what cfg_bool gives for the switch of the low-end GPU mode, +// which is gone (cfg.c lowend_set), what two of the mode's keys read and the default of one of them // norow cfg_int and cfg_double of a key without a row whose value (the environment's) does not parse #include #include @@ -106,9 +106,9 @@ int main(int argc, char **argv) { if (!strcmp(argv[1], "lowend")) { if (!cfg_load(ini)) return printf("cfg_load failed\n"), 2; cfg_init(); - const char *mesh = cfg_get("NX2NAVI_MESH_EMULATION"); - printf("got: low_end %d bool %d mesh_emulation '%s'\n", cfg_low_end_active(), cfg_bool("NX2NAVI_LOW_END_GPU"), - mesh ? mesh : "(unset)"); + const char *mesh = cfg_get("NX2NAVI_MESH_EMULATION"), *res = cfg_get("NX2NAVI_VRAM_RESERVE_MB"); + printf("got: bool %d mesh_emulation '%s' vram_reserve_mb '%s' default '%s'\n", cfg_bool("NX2NAVI_LOW_END_GPU"), + mesh ? mesh : "(unset)", res ? res : "(unset)", cfg_default("NX2NAVI_VRAM_RESERVE_MB")); return 0; } if (!strcmp(argv[1], "norow")) { diff --git a/tests/cfg_parse_check.py b/tests/cfg_parse_check.py index 5d54fc4e..1ebd92e5 100644 --- a/tests/cfg_parse_check.py +++ b/tests/cfg_parse_check.py @@ -7,8 +7,8 @@ for what it links with. What the readers get and what the log says about the val it is part of the value; at most 16 lines, then a count; - switches written as words (cfg.c switch_word, cfg_bool): false, off and no in any case read as 0 and true, on and yes as 1 through cfg_get, cfg_bool and cfg_int, from the file and from the environment, with no line about them; - the low-end mode's switch (cfg.c lowend_of, read apart from cfg_get) takes the same words, so "low_end_gpu = off" - leaves the mode and its keys off; + the switch of the low-end GPU mode, which is gone (cfg.c lowend_set), takes the same words for its one log line + and turns nothing on: the mode's keys keep their own defaults and are read by themselves; - values outside their rows' sets (cfg.c check_value): a 0|1 switch with another value, a number outside its range, a word that is none of the menu's choices, each named with its line; none for a file whose values fit, nor for a list with numbers in it (the menu's presets); at most 16 lines, then a count; @@ -187,17 +187,26 @@ def main(): 'a file with 601 keys: one line at load from line 513 on', out) check(rc == 0 and len(set_lines) == 1 and 'VK_PRESENT is not kept' in set_lines[0], 'two menu changes past a full table: one line', out) - # the low-end mode's switch, read apart from cfg_get (cfg.c lowend_of): the same words as cfg_bool, from the file - # and from the environment; the mode is decided once per process, so each value is its own run - for text, extra, want in ( - ('low_end_gpu = Off\n', None, "low_end 0 bool 0 mesh_emulation '(unset)'"), - ('low_end_gpu = 0 ; note\n', None, "low_end 0 bool 0 mesh_emulation '(unset)'"), - ('low_end_gpu = yes\n', None, "low_end 1 bool 1 mesh_emulation '1'"), - ('; nothing\n', {'NX2NAVI_LOW_END_GPU': 'FALSE'}, "low_end 0 bool 0 mesh_emulation '(unset)'"), - ('; nothing\n', {'NX2NAVI_LOW_END_GPU': '0 ; x'}, "low_end 1 bool 1 mesh_emulation '1'")): + # the switch of the low-end GPU mode, which is gone (cfg.c lowend_set): on, it turns none of the mode's keys on and + # gives none another default, and the log says once that the line does nothing; the same words as cfg_bool, from + # the file and from the environment. The mode's keys are read by themselves, with or without the switch. + gone = 'the low-end GPU mode was removed' + unset = "mesh_emulation '(unset)' vram_reserve_mb '(unset)' default '0'" + for text, extra, want, said in ( + ('low_end_gpu = Off\n', None, f'bool 0 {unset}', 0), + ('low_end_gpu = 0 ; note\n', None, f'bool 0 {unset}', 0), + ('low_end_gpu = yes\n', None, f'bool 1 {unset}', 1), + ('low_end_gpu = 1\n', None, f'bool 1 {unset}', 1), + ('; nothing\n', {'NX2NAVI_LOW_END_GPU': 'FALSE'}, f'bool 0 {unset}', 0), + ('; nothing\n', {'NX2NAVI_LOW_END_GPU': '0 ; x'}, f'bool 1 {unset}', 1), + ('mesh_emulation = 1\nvram_reserve_mb = 512\n', None, + "bool 0 mesh_emulation '1' vram_reserve_mb '512' default '0'", 0), + ('low_end_gpu = 1\nmesh_emulation = 1\n', None, + "bool 1 mesh_emulation '1' vram_reserve_mb '(unset)' default '0'", 1)): rc, out = run(exe, env, 'lowend', text, work, extra) - what = text.strip() if extra is None else f"the environment's {extra['NX2NAVI_LOW_END_GPU']!r}" - check(rc == 0 and f'got: {want}' in out, f'low end: {what}: {want}', out) + what = text.strip().replace('\n', ', ') if extra is None else f"the environment's {extra['NX2NAVI_LOW_END_GPU']!r}" + check(rc == 0 and f'got: {want}' in out and out.count(gone) == said, + f'low end: {what}: {want}, the removal said {said} time(s)', out) rc, out = run(exe, env, 'norow', CLEAN, work, {'NX2NAVI_NO_ROW_CHECK': 'abc'}) check(rc == 0 and 'got: cfg_int 0 cfg_double 0' in out, 'cfg_int of a set, unparsable key without a row: 0', out) print(f'cfg_parse_check: {"FAILED" if bad else "ok"}') diff --git a/tests/cfg_rows_check.py b/tests/cfg_rows_check.py index 869032ed..f663dc19 100644 --- a/tests/cfg_rows_check.py +++ b/tests/cfg_rows_check.py @@ -2,7 +2,7 @@ content guard workflow runs it beside tools/check_content.py. It fails on: -- a row or name after a // on a line of known[], metas[], sections[], DECK[] or LOWEND[]: it is not compiled, and a +- a row or name after a // on a line of known[], metas[], sections[] or DECK[]: it is not compiled, and a hidden metas[] row ends every start with "FATAL: cfg: NX2NAVI_ has no row in the settings table" (this shipped in two test builds); a /* inside those tables, which this check does not read; - a name twice in known[], or two metas[] rows for one key in one #if branch (the first branch stands for the table, @@ -32,7 +32,6 @@ TABLES = { # declaration, what a row looks like on a line 'metas[]': ('static const CfgMeta metas[]', r'\{\s*"(' + KEY + r')"'), 'sections[]': ('sections[] = {', r'\{\s*"(' + KEY + r')"'), 'DECK[]': ('DECK[] = {', r'\{\s*"(' + KEY + r')"'), - 'LOWEND[]': ('LOWEND[] = {', r'\{\s*"(' + KEY + r')"'), } VALUE_FNS = ('cfg_value', 'cfg_int', 'cfg_bool', 'cfg_double') GUARD_FNS = ('cfg_get', 'cfg_is_set', 'cfg_meta') diff --git a/tests/launcher_test.py b/tests/launcher_test.py index ba0c84eb..556b654a 100644 --- a/tests/launcher_test.py +++ b/tests/launcher_test.py @@ -2932,18 +2932,26 @@ class MakeGameTest(Tmp): with mock.patch.dict(os.environ, {'NX2NAVI_SHADER_CARRY': 'Off'}): self.assertFalse(self.mg.shader_carry(out)) - def test_guest_opt_from_the_ini_only_with_the_low_end_mode_on(self): - """guest_opt_ini takes guest_opt from nx2navi.ini only while low_end_gpu is on as runtime/cfg.c lowend_of - reads it: 0, off, false and no in any case are off.""" + def test_guest_opt_from_the_ini_counts_without_the_low_end_mode(self): + """guest_opt_ini takes guest_opt from nx2navi.ini by itself. Up to 0.10.1 it needed low_end_gpu on in the file; + that mode is gone, and a low_end_gpu line of any value changes nothing. The environment's value stays.""" out = self.tmp / 'game' out.mkdir() env = {k: v for k, v in os.environ.items() if k.upper() != 'NX2NAVI_GUEST_OPT'} - for low, taken in (('1', True), ('yes', True), ('On', True), ('0', False), ('off', False), ('FALSE', False), - ('no', False), ('0 ; note', False)): - (out / 'nx2navi.ini').write_text(f'guest_opt = 2\nlow_end_gpu = {low}\n') + for low in ('', 'low_end_gpu = 1\n', 'low_end_gpu = yes\n', 'low_end_gpu = 0\n', 'low_end_gpu = off\n', + 'low_end_gpu = 0 ; note\n'): + (out / 'nx2navi.ini').write_text('guest_opt = 2\n' + low) with mock.patch.dict(os.environ, env, clear=True): self.mg.guest_opt_ini(out) - self.assertEqual(os.environ.get('NX2NAVI_GUEST_OPT'), '2' if taken else None, low) + self.assertEqual(os.environ.get('NX2NAVI_GUEST_OPT'), '2', low) + (out / 'nx2navi.ini').write_text('low_end_gpu = 1\n') + with mock.patch.dict(os.environ, env, clear=True): + self.mg.guest_opt_ini(out) + self.assertIsNone(os.environ.get('NX2NAVI_GUEST_OPT')) # no guest_opt line: nothing is set + (out / 'nx2navi.ini').write_text('guest_opt = 2\n') + with mock.patch.dict(os.environ, dict(env, NX2NAVI_GUEST_OPT='1'), clear=True): + self.mg.guest_opt_ini(out) + self.assertEqual(os.environ.get('NX2NAVI_GUEST_OPT'), '1') # the environment wins over the file def test_cache_from_before_carrying_names_its_translator(self): """Before a new translator goes beside the game, a shader cache with no identities.txt gets one naming the diff --git a/tests/mesh_path_check.c b/tests/mesh_path_check.c index 467b73f3..c3198ff0 100644 --- a/tests/mesh_path_check.c +++ b/tests/mesh_path_check.c @@ -39,10 +39,11 @@ int main(void) { // ---- the mesh emulation acts only without mesh shaders, and then before the fallback expect(0, 0, "auto", "1", MESH_PATH_EMULATION, "no mesh shaders, mesh_emulation = 1"); expect(0, 1, "1", "1", MESH_PATH_EMULATION, "no mesh shaders, both set"); - expect(1, 1, "auto", "1", MESH_PATH_FALLBACK, "an RX 6000 card with mesh_emulation = 1 (low_end_gpu)"); + expect(1, 1, "auto", "1", MESH_PATH_FALLBACK, "an RX 6000 card with mesh_emulation = 1"); expect(1, 0, "auto", "1", MESH_PATH_NATIVE, "a card with mesh shaders and mesh_emulation = 1"); - // ---- an NVIDIA card never takes the emulation, which ended the game inside its driver (GTX 10, low_end_gpu) - expect_nv(0, 0, 1, "auto", "1", MESH_PATH_FALLBACK, "a GTX 10 card with mesh_emulation = 1 (low_end_gpu)"); + // ---- an NVIDIA card never takes the emulation, which ended the game inside its driver (GTX 10 cards in the + // low-end GPU mode of 0.10.1, which set mesh_emulation = 1) + expect_nv(0, 0, 1, "auto", "1", MESH_PATH_FALLBACK, "a GTX 10 card with mesh_emulation = 1"); expect_nv(0, 0, 1, "1", "1", MESH_PATH_FALLBACK, "a GTX 10 card with both set"); expect_nv(0, 0, 1, "0", "1", MESH_PATH_NONE, "a GTX 10 card with mesh_emulation = 1 and mesh_fallback = 0"); expect_nv(0, 0, 1, "auto", "0", MESH_PATH_FALLBACK, "a GTX 10 card by default"); diff --git a/tools/make_game.py b/tools/make_game.py index 14313a2e..7c7f8725 100644 --- a/tools/make_game.py +++ b/tools/make_game.py @@ -1632,13 +1632,12 @@ SWITCH_OFF = ('0', 'off', 'false', 'no') def guest_opt_ini(out): - """NX2NAVI_GUEST_OPT from nx2navi.ini next to the exe (the low-end GPU rows of the menu's Game tab write it there) - when the environment does not set it: the next build of the game folder out takes it. Only while low_end_gpu is on - in the file too (not empty, 0, off, false or no, as runtime/cfg.c lowend_of reads it): the mode's settings count - only with the mode on (runtime/cfg.c LOWEND_ONLY).""" + """NX2NAVI_GUEST_OPT from nx2navi.ini next to the exe when the environment does not set it: the next build of the + game folder out takes it. The line counts by itself. Up to 0.10.1 it counted only while low_end_gpu was on in the + file too; that mode is gone (runtime/cfg.c lowend_set) and its settings are read like any other.""" if os.environ.get('NX2NAVI_GUEST_OPT', '').strip(): return - found, low = '', False + found = '' try: for line in (Path(out) / 'nx2navi.ini').read_text(encoding='utf-8', errors='replace').splitlines(): key, eq, value = line.partition('=') @@ -1646,11 +1645,9 @@ def guest_opt_ini(out): value = value.split('#')[0].split(';')[0].strip().strip('"') if eq and key in ('guest_opt', 'nx2navi_guest_opt') and value: found = value - if eq and key in ('low_end_gpu', 'nx2navi_low_end_gpu'): - low = value.lower() not in ('', *SWITCH_OFF) except OSError: pass - if found and low: + if found: os.environ['NX2NAVI_GUEST_OPT'] = found