feat(fsr4): FSR 4 for the game's native HDR, given linear light #2342
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
No milestone
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!2342
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/fsr4-native-hdr"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
With HDR on Native and AMD FSR 4 as the upscaler, every highlight is cut at the paper white. #2243 gives DLSS the game's HDR colour as linear light, but FSR 4 keeps its LDR context and the chain's clamped colour ("FSR 4 has none and keeps the LDR pair"). This PR gives FSR 4 the same treatment, on #2243's mechanism.
What changed
vk_fsr4.cpp: whilepresent_native_pqsays the game presents PQ, FSR 4's context is made withFFX_UPSCALE_ENABLE_HIGH_DYNAMIC_RANGE | FFX_UPSCALE_ENABLE_AUTO_EXPOSURE(linear colour, AMD's own exposure) instead ofFFX_UPSCALE_ENABLE_NON_LINEAR_COLORSPACE.FFX_UPSCALE_FLAG_NON_LINEAR_COLOR_SRGB. On Linux, the unit exposure image the LDR context needs isn't passed: the HDR context works out its own.TemporalEngine::hdr, so the chain uses #2243's HDR pair: linear light in, unclamped, and the linear picture out as it is.RX_VK_FSR4_HDR=0keeps the LDR context and the clamped colour with Native too, for comparisons (docs/development.md, the readme's FSR 4 section).test_hdr_encode.py's newcheck_fsr4checks:preparekeys the context onpresent_native_pqand remakes it when that changes;hdr.It fails on #2243 without this commit.
docs/tested-configurations.md: the run below.Testing
tests/run_all.py: 363 passed, 0 failed, 11 skipped (Linux), on main49f75dc8+ #1941 + #1942 + #2243 + this commit. The renderer builds with and withoutHOOKSHOT_FSR.In game: RX 9070 XT 16 GB, Mesa RADV 26.2.6, Gentoo Linux (kernel 7.3.3), KDE Plasma Wayland, windowed.
49f75dc8+ #1941 + #1942 + #2243 + this commit. #2243 is based ond7a7306, which has renderer API 14, while this host needs 15, so the stack was cherry-picked onto current main for testing. All four commits apply cleanly.RX_VK_FSR4_HDR=0(as with #2243 alone)AMD FSR 4: FSR 4.1.1 Vulkan FP8 made for outputs of 2560x1440 ..., HDR colour, linear (the game's native HDR).Not tested:
🤖 Generated with Claude Code
Reviewed the last commit (
6b55c5ba); the rest of the diff is the #1941/#1942/#2243 stack, so this has to merge after those (or along with them). Nobody has reviewed #2243 yet either.This looks right to me, and it closely follows what #2243 does for DLSS:
present_native_pq, not on the option, so Native with a non-PQ picture stays LDR. It's made again when that changes, with the same reason in the log as DLSS's.FFX_UPSCALE_ENABLE_HIGH_DYNAMIC_RANGE | FFX_UPSCALE_ENABLE_AUTO_EXPOSUREwith noNON_LINEAR_COLORSPACE, and the dispatch flags go to 0. That matches what the chain feeds it throughTemporalEngine::hdr: #2243'sprep_hdr/out_hdrpair, linear light in an R16G16B16A16_SFLOAT colour image and linear back out (out_hdr_square = false).preExposurestays 1, which is right with auto exposure. Skipping the Linux unit exposure image for the HDR context is correct; leaving it in would mean an exposure of 1 on top of the auto-exposure flag.hdr()reads the context thatpreparejust made, and the temporal pass callspreparebefore choosing the prep/out pipelines, so the chain and the context can't disagree within a frame.The test on real RDNA4 hardware (9070 XT, fsr4-vk 4.1.1 FP8) with the A/B through
RX_VK_FSR4_HDR=0is convincing: highlights go past 132, the rest of the scene stays within a code value, and brightness holds steady. The auto vs. unit exposure comparison is useful too.Things that are still open, all listed under Not tested:
Duplication with #2243 is small and fine for now: both engines repeat the
extern present_native_pqand thehdr_allowed && present_native_pqkey. If a third engine ever needs this, it could move intovk_temporal.h, or the chain could pass it toprepare. Not for this PR.CI only has the Conventional Commit title check here (pending), the same as on #2243; the stack's test run is the one in the description. Approving this commit; it's good to go once #1941, #1942 and #2243 are in.
Nit (shared with #2243's DLSS
prepare):present_native_pqis stored asfalseon any present without a texture (tex && ...indo_present). So if the game ever presents a frame with no texture, or switches to a non-PQ picture for a moment (a movie or a loading frame) while Native is on, the FSR 4 context is torn down and made twice, which costs a hitch and drops the history each time. I don't think it happens in normal play, but it would be worth looking for repeatedmade again: the game's native HDR turnedlines in a longer HDR session. If they show up, a few frames of hysteresis would fix it for both engines.Checked rather than changed: three 90 s HDR Native sessions with FSR 4 Native AA (RX 9070 XT, RADV 26.2.6, two with a warp to Castle Town and its loading frames) each made FSR 4's context once and logged no
made again: the game's native HDR turnedline. The presented picture changed from the SDR expansion to PQ only at start, before FSR 4 drew, so no hysteresis for now; if it shows up later it fits best in the sharedpresent_native_pq(both engines).🤖 Addressed by Claude Code
github-sync referenced this pull request2026-11-12 06:22:54 +00:00