Zero shader locals with DLSS and DLAA on too, which removes the speckled floor tiles there.

With DLAA on, function-local variables stayed undefined, and NVIDIA's driver filled the game's clustered-light reads
with other warp lanes' values: floors around Link lit in 4x8-pixel tiles. The setting was also part of every shader
cache key, so shaders prepared with DLSS off missed with it on. Zeroing is now on for every setting; DLSS still finds
the game's FXAA by its zeroed hash and keeps its camera motion. A log line now says when DLSS replaces the game's
scaling draw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
chrg6
2026-11-07 11:54:53 -05:00
parent b48b05dacf
commit ee6fbaf0bb
3 changed files with 11 additions and 6 deletions

View File

@@ -74,7 +74,7 @@ Source shorthands:
| 3.9 | **Integer vertex inputs read as raw bits** (bone indices `R8UI`). | Float-declared inputs convert integers. | Without it characters stretch; re-translating with `uint` inputs fixes it. Ours: attribute types passed to `QueryGraphicsState` (`Program.cs`). | — |
| 3.10 | **BFE / BFI fields past bit 31** (as PTX `bfe` / `bfi`): a field that runs past bit 31 is cut there; one that starts past it extracts 0 (signed: bit 31 repeated) and inserts nothing. Terrain vertex shaders (42 variants) have taken the position from a register, `((2y + x) * 8) & 0xff` with 5-bit x and y, so up to 248. | `OpBitField*Extract` / `OpBitFieldInsert` undefined when offset or offset + count exceeds 32; AMD's bitfield instructions take offset and width modulo 32. | The translator passes the fields through. Terrain walls and ground went missing on the Steam Deck and a Linux RX 570 (RADV). Ours: clamped where the field is not a constant inside the word (translator patch 0012). RX 9070 on Windows drew the terrain the same before and after. | PTX ISA `bfe`, `bfi` |
| 3.11 | **SHF by 0** gives the unshifted word (C for `SHF.L`, A for `SHF.R`). | The translator's funnel shifts the other word by 32: undefined in SPIR-V; AMD shifts take the low 5 bits and give A \| C. | Gives terrain gaps at a distance. Ours: a select on a zero amount (translator patch 0013). In the shaders checked, every register SHF pairs its word with 0, so the result was right already. | — |
| 3.12 | **Registers read before any write** on a path (paths the structurizer adds included) have no defined value in the game's code; the NVIDIA driver has been reported to give 0. | An `OpVariable` without an initializer loads an undefined value; Mesa folds undefined values freely. | Ours: every function-local variable starts at 0 (`OpConstantNull`, job flag `zero_locals`, translator patch 0016; `NX2NAVI_ZERO_LOCALS` overrides) on Mesa drivers (RADV, ANV, NVK; `vk_caps_driver`) and, with DLAA off, on every other driver too: on NVIDIA an undefined read takes another warp lane's value, and Ocarina's clustered-light loop lit its floors in 4x8-pixel tiles (one warp each) and darkened Link (runtime/vk_caps.c). With DLAA on, off Mesa, the load stays undefined: a zero start on every driver (the old patch 0014) made the whole picture shake by about 0.9 output pixels a frame with DLSS or DLAA on an RTX 4080 SUPER (#612). It also moved the SPIR-V hash of the game's FXAA shader out of `FXAA_FS` (`vk_dlaa.c` `vk_dlaa_skip_draw`), the likely cause of the shake; that path is not traced. | — |
| 3.12 | **Registers read before any write** on a path (paths the structurizer adds included) have no defined value in the game's code; the NVIDIA driver has been reported to give 0. | An `OpVariable` without an initializer loads an undefined value; Mesa folds undefined values freely. | Ours: every function-local variable starts at 0 (`OpConstantNull`, job flag `zero_locals`, translator patch 0016) on every driver; `NX2NAVI_ZERO_LOCALS=0` turns it off. On NVIDIA an undefined read takes another warp lane's value: Ocarina's clustered-light loop lit its floors in 4x8-pixel tiles (one warp each) and darkened Link. It was off while DLAA was on, because zeroing moves the SPIR-V hash of the game's FXAA shader that `vk_dlaa.c` `vk_dlaa_skip_draw` matches (`FXAA_FS` holds the zeroed hash too); with it off the tiles showed under DLSS and DLAA, and the shader cache keys, which include the flag, changed with the upscaler, so shaders prepared with one setting missed under the other. Checked on an RTX 5090: zeroed, DLAA keeps its camera motion (`NX2NAVI_MV_CHECK`) and the floor is clean. | — |
## 4. Memory model

View File

@@ -121,10 +121,10 @@ void vk_caps_init(VkCtx *c) {
// (docs/maxwell.md 3.12). Mesa folds undefined values freely; NVIDIA's compiler gives such a read a value of another
// lane of the warp: Ocarina's clustered-light loop reads registers that only some paths write, and on an RTX 5090
// the Great Fairy Fountain floor took an extra light term in 4x8-pixel tiles (one 32-lane warp each) and Link went
// dark with green speckles. With DLAA on (vk_dlaa.c, which finds the game's FXAA by its SPIR-V hash) they stay
// undefined off Mesa, as before: zeroing moved that hash and the picture shook under DLAA (maxwell.md 3.12).
// NX2NAVI_ZERO_LOCALS=1 / 0 forces either.
uint32_t zero_locals = env_u32("NX2NAVI_ZERO_LOCALS", vk_caps.mesa || !cfg_bool("NX2NAVI_DLAA"));
// dark with green speckles. On with every setting: vk_dlaa.c knows the game's FXAA by its zeroed SPIR-V hash too,
// and the shader cache keys (which include this) stay the same whether DLSS is on or off, so shaders prepared
// with one setting serve the other. NX2NAVI_ZERO_LOCALS=0 turns it off.
uint32_t zero_locals = env_u32("NX2NAVI_ZERO_LOCALS", 1);
// bda: global accesses the translator finds no storage buffer for go through the device address table (vk_gpa.c)
gfx_shader_set_host(vk_caps.float64, vk_caps.sbuf_align, told, gather, zero_locals != 0, vk_gpa_wanted_ctx(c));
if (gather) rt_log("vk caps: gather coordinates biased for %u sub-texel bits (NX2NAVI_GATHER_BIAS)", gather);

View File

@@ -1333,7 +1333,12 @@ int vk_dlaa_skip_draw(VkExec *ex, const GfxShader *fs) {
int known = 0;
for (size_t i = 0; i < sizeof FXAA_FS / sizeof FXAA_FS[0]; i++) known |= h == FXAA_FS[i];
if (!known) return 0;
if (!ex->depth.image) return D.up; // the scaling pass, which DLSS replaced
if (!ex->depth.image) { // the scaling pass, which DLSS replaced
static int told;
if (D.up && !told++) rt_log("dlaa: the game's scaling draw left out, DLSS wrote it (fragment shader %016llx)",
(unsigned long long)h);
return D.up;
}
if (!fxaa && !fx_found) {
fx_found = 1;
rt_log("dlaa: fxaa = 0 skips the game's FXAA (fragment shader %016llx)", (unsigned long long)h);