This is an overview of HDR output support on different platforms.
Windows 10 Creators Update added native HDR support to DXGI:
- must be enabled for display in Settings
- requires flip-mode swap chain
For any IDXGIOutput
:
- obtain
IDXGIOutput6
- use
GetDesc1
- HDR color space will be:
RGB_FULL_G2084_NONE_P2020
- SDR color space will be:
RGB_FULL_G22_NONE_P709
Sample code:
IDXGIOutput6 *output6 = nullptr;
output->QueryInterface(&output6)
DXGI_OUTPUT_DESC1 oDesc;
output6->GetDesc1(&oDesc);
bool supportsHDR = (oDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020);
In DXGI_OUTPUT_DESC1
:
MinLuminance
provides min luminance in nitsMaxLuminance
provides max luminance in nits, likely for just a small area of the displayMaxFullFrameLuminance
provides max luminance in nits that's valid for the entire display
IDXGIFactory1::IsCurrent
can be called each frame to notify the app when display properties change.
The recommended way to render HDR content is
to use DXGI's RGB_FULL_G10_NONE_P709
color space with R16G16B16A16_FLOAT
back buffer.
Do not use RGB10 for back buffers!
The color space RGB_FULL_G10_NONE_P709
:
- linear sRGB with extended range = scRGB
- native composition format on Windows
- luminance is 80 nits for (1,1,1), so 1000 nits white is 12.5
- color primaries are Rec 709 / sRGB
- wide gamut supported via negative colors
How to use:
- obtain
IDXGISwapChain3
- check support using
CheckColorSpaceSupport
- set color space using
SetColorSpace1
Never use SetHDRMetaData
, obtain the range from DXGI_OUTPUT_DESC1
and tonemap to it.
https://learn.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range https://developer.nvidia.com/downloads/hdr-gdc-2018 https://www.asawicki.info/news_1703_programming_hdr_monitor_support_in_direct3d
macOS calls its HDR features EDR (extended dynamic range).
CAMetalLayer
always supports EDR.
NSScreen
provides two values:
maximumPotentialExtendedDynamicRangeColorComponentValue
should be used for checking the EDR capability of the display. If the value is 1.0, the display does not support EDR. If it's greater, the display supports EDR.maximumExtendedDynamicRangeColorComponentValue
should be used after requesting EDR for tonemapping
The metadata corresponds directly to component values with (e.g. 100 nits = 1.0; 1000 nits = 10.0).
NSApplicationDidChangeScreenParametersNotification
can be used to notify the app when the max component value changes.
- use RGBA16Float format
- set
metalLayer.wantsExtendedDynamicRangeContent
onCAMetalLayer
- set color space to
kCGColorSpaceExtendedLinearSRGB
Sample code:
CAMetalLayer *metalLayer = [CAMetalLayer new];
metalLayer.wantsExtendedDynamicRangeContent = YES;
metalLayer.pixelFormat = MTLPixelFormatRGBA16Float;
const CFStringRef name = kCGColorSpaceExtendedLinearSRGB;
CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(name);
metalLayer.colorspace = colorspace;
CGColorSpaceRelease(colorspace);
https://developer.apple.com/documentation/metal/hdr_content/displaying_hdr_content_in_a_metal_layer?language=objc https://developer.apple.com/documentation/metal/hdr_content/performing_your_own_tone_mapping?language=objc
It's a mess right now, can't document it properly. Use Vulkan only on Linux.