diff --git a/runtime/ui/menu.cpp b/runtime/ui/menu.cpp index 14acb19b..f8f1cb32 100644 --- a/runtime/ui/menu.cpp +++ b/runtime/ui/menu.cpp @@ -84,6 +84,7 @@ 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 double frame_step_limit_hz(void); int frame_limit_adjustable(void); int rtss_limit_state(void); @@ -1423,6 +1424,10 @@ static void tab_game(float scale) { } // 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(); diff --git a/runtime/ui_text.c b/runtime/ui_text.c index 808bc33e..9e52292f 100644 --- a/runtime/ui_text.c +++ b/runtime/ui_text.c @@ -91,6 +91,8 @@ static const char *const text_en[UI_TEXT_COUNT] = { [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", diff --git a/runtime/ui_text.h b/runtime/ui_text.h index 4de41427..41ae0fc7 100644 --- a/runtime/ui_text.h +++ b/runtime/ui_text.h @@ -333,7 +333,7 @@ typedef enum { UI_MENU_FRAMEGEN_MULT_OLD_DLL, // nx2navi_dlssg.dll is older than multi frame generation UI_MENU_FRAMEGEN_UNAVAILABLE, UI_MENU_FRAMEGEN_OFF_FILES, // 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_MEMORY, UI_MENU_LOWEND_RENDER, UI_MENU_LOWEND_BUILD, + 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, diff --git a/runtime/vk_device.c b/runtime/vk_device.c index 6ad94c89..0e0976f3 100644 --- a/runtime/vk_device.c +++ b/runtime/vk_device.c @@ -863,3 +863,14 @@ int probe_vkdevice(void) { // 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). 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; +}