HDR not working on WindowsD3D12 Platform with DCI-P3 Monitor?

Hello! I’m exploring setting up HDR for our game and running into an issue on a HDR10 LG DCI-P3 90% monitor.

Some background: Our studio traditionally relied on sRGB LUTs for color grading (it’s what our artists are comfortable with) but reading the docs I saw that they have the downside of forcing output to LDR. I’ve been reading through source code to try to understand the UE ACES implementation, and wanted to see how well colours were preserved on some test monitors.

I started by enabling HDR in blueprints as suggested here and enabling HDR in my Windows display settings, but it looked off. I found ChooseHDRDeviceAndColorGamut and confirmed that the OutputDevice and ColorGamut were being set to SDR_sRGB and sRGB_D65 respectively. I figured it must be because of the WITH_EDITOR preprocessors, so as a test, I commented the editor case entirely and rebuilt the engine. I also added these lines to the project DefaultEngine.ini:

r.AllowHDR=1
r.HDR.EnableHDROutput=1

Execution then hit FD3D12Viewport::EnsureColorSpace. Because the OutputDevice was now HDR_ACES_1000nit_ST2084, DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 was passed into SwapChain4->CheckColorSpaceSupport, which would fail and result in these logs:

LogD3D12RHI: Error: Warning: unabled to set color space RGB_FULL_G2084_NONE_P2020 to the swapchain: verify EDisplayOutputFormat / swapchain format.I felt like this made sense as the monitor’s color space was DCI-P3, not Rec. 2020.

This lead me to look at the DXGI_COLOR_SPACE_TYPE itself, and I learned there’s no entry for DCI-P3 at all. I believe this means that on Windows, OutputGamut never matches TONEMAPPER_GAMUT_DCIP3_D65 and that matrix would never be applied. Does this mean that on Windows, only Rec2020 and sRGB/Rec709 are supported? That there never was support for DCI-P3? Or is there something wrong with how I’m making the engine modification to test this?

If DCI-P3 isn’t supported, what’s best practice for detecting this case and disabling HDR? I’m not sure what to do here aside from calling CheckColorSpaceSupport directly myself and checking if it fails, which seems hacky?

Thanks for reading!

[Attachment Removed]

Steps to Reproduce

  1. Run any UE project on Windows with a DCI-P3 color space monitor
  2. Enable HDR (more details in post)

Actual behaviour: No HDR applied?

Expected behaviour: HDR applied

[Attachment Removed]

Hi,

I’m verifying what the state of DCI-P3 support is, but at first glance we only mention it in our Mac platform HDR code in MacPlatformMisc.h.

What’s best practice for detecting this case and disabling HDR?

We don’t have a great way to detect if EnsureColorSpace will fail on DX12 so you can disable HDR, currently discussing with my colleagues if we intend to expose this functionality somewhere. In Fortnite, we use the engine default (ChooseHDRDeviceAndColorGamut) and rely on HDR being enabled at the OS level and don’t let the user pick an alternate color gamut.

[Attachment Removed]

OK, there may be additional feedback to add later, but here’s what should be happening. Without engine modifications, the Editor should use HDR if you enable HDR in your Windows display settings and r.AllowHDR=1. In Editor, you should get RGBA16F (WindowsD3D12Device.cpp:1947 & WindowsPlatformMisc.h:370) and scRGB to support negative values and values beyond Rec.2020. ChooseHDRDeviceAndColorGamutshouldn’t return any SDR OutputDevice, only HDR. In game, There is no DXGI DXGI_COLOR_SPACE_TYPE for DCI-P3, all platforms do choose their HDR format through ChooseHDRDeviceAndColorGamut. This is driven which format the swapchain may support. From https://learn.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range you can see the different options used for the swapchain. The editor will choose DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709 while the cooked game will use DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020. Both color spaces are larger than DCI-P3. When the Rec.2020 exceeds the monitor color space (DCI-P3) clipping will occur. With the new ACES2 tonemapper (USE_ACES_2) the amount of clipping should be little to none if the display reports correctly. If the above isn’t happening for you, then we likely have a bug somewhere and need to address it.

One thing that was new to me in talking to my colleagues about this is that we’ve added HDR setting to Lyra in 5.8 that may be helpful:

CL#51352403 (db3770) Add HDR settings to Lyra

- Allow HDR: Enable HDR if the display is capable of it

- HDR Use Calibration: Use UGameUserSettings::HDRDisplayOutputNits if true, use OS display info otherwise

- HDR Calibration: Enter the calibration flow to update UG…

Hope that helps, please let me know if you aren’t seeing HDR enabled in Editor without the Blueprint, and if you see clipping or other color/brightness issues.

[Attachment Removed]

Hi Alex,

You’re right about ChooseHDRDeviceAndColorGamut, I misread ScSRGB as sRGB and was missing the key information that it can go into negatives to exceed the sRGB primaries. It was hard to tell if what I was seeing on screen was correct, so I went through code, saw the multiplication by `AP1_2_sRGB` in PostProcessDeviceEncodingOnly.usf, and assumed it was still in SDR. My mistake, I see now that the ACESOutputTransform(…) line lifts colours above 1.0 range once converted to sRGB, which I confirmed with RenderDoc captures. I also confirmed that the blueprint changes are not necessary for execution to enter that function, only r.AllowHDR=1.

Thanks for confirming that DCI-P3 is not targeted on Windows, and directing us to Lyra in 5.8. We just implemented options based on Lyra so it shouldn’t be hard to integrate the HDR settings as well. We’ll go with ACES 2 to minimize colour clipping, as you suggest. Thanks a lot!

[Attachment Removed]