Skip to content

Instantly share code, notes, and snippets.

@equalent
Last active February 16, 2024 13:03
Show Gist options
  • Save equalent/ee23621627169a86d52301cf40f39fdd to your computer and use it in GitHub Desktop.
Save equalent/ee23621627169a86d52301cf40f39fdd to your computer and use it in GitHub Desktop.
HDR Output

HDR Output

This is an overview of HDR output support on different platforms.

DXGI

Windows 10 Creators Update added native HDR support to DXGI:

  • must be enabled for display in Settings
  • requires flip-mode swap chain

Detecting HDR

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);

Display metadata

In DXGI_OUTPUT_DESC1:

  • MinLuminance provides min luminance in nits
  • MaxLuminance provides max luminance in nits, likely for just a small area of the display
  • MaxFullFrameLuminance 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.

Rendering

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.

References

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

macOS calls its HDR features EDR (extended dynamic range).

Detecting HDR

CAMetalLayer always supports EDR.

Dispay metadata

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.

Rendering

  • use RGBA16Float format
  • set metalLayer.wantsExtendedDynamicRangeContent on CAMetalLayer
  • 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);

References

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

Vulkan

It's a mess right now, can't document it properly. Use Vulkan only on Linux.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment