OCIO + nDisplay not producing expected output

The issue is just that when using UE 5.6 or later the resulting colour looks off compared to what 5.5 and pevious versions would produce. I have made 2 other threads about this issue but I didn’t have a repro without using our software and I didn’t know what the actual problem was. However now I have found the error and was even able to make a workaround on the plugin side. I still wanted to explain what I found in case it’s a bug and not intended.

The specific code that causes the problem is this in UnrealEngine.cpp line 2199:

if (IsDefaultBackBufferLinearSDR())
{
    DisplayGamma = 1.0f;
}

This was added in this commit: https://github.com/EpicGames/UnrealEngine/commit/5ca4e76b4b106a5ae1a5cccd4383e2587b80f17a

If I comment this bit out then I get the colour I expect. So this sets the DisplayGamma to be linear if the default back buffer is FloatRGBA. This in turn causes FDisplayClusterViewportProxy::GetResourceColorEncoding_RenderThread to return linear as the colour encoding because of this logic:

const float DefaultDisplayGamma = UTextureRenderTarget::GetDefaultDisplayGamma();
const float DisplayGamma = Contexts[0].RenderThreadData.EngineDisplayGamma; // is 1.0
if (DisplayGamma == DefaultDisplayGamma) // They don't match
{
    return { EDisplayClusterColorEncoding::Gamma };
}

// Custom gamma value is different from default
return { DisplayGamma }; // Linear encoding

This seems to create one issue where when the InternalRenderTarget resolves to the InputShaderResource there is some conversion that occurs because the encodings don’t match. This makes the final output look brighter than expected. That’s not the only issue though

The second consequence of this is that when calculating the gamma correction before OCIO in FOpenColorIORendering::AddPass_RenderThread (the one without the gamma parameter) it is different than previous versions because of the new 1.0 display gamma value

float DisplayGamma = (View.Family->EngineShowFlags.Tonemapper == 0) || (View.Family->EngineShowFlags.PostProcessing == 0) ? DefaultDisplayGammaRT : DefaultDisplayGammaRT / EngineDisplayGamma;

Since EngineDisplayGamma is now 1.0 the resulting DisplayGamma is 2.2 instead of 1.0. This is what results in the weird colour output.

So was this an oversight ? Why is the display gamma now always 1.0 when the back buffer is FloatRGBA ? I have attached the captures from 5.7 and 5.5 so you can see the difference.

Capture_5_5.jpg(73.9 KB)
Capture_5_7.jpg(77.8 KB)

Thanks for the detailed report. We have created a jira for tracking which should become public (UE-366670).

The CL you mention was to fix a longstanding issue where users would enable the FloatRGBA backbuffer project setting, and the editor user interface would look completely washed out. Unfortunately, DisplayGamma remains highly problematic throughout the engine (see UTextureRenderTarget::GetDefaultDisplayGamma()), since it acts both as a boolean and a gamma value.

However, Disguise is certainly one of the very few valid use cases for this setting (such that the backbuffer can be copied/DMA’ed while maintaining precision). Will continue investigating.

Quick update on this issue.

Upon further review, the crux of the issue is that when users set their backbuffer to FloatRGBA, we must output linear colors. In fact, this is enforced by DXGI: if you try to use a G22 DXGI_FORMAT_R16G16B16A16_FLOAT backbuffer, you get this error:

Attempting to set G22 on a float16 backbuffer is actively rejected: "DXGI ERROR: IDXGISwapChain3::SetColorSpace1: Unsupported ColorSpace specified. [ MISCELLANEOUS ERROR #262: ]"

As such, we cannot revert the previous fix, but instead must continue outputting linear colors (which does imply a linear color space output in OCIO transforms):

https://github.com/EpicGames/UnrealEngine/commit/628ddcb23d5f2d07627c585c1a845a2caa5652da

https://github.com/EpicGames/UnrealEngine/commit/ac81661033ce29c0581a5aeaa8551277afda8fbc

nDisplay fixes will be next.