godot icon indicating copy to clipboard operation
godot copied to clipboard

[WIP Prototype] Add HDR support to tonemappers

Open allenwp opened this issue 6 months ago • 12 comments
trafficstars

This prototype demonstrates how tonemappers could behave when HDR output is enabled. Please provide feedback in the comments! You can use Windows Game bar to take HDR screenshots OBS Studio has good support for HDR video recording as well (let me know if you want me to give you OBS configuration details).

This branch builds on top of #94496. Please share any feedback relating to HDR (not tonemappers) on that PR instead! Many of the changes from this PR should be merged in a separate PR, as these changes include adding white parameter support to the AgX tonemapper, which is required independently of HDR output support.

This draft PR implements godotengine/godot-proposals#12317, including the addition of two new tonemaping user parameters: black and contrast, both of which I feel are required for flexible and stable HDR output behaviour. Please review this proposal for rationale.

Importantly, Flimic and ACES tonemappers cannot support HDR output. This is because the white parameter of these tonemappers was designed exclusively for SDR and this style of white parameter cannot work with HDR and variable Extended Dynamic Range (EDR). This PR demonstrates how they should behave in HDR mode: exactly the same as they behave in SDR mode, limited to [0.0, 1.0] range.

Because Filmic cannot support HDR mode, I have introduced a new tonemapper that is HDR-compatible to replace it: the Adjustable tonemapper. Unlike AgX, this tonemapper does not desaturate colours to white as they become very bright and applies the tone curve directly in the linear sRGB working colour space, just like Filmic does. It's configuration parameters match AgX and it can be configured to appear similar to Filmic in SDR.

Check out videos of how this new "Adjustable" tonemapping curve works on my blog post.

On a related note, the new configuration parameters of AgX (specifically contrast) can be used to make it appear similar to ACES, but with correct HDR output support.

Usage

Download windows-editor build artifact here.

The basics of tonemapping in Godot is covered in the docs. In this PR I've updated the in-engine docs to have some more detail.

HDR output is covered in detail in the original PR #94496, but here's a quick summary:

  1. Enable 2D HDR: rendering/viewport/hdr_2d
  2. Enable HDR output: display/window/hdr/enabled

To control HDR brightness settings:

Option 1: Simply change the SDR content brightness in Windows (you might need to move or resize the Godot window to force it to refresh): image

Option 2: Disable display/window/hdr/use_screen_luminance and manually set the Reference Luminance (this is equivalent to SDR content brightness) and Max Luminance.

Note: Reducing the max luminance with Option 2 may be necessary to circumvent the built-in tonemapping of your display.

Performance

Performance of the AgX tonemapper is better than the current implementation in master. I wasn't able to get as good of performance as my best attempt using Timothy Lottes' curve in #102435, but the stability and predictability of the curve in this PR across all of variable EDR is a reasonable trade off that gives a significantly better user experience when targeting both SDR and HDR.

A number of additional parameters are now passed from the CPU to the GPU, increasing the number of bytes passed into the tonemapper. This has a minor impact on performance (barely measurable on my NVIDIA 980 Ti for a 4K window). Unfortunately, this affects all tonemappers... which leads me to my next point:

Adding another tonemapper to Godot, as it is currently implemented, causes a notable performance degradation to all tonemappers. This happened in Godot 4.4 when AgX was added to Godot, and it will happen again when the new Adjustable tonemapper is added. Work needs to be done to address this at a structural level.

The black parameter makes ALL tonemapping notably slower. I haven't looked into how this can be optimized yet; this PR simply demonstrates how it should look when it is correctly implemented.

Limitations

  • Windows only
  • Currently only works with Mobile and Forward+ rendering methods.
  • Optimization work is not complete: It's possible these changes cause a minor performance regression and performance of the new tonemappers is not representative of their final optimized form.

Known Issues

  • My intent is for Reinhard to behave differently than SDR when white is less than 1.0 and HDR has been enabled. The code currently checks to see if max_value != 1.0 instead of checking if HDR is enabled, but this is incorrect because max_value can equal 1.0 when HDR is enabled and reference_luminance == max_luminance.

allenwp avatar May 21 '25 21:05 allenwp