Monitor Display Changes and HDR with DXGI
This article provides an overview of how Windows applications use the DirectX Graphics Infrastructure (DXGI) to detect display connectivity changes and query High Dynamic Range (HDR) capabilities. It covers the detection of display topology shifts through Windows messaging and DXGI factory status checks, the retrieval of color space metadata using updated DXGI interfaces, and the necessary adjustments required to update swap chains for seamless HDR rendering.
Detecting Display Connectivity and Topology Changes
DXGI does not natively provide a standalone, push-based event system specifically for display hot-plugging. Instead, applications monitor display connectivity changes by combining the Win32 window messaging loop with DXGI factory validation.
- Listen for System Notifications: The application's
window procedure should intercept the
WM_DISPLAYCHANGEandWM_SETTINGCHANGEmessages. The operating system broadcastsWM_DISPLAYCHANGEwhenever the display resolution, color depth, or multi-monitor topology changes. - Verify DXGI Factory State: An existing
IDXGIFactoryinstance can become stale after a display event or GPU driver restart. CallingIDXGIFactory::IsCurrent()returnsFALSEif the underlying display topology has changed. - Re-enumerate Outputs: If
IsCurrent()returnsFALSEor aWM_DISPLAYCHANGEmessage is received, release the outdatedIDXGIFactoryinstance and create a new one usingCreateDXGIFactory2. Next, iterate through adapters usingIDXGIFactory::EnumAdaptersand their corresponding displays usingIDXGIAdapter::EnumOutputsto rebuild the list of active display outputs.
Querying HDR Capabilities
HDR metadata and capabilities are associated with specific display outputs rather than the GPU adapter as a whole. To inspect HDR characteristics, the application queries modern DXGI output interfaces.
- Obtain
IDXGIOutput6: Acquire anIDXGIOutputinterface for the target display (either from adapter enumeration or viaIDXGISwapChain::GetContainingOutput) and callQueryInterfaceto retrieve anIDXGIOutput6pointer. - Retrieve
DXGI_OUTPUT_DESC1: CallIDXGIOutput6::GetDesc1to fill theDXGI_OUTPUT_DESC1structure. This structure extends legacy display information with vital colorimetry and luminance data:- ColorSpace: A
DXGI_COLOR_SPACE_TYPEvalue indicating the current color space of the display. If the display is in HDR mode, this will typically reportDXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020(HDR10). - Luminance Parameters:
MinLuminance,MaxLuminance, andMaxFullFrameLuminancedefine the minimum, peak, and sustained nit values supported by the panel. - Gamut Coordinates:
RedPrimary,GreenPrimary,BluePrimary, andWhitePointdefine the chromaticity coordinates for tone mapping.
- ColorSpace: A
- Evaluate HDR Active State: A monitor may physically
support HDR, but the user may have disabled Windows HD Color in system
settings. HDR is actively enabled on the target display only when
DXGI_OUTPUT_DESC1::ColorSpacematchesDXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020andMaxLuminanceexceeds standard SDR thresholds (typically 80 to 100 nits).
Updating the Pipeline and Swap Chain
When a display change or HDR toggle is detected, the rendering pipeline must dynamically adapt to prevent visual clipping or incorrect color mapping.
- Select the Back Buffer Format:
- For HDR10, configure the swap chain with
DXGI_FORMAT_R10G10B10A2_UNORM. - For scRGB, configure the swap chain with
DXGI_FORMAT_R16G16B16A16_FLOAT, which allows rendering values outside the standard [0.0, 1.0] range into linear space.
- For HDR10, configure the swap chain with
- Apply the Color Space: Call
IDXGISwapChain3::SetColorSpace1on the swap chain to match the desired color output:- Use
DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020for HDR10/PQ. - Use
DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709for scRGB linear. - Revert to
DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709if the display operates in standard SDR.
- Use
- Handle Window Repositioning: When a window
transitions across monitors in a multi-display setup, listen for
WM_MOVE. Retrieve the new containing output viaIDXGISwapChain::GetContainingOutput, re-run theIDXGIOutput6::GetDesc1query, and invokeSetColorSpace1to match the configuration of the current target monitor.