Repository navigation
fix(hdr): Sharpness with HDR, and DLSS for the game's native HDR - #1940
j64esatxzdrhfg wants to merge 1 commit into
Conversation
With HDR on, the picture went black whenever Sharpness, the Window scaling filter or ultrawide's menu sides were on. With HDR on Native, DLSS was made for LDR colour and its inputs pass clamped the scene to 1, so every highlight was cut at the paper white: a flat, SDR-looking picture. - vk_framegen.cpp: framegen_scale's picture is made with SAMPLED usage. The HDR pass (framegen_hdr) samples it through framegen_scaled_view; made without it, the pass read black. - vk_dlss.cpp, vk_temporal.cpp/.h: with the game's native HDR (the Insert menu's HDR on Native, on an HDR10 swapchain) DLSS's feature is made with IsHDR | AutoExposure, and made again when that turns on or off. The engine says so through TemporalEngine::hdr, and the chain then runs dlss_prep.comp with its colour ceiling (kColorMax, a specialization constant, 1 by default) at 16384. FSR 4 has no hdr() and keeps the clamped colour. - shaders/dlss_prep_comp_spv.h: glslangValidator 16.6.0 -V --target-env vulkan1.3 --vn DLSS_PREP_COMP_SPV from dlss_prep.comp (the version CI pins). - vk_replay.cpp: one log line when the presented format or the HDR path changes, for HDR reports. - tests: test_hdr_encode.py checks the scaled picture's SAMPLED usage and the native-HDR DLSS path; upscale_independent_test.cpp expects the new usage. The local patch's menu part is left out: main draws the menu, the FPS counter and the start-up screen with Dear ImGui into a view of the swapchain in its own format, and on an HDR10 swapchain their colours and the logo are PQ coded at the paper white (vk_imgui.cpp hdr10). No 8-bit bitmap is copied into the 10-bit image any more. Tested before the port, on v2.0.13: RTX 5080, 3840x2160 HDR10, Sharpness 0 and 50 with Expanded. The port compiles with the build's clang and passes the game-free checks; it has not been run in the game. Assisted-by: Claude Code Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Confirming the Setup: v2.0.14 release (source 3a9998c3), Windows 11 Pro 26200, RTX 5090 at driver 621.14, a single 3840x2160 HDR10 display, DLSS Quality. Before: HDR Expanded gave a black picture and Native gave a flat one, with frame generation off or on, as in #1613. Run with That's After: with only Native, as data for #1942 / #1941: I tried the same cause #1942 describes on v2.0.14 (Native also told by
|
ghost
left a comment
There was a problem hiding this comment.
Thanks. The SAMPLED fix in framegen_scale is correct and ready. It's the exact error @sling86 got from the validation layer on a 5090 (VUID-VkWriteDescriptorSet-descriptorType-00337 on scale.scaled), and they saw the same one-flag change fix Expanded. The test changes cover it.
The DLSS-for-Native half reads fine as code. The feature is made again when feature_hdr flips. The second dlss_prep pipeline with the specialization constant is wired correctly (map entry 0/0/4, layout and push constants match). hdr() follows what prepare made in the same frame. FSR 4's kEngine still compiles, since hdr defaults to null. I rebuilt dlss_prep_comp_spv.h with glslang 16.6.0 (--target-env vulkan1.3) and it matches the PR byte for byte. Two things before I'd call that half done:
- Nothing shows yet what it does in game. The testing and screenshots cover Sharpness with HDR Expanded only. There's no Native-with-DLSS before/after. sling86's data from the Native path (the picture looks almost like SDR, and going from 1200 to 4000 nits peak changes nothing) suggests the game's own grade may rarely go past 1. A before/after pair, or the largest scene value seen with Native on, would back up "clips every highlight at the paper white".
- Your question about linear input: NVIDIA's guide documents
IsHDRas linear radiance, andAutoExposureworks out its exposure from that signal. With the square-root encoding, DLSS's internal tonemap and auto exposure both see a compressed signal. That probably explains why it still looks fine, but it isn't what the network was trained on. In the HDR variant you could square indlss_prepand skip the square indlss_out(one more specialization constant on each), so DLSS gets linear light. That's not a blocker, but I'd lean towards linear. Details inline.
Stacking: #1941 and #1942 carry this commit (eea8875) as their first, so they'll rebase cleanly once this lands. #1831 carries the same SAMPLED line, as the description says. No CI ran on this branch (fork workflows not approved yet), so nothing is green or red here.
The Sharpness fix alone could merge today. Whether the DLSS-Native part goes in as is, or waits for an in-game comparison, is @NotRexed's call.
| const char** fail) { | ||
| State& s = st(); | ||
| const unsigned preset = wanted_preset(); | ||
| const bool hdr = dev.hdr && opts.hdr == 2; // (the game's native HDR: State::feature_hdr) |
There was a problem hiding this comment.
A small one: this gate is the option and the swapchain, not what the game actually presents. With Native picked but the game's picture not taking the PQ path (present_native_pq false, the case #1942 is about), DLSS still gets an IsHDR | AutoExposure feature fed LDR content. That's probably harmless, but it's a different network mode with its own exposure. Once #1942 settles how Native is detected, it may be worth keying this on the same test.
| // (LDR colour, already tonemapped: no exposure; motion at the render size, not jittered; depth not reversed. With the | ||
| // game's native HDR the colour goes past 1: an HDR feature, with DLSS's own exposure) | ||
| cp.InFeatureCreateFlags = NVSDK_NGX_DLSS_Feature_Flags_MVLowRes | | ||
| (hdr ? NVSDK_NGX_DLSS_Feature_Flags_IsHDR | NVSDK_NGX_DLSS_Feature_Flags_AutoExposure : 0); |
There was a problem hiding this comment.
On the linear-input question: with IsHDR, NVIDIA expects linear scene colour, and AutoExposure reads exposure from it. This passes the square-root encoded value, so both see a compressed signal. A kSquare constant in dlss_prep (c*c for the HDR pipeline) plus a matching one in dlss_out (no c *= c after) would hand DLSS linear light and give the same output scale. Not blocking.
|
Closing this: the fix landed in main with #2038 (0a28ff2), the same The DLSS-for-Native part will come as its own PR after an in-game comparison. As reviewed, it gives DLSS linear input and is gated on the format the game presents. #1941 and #1942 are rebased straight onto main without this commit. |
With HDR on, the picture goes black as soon as Sharpness, the Window scaling filter or ultrawide's menu sides are used, and with HDR on Native, DLSS clips every highlight at the paper white.
What changed
vk_framegen.cpp:framegen_scale's image is created withSAMPLEDusage. The HDR pass samples it throughframegen_scaled_view; without the flag it read black. (feat(vk): DLSS frame generation (NGX), more actor motion for DLSS, FidelityFX FSR 4 fallback (builds with #1833, #1834) #1831 carries the same one-line fix as part of its series; whichever lands first, the other drops it.)vk_dlss.cpp,vk_temporal.cpp/.h: with Native HDR on an HDR10 swapchain, DLSS's feature is created withIsHDR | AutoExposureand recreated when that changes (TemporalEngine::hdr). The chain then runsdlss_prep.compwith its colour ceiling, the new specialization constantkColorMax(1 by default), at 16384. FSR 4 has nohdr()and keeps the clamped colour.shaders/dlss_prep_comp_spv.h: regenerated with glslang 16.6.0 (the version CI pins).vk_replay.cpp: one log line when the presented format or the HDR path changes, for HDR reports.test_hdr_encode.pychecks theSAMPLEDusage and the native-HDR DLSS path;upscale_independent_test.cppexpects the new usage.Testing
tests/run_all.py: the checks touching this pass. The ones failing here fail the same on untouched main (local toolchain:present_aspect_vulkan,fpx_sticky).Not tested: AMD/Intel GPUs, FSR 4 with Native HDR, Linux.
A question for review: DLSS gets the chain's existing (square-root encoded) colour with
IsHDR, not linear light. It looked right in game, but you may prefer linear input.Screenshots (HDR Expanded, Sharpness 100%; before the fix this picture was black)
HDR10 captures, tone-mapped to SDR for this page (paper white to white, highlights rolled off up to 800 nits).
🤖 Generated with Claude Code