mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Leave the pools as imports for NVIDIA's own driver on Linux in the game itself.
On Linux every driver got shadow storage (copies of guest memory beside it), which exists for amdgpu, where importing guest memory costs the write protection of its pages. NVIDIA's own driver imports without that cost, so there the copies are only the slower path: in Kokiri Forest on 0.7.1 (RTX 4090) imports ran at 51.9 frames a second and the copies at 27.4. Until now only the AppImage's play.sh knew, by setting NX2NAVI_SHADOW=0 when NVIDIA's kernel driver was present at build time, so a game started any other way got the copies, and a PC with that kernel driver whose game ran on another card got imports where it should not. The game now chooses by the driver of the device it runs on, play.sh no longer sets the variable, and NX2NAVI_SHADOW=1 or 0 still decides. The driver is asked when the device is picked, before the storage is chosen. Windows is unchanged: the device probe here reads "mem: mode mirror" with no shadow storage line, and the shadow line with NX2NAVI_SHADOW=1. The Linux path itself was not run: there is no Linux machine here. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
@@ -282,7 +282,11 @@ Forest (1.1.1, RTX 4090) that costs about 1 ms a frame (copy-in 0.5 ms, write-ba
|
||||
after a frame's first submission covers the write-backs there (`runtime/vk_sync.c`, "the executed timeline"): the game
|
||||
rewrites what those passes wrote without a fence, and a write-back that landed after the rewrite left the GPU adding
|
||||
light onto its own last output, the whole scene brighter for a frame. `NX2NAVI_SHADOW=1` turns it on under Windows too. The Steam Deck's RADV has `VK_EXT_external_memory_host` as
|
||||
well: the shadow copies are chosen for the measured cost above, not for a missing extension.
|
||||
well: the shadow copies are chosen for the measured cost above, not for a missing extension. NVIDIA's own driver on Linux
|
||||
imports instead (`NX2NAVI_SHADOW=1` brings the copies back): it imports guest memory without that cost, so there the
|
||||
copies are only the slower path. In Kokiri Forest on 0.7.1 (RTX 4090, driver 615.78), imports with VRAM mirrors ran at
|
||||
51.9 frames a second and the copies at 27.4; on that version the copies also flickered between two looks almost every
|
||||
frame, which the wait for the write-backs under shadow storage (`vk_sync_exec_wait`) has since addressed.
|
||||
|
||||
The device address table (`runtime/vk_gpa.c`) names a pool's shadow copy as it names an import, so shaders follow guest
|
||||
pointers into either. A shader that reads through the table resolves nothing, so the pool it reaches is not queued for
|
||||
|
||||
@@ -89,8 +89,8 @@ static void mesa_cache_beside_exe(void) {
|
||||
// beside the exe, which nothing else writes, with a limit of NV_CACHE_BYTES. The driver makes GLCache inside that
|
||||
// folder but not the folder, so it is made here; pointed at a folder that is missing or not writable it caches nothing
|
||||
// at all, so when that folder cannot be made or written neither variable is set and the driver keeps its own folder
|
||||
// and limit. Without NVIDIA's kernel driver (no /proc/driver/nvidia/version, the test play.sh makes) the variables do
|
||||
// nothing and the folder would stay empty, so nothing is done.
|
||||
// and limit. Without NVIDIA's kernel driver (no /proc/driver/nvidia/version, the test the AppImage's build makes for
|
||||
// DLSS) the variables do nothing and the folder would stay empty, so nothing is done.
|
||||
#define NV_CACHE_BYTES "8589934592" // 8 GiB
|
||||
static void nvidia_cache_beside_exe(void) {
|
||||
if (plat_fs_kind("/proc/driver/nvidia/version") != PLAT_FS_FILE) return;
|
||||
@@ -274,6 +274,7 @@ retry:
|
||||
}
|
||||
free(qp);
|
||||
rt_log("vk: using gpu %d: %s", best, g_vk.props.deviceName);
|
||||
vk_caps_driver(g_vk.phys); // before vk_mem_class_log, which chooses the pools' storage by driver
|
||||
vk_mem_class_log(&g_vk.props, &g_vk.mem_props);
|
||||
return 1;
|
||||
}
|
||||
@@ -421,7 +422,6 @@ static int create_device(void) {
|
||||
// The driver fills the chain with what it supports; the same chain then enables all of it (robustBufferAccess
|
||||
// stays on: guest shaders index constant buffers freely and out-of-range reads must stay harmless).
|
||||
vkGetPhysicalDeviceFeatures2(g_vk.phys, &c->f2);
|
||||
vk_caps_driver(g_vk.phys);
|
||||
vk_caps_features(&c->f2.features);
|
||||
if (gpl_link) {
|
||||
VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT gp = {
|
||||
|
||||
@@ -1152,7 +1152,8 @@ static int query_stamp(uint64_t lo, uint64_t hi, uint32_t g) {
|
||||
// copy-ins that overwrote a store through the table, per pool; the write-backs that moved bytes into a page the CPU
|
||||
// had written since its copy-in (cpu_wrote_since); the bytes both sides changed since their base copy (taken from the
|
||||
// CPU at a copy-in, from the GPU at a fence); what the copy-ins cost by kind.
|
||||
// NX2NAVI_SHADOW=1/0 forces the mode on or off; the default is on for Linux and Wine.
|
||||
// NX2NAVI_SHADOW=1/0 forces the mode on or off; the default is on for Linux and Wine, except for NVIDIA's own driver on
|
||||
// Linux, where imports ran about twice as fast on 0.7.1 (mirror_mode).
|
||||
#define SB_PAGE 4096ull
|
||||
static PlatMutex shadow_lock = PLAT_MUTEX_INIT; // after pool_lock; before gen_lock
|
||||
static PoolRec **stouch; // shadow_lock: pools resolved since the last sync
|
||||
@@ -2003,7 +2004,7 @@ static PlatMutex mirror_stat_lock = PLAT_MUTEX_INIT;
|
||||
static volatile int64_t m_live_n, m_live_bytes, m_refused_n[MR_N], m_refused_bytes[MR_N];
|
||||
static volatile int64_t m_flush_calls, m_flush_bytes, v_pages, v_skipped, v_mismatch;
|
||||
|
||||
static void mirror_mode(int discrete) {
|
||||
static void mirror_mode(int discrete, int nvidia_own) {
|
||||
const char *e = cfg_value("NX2NAVI_MEMORY");
|
||||
int mode = discrete ? 1 : 0; // 0 import, 1 mirror, 2 verify
|
||||
const char *why = discrete ? "auto, discrete gpu" : "auto, uma";
|
||||
@@ -2033,7 +2034,13 @@ static void mirror_mode(int discrete) {
|
||||
#ifdef _WIN32
|
||||
shadow_on = sh && *sh ? strcmp(sh, "0") != 0 : plat_is_wine();
|
||||
#else
|
||||
shadow_on = !sh || !*sh || strcmp(sh, "0");
|
||||
// NVIDIA's own driver imports guest memory without the cost shadow storage avoids on amdgpu (re-protecting imported
|
||||
// pages), so there the copies are only the slower path: in Kokiri Forest on 0.7.1 (RTX 4090, driver 615.78) imports
|
||||
// with VRAM mirrors ran at 51.9 frames a second and the copies at 27.4, and the copies hold about 5 GB. What a
|
||||
// shader stores through the device address table into a pool with a shadow copy also does not come back to guest
|
||||
// memory (vk_gpa.c). The pools stay imports unless NX2NAVI_SHADOW asks for the copies. The open driver for the same
|
||||
// cards keeps the copies: it is not measured. The AppImage's play.sh has set the same for this driver since 0.6.0.
|
||||
shadow_on = sh && *sh ? strcmp(sh, "0") != 0 : !nvidia_own;
|
||||
#endif
|
||||
if (shadow_on) rt_log("mem: shadow storage: CPU-visible pools are host-visible copies of guest memory, not imports%s",
|
||||
sh && *sh ? " (NX2NAVI_SHADOW)" : "");
|
||||
@@ -3899,7 +3906,7 @@ void vk_mem_class_log(const VkPhysicalDeviceProperties *p, const VkPhysicalDevic
|
||||
f & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT ? " LAZY" : "");
|
||||
}
|
||||
rt_log("%s", line);
|
||||
mirror_mode(discrete);
|
||||
mirror_mode(discrete, vk_caps.driver_id == VK_DRIVER_ID_NVIDIA_PROPRIETARY);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- upload batches and deferred destruction
|
||||
|
||||
@@ -153,14 +153,11 @@ else
|
||||
ev step dlss '"state":"skip"'
|
||||
fi
|
||||
|
||||
# play.sh: the environment the game wants on this machine, then the game
|
||||
# play.sh: starts the game from its own folder. It sets no storage mode: the game leaves shadow storage off for
|
||||
# NVIDIA's own driver itself (runtime/vk_memory.c mirror_mode), by the driver of the device it runs on.
|
||||
{
|
||||
echo '#!/bin/bash'
|
||||
echo 'cd "$(dirname "$(readlink -f "$0")")"'
|
||||
if [ -e /proc/driver/nvidia/version ]; then
|
||||
echo '# NVIDIA: the default shadow storage leaves the 3D world black (issue #72)'
|
||||
echo 'export NX2NAVI_SHADOW="${NX2NAVI_SHADOW:-0}"'
|
||||
fi
|
||||
echo 'exec ./ocarina "$@"'
|
||||
} > "$OUT/play.sh"
|
||||
chmod +x "$OUT/play.sh"
|
||||
|
||||
Reference in New Issue
Block a user