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:
MinLuminanceprovides min luminance in nitsMaxLuminanceprovides max luminance in nits, likely for just a small area of the displayMaxFullFrameLuminanceprovides 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:
maximumPotentialExtendedDynamicRangeColorComponentValueshould 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.maximumExtendedDynamicRangeColorComponentValueshould 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.wantsExtendedDynamicRangeContentonCAMetalLayer - 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.