Skip to content

AutoHDR: Use display-reported peak luminance to prevent HDR clipping#14486

Open
jasaaved wants to merge 9 commits intodolphin-emu:masterfrom
jasaaved:HDR-Tests
Open

AutoHDR: Use display-reported peak luminance to prevent HDR clipping#14486
jasaaved wants to merge 9 commits intodolphin-emu:masterfrom
jasaaved:HDR-Tests

Conversation

@jasaaved
Copy link
Copy Markdown

Overview

When the HDR nit value is set higher than what a display can actually reproduce, HDR values get clipped. Because RGB channels don’t clip at the same point, this can cause hue shifts that make colors appear neon or fluorescent.

This often looks brighter or more intense at first glance, but it’s actually an artifact of clipping rather than correct HDR behavior.

This is easy to trigger since most users don’t know their display’s actual peak brightness and end up setting a value that’s too high.

This PR queries the display’s peak luminance directly from the OS on DirectX 11/12 backends and exposes it to post-processing shaders, so users don’t have to guess or manually enter it.

Changes

  • Adds QueryDisplayHDRCapabilities() to the D3D swap chain (called on swap chain creation and recreation)
    • Queries:
      • Peak and minimum luminance via IDXGIOutput6
      • SDR white level via WinRT DisplayInformation
  • Stores results in BackendInfo
  • Exposes new shader uniforms:
    • hdr_max_luminance_nits
    • hdr_min_luminance_nits
    • hdr_sdr_white_nits
  • Adds "Use Display Peak Luminance (DX11+)" checkbox to the AutoHDR shader
    • Uses queried peak instead of manual slider
    • Prevents values from exceeding display capability
  • Disables manual nit slider when enabled (re-enabled if unchecked)
  • Replaces hardcoded SDR white (80 nits) with queried value

Backend / Requirements

  • Requires DirectX 11 or DirectX 12 with HDR enabled
  • On other graphics APIs (Vulkan/OpenGL), the original behavior is used and default values are preserved

Notes

  • Recommended to run the Windows HDR Calibration app beforehand
    (ensures OS-reported luminance values are accurate)

Testing

  • Enable HDR with D3D11 or D3D12
  • Open the AutoHDR shader configuration
  • Enable "Use Display Peak Luminance (DX11+)"
  • Verify:
    • Slider updates to detected peak and is disabled
    • Colors no longer show clipping/neon artifacts
    • Value persists after window resize, swap chain recreation
    • Value updates correctly when moving the window to a different monitor

Query the display's HDR min/max luminance and feed those values into the post-processing pipeline and shaders.

- Add SwapChain::QueryDisplayHDRCapabilities(), include dxgi1_6, and call it during swapchain creation and resize to populate g_backend_info.hdr_max_luminance_nits and hdr_min_luminance_nits.
- Extend BackendInfo with hdr_max_luminance_nits and hdr_min_luminance_nits.
- Add hdr_max_luminance_nits/min to the built-in uniform block and fill them in PostProcessing::FillUniformBuffer so shaders can access actual panel values.
- Update AutoHDR.glsl to use the reported hdr_max_luminance_nits (with a fallback to HDR_DISPLAY_MAX_NITS) when computing the auto-HDR white scaling.

This enables more accurate AutoHDR tonemapping by using the display's real luminance capabilities when available.
Obtain SDR white data from the display when it is available.
If the user hasn't set a HDR DISPLAY MAX NITS, the first time a game is launched using DirectX11 or 12, the queried display values are saved in the ini

Of course user settings always take preference.

But for someone that doesn't have the HDR settings set, the correct default value should be set so clipping and those bright neon/fluorescent colors can be avoided.
Perceptual HDR does not benefit from the queries we make for luminance so we can restore the default values and the original code.
If checked, display peak will always be used. Works even across different devices if ini is saved on the cloud. Or game is changed between different displays.
-Whenever the config setting for AutoHDR is loaded, the current display nits are shown on the slider.

-Added some text to the checkbox clarifying DX11+ API is needed for this feature to work properly.
Also removed an old comment that no longer applies to current code.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant