fix(dlss): the DLSS model row's preset is taken once it holds it, not a feature for each one stepped past #39

Merged
HumanBean merged 2 commits from llun/Longshot:fix/dlss-preset-settle into main 2026-11-13 01:35:58 +00:00
Contributor

Why

Picking the DLSS model L in the menu also made a DLSS feature for M on the way there (the row goes K, M, L, NVIDIA's default). NVIDIA's runtime keeps a released feature's video memory for some seconds, so at 3440x1440 DLAA three models were held at once: VRAM jumped about 1.2 GB for a few seconds. On the reporter's 12 GB card that is the moment it nearly ran out.

What changed

  • dlss_checks::PresetSettle (gpu/vk/dlss_checks.h): the DLSS model row's preset is taken once the row has held it for 30 frames (half a second at 60 fps). Until then the feature already made keeps drawing with its own preset. The first feature, or one made again after being let go, takes the row's preset at once.
  • vk_dlss.cpp prepare() reads the preset through it. RX_VK_DLSS_PRESET is unaffected, since it never changes in a run.
  • Tests: tests/test_dlss_checks.cpp steps K to M to L 11 frames apart, as in the report, then away and back, with no feature, and NVIDIA's default. tests/test_dlss_checks.py checks that prepare reads the preset only through the settle. The Python check fails on main and passes here.
  • A row in docs/tested-configurations.md for the runs below.

The rest of #17, fewer fps with L or M at DLAA, is not this: it is the models' own cost, measured below on both builds. The preset, sizes and creation flags reaching NGX are right. L's extra GPU time grows with DLSS's input size: in the reporter's RTX 5070 log, +0.4 ms at Ultra Performance (1147x480) and +4.4 ms at DLAA (3440x1440). See also NotRexed/Hookshot#2836.

Flags and settings

None: no new switch, ini key or menu row. The DLSS model row (dlss_model) keeps its values; only when its new preset takes effect changes.

Measurements

main: d4a69456 (2026-11-12), renderer
this PR: fix/dlss-preset-settle @ e8c02084, renderer (rebased since onto main d725b363 as 6f545914/ac7ff634: main's change between is forge tooling and docs only, #48, so the renderer measured is the same code and the numbers hold)
Baseline: main @ d4a69456
Hardware: RTX 5080 16 GB, Windows 11
Scene: Kokiri Forest (child, the debug teleport's arrival), standing; output 3440x1440, Upscaler NVIDIA DLSS, Render resolution Native (DLAA), frame rate cap 240, frame generation off
Method: one game build (main 82de567a) with its longshot_vk.dll swapped. Both renderers were built alone (RX_VK_ONLY) the same way. 4 runs, before/after/after/before, headless, through the control bridge. Each run measured steady K (1500 frames), then set the DLSS model row M and 11 frames later L, as the menu does when stepped (steady L), then M and K (steady K), then M alone (steady M). GPU time and fps from longshot_log.txt's GPU time and presents lines (median over each steady phase); DLSS's own memory from the status lines (NGX_DLSS_GET_STATS); VRAM and power from nvidia-smi every 100 ms, the peak in the 15 s after a switch against the 3 s before it.

Switch main @ d4a69456 (2 runs) this PR @ e8c02084 (2 runs)
K → M → L: features made M, L L
K → M → L: DLSS's own memory, first status line 1419 MB 813 MB
K → M → L: VRAM peak over before +1254, +1143 MB +637, +637 MB
L → M → K: features made M, K K
L → M → K: VRAM peak over before +806, +827 MB +126, +189 MB
M alone (one feature either way): VRAM peak +657, +657 MB +576, +722 MB
Steady (median, 4 runs) GPU a frame fps power
K 7.4–7.6 ms 80–84 140–145 W
L 10.6–10.7 ms 66–67 198–202 W
M 9.7–9.9 ms 70–72 186–188 W

The steady numbers are the same on both builds. The second before run ran a lighter scene throughout (K 6.8, L 9.6 ms), so the ranges leave it out. L costs about 3 ms more GPU than K at 3440x1440 DLAA on this card and drops fps by about 20% at about 40% more power: what the reporter saw on an RTX 5070, and the same before and after.

before  step_KML  made M@8948 L@8971; VRAM before 10697 MB, peak 11951 MB in 15 s; DLSS's own on status lines 1419 MB, 631 MB
after   step_KML  made L@5941;        VRAM before 10053 MB, peak 10690 MB in 15 s; DLSS's own on status lines 813 MB, 813 MB, 631 MB
after   step_KML  made L@5873;        VRAM before 10229 MB, peak 10866 MB in 15 s; DLSS's own on status lines 813 MB, 631 MB
before  step_KML  made M@11707 L@11730; VRAM before 11269 MB, peak 12412 MB in 15 s; DLSS's own on status lines 1419 MB, 631 MB

Not tested

Linux, AMD and Intel are not affected (DLSS only), and dlss_checks.h is plain C++. Not run on a 12 GB card, where the peak mattered most, or with a controller stepping the row in the menu by hand (the control bridge sets the row the same way, option set dlss_model).

python -I -B tests/run_all.py on Windows 11 (llvm-mingw): 452 passed, 4 failed, 75 skipped (on the rebase onto main d725b363). The four fail the same way on main on this PC, for its setup: test_bake_portability (no zstandard), test_lift_cache (no numpy), test_fpx_sticky and test_spawn_emit (<algorithm> not found compiling a64emit). Forgejo runs no CI, so this was run locally.

Screenshots

Nothing on screen.

Risk and rollback

A preset picked in the menu now takes effect half a second (30 frames) later; until then the feature already made keeps drawing with its old preset. If the row is stepped and left within those frames, no extra feature is made, which is the point. Nothing else in DLSS changes, and FSR, XeSS and the native path are untouched. Reverting the fix commit is enough.

Issues

See #17

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above).
  • Tested in the game, or what wasn't is named under Not tested.
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported.
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • A row in docs/tested-configurations.md for each measured run.
  • A game-free test added for the fix, failing on main and passing here.
  • A check under tests/ that reads changed source updated in this PR, not weakened.

🤖 Generated with Claude Code

## Why Picking the DLSS model L in the menu also made a DLSS feature for M on the way there (the row goes K, M, L, NVIDIA's default). NVIDIA's runtime keeps a released feature's video memory for some seconds, so at 3440x1440 DLAA three models were held at once: VRAM jumped about 1.2 GB for a few seconds. On the reporter's 12 GB card that is the moment it nearly ran out. ## What changed - `dlss_checks::PresetSettle` (`gpu/vk/dlss_checks.h`): the DLSS model row's preset is taken once the row has held it for 30 frames (half a second at 60 fps). Until then the feature already made keeps drawing with its own preset. The first feature, or one made again after being let go, takes the row's preset at once. - `vk_dlss.cpp` `prepare()` reads the preset through it. `RX_VK_DLSS_PRESET` is unaffected, since it never changes in a run. - Tests: `tests/test_dlss_checks.cpp` steps K to M to L 11 frames apart, as in the report, then away and back, with no feature, and NVIDIA's default. `tests/test_dlss_checks.py` checks that `prepare` reads the preset only through the settle. The Python check fails on `main` and passes here. - A row in `docs/tested-configurations.md` for the runs below. The rest of #17, fewer fps with L or M at DLAA, is not this: it is the models' own cost, measured below on both builds. The preset, sizes and creation flags reaching NGX are right. L's extra GPU time grows with DLSS's input size: in the reporter's RTX 5070 log, +0.4 ms at Ultra Performance (1147x480) and +4.4 ms at DLAA (3440x1440). See also NotRexed/Hookshot#2836. ## Flags and settings None: no new switch, ini key or menu row. The DLSS model row (`dlss_model`) keeps its values; only when its new preset takes effect changes. ## Measurements main: d4a69456 (2026-11-12), renderer this PR: fix/dlss-preset-settle @ e8c02084, renderer (rebased since onto main d725b363 as 6f545914/ac7ff634: main's change between is forge tooling and docs only, #48, so the renderer measured is the same code and the numbers hold) Baseline: main @ d4a69456 Hardware: RTX 5080 16 GB, Windows 11 Scene: Kokiri Forest (child, the debug teleport's arrival), standing; output 3440x1440, Upscaler NVIDIA DLSS, Render resolution Native (DLAA), frame rate cap 240, frame generation off Method: one game build (main 82de567a) with its `longshot_vk.dll` swapped. Both renderers were built alone (`RX_VK_ONLY`) the same way. 4 runs, before/after/after/before, headless, through the control bridge. Each run measured steady K (1500 frames), then set the DLSS model row M and 11 frames later L, as the menu does when stepped (steady L), then M and K (steady K), then M alone (steady M). GPU time and fps from `longshot_log.txt`'s `GPU time` and `presents` lines (median over each steady phase); DLSS's own memory from the status lines (`NGX_DLSS_GET_STATS`); VRAM and power from `nvidia-smi` every 100 ms, the peak in the 15 s after a switch against the 3 s before it. | Switch | main @ d4a69456 (2 runs) | this PR @ e8c02084 (2 runs) | |---|---|---| | K → M → L: features made | M, L | L | | K → M → L: DLSS's own memory, first status line | 1419 MB | 813 MB | | K → M → L: VRAM peak over before | +1254, +1143 MB | +637, +637 MB | | L → M → K: features made | M, K | K | | L → M → K: VRAM peak over before | +806, +827 MB | +126, +189 MB | | M alone (one feature either way): VRAM peak | +657, +657 MB | +576, +722 MB | | Steady (median, 4 runs) | GPU a frame | fps | power | |---|---|---|---| | K | 7.4–7.6 ms | 80–84 | 140–145 W | | L | 10.6–10.7 ms | 66–67 | 198–202 W | | M | 9.7–9.9 ms | 70–72 | 186–188 W | The steady numbers are the same on both builds. The second before run ran a lighter scene throughout (K 6.8, L 9.6 ms), so the ranges leave it out. L costs about 3 ms more GPU than K at 3440x1440 DLAA on this card and drops fps by about 20% at about 40% more power: what the reporter saw on an RTX 5070, and the same before and after. ``` before step_KML made M@8948 L@8971; VRAM before 10697 MB, peak 11951 MB in 15 s; DLSS's own on status lines 1419 MB, 631 MB after step_KML made L@5941; VRAM before 10053 MB, peak 10690 MB in 15 s; DLSS's own on status lines 813 MB, 813 MB, 631 MB after step_KML made L@5873; VRAM before 10229 MB, peak 10866 MB in 15 s; DLSS's own on status lines 813 MB, 631 MB before step_KML made M@11707 L@11730; VRAM before 11269 MB, peak 12412 MB in 15 s; DLSS's own on status lines 1419 MB, 631 MB ``` ## Not tested Linux, AMD and Intel are not affected (DLSS only), and `dlss_checks.h` is plain C++. Not run on a 12 GB card, where the peak mattered most, or with a controller stepping the row in the menu by hand (the control bridge sets the row the same way, `option set dlss_model`). `python -I -B tests/run_all.py` on Windows 11 (llvm-mingw): 452 passed, 4 failed, 75 skipped (on the rebase onto main d725b363). The four fail the same way on `main` on this PC, for its setup: `test_bake_portability` (no `zstandard`), `test_lift_cache` (no `numpy`), `test_fpx_sticky` and `test_spawn_emit` (`<algorithm>` not found compiling a64emit). Forgejo runs no CI, so this was run locally. ## Screenshots Nothing on screen. ## Risk and rollback A preset picked in the menu now takes effect half a second (30 frames) later; until then the feature already made keeps drawing with its old preset. If the row is stepped and left within those frames, no extra feature is made, which is the point. Nothing else in DLSS changes, and FSR, XeSS and the native path are untouched. Reverting the fix commit is enough. ## Issues See #17 ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). - [x] Tested in the game, or what wasn't is named under Not tested. - [x] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] A row in `docs/tested-configurations.md` for each measured run. - [x] A game-free test added for the fix, failing on `main` and passing here. - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The row goes K, M, L, NVIDIA's default, so K to L passes M; each preset passed
over made a feature, and NGX keeps a released feature's video memory for some
seconds (issue 17: 1419 MB of DLSS's on a 12 GB card at 3440x1440 DLAA, against
631 MB for L alone). The feature drawing keeps its preset until the row has held
a new one for 30 frames.

Fixes #17

Co-Authored-By: Claude Opus 5.5 <[email protected]>
llun changed title from WIP: fix(dlss): the DLSS model row's preset is taken once it holds it, not a feature for each one stepped past to fix(dlss): the DLSS model row's preset is taken once it holds it, not a feature for each one stepped past 2026-11-13 00:43:12 +00:00
Author
Contributor

Rebased onto main d725b363 (#48, forge tooling and docs only); head ac7ff634. Full suite run again on Windows 11 (llvm-mingw): 452 passed, 4 failed, 75 skipped, the same four that fail on main here. The description now follows #48's template: Flags and settings (none), Risk and rollback, the measurement columns named by commit, and the checklist; the in-game numbers are from e8c02084, the same renderer code.

Rebased onto main d725b363 (#48, forge tooling and docs only); head ac7ff634. Full suite run again on Windows 11 (llvm-mingw): 452 passed, 4 failed, 75 skipped, the same four that fail on main here. The description now follows #48's template: Flags and settings (none), Risk and rollback, the measurement columns named by commit, and the checklist; the in-game numbers are from e8c02084, the same renderer code.
llun force-pushed fix/dlss-preset-settle from 5e7d152878 to ac7ff6340e 2026-11-13 01:29:39 +00:00 Compare
HumanBean deleted branch fix/dlss-preset-settle 2026-11-13 01:35:58 +00:00
Sign in to join this conversation.
No description provided.