fix(vk): RX_VK_FSR4 and RX_VK_DLSS go over a saved FSR 3.1 (#1008 follow-up) #1773

Merged
madebyjordan merged 2 commits from amd/fsr4-env-over-fsr3 into main 2026-11-10 16:32:44 +00:00
madebyjordan commented 2026-11-10 16:22:14 +00:00 (Migrated from github.com)

Follow-up to #1008, for hckrman101's last review nit there.

The problem

With the Upscaler row saved on FSR 3.1 (dlss=3), RX_VK_FSR4=1/2 or RX_VK_DLSS=1/2 was ignored without a word. fsr3_wanted() was true from the row alone, and the frame chain stands aside while FSR 3.1 upscales. development.md says these switches go over the row.

The fix

  • fsr3_wanted() leaves a saved FSR 3.1 to those switches (temporal_env_chosen(), new in vk_temporal.cpp).
  • Only where the engine they ask for runs (dlss_why() / fsr4_why()): otherwise a saved FSR 3.1 stays, rather than the game's own upscale (hckrman101's suggestion).
  • RX_VK_FSR=1 still goes over everything, so it's still one upscaler and one jitter.
  • The switches are still read at the first ask, as before.
  • development.md states the order; test_upscaler_rows.py checks fsr3_wanted asks the chain.

Tested

  • The renderer builds with and without FSR 4, no warnings.
  • tests/run_all.py: 237 pass, and the same 20 fail on plain main (ef028cb) here (local tools).
  • Not run in game: it's a switch-order change.

🤖 Generated with Claude Code

Follow-up to #1008, for hckrman101's last review nit there. ## The problem With the Upscaler row saved on FSR 3.1 (`dlss=3`), `RX_VK_FSR4=1/2` or `RX_VK_DLSS=1/2` was ignored without a word. `fsr3_wanted()` was true from the row alone, and the frame chain stands aside while FSR 3.1 upscales. `development.md` says these switches go over the row. ## The fix - `fsr3_wanted()` leaves a saved FSR 3.1 to those switches (`temporal_env_chosen()`, new in `vk_temporal.cpp`). - Only where the engine they ask for runs (`dlss_why()` / `fsr4_why()`): otherwise a saved FSR 3.1 stays, rather than the game's own upscale (hckrman101's suggestion). - `RX_VK_FSR=1` still goes over everything, so it's still one upscaler and one jitter. - The switches are still read at the first ask, as before. - `development.md` states the order; `test_upscaler_rows.py` checks `fsr3_wanted` asks the chain. ## Tested - The renderer builds with and without FSR 4, no warnings. - `tests/run_all.py`: 237 pass, and the same 20 fail on plain `main` (ef028cb) here (local tools). - Not run in game: it's a switch-order change. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
hckrman101 (Migrated from github.com) approved these changes 2026-11-10 16:25:35 +00:00
hckrman101 (Migrated from github.com) left a comment

Thanks, this fixes the nit from my #1008 review: with the row saved on FSR 3.1, RX_VK_DLSS=1/2 and RX_VK_FSR4=1/2 now go over it like the docs say.

I went through the combinations. =0 on either switch leaves the saved FSR 3.1 alone. Rows 0, 1, 2, 4 and 5 behave as before. RX_VK_FSR=1 still wins and RX_VK_FSR=0 still turns it off. Only one upscaler draws and only one jitter source is active: fsr3_inputs::jitter_size checks fsr3_wanted(), so the FSR 3.1 jitter turns off when the chain takes over. Frame interpolation still gets its inputs through fsr3_inputs::wanted() (frames_wanted()). The menu's upscaler() now shows the engine that actually runs. The docs match the code, and the test is picked up by the tests/test_*.py glob.

One non-blocking suggestion inline, about builds or GPUs where the engine you asked for can't run.

Thanks, this fixes the nit from my #1008 review: with the row saved on FSR 3.1, `RX_VK_DLSS=1/2` and `RX_VK_FSR4=1/2` now go over it like the docs say. I went through the combinations. `=0` on either switch leaves the saved FSR 3.1 alone. Rows 0, 1, 2, 4 and 5 behave as before. `RX_VK_FSR=1` still wins and `RX_VK_FSR=0` still turns it off. Only one upscaler draws and only one jitter source is active: `fsr3_inputs::jitter_size` checks `fsr3_wanted()`, so the FSR 3.1 jitter turns off when the chain takes over. Frame interpolation still gets its inputs through `fsr3_inputs::wanted()` (`frames_wanted()`). The menu's `upscaler()` now shows the engine that actually runs. The docs match the code, and the test is picked up by the `tests/test_*.py` glob. One non-blocking suggestion inline, about builds or GPUs where the engine you asked for can't run.
@ -74,13 +74,25 @@ int env_switch(const char* name) { // (-1: unset)
}
hckrman101 (Migrated from github.com) commented 2026-11-10 16:25:34 +00:00

Suggestion, not blocking: this is true even when the engine the switch picks can't run here. Say the row is saved on FSR 3.1 and RX_VK_DLSS=1 is set on a build without NGX or on an AMD card. Then fsr3_wanted() turns false, temporal_mode() hits dlss_why() != DLSS_OK and returns GAME, and the game's own upscale runs with no log line. Before this PR, FSR 3.1 kept running in that case. RX_VK_FSR4=1 without FSR 4 compiled in does the same. dlss_why() and fsr4_why() are cheap and don't call back into fsr3_wanted, so gating on them would keep FSR 3.1 as the fallback:

bool temporal_env_chosen() {
    if (env_dlss() > 0) return dlss_why() == DLSS_OK;
    return env_fsr4() > 0 && fsr4_why() == FSR_OK;
}

(DLSS still comes before FSR 4, as in temporal_mode.) You could also say this is just what 'goes over the row' means, since a saved DLSS row on an AMD card gives you the game's own upscale too. Either way works for me.

Suggestion, not blocking: this is true even when the engine the switch picks can't run here. Say the row is saved on FSR 3.1 and `RX_VK_DLSS=1` is set on a build without NGX or on an AMD card. Then `fsr3_wanted()` turns false, `temporal_mode()` hits `dlss_why() != DLSS_OK` and returns GAME, and the game's own upscale runs with no log line. Before this PR, FSR 3.1 kept running in that case. `RX_VK_FSR4=1` without FSR 4 compiled in does the same. `dlss_why()` and `fsr4_why()` are cheap and don't call back into `fsr3_wanted`, so gating on them would keep FSR 3.1 as the fallback: ```cpp bool temporal_env_chosen() { if (env_dlss() > 0) return dlss_why() == DLSS_OK; return env_fsr4() > 0 && fsr4_why() == FSR_OK; } ``` (DLSS still comes before FSR 4, as in `temporal_mode`.) You could also say this is just what 'goes over the row' means, since a saved DLSS row on an AMD card gives you the game's own upscale too. Either way works for me.
Commenting is not possible because the repository is archived.
No description provided.