fix(vk): opt-in RGBA16F route for PsychoV35 HDR with AMD FSR 4 #247

Merged
HumanBean merged 2 commits from MustardTiger/Longshot:fix/psychov35-fsr4 into main 2026-11-13 18:14:58 +00:00
Contributor

Why

With HDR on Native, the HDR tone mapper on PsychoV35 and AMD FSR 4 (or its Native AA) as the upscaler, FSR 4 silently drops out and the game's own upscale runs instead: jagged edges, a heavily oversharpened picture, and the Sharpness row doing nothing (#226). #108 added an opt-in RGBA16F route for DLSS/DLAA only; this is the FSR 4 follow-up its review asked for.

What changed

  • upscaler rows: takes_psychov35() in gpu/vk/upscaler_rows.h: DLSS/DLAA and FSR 4 / its Native AA, the engines the frame chain gives linear light in an HDR context. FSR 3.1 (its own packed inputs), the game's network and Off are unchanged.
  • chain: temporal_scene_format() and temporal_upscale()'s psycho guard in gpu/vk/vk_temporal.cpp use it in place of ur::is_dlss(). The route waits for FSR 4's HDR context as it does for DLSS's HDR feature, and the route log line names the engine: vk: PsychoV35 FSR 4: RGBA16F linear route. The DLSS line is unchanged.
  • tests: tests/test_psychov35_dlss.py checks the gate over every upscaler (DLSS, DLAA, FSR 4, FSR 4 AA in; game, FSR 3.1, Off out) and the history log for FSR 4. It fails on main and passes here.
  • docs: the switch's reach in docs/temporal-history.md, docs/development.md and the README's HDR tone mapper row.

No new shader, no change to #108's RGBA16F output pass, view binding or history reset: FSR 4 goes through them as DLSS does.

Flags and settings

Flag What it does Default now Recommendation Helps on Doesn't help on Untested on
RX_VK_PSYCHOV35_DLSS=1 (existing, from #108) Now also lets AMD FSR 4 and its Native AA take the Native HDR PsychoV35 scene Off Keep opt-in, as #108 does, until more cards have run it. The name now covers FSR 4 too; renaming it (e.g. RX_VK_PSYCHOV35_RGBA16F) is left to the maintainers RX 9070 XT, Windows, FSR 4 Native AA with Native HDR + PsychoV35 FSR 3.1, TAAU, Upscaler Off (still the game's network) FSR 4 (not Native AA) at a lower render size beyond a short run, Linux (Mesa RADV), other RDNA 4 cards and drivers

RX_VK_FSR4_HDR=0 prevents the route for FSR 4, as RX_VK_DLSS_HDR=0 does for DLSS: it needs the HDR context.

Measurements

main: 9eae480e (2026-11-13)
this PR: fix/psychov35-fsr4 @ ea988050 (the first pair of runs at 1ba927d0, the same change on #108's branch before it merged)
Rebased since: the branch is now acd851c8 (the code) and e72f4077 (the tested-configurations rows) on main 2e1e2e8c. Its three new commits (#107's clustered-light shadow maps, #55's render scale across upscaler switches, #159's docs) leave the PsychoV35 gate and the route alone: git range-diff shows both commits unchanged, the renderer builds at acd851c8, and the checks below pass there, so the numbers still hold.
Baseline: this PR @ ea988050, RX_VK_PSYCHOV35_DLSS=0 (main's route). With the switch off the chain takes exactly main's route (main's gate leaves FSR 4 out with the switch on or off), so it isolates this change on one build.
Hardware: AMD Radeon RX 9070 XT 16 GB, Adrenalin 26.10.2, Ryzen 7 9800X3D, 32 GB, Windows 11 Pro 26300
Scene: Forest Temple, indoors, standing; 2560x1440 output, fullscreen, HDR10 (paper white 200, peak 700 nits), HDR Native, HDR tone mapper PsychoV35, Upscaler AMD FSR 4 Native AA (FSR 4.1.2), Sharpness 50, no frame generation
Method: the game folder of main fdc2840b built with FSR 4 (make_game.py --fsr); the renderer built alone (RX_VK_ONLY, llvm-mingw, LONGSHOT_FSR=1) from this branch and put in its place. A cold start per run (load the save, about a minute standing), runs interleaved ON / OFF / OFF / ON / Vanilla. Counts from the 600-frame status: lines of longshot_log.txt; only complete intervals after loading are counted (the first interval holds the title screen and the load).
How to reproduce: Native HDR, HDR tone mapper PsychoV35, Upscaler AMD FSR 4 Native AA; start once with RX_VK_PSYCHOV35_DLSS=1 and once with it unset; check PsychoV35 FSR 4: RGBA16F linear route and the AMD FSR 4 Native AA: N frames drawn counts rather than the menu row.

this PR @ ea988050, RX_VK_PSYCHOV35_DLSS=0 (main's route) this PR @ ea988050, RX_VK_PSYCHOV35_DLSS=1
PsychoV35: FSR 4 frames drawn per 600, median of complete intervals 0 (2 runs: 0 and 0; the game's upscale runs (no scene camera this frame) every time) 600 (2 runs: 600 and 600; 8 of 8 complete intervals at 600 in the short run, 19 of 27 in the long one, see below)
Vanilla, switch on: FSR 4 frames drawn per 600 600 (1 run, 6 of 6 complete intervals; no PsychoV35 line, as on main)
vk: AMD FSR 4: FSR 4.1.2 made for outputs of 2560x1440 (frame 1711, 68.4 ms of CPU; its own 180 MB), HDR colour, linear (the game's native HDR)
vk: PsychoV35 FSR 4: RGBA16F linear route; scene format 122, network input 97, output 97
vk: status: 600 frames, the slowest 19.6 ms; VRAM 7.3 of 15.1 GB; AMD FSR 4 Native AA: 600 frames drawn, 1 made, ...

switch off:
vk: AMD FSR 4 Native AA: the game's upscale runs (no scene camera this frame)
vk: status: 600 frames, the slowest 19.2 ms; VRAM 6.3 of 15.1 GB

The long ON run is the first one, where the tone mapper and HDR mode were also switched during play. Its eight intervals under 600: 595 to 599 around those switches (each logs the game's upscale runs (unexpected scene colour format) for the one to three frames the game takes to change its scene buffer, then the new route); 532 and 522 after moving to another area, following a history reset and a burst of new textures, with no new fallback reason logged; and 351 in one interval whose cause the log doesn't show. One of its complete intervals ran FSR 4 (not Native AA) at 600 of 600. This is a correctness fix; no frame rate is claimed.

Testing

Tested: On the RX 9070 XT above, in the game: PsychoV35 with FSR 4 Native AA and the switch on keeps FSR 4 drawing: smooth edges, the Sharpness row works again (0 / 50 / 100 checked by eye), and HDR brightness looks right on an HDR10 display (white 200, peak 700 nits). With the switch off the jagged, oversharpened picture comes back. During play: the tone mapper switched Vanilla / PsychoV35 and HDR Native / Extended / Native several times; each switch logs the route change (packed / RGBA16F linear) and FSR 4 is back at 600/600 within 1 to 3 frames. Vanilla with the switch on is unchanged (600/600, no PsychoV35 line). Game-free checks: python -I -B tests/run_all.py --jobs 12 on Windows (the launcher's Python and llvm-mingw, glslang 16.5.0): 489 passed, 5 failed, 33 skipped. Three of the failures fail the same way on main 9eae480e here (run at ea988050; the touched checks again at acd851c8, all passing, with test_upscaler_round_trip from #55) (test_check_third_party, test_gpu_hang_watch, test_release); the other two (test_dlss_sdk_cache, test_portable_builder_home) failed only under the 12-way load and pass run alone, and pass on main too. The checks this PR touches pass: test_psychov35_dlss (fails on main), test_temporal_history, test_reactive_mask, test_upscaler_rows, test_hdr_encode, test_dlss_actor.

Not tested: FSR 4 (not Native AA) at a lower render size beyond one 600-frame interval of the first run; DLSS/DLAA on this branch (no NVIDIA card here; the DLSS path is #108's unchanged code, and its test still covers it); Linux (Mesa RADV), including a Linux build of the renderer: there is no Linux system here (the change is portable C++ with no platform code, as #108's was); other RDNA 4 cards and drivers.

Needs other testers:

  • Linux, RDNA 4 with an HDR display: Native HDR + PsychoV35 + FSR 4 Native AA with RX_VK_PSYCHOV35_DLSS=1, the renderer builds, and expecting PsychoV35 FSR 4: RGBA16F linear route and 600/600 AMD FSR 4 ... frames drawn (T-NV7J; needs the testing wanted label to be claimed)

Screenshots

Nothing captured: an HDR10 (PQ) screenshot does not show the difference faithfully on an SDR viewer. The difference is the one #226 describes (jagged and oversharpened with the switch off, FSR 4's anti-aliasing with it on); the log counts above show which upscaler drew each frame.

Risk and rollback

Only runs with RX_VK_PSYCHOV35_DLSS=1, Native HDR, PsychoV35 and FSR 4 or its Native AA: nobody gets it by default. Unsetting the switch restores main's behaviour; RX_VK_FSR4_HDR=0 also keeps FSR 4 off this route. Reverting the commit is enough.

Reviewer notes

The change is the gate: takes_psychov35() and its two uses in vk_temporal.cpp. Everything the route needs past the gate (the RGBA16F views, the typed output pass, the HDR decode, the history reset) is #108's and engine-neutral; FSR 4's HDR context comes from https://github.com/NotRexed/Hookshot/pull/2342.

Left for a follow-up on purpose: the menu saying that PsychoV35 makes the upscaler fall back while the switch is off (#226's "silently"), which needs the help text in every menu language; and whether the route should become the default. Separately, one run logged program 946589f514448dc6: scene tone map left as the game's: a fit's channel not found by the luminance in one area: PsychoV35 itself (https://github.com/NotRexed/Hookshot/pull/2481) not finding the game's fit in one shader, unrelated to this change.

Issues

Fixes #226

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 Testing.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests).
  • 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.
  • Flags noted, and the switch reference updated (docs/development.md, the README).
  • 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.
  • Docs updated.
## Why With HDR on Native, the HDR tone mapper on PsychoV35 and AMD FSR 4 (or its Native AA) as the upscaler, FSR 4 silently drops out and the game's own upscale runs instead: jagged edges, a heavily oversharpened picture, and the Sharpness row doing nothing (https://git.magicbean.dev/MagicBeanDev/Longshot/issues/226). https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/108 added an opt-in RGBA16F route for DLSS/DLAA only; this is the FSR 4 follow-up its review asked for. ## What changed - upscaler rows: `takes_psychov35()` in `gpu/vk/upscaler_rows.h`: DLSS/DLAA and FSR 4 / its Native AA, the engines the frame chain gives linear light in an HDR context. FSR 3.1 (its own packed inputs), the game's network and Off are unchanged. - chain: `temporal_scene_format()` and `temporal_upscale()`'s `psycho` guard in `gpu/vk/vk_temporal.cpp` use it in place of `ur::is_dlss()`. The route waits for FSR 4's HDR context as it does for DLSS's HDR feature, and the route log line names the engine: `vk: PsychoV35 FSR 4: RGBA16F linear route`. The DLSS line is unchanged. - tests: `tests/test_psychov35_dlss.py` checks the gate over every upscaler (DLSS, DLAA, FSR 4, FSR 4 AA in; game, FSR 3.1, Off out) and the history log for FSR 4. It fails on main and passes here. - docs: the switch's reach in `docs/temporal-history.md`, `docs/development.md` and the README's HDR tone mapper row. No new shader, no change to #108's RGBA16F output pass, view binding or history reset: FSR 4 goes through them as DLSS does. ## Flags and settings | Flag | What it does | Default now | Recommendation | Helps on | Doesn't help on | Untested on | |---|---|---|---|---|---|---| | `RX_VK_PSYCHOV35_DLSS=1` (existing, from #108) | Now also lets AMD FSR 4 and its Native AA take the Native HDR PsychoV35 scene | Off | Keep opt-in, as #108 does, until more cards have run it. The name now covers FSR 4 too; renaming it (e.g. `RX_VK_PSYCHOV35_RGBA16F`) is left to the maintainers | RX 9070 XT, Windows, FSR 4 Native AA with Native HDR + PsychoV35 | FSR 3.1, TAAU, Upscaler Off (still the game's network) | FSR 4 (not Native AA) at a lower render size beyond a short run, Linux (Mesa RADV), other RDNA 4 cards and drivers | `RX_VK_FSR4_HDR=0` prevents the route for FSR 4, as `RX_VK_DLSS_HDR=0` does for DLSS: it needs the HDR context. ## Measurements main: 9eae480e (2026-11-13) this PR: fix/psychov35-fsr4 @ ea988050 (the first pair of runs at 1ba927d0, the same change on #108's branch before it merged) Rebased since: the branch is now acd851c8 (the code) and e72f4077 (the tested-configurations rows) on main 2e1e2e8c. Its three new commits (#107's clustered-light shadow maps, #55's render scale across upscaler switches, #159's docs) leave the PsychoV35 gate and the route alone: `git range-diff` shows both commits unchanged, the renderer builds at acd851c8, and the checks below pass there, so the numbers still hold. Baseline: this PR @ ea988050, `RX_VK_PSYCHOV35_DLSS=0` (main's route). With the switch off the chain takes exactly main's route (main's gate leaves FSR 4 out with the switch on or off), so it isolates this change on one build. Hardware: AMD Radeon RX 9070 XT 16 GB, Adrenalin 26.10.2, Ryzen 7 9800X3D, 32 GB, Windows 11 Pro 26300 Scene: Forest Temple, indoors, standing; 2560x1440 output, fullscreen, HDR10 (paper white 200, peak 700 nits), HDR Native, HDR tone mapper PsychoV35, Upscaler AMD FSR 4 Native AA (FSR 4.1.2), Sharpness 50, no frame generation Method: the game folder of main fdc2840b built with FSR 4 (`make_game.py --fsr`); the renderer built alone (`RX_VK_ONLY`, llvm-mingw, `LONGSHOT_FSR=1`) from this branch and put in its place. A cold start per run (load the save, about a minute standing), runs interleaved ON / OFF / OFF / ON / Vanilla. Counts from the 600-frame `status:` lines of `longshot_log.txt`; only complete intervals after loading are counted (the first interval holds the title screen and the load). How to reproduce: Native HDR, HDR tone mapper PsychoV35, Upscaler AMD FSR 4 Native AA; start once with `RX_VK_PSYCHOV35_DLSS=1` and once with it unset; check `PsychoV35 FSR 4: RGBA16F linear route` and the `AMD FSR 4 Native AA: N frames drawn` counts rather than the menu row. | | this PR @ ea988050, `RX_VK_PSYCHOV35_DLSS=0` (main's route) | this PR @ ea988050, `RX_VK_PSYCHOV35_DLSS=1` | |---|---|---| | PsychoV35: FSR 4 frames drawn per 600, median of complete intervals | 0 (2 runs: 0 and 0; `the game's upscale runs (no scene camera this frame)` every time) | 600 (2 runs: 600 and 600; 8 of 8 complete intervals at 600 in the short run, 19 of 27 in the long one, see below) | | Vanilla, switch on: FSR 4 frames drawn per 600 | | 600 (1 run, 6 of 6 complete intervals; no PsychoV35 line, as on main) | ``` vk: AMD FSR 4: FSR 4.1.2 made for outputs of 2560x1440 (frame 1711, 68.4 ms of CPU; its own 180 MB), HDR colour, linear (the game's native HDR) vk: PsychoV35 FSR 4: RGBA16F linear route; scene format 122, network input 97, output 97 vk: status: 600 frames, the slowest 19.6 ms; VRAM 7.3 of 15.1 GB; AMD FSR 4 Native AA: 600 frames drawn, 1 made, ... switch off: vk: AMD FSR 4 Native AA: the game's upscale runs (no scene camera this frame) vk: status: 600 frames, the slowest 19.2 ms; VRAM 6.3 of 15.1 GB ``` The long ON run is the first one, where the tone mapper and HDR mode were also switched during play. Its eight intervals under 600: 595 to 599 around those switches (each logs `the game's upscale runs (unexpected scene colour format)` for the one to three frames the game takes to change its scene buffer, then the new route); 532 and 522 after moving to another area, following a history reset and a burst of new textures, with no new fallback reason logged; and 351 in one interval whose cause the log doesn't show. One of its complete intervals ran FSR 4 (not Native AA) at 600 of 600. This is a correctness fix; no frame rate is claimed. ## Testing **Tested:** On the RX 9070 XT above, in the game: PsychoV35 with FSR 4 Native AA and the switch on keeps FSR 4 drawing: smooth edges, the Sharpness row works again (0 / 50 / 100 checked by eye), and HDR brightness looks right on an HDR10 display (white 200, peak 700 nits). With the switch off the jagged, oversharpened picture comes back. During play: the tone mapper switched Vanilla / PsychoV35 and HDR Native / Extended / Native several times; each switch logs the route change (`packed` / `RGBA16F linear`) and FSR 4 is back at 600/600 within 1 to 3 frames. Vanilla with the switch on is unchanged (600/600, no PsychoV35 line). Game-free checks: `python -I -B tests/run_all.py --jobs 12` on Windows (the launcher's Python and llvm-mingw, glslang 16.5.0): 489 passed, 5 failed, 33 skipped. Three of the failures fail the same way on main 9eae480e here (run at ea988050; the touched checks again at acd851c8, all passing, with `test_upscaler_round_trip` from #55) (`test_check_third_party`, `test_gpu_hang_watch`, `test_release`); the other two (`test_dlss_sdk_cache`, `test_portable_builder_home`) failed only under the 12-way load and pass run alone, and pass on main too. The checks this PR touches pass: `test_psychov35_dlss` (fails on main), `test_temporal_history`, `test_reactive_mask`, `test_upscaler_rows`, `test_hdr_encode`, `test_dlss_actor`. **Not tested:** FSR 4 (not Native AA) at a lower render size beyond one 600-frame interval of the first run; DLSS/DLAA on this branch (no NVIDIA card here; the DLSS path is #108's unchanged code, and its test still covers it); Linux (Mesa RADV), including a Linux build of the renderer: there is no Linux system here (the change is portable C++ with no platform code, as #108's was); other RDNA 4 cards and drivers. **Needs other testers:** - Linux, RDNA 4 with an HDR display: Native HDR + PsychoV35 + FSR 4 Native AA with `RX_VK_PSYCHOV35_DLSS=1`, the renderer builds, and expecting `PsychoV35 FSR 4: RGBA16F linear route` and 600/600 `AMD FSR 4 ... frames drawn` (T-NV7J; needs the `testing wanted` label to be claimed) ## Screenshots Nothing captured: an HDR10 (PQ) screenshot does not show the difference faithfully on an SDR viewer. The difference is the one #226 describes (jagged and oversharpened with the switch off, FSR 4's anti-aliasing with it on); the log counts above show which upscaler drew each frame. ## Risk and rollback Only runs with `RX_VK_PSYCHOV35_DLSS=1`, Native HDR, PsychoV35 and FSR 4 or its Native AA: nobody gets it by default. Unsetting the switch restores main's behaviour; `RX_VK_FSR4_HDR=0` also keeps FSR 4 off this route. Reverting the commit is enough. ## Reviewer notes The change is the gate: `takes_psychov35()` and its two uses in `vk_temporal.cpp`. Everything the route needs past the gate (the RGBA16F views, the typed output pass, the HDR decode, the history reset) is #108's and engine-neutral; FSR 4's HDR context comes from https://github.com/NotRexed/Hookshot/pull/2342. Left for a follow-up on purpose: the menu saying that PsychoV35 makes the upscaler fall back while the switch is off (#226's "silently"), which needs the help text in every menu language; and whether the route should become the default. Separately, one run logged `program 946589f514448dc6: scene tone map left as the game's: a fit's channel not found by the luminance` in one area: PsychoV35 itself (https://github.com/NotRexed/Hookshot/pull/2481) not finding the game's fit in one shader, unrelated to this change. ## Issues Fixes #226 ## 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 Testing. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). - [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] Flags noted, and the switch reference updated (docs/development.md, the README). - [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. - [x] Docs updated.
With HDR on Native, the HDR tone mapper on PsychoV35 and AMD FSR 4 (or its Native AA) as the
upscaler, the game's own upscale still runs in FSR 4's place: no temporal anti-aliasing, the
Sharpness row doing nothing, a jagged, oversharpened picture
(#226). The RGBA16F route
(#108) takes DLSS/DLAA alone.

- upscaler_rows.h takes_psychov35: DLSS/DLAA and FSR 4 / its Native AA, the engines the chain
  gives linear light in an HDR context. temporal_scene_format and temporal_upscale's psycho guard
  use it in place of is_dlss. FSR 3.1 (its own packed inputs), the game's network and Off are
  unchanged.
- The route waits for FSR 4's HDR context as it does for DLSS's HDR feature, and its log line
  names the engine: "vk: PsychoV35 FSR 4: RGBA16F linear route".
- test_psychov35_dlss.py: the gate over every upscaler, and the history log for FSR 4. It fails
  on #108 as it is and passes here.
- docs: the switch's reach (temporal-history.md, development.md, the README's row).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
docs(tested): five FSR 4 runs of PsychoV35's RGBA16F route on an RX 9070 XT
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 4s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
e72f407782
Forest Temple, Native HDR, FSR 4 Native AA: the switch on and off with PsychoV35, interleaved,
and Vanilla with the switch on.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Author
Contributor

Test request T-NV7J is open for a Linux RDNA 4 run (and a Linux build of the renderer); it can be claimed once the testing wanted label is on this PR. Measured and tested on an RX 9070 XT (Windows, Adrenalin 26.10.2) as in the description; rebased onto main 2e1e2e8c with both commits unchanged.

Test request T-NV7J is open for a Linux RDNA 4 run (and a Linux build of the renderer); it can be claimed once the testing wanted label is on this PR. Measured and tested on an RX 9070 XT (Windows, Adrenalin 26.10.2) as in the description; rebased onto main 2e1e2e8c with both commits unchanged.
MustardTiger changed title from WIP: fix(vk): opt-in RGBA16F route for PsychoV35 HDR with AMD FSR 4 to fix(vk): opt-in RGBA16F route for PsychoV35 HDR with AMD FSR 4 2026-11-13 17:10:48 +00:00
HumanBean added this to the v3.0.0 milestone 2026-11-13 17:37:22 +00:00
HumanBean force-pushed fix/psychov35-fsr4 from e72f407782
Some checks failed
PR description / Description follows the template (pull_request_target) Successful in 4s
CI / Conventional Commit title (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been cancelled
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been cancelled
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been cancelled
CI / Workflow lint (actionlint) (pull_request) Has been cancelled
Third-party parts / As their notes say (pull_request) Has been cancelled
Third-party parts / The same as upstream (pull_request) Has been cancelled
to f4033932f9
All checks were successful
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 3s
PR description / Description follows the template (pull_request_target) Successful in 4s
CI / Workflow lint (actionlint) (pull_request) Successful in 5s
Third-party parts / As their notes say (pull_request) Successful in 6s
Website / Website on Cloudflare (pull_request_target) Has been skipped
2026-11-13 17:37:46 +00:00
Compare
Owner

I rebased this onto main @ fbd42024 to clear the conflict; it's pushed as f4033932, with your two commits unchanged otherwise. The code applied cleanly. The only conflict was docs/tested-configurations.md, where main had added a row at the same place as your five FSR 4 rows. I kept all of them. I didn't run the test suite. Forgejo now shows the PR as mergeable.

I rebased this onto main @ fbd42024 to clear the conflict; it's pushed as f4033932, with your two commits unchanged otherwise. The code applied cleanly. The only conflict was `docs/tested-configurations.md`, where main had added a row at the same place as your five FSR 4 rows. I kept all of them. I didn't run the test suite. Forgejo now shows the PR as mergeable.
Author
Contributor

Thanks for the rebase. Checked at f4033932 (main fbd42024): the fix commit is unchanged (git range-diff), and all five tested-configurations rows are kept. Full suite on Windows: 493 passed, 3 failed, 33 skipped; the three (test_check_third_party, test_gpu_hang_watch, test_release) fail the same way on main here. The renderer builds with llvm-mingw and FSR 4, 0 failures.

Thanks for the rebase. Checked at f4033932 (main fbd42024): the fix commit is unchanged (git range-diff), and all five tested-configurations rows are kept. Full suite on Windows: 493 passed, 3 failed, 33 skipped; the three (test_check_third_party, test_gpu_hang_watch, test_release) fail the same way on main here. The renderer builds with llvm-mingw and FSR 4, 0 failures.
HumanBean approved these changes 2026-11-13 18:14:38 +00:00
HumanBean left a comment

Read through end to end against main fbd42024 (the fork point, so "Rebased on current main" holds). Approving: the change is small and correct, and the evidence backs it.

What's good

  • The gate is widened in one place. temporal_scene_format() is what the camera (temporal_note_scene_draw), actor motion (skin_check), the reactive copy (reactive_scene_draw), temporal_colour_pair() and both temporal_stand_in and temporal_rejected_network (the RGBA16F sample and storage views) all ask. So switching it from is_dlss to takes_psychov35 moves every consumer together, and the psycho guard in temporal_upscale follows. I found no format decision left that still assumes DLSS.
  • The reactive mask is still left out for FSR 4. reactive_scene_draw zeroes its size while FSR 4 draws on the chain, so the wider gate copies nothing extra.
  • The colour encoding matches what FSR 4 already gets with Vanilla Native HDR. The HDR prep squares to linear (clamped at 16384), the HDR context is made with FFX_UPSCALE_ENABLE_HIGH_DYNAMIC_RANGE | AUTO_EXPOSURE, preExposure is 1 and no sRGB flag is set. The only difference is that the typed RGBA16F output pass does not square again, which is engine-neutral. hdr() keys off present_native_pq and RX_VK_FSR4_HDR, so "waits for the native HDR FSR 4 context" is the right gate.
  • History is handled: a DLSS to FSR 4 change resets through s.drawing, and the route log now names the engine.
  • Vanilla is unchanged, because B10G11R11 is accepted first and the RGBA16F branch needs scene_tonemap_on().
  • The test is updated, not weakened. The gate is checked over every upscaler, explicit in/out asserts are added for each engine, and the cut switch block's logf stub matches the new signature.
  • Docs are updated: the doc anchor is renamed with no dangling links, and the development.md, README and Flags rows are revised. GitHub references are full URLs.
  • Evidence: five RX 9070 XT rows name the tested commits. They show switch off vs on on one build (0 vs 600/600 FSR 4 frames), a Vanilla control, and hot switches. The current code commit has an empty interdiff against the pushed acd851c8 that the rebase note cites.

Must change

Nothing.

Should change

  • AMD FSR 3.1 frame interpolation gets no inputs under PsychoV35. fsr3_inputs::note_scene_draw accepts only a B10G11R11 scene, so with the RGBA16F scene fsr3_inputs::prepare has no camera and fsr3fi::generate makes no frames. This is not a regression: on main, PsychoV35 had no FI inputs either. But FSR 4 with FSR 3.1 frame interpolation is the pairing AMD players are likely to use, and the docs only say "there is no NVIDIA frame generation to check". One line in temporal-history.md and in the Flags row would set expectations: FSR 3.1 frame interpolation is not fed on this route. Widening its gate could be a follow-up.
  • The switch name RX_VK_PSYCHOV35_DLSS now also covers FSR 4. The description already leaves renaming it to maintainers. A follow-up could add a neutral alias (e.g. RX_VK_PSYCHOV35_RGBA16F) and keep the old name working.

Not checked: I ran no build or tests (code review only), and I could not inspect the tested commits ea988050 and 1ba927d0 locally. For those I relied on the author's range-diff note, plus the empty interdiff I did confirm for acd851c8.

Read through end to end against main fbd42024 (the fork point, so "Rebased on current main" holds). Approving: the change is small and correct, and the evidence backs it. **What's good** - The gate is widened in one place. `temporal_scene_format()` is what the camera (`temporal_note_scene_draw`), actor motion (`skin_check`), the reactive copy (`reactive_scene_draw`), `temporal_colour_pair()` and both `temporal_stand_in` and `temporal_rejected_network` (the RGBA16F sample and storage views) all ask. So switching it from `is_dlss` to `takes_psychov35` moves every consumer together, and the `psycho` guard in `temporal_upscale` follows. I found no format decision left that still assumes DLSS. - The reactive mask is still left out for FSR 4. `reactive_scene_draw` zeroes its size while FSR 4 draws on the chain, so the wider gate copies nothing extra. - The colour encoding matches what FSR 4 already gets with Vanilla Native HDR. The HDR prep squares to linear (clamped at 16384), the HDR context is made with `FFX_UPSCALE_ENABLE_HIGH_DYNAMIC_RANGE | AUTO_EXPOSURE`, `preExposure` is 1 and no sRGB flag is set. The only difference is that the typed RGBA16F output pass does not square again, which is engine-neutral. `hdr()` keys off `present_native_pq` and `RX_VK_FSR4_HDR`, so "waits for the native HDR FSR 4 context" is the right gate. - History is handled: a DLSS to FSR 4 change resets through `s.drawing`, and the route log now names the engine. - Vanilla is unchanged, because B10G11R11 is accepted first and the RGBA16F branch needs `scene_tonemap_on()`. - The test is updated, not weakened. The gate is checked over every upscaler, explicit in/out asserts are added for each engine, and the cut switch block's `logf` stub matches the new signature. - Docs are updated: the doc anchor is renamed with no dangling links, and the development.md, README and Flags rows are revised. GitHub references are full URLs. - Evidence: five RX 9070 XT rows name the tested commits. They show switch off vs on on one build (0 vs 600/600 FSR 4 frames), a Vanilla control, and hot switches. The current code commit has an empty interdiff against the pushed acd851c8 that the rebase note cites. **Must change** Nothing. **Should change** - AMD FSR 3.1 frame interpolation gets no inputs under PsychoV35. `fsr3_inputs::note_scene_draw` accepts only a B10G11R11 scene, so with the RGBA16F scene `fsr3_inputs::prepare` has no camera and `fsr3fi::generate` makes no frames. This is not a regression: on main, PsychoV35 had no FI inputs either. But FSR 4 with FSR 3.1 frame interpolation is the pairing AMD players are likely to use, and the docs only say "there is no NVIDIA frame generation to check". One line in temporal-history.md and in the Flags row would set expectations: FSR 3.1 frame interpolation is not fed on this route. Widening its gate could be a follow-up. - The switch name `RX_VK_PSYCHOV35_DLSS` now also covers FSR 4. The description already leaves renaming it to maintainers. A follow-up could add a neutral alias (e.g. `RX_VK_PSYCHOV35_RGBA16F`) and keep the old name working. Not checked: I ran no build or tests (code review only), and I could not inspect the tested commits ea988050 and 1ba927d0 locally. For those I relied on the author's range-diff note, plus the empty interdiff I did confirm for acd851c8.
@ -134,3 +133,1 @@
The successful upscale supplies NVIDIA frame generation with depth, camera and actor motion as usual. It requires
the native-HDR DLSS feature (`RX_VK_DLSS_HDR=0` prevents this path). FSR and TAAU are not enabled by this switch.
See [the format and history rules](temporal-history.md#psychov35-with-dlssdlaa-opt-in) for validation and shader regeneration.
`RX_VK_PSYCHOV35_DLSS=1` enables the experimental RGBA16F scene path for DLSS/DLAA and AMD FSR 4 (and its Native AA)
Owner

Nit, fine for this PR: the switch's name now says DLSS but covers FSR 4 too. A follow-up could add a neutral alias (e.g. RX_VK_PSYCHOV35_RGBA16F) and keep this name working.

Nit, fine for this PR: the switch's name now says DLSS but covers FSR 4 too. A follow-up could add a neutral alias (e.g. `RX_VK_PSYCHOV35_RGBA16F`) and keep this name working.
@ -54,1 +54,3 @@
brightness on an HDR display, edges, actor motion, history resets and validation errors. A transitional packed-format
brightness on an HDR display, edges, actor motion, history resets and validation errors. With FSR 4 or its Native AA, the log
line is `vk: PsychoV35 FSR 4: RGBA16F linear route`, the status lines count `AMD FSR 4 ...: N frames drawn`, and no
`the game's upscale runs` follows; there is no NVIDIA frame generation to check. A transitional packed-format
Owner

There is no NVIDIA frame generation here, but AMD FSR 3.1 frame interpolation is the likely pairing with FSR 4, and it gets no inputs on this route. fsr3_inputs::note_scene_draw (vk_fsr3_inputs.cpp) accepts only a B10G11R11 scene, so prepare finds no camera and fsr3fi::generate makes no frames. This isn't a regression (main's PsychoV35 is the same), but a sentence saying FSR 3.1 frame interpolation is not fed on this route would save someone a confused test.

There is no NVIDIA frame generation here, but AMD FSR 3.1 frame interpolation is the likely pairing with FSR 4, and it gets no inputs on this route. `fsr3_inputs::note_scene_draw` (vk_fsr3_inputs.cpp) accepts only a B10G11R11 scene, so `prepare` finds no camera and `fsr3fi::generate` makes no frames. This isn't a regression (main's PsychoV35 is the same), but a sentence saying FSR 3.1 frame interpolation is not fed on this route would save someone a confused test.
HumanBean deleted branch fix/psychov35-fsr4 2026-11-13 18:14:59 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!247
No description provided.