Let shader_cache_flush = 1 flush the shader cache files to the disk again.

The faster cache writes leave the .spv, .res.json and .use files unflushed and rely on the checks every read makes. The
setting puts the earlier flushed, written-through writes back for a drive or setup where a torn file shows up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
chrg6
2026-11-09 08:19:13 -05:00
parent a4ee74b74e
commit 837926d8e1
3 changed files with 19 additions and 6 deletions

View File

@@ -150,6 +150,9 @@
# skip push constants that did not change.
# bind_skip = 1
# shader_memo = 1
# 1 flushes every shader cache file to the disk before it is used, as earlier versions did; 0 (default) flushes only
# the stored game code, which makes shader preparation about twice as fast (a torn file is translated again).
# shader_cache_flush = 0
# pipe_memo = 1
# tex_memo = 1
# desc_template = 1

View File

@@ -56,7 +56,7 @@ static const char *const known[] = {
"REFLEX", "RENDER_SCALE", "REPLAY_ASYNC", "RTSS",
"REPLAY_CHECK", "RESOLVE_CHECK", "RESTART_WAIT", "ROMFS", "ROMFS_INDEX", "ROMFS_MMAP", "ROMFS_MODS", "ROMFS_PATCHES",
"ROMFS_PROOF_DIR", "ROMFS_VERIFY", "RSTICK_DEADZONE", "RUMBLE", "RUMBLE_CURVE", "RUMBLE_STRENGTH", "RUMBLE_TRIGGERS", "SHADER_CACHE",
"SHADER_MEMO", "SHADOW_COMPARE", "SHADOW_RANGE", "SHADOW_RES", "SHADOW_SCALE", "SHARED_FONTS", "SHARPNESS", "SHOTS", "SHOTS_DIR",
"SHADER_CACHE_FLUSH", "SHADER_MEMO", "SHADOW_COMPARE", "SHADOW_RANGE", "SHADOW_RES", "SHADOW_SCALE", "SHARED_FONTS", "SHARPNESS", "SHOTS", "SHOTS_DIR",
"SVC_SLOW_MS",
"SHOTS_FULL", "SPEED_PROBE", "SPIN", "SPIN_HANDOFF_US", "SPLIT_DRAWS", "SPLIT_US", "SPV_OVERRIDE", "STICK_DEADZONE", "STICK_SENS",
"SWKBD_ANSWER",
@@ -110,7 +110,7 @@ static const struct { const char *key, *section; } sections[] = {
{"LIB_PREBUILD", "performance"}, {"LIB_PREBUILD_THREADS", "performance"}, {"PIPE_PREBUILD", "performance"},
{"PREWARM_XLATE", "performance"}, {"GPL", "performance"}, {"ASTC", "performance"}, {"MEMORY", "performance"},
{"TEX_ALIAS", "performance"}, {"TEX_VRAM_PRESSURE", "performance"}, {"ASTC_BC", "performance"}, {"LOD_GUARD", "performance"}, {"FIX_C0", "performance"}, {"FIX_ZERO", "performance"},
{"BIND_SKIP", "performance"}, {"SHADER_MEMO", "performance"}, {"PIPE_MEMO", "performance"}, {"TEX_MEMO", "performance"}, {"DESC_TEMPLATE", "performance"},
{"BIND_SKIP", "performance"}, {"SHADER_CACHE_FLUSH", "performance"}, {"SHADER_MEMO", "performance"}, {"PIPE_MEMO", "performance"}, {"TEX_MEMO", "performance"}, {"DESC_TEMPLATE", "performance"},
{"PUSH_SKIP", "performance"}, {"SPLIT_DRAWS", "performance"}, {"SPLIT_US", "performance"}, {"VK_VALIDATION", "performance"},
{"VK_DYN_VERTEX", "performance"}, {"VK_DYN_A2C", "performance"}, {"VK_SUBGROUP_PIN", "performance"}, {"VK_RECONVERGE", "performance"},
{"TRACE", "diagnostics"}, {"FLIGHT", "diagnostics"}, {"PASS_CRUMBS", "diagnostics"}, {"FLIGHT_SPIKE_MS", "diagnostics"},
@@ -209,7 +209,7 @@ static const CfgMeta metas[] = {
{"ASTC_SCRATCH_KEEP", "0", "0|1", RESTART}, {"ASTC_ARENA", "0", "0|1", RESTART}, // vk_astc.c scratch_get, vk_texture.c astc_arena
// render fixes
{"LOD_GUARD", "1", "0|1", RESTART}, {"FIX_C0", "1", "0|1", RESTART}, {"FIX_ZERO", "1", "0|1", RESTART},
{"BIND_SKIP", "1", "0|1", RESTART}, {"SHADER_MEMO", "1", "0|1", RESTART}, {"PIPE_MEMO", "1", "0|1", RESTART}, {"TEX_MEMO", "1", "0|1", RESTART},
{"BIND_SKIP", "1", "0|1", RESTART}, {"SHADER_CACHE_FLUSH", "0", "0|1", RESTART}, {"SHADER_MEMO", "1", "0|1", RESTART}, {"PIPE_MEMO", "1", "0|1", RESTART}, {"TEX_MEMO", "1", "0|1", RESTART},
{"BIND_REUSE", "1", "0|1", RESTART}, {"DYN_DELTA", "1", "0|1", RESTART},
{"DESC_TEMPLATE", "1", "0|1", RESTART},
{"PUSH_SKIP", "1", "0|1", RESTART}, {"SPLIT_DRAWS", "64", "0..1000", RESTART},

View File

@@ -1063,11 +1063,20 @@ static int use_find(const uint8_t h[32], UseMask *m) {
return known;
}
// NX2NAVI_SHADER_CACHE_FLUSH (default 0): 1 flushes the .spv, .res.json and .use files to the disk too, as the cache
// did before (see "Durability" at the top), for a drive or setup where a torn file was seen.
static int cache_flush(void) {
static int on = -1;
if (on < 0) on = rt_knob("SHADER_CACHE_FLUSH", "0") == 1;
return on;
}
static void use_store(const uint8_t h[32], const UseMask *m) {
char p[PATH_CAP + 80];
use_path(h, p);
uint32_t f[5] = {USE_MAGIC, USE_VERSION, m->slots, m->attrs, m->fouts};
plat_file_write_cached(p, f, sizeof f); // not flushed: a torn mask fails its magic and size check (see the top)
if (cache_flush()) plat_file_write_atomic(p, f, sizeof f);
else plat_file_write_cached(p, f, sizeof f); // not flushed: a torn mask fails its magic and size check (see the top)
plat_mutex_lock(&cache_lock);
use_put(h, 1, m);
plat_mutex_unlock(&cache_lock);
@@ -1529,6 +1538,7 @@ static const GfxShader *translate_one(const Req *r, int stage, const uint8_t *co
return fail(reply, hex);
}
// Not flushed (see "Durability" at the top): the translator wrote them whole, and disk_load checks both.
if (cache_flush()) plat_file_flush(spv_path), plat_file_flush(res_path);
if (!(s = disk_load(key, r->iid))) return fail("translator output missing or malformed", hex);
if (!r->final) { // name the files after the cache key, remember the mask
m = use_of(s);
@@ -1536,9 +1546,9 @@ static const GfxShader *translate_one(const Req *r, int stage, const uint8_t *co
char mhex[65], to[PATH_CAP + 80];
key_hex(mk, mhex);
snprintf(to, PATH_CAP + 80, "%s/%s.spv", cache_dir, mhex);
int moved = plat_file_replace(spv_path, to, 0);
int moved = plat_file_replace(spv_path, to, cache_flush());
snprintf(to, PATH_CAP + 80, "%s/%s.res.json", cache_dir, mhex);
moved = moved && plat_file_replace(res_path, to, 0);
moved = moved && plat_file_replace(res_path, to, cache_flush());
if (moved) {
use_store(r->code_hash, &m);
} else { // keep the mask for this run only