Skip to content

Conversation

@DarkKilauea
Copy link
Contributor

@DarkKilauea DarkKilauea commented Jul 18, 2024

Implements: godotengine/godot-proposals#10817 for Windows.

Overview

This PR enables the ability for Godot to output to HDR capable displays on Windows. This allows Godot to output brighter images than allowed in SDR mode and with more vibrant colors.

HDR output is implemented using Extended Dynamic Range (EDR), which is a technique that preserves the SDR range (of 0 to 1) while extending the upper range to include brighter values, up to the maximum brightness of the display. This approach preserves the shadows and darker areas of the scene while allowing highlights to reach much brighter values.

It also allows for 2D content take advantage of HDR displays by producing brighter colors that have a value over 1.0, without having to opt into tonemapping and the effects pipeline. 2D and 3D content can also be mixed in the same scene while keeping a consistent brightness between the two, based on a shared "reference" luminance.

Testing/Sample projects:

  1. https://github.com/DarkKilauea/godot-hdr-output
  2. https://github.com/allenwp/godot-hdr-output-test-project
  3. [WIP Draft] The HDR mega-PR #110701 This PR combined with other related PRs

Examples (converted to SDR to work on all browsers):

SDR HDR
Sponza SDR output Sponza HDR output
Color Tester SDR output Color Tester HDR output

Examples (HDR images, may not display correctly on all browsers):

SDR HDR
Sponza SDR output Sponza HDR output
Color Tester SDR output Color Tester HDR output

Supported Platforms:

  • Windows

Supported Graphics APIs:

  • Vulkan
  • D3D12

Supported HDR Formats:

  • scRGB (Linear 16-bit color)

Supported Tonemappers:

  • Linear
  • Reinhard

Features:

  • Request a HDR capable swap chain for a window at runtime
  • Automatic luminance adjustment for each window
  • Automatic switching between HDR and SDR output as OS settings change or as the window moves between monitors
  • Opt-in manual control of luminance output for each window
  • Editor automatically updates to use HDR when changed in project settings

Limitations:

  • Enabling HDR output on Windows requires Godot to be compiled with D3D support.
  • Only the Linear and Reinhard tonemappers extend into the additional headroom of the display. This is due to the Flimic ACES, and AgX tonemappers being designed for SDR displays. Updating them to output to an HDR range is not trivial. AgX will be extended into HDR in a future PR.
  • HDR output requires viewports to enable hdr_2d to output the additional dynamic range needed for HDR displays. Blending, glow, color correction, brightness, contrast, and saturation adjustments may look different when hdr_2d is enabled. hdr_2d will automatically be enabled for windows that turn on HDR output, which may result in a change in appearance of the scene. It's advised that applications planning to support HDR output create their content with hdr_2d enabled, even when HDR output is disabled. Future PRs may resolve some of these differences.
  • The mobile renderer is not supported, due to it limiting the dynamic range of the scene. See AgX has low dynamic range output with Mobile renderer #101558 for details. A future PR may lift this limitation.
  • The compatibility rendering method is also not supported, due to it targeting lower end devices that may not support the extensions required for OpenGL to output to HDR capable swap chains.

Follow up work:

Getting Started

Project Settings

  1. Enable display/window/hdr/enabled: godot_hdr_window_settings
  2. Optional (but recommended): Enable rendering/viewport/hdr_2d:
    godot_hdr_viewport_settings
  3. Adjust the environment of your 3D scenes to use Linear or Reinhard as the tonemapper:
    godot_hdr_tonemap_settings

Runtime

  1. First, check that HDR is available (optional: if you turn on HDR for a window that does not support it, HDR will be enabled later when support becomes available):
var window := get_window();
var hdr_supported := window.is_hdr_output_supported();
if hdr_supported:
	print("HDR is supported!");
else:
	print("HDR is not supported.");
  1. Next, we can enable it on our current window:
if hdr_supported:
	var window := get_window();
	window.hdr_output_requested = true;
  1. Adjust the environment of your 3D scenes to use Linear or Reinhard as the tonemapper: godot_hdr_tonemap_settings

Help Needed

Please give this a test, either with the linked sample project or with your own projects, and give feedback. Specifically I'm looking for input on how easy this feature was to use and if you encountered any issues with your particular display, OS, or driver configuration.

@Calinou
Copy link
Member

Calinou commented Jul 19, 2024

I gave this a quick test locally (on Windows 11 23H2 + NVIDIA 560.80 + LG C2 42"), it works as expected. This is encouraging to see, I've been wanting this for a while 🙂

I'll need to look into building more extensive scenes and getting tonemapped screenshots/videos out of this. 2D HDR also needs to be tested thoroughly.

Remember that JPEG XL or AVIF for images and AV1 for videos are a must for HDR, as other formats can only store SDR data. You may need to embed those in ZIP archives and ask users to preview them in a local media player, as GitHub doesn't allow uploading those formats and browsers often struggle displaying HDR correctly.

I noticed some issues for now:

  • Having RTX HDR enabled will mess with the HDR that is enabled in the editor. It will continuously enable and disable itself whenever you make any input in the editor (and disable itself after being idle for a second). This is also an issue on master with HDR disabled.
  • HDR Max Luminance affects both 2D (UI) and 3D rendering. Is that intended?
  • The HDR editor setting is not applied instantly when you change it, even though the demo project shows a working example of it being toggled at runtime. You can update the viewport's status based on editor settings here:
    void EditorNode::_update_from_settings() {
  • There doesn't appear to be a paperwhite setting you can use to adjust UI brightness. This is typically offered in games to prevent the UI from being too bright. Using a paperwhite value around 200 nits is common, since a lot of OLED displays cap out at that brightness level in SDR. Either way, this should be exposed in the project settings and the documentation should recommend exposing this setting to player (just like HDR peak luminance).
    • There should also be a way for unshaded materials to base themselves on paperwhite, so that Sprite3D and Label3D used for UI purposes are not overly bright in HDR. I suppose this would be a BaseMaterial3D property or a shader render mode.
      • In the interest of compatibility, we may not be able to enable this by default in Sprite3D due to VFX usage (where HDR display can be intended), but for Label3D, we may be able to safely default to this.

See the settings exposed by the Control HDR mod for an example of a best-in-class HDR implementation (related video):

control_hdr_mod_settings.mp4

Interesting, that UI seems to use the term "paperwhite" in a different way, and has a dedicated setting for the brightness of UI and HUD elements.

@DarkKilauea DarkKilauea force-pushed the rendering/hdr-output branch 2 times, most recently from 88beb60 to 8df131d Compare July 19, 2024 06:30
@DarkKilauea
Copy link
Contributor Author

I gave this a quick test locally (on Windows 11 23H2 + NVIDIA 560.80 + LG C2 42"), it works as expected. This is encouraging to see, I've been wanting this for a while 🙂

Thanks for taking a look!

I noticed some issues for now:

* Having RTX HDR enabled will mess with the HDR that is enabled in the editor. It will continuously enable and disable itself whenever you make any input in the editor (and disable itself after being idle for a second). This is also an issue on `master` with HDR disabled.

* See [[4.3 Beta 3] Strange editor brightness and colors caused by RTX Dynamic Vibrance affecting the editor #94231](https://github.com/godotengine/godot/issues/94231). We should see if we can forcibly disable RTX HDR and RTX Dynamic Vibrance for the editor using a NVIDIA profile. I haven't seen options for those in NVIDIA Profile Inspector so far.

Odd that NVidia's RTX HDR doesn't detect the HDR color space and avoid messing with the final swap chain buffer. Auto-HDR in Windows 11 appears to avoid messing with Godot when HDR is enabled. Updating the NVidia Profile may be outside the scope of this PR and be best done with a more focused PR.

* HDR Max Luminance affects both 2D (UI) and 3D rendering. Is that intended?

For the initial draft, yes, everything is mapped using the same tonemapper. However, we should map UI elements to a different brightness to avoid them being too bright. For now, that can be worked around with dimming the brightness of any UI elements via the theme, but I would like to fix that in this PR.

* The HDR editor setting is not applied instantly when you change it, even though the demo project shows a working example of it being toggled at runtime. You can update the viewport's status based on editor settings here: https://github.com/godotengine/godot/blob/ff8a2780ee777c2456ce42368e1065774c7c4c3f/editor/editor_node.cpp#L356

I haven't looked into configuring the editor to use HDR yet. Will do after I figure out how to properly tone map UI elements, if you enable HDR on the editor now, the UI is a little unpleasant.

* There doesn't appear to be a paperwhite setting you can use to adjust UI brightness. This is typically offered in games to prevent the UI from being too bright. Using a paperwhite value around 200 nits is common, since a lot of OLED displays cap out at that brightness level in SDR. Either way, this should be exposed in the project settings and the documentation should recommend exposing this setting to player (just like HDR peak luminance).

Agreed, UI elements and other 2D elements should probably be mapped to a different brightness curve. I'll probably have to figure out where in the engine 3D and 2D elements are composited together and perform the tone mapping there.

  * There should also be a way for unshaded materials to base themselves on paperwhite, so that Sprite3D and Label3D used for UI purposes are not overly bright in HDR. I suppose this would be a BaseMaterial3D property or a shader render mode.

    * In the interest of compatibility, we may not be able to enable this by default in Sprite3D due to VFX usage (where HDR display can be intended), but for Label3D, we may be able to safely default to this.

That might be outside of the scope of this PR. I'm not sure how I would indicate that certain 3D elements need to be mapped using a different brightness curve once they are all combined into the same buffer. It would be similar to trying to avoid sRGB mapping certain rendered elements.

For now, this can be worked around by decreasing the brightness of the color of these elements.

See the settings exposed by the Control HDR mod for an example of a best-in-class HDR implementation (related video):
control_hdr_mod_settings.mp4

Interesting, that UI seems to use the term "paperwhite" in a different way, and has a dedicated setting for the brightness of UI and HUD elements.

Baldur's Gate 3 and Cyberpunk 2077 also have really nice HDR settings menus. I've been basing some of this work off their approach, though modifying contrast and brightness I'm leaving up to Environment since those effects are already there.

Thanks again for your comments! I'll add some TODO items to the description for tracking.

@Jamsers
Copy link

Jamsers commented Aug 28, 2024

Can you use any Godot project to test this PR? Bistro-Demo-Tweaked and Crater-Province-Level both use physical light units, and use as close to reference values for luminosity on light sources. (i.e. the sun at noon is 100000 lux, the moon at midnight is 0.3 lux)

I'd love to help test this PR but unfortunately I don't have HDR hardware ☹️

@alvinhochun
Copy link
Contributor

I recently got a monitor that supports fake HDR DisplayHDR 400 so I thought I could give this a try, but on Intel UHD 620 it prints "WARNING: HDR output requested but no HDR compatible format was found, falling back to SDR." and doesn't display in HDR. I was kind of expected this since it is using Vulkan, but I'm a bit surprised it works for you, even on windowed mode no less. I guess there is some special handling in the NVIDIA driver?

Anyway, adding HDR output to D3D12 should be trivial and I might give it a try. (No promises!)


Shall we also consider implementing HDR display for the compatibility renderer? I am not sure if native OpenGL can do HDR, but it is very possible to implement on Windows with the help of ANGLE and some manual setting up.

@fire
Copy link
Member

fire commented Aug 28, 2024

This needs a rebase on master, but I have a https://www.dell.com/en-ca/shop/alienware-34-curved-qd-oled-gaming-monitor-aw3423dw/apd/210-bcye/monitors-monitor-accessories HDR display.

I can help test.

@DarkKilauea
Copy link
Contributor Author

Can you use any Godot project to test this PR? Bistro-Demo-Tweaked and Crater-Province-Level both use physical light units, and use as close to reference values for luminosity on light sources. (i.e. the sun at noon is 100000 lux, the moon at midnight is 0.3 lux)

I'd love to help test this PR but unfortunately I don't have HDR hardware ☹️

You should be able to test with any scene, though keep in mind that the realistic light units will not map directly to the brightness of the display. Consumer desktop displays typically don't go much above 1000 nits on the high end, which is far too dim to simulate sunlight. Values from the scene will be mapped to a range fitting within the max luminosity set for the window.

@DarkKilauea DarkKilauea force-pushed the rendering/hdr-output branch from b2bd1a1 to 728912f Compare August 29, 2024 08:49
@alvinhochun
Copy link
Contributor

Here are the changes to get Rec. 2020 HDR output on D3D12: master...alvinhochun:godot:hdr-output-d3d12

@alvinhochun
Copy link
Contributor

Quote

HDR (blown out a bit, looks better on an HDR display): image

SDR: image

The over-exposure in your screenshot is expected, but the colours are oversaturated because it is missing a colour space conversion. The colours need to be converted from BT.709 primaries to BT.2020 primaries. This is how it should look with the correct colours:

image

The conversion may be done with something like this:

diff --git a/servers/rendering/renderer_rd/shaders/color_space_inc.glsl b/servers/rendering/renderer_rd/shaders/color_space_inc.glsl
index 3583ee8365..76305a8a3c 100644
--- a/servers/rendering/renderer_rd/shaders/color_space_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/color_space_inc.glsl
@@ -19,6 +19,15 @@ vec3 linear_to_st2084(vec3 color, float max_luminance) {
        // max_luminance is the display's peak luminance in nits
        // we map it here to the native 10000 nits range of ST2084
        float adjustment = max_luminance * (1.0f / 10000.0f);
+       color = color * adjustment;
+
+       // Color transformation matrix values taken from DirectXTK, may need verification.
+    const mat3 from709to2020 = mat3(
+          0.6274040f, 0.0690970f, 0.0163916f,
+          0.3292820f, 0.9195400f, 0.0880132f,
+          0.0433136f, 0.0113612f, 0.8955950f
+       );
+       color = from709to2020 * color;

        // Apply ST2084 curve
        const float c1 = 0.8359375;
@@ -26,7 +35,7 @@ vec3 linear_to_st2084(vec3 color, float max_luminance) {
        const float c3 = 18.6875;
        const float m1 = 0.1593017578125;
        const float m2 = 78.84375;
-       vec3 cp = pow(abs(color.rgb * adjustment), vec3(m1));
+       vec3 cp = pow(abs(color.rgb), vec3(m1));

        return pow((c1 + c2 * cp) / (1 + c3 * cp), vec3(m2));
 }

@DarkKilauea DarkKilauea force-pushed the rendering/hdr-output branch from 728912f to 56d27a6 Compare August 31, 2024 02:29
@iuymatiao
Copy link

iuymatiao commented Nov 4, 2025

We get a black screen because creating the D3D12 swapchain fails, I'm unsure if this is fixable within godot or if we need to contact upstream vkd3d yet but changing the driver to vulkan solves the issue (which clearly also disables HDR).

I don’t think the issue is with being able to create the D3D12 swapchain in general. If I export a D3D12 game from a Godot branch that does not support HDR (ex: 4.5, 4.6dev2), it appears to run just fine, so a D3D12 swapchain in SDR is still working for me. You might want to double-check by running a 4.5 project through Gamescope to see what happens.

I still think it’s possible that something about the HDR implementation is not playing nicely with Gamescope.

@ArchercatNEO
Copy link
Contributor

Are you sure the problem is in gamescope and not proton itself? I've reproduced the issue using only umu-run (which is simply a wrapper around proton) without invoking gamescope.

@iuymatiao
Copy link

iuymatiao commented Nov 5, 2025

Are you sure the problem is in gamescope and not proton itself? I've reproduced the issue using only umu-run (which is simply a wrapper around proton) without invoking gamescope.

Messed up my grammar in my previous posts. What I meant to say is that there is probably something wrong with Godot’s HDR implementation (I.e. this PR) that is currently incompatible with what’s expected on the Proton+Gamescope end.

There is nothing wrong with Proton or Gamescope AFAIK. HDR games (whether using DX11, DX12 or Vulkan) do output HDR on the Steam Deck OLED, presumably as long as they’re outputting to the DXGI swapchain.

@ArchercatNEO
Copy link
Contributor

According to my testing this PR has not broken anything, d3d12 has always been broken.

Using the official godot 4.5.1 windows editor download and this MRP minimal-reproduction-project.zip (after importing)
Running with umu-run godot --path ./path/to/project we should get music and the sample godot icon.
Running with umu-run godot --path ./path/to/project --rendering-driver d3d12 there is still music but a gray screen.

@iuymatiao
Copy link

OK. I will attempt to run this MRP on my Deck OLED to see what happens.

@iuymatiao
Copy link

iuymatiao commented Nov 5, 2025

Just finished performing a couple of tests.

It turns out that I did make a mistake, and that the previous tests that were previously assumed to be D3D12 were, in fact, Vulkan. This was because I missed an export setting to force D3D12 for the Windows export. When testing 4.5 TPS-Demo using just D3D12, I get the blank screen with music.

However, to confirm if the problem is D3D12 support within Proton+Gamescope, I compiled Microsoft's HDR Sample, and then loaded the exe into the Steam Deck OLED. I managed to get it to work, HDR included.

Deck OLED HDR

The bad news is that Godot's D3D12 might be borked as far as Proton compatibility is concerned. The good news is that if we can resolve this issue, then there is a good chance that HDR should just work via Proton-D3D12 as well. However, fixing Godot's D3D12 implementation for better Proton compatibility is out-of-scope for this PR.

@ArchercatNEO
Copy link
Contributor

Seems like the issue was fixed in #112344 which means we should be able to test HDR through proton after the next rebase.

@iuymatiao
Copy link

Seems like the issue was fixed in #112344 which means we should be able to test HDR through proton after the next rebase.

Yeah, I’ll wait for the rebase and try again. If nothing improves, I can file this as a new bug.

@DarkKilauea
Copy link
Contributor Author

Seems like the issue was fixed in #112344 which means we should be able to test HDR through proton after the next rebase.

Yeah, I’ll wait for the rebase and try again. If nothing improves, I can file this as a new bug.

Rebased as requested!

@iuymatiao
Copy link

Just tried again. Still no graphical output on Steam Deck OLED. @ArchercatNEO Can you run another test with this rebase?

We might need #112497 as well, which just got merged hours ago. We might need another rebase.

@ArchercatNEO
Copy link
Contributor

Using umu-run I can get graphical output

image

I should test if I can get HDR output at all (first without gamescope, if that fails then with gamescope) but perhaps this is an issue with the version of proton we are testing with? Whenever the next rebase happens you can verify whether #112497 solves the issue for you but so far I can test without it.

@ArchercatNEO
Copy link
Contributor

I have tested that native HDR output does not work. Different flags and arguments mean variations between there isn't HDR and little more to large flickering to a black screen. In all cases godot reports that the window does not support HDR and will therefore refuse to do HDR. I know far too little about vkd3d/proton to know what it says the colorspace of my monitor is and I haven't set up cross compilation so I can't find out.

@iuymatiao
Copy link

@ArchercatNEO This Reddit post suggests that Proton does not support HDR output with any compositor other than Gamescope.

I will also check some SDR projects to see if they at least work with master.

@ArchercatNEO
Copy link
Contributor

After a lot of messing about here's the combination of env and command that means we "should" be getting HDR.
This is with this layer https://github.com/Zamundaaa/VK_hdr_layer too because somehow proton doesn't seem to send any HDR metadata (I checked with WAYLAND_DEBUG=1).

PROTONPATH=GE-Proton PROTON_ENABLE_WAYLAND=1 PROTON_ENABLE_HDR=1 ENABLE_WSI_HDR=1 umu-run godot.exe --path ./path/to/project/

I edited one of the HDR projects to check if godot believes HDR is supported and the answer was yes but I got a black screen anyway.

@ArchercatNEO
Copy link
Contributor

I have discovered the true issue: there is no problem with HDR in proton or godot, we just default to 0 nits.
The image is SDR only because I haven't figured out how to take HDR screenshots yet.

image

What happens is that godot defaults to auto adjusting reference/max luminance which is unavailable under proton.
Because we can't actually get any lumiance we use the default luminance (0 nits).
0 nits means all UI goes to black.

Simply using the scripting API to set the luminances to anything else fixes the issue

Cmd PROTONPATH=GE-Proton PROTON_ENABLE_WAYLAND=1 PROTON_ENABLE_HDR=1 umu-run godot.exe

@iuymatiao
Copy link

iuymatiao commented Nov 8, 2025

Some updates on my end.

The good news is that I have D3D12 graphical output on the Steam Deck OLED when using the latest commits from master.

The bad news is that I'm still unable to get HDR output. I did try @ArchercatNEO's suggestion to manually set the luminance values, which I did using this code in _ready():

DisplayServer.window_set_hdr_output_reference_luminance(200, window_id)
DisplayServer.window_set_hdr_output_max_luminance(600, window_id)

But all I get is a black screen, which arguably is an improvement over the gray screen I was previously getting. Also the Steam Deck overlay detected an active framerate, which I assume means the swapchain is working as intended.

It's admittedly difficult to get debug information out of the Steam Deck itself, so I'll probably keep trying things out on my end.

Edit: I should add that I'm currently testing with Proton Experimental, as this is probably the most feature-filled version of Proton that can be used out-of-the-box (GE Proton is a community fork IIRC).

@bruvzg
Copy link
Member

bruvzg commented Nov 8, 2025

Had the same black screen issue on macOS + game porting toolkit 3 (Wine variant with DX12 over Metal).

It seems to be working with the following patch:

diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 6fda95344a..d047a8fc95 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -1606,6 +1606,8 @@ static BOOL CALLBACK _MonitorEnumProcSdrWhiteLevel(HMONITOR hMonitor, HDC hdcMon
                ERR_FAIL_V_MSG(FALSE, vformat("Failed to get monitor info for screen: %d", data->screen));
        }

+       data->sdrWhiteLevelInNits = 160;
+
        // Find this screen's path.
        for (const DISPLAYCONFIG_PATH_INFO &path : data->paths) {
                DISPLAYCONFIG_SOURCE_DEVICE_NAME source_name;
@@ -1633,7 +1635,7 @@ static BOOL CALLBACK _MonitorEnumProcSdrWhiteLevel(HMONITOR hMonitor, HDC hdcMon
                sdr_white_level.header.id = path.targetInfo.id;

                if (DisplayConfigGetDeviceInfo(&sdr_white_level.header) != ERROR_SUCCESS) {
-                       ERR_PRINT(vformat("Failed to get SDR white level for screen: %d, adapterId: 0x%08X%08X, id: %d", data->screen, (uint32_t)path.targetInfo.adapterId.HighPart, (uint32_t)path.targetInfo.adapterId.LowPart, path.targetInfo.id));
+                       //ERR_PRINT(vformat("Failed to get SDR white level for screen: %d, adapterId: 0x%08X%08X, id: %d", data->screen, (uint32_t)path.targetInfo.adapterId.HighPart, (uint32_t)path.targetInfo.adapterId.LowPart, path.targetInfo.id));
                        continue;
                }

PXL_20251108_161842567~2

@ArchercatNEO
Copy link
Contributor

Edit: I should add that I'm currently testing with Proton Experimental, as this is probably the most feature-filled version of Proton that can be used out-of-the-box (GE Proton is a community fork IIRC).

In terms of HDR, me using GE Proton is very important. The reason gamescope was neccesary is that X11 doesn't have good HDR support so you need gamescope to act as the mini compositor to enable HDR.

GE Proton has support for the native wayland wine driver (standard proton doesn't) which I enabled, once enabled you can use the native wayland HDR protocol which is why I went that route. Gamescope for some reason was just extremely buggy for me so this seemed easier too.

@DarkKilauea
Copy link
Contributor Author

I have discovered the true issue: there is no problem with HDR in proton or godot, we just default to 0 nits. The image is SDR only because I haven't figured out how to take HDR screenshots yet.

I've pushed an update which sets some sane defaults within each rendering context for this situation. If auto luminance fails, it should now fall back to the last known luminance values, or to these defaults.

@iuymatiao
Copy link

I have some good news!

Godot HDR Steam Deck OLED

@iuymatiao
Copy link

This did not yet use @DarkKilauea's latest rebase. This is using yesterday's rebase, but I had to remove the following lines from the test project:

//Within "in_game_hdr_settings.gd"
_auto_adjust_reference = DisplayServer.window_get_hdr_output_reference_luminance(window_id) < 0
_auto_adjust_max = DisplayServer.window_get_hdr_output_max_luminance(window_id) < 0

This is probably related to @ArchercatNEO's findings that auto-adjust luminance does not work when running under Proton.

There is a small catch, though, where the reference luminance is currently defaulting to a mere 10 nits. This is easily fixed by adjusting the reference luminance slider (I manually adjusted to 200 nits in the picture above).

I'll be performing some follow-up work after this, such as testing @DarkKilauea's latest rebase, checking if a reasonable reference luminance can be set when running under Proton, as well as testing some other sample projects like "TPS Demo".

@iuymatiao
Copy link

@DarkKilauea May I know which steps you took to mitigate the issue with Proton not returning a reference luminance? I found this in my working copy of your PR in the display_server_windows.cpp file:

// If auto reference luminance is enabled, update it based on the current SDR white level.
if (p_window_data.hdr_output_reference_luminance < 0.0f) {
	if (p_screen_data.sdr_white_level > 0.0f) {
		rendering_context->window_set_hdr_output_reference_luminance(p_window, p_screen_data.sdr_white_level);
	}
	// If we cannot get the SDR white level, leave the previous value unchanged.
}

I interpret this as doing nothing if auto-adjust fails, which is fair enough, but this might be an issue if the game ships with auto-adjust by default. I believe the goal is for auto-adjust (luminance == -1) to never return a value of 0 nits.

Just let me know if I missed where the fallback code is. It's admittedly hard for me to find the very latest code modifications since the commits keep getting squashed.

Copy link
Member

@Mickeon Mickeon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be far along in development that a documentation review is due.
Do look at the suggestions a bit carefully because there's always the possibility of having lost important information from the rewording.

Support for 32-bit image atomic operations.
</constant>
<constant name="SUPPORTS_HDR_OUTPUT" value="9" enum="Features">
Features support for high dynamic range (HDR) output.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be more consistent (yes I see the outlier):

Suggested change
Features support for high dynamic range (HDR) output.
Support for high dynamic range (HDR) output.

Comment on lines +142 to +144
[csharp]
// TODO
[/csharp]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you got nothing strip this out entirely. There are no TODOs in the class reference XMLs anymore.

Suggested change
[csharp]
// TODO
[/csharp]

<member name="hdr_output_requested" type="bool" setter="set_hdr_output_requested" getter="is_hdr_output_requested" default="false">
If [code]true[/code], requests HDR output for the window, falling back to SDR if not supported, and automatically switching between HDR and SDR as the window moves between displays, display capabilities change, or system settings are modified.
Only available on platforms that support HDR output, have HDR enabled in the system settings, and have a compatible display connected.
[b]Note:[/b] Some integrated GPUs have poor support for HDR output, even when they claim to support it. If you experience issues, try disabling this setting.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a property, and it seems to be false by default already(?)

Suggested change
[b]Note:[/b] Some integrated GPUs have poor support for HDR output, even when they claim to support it. If you experience issues, try disabling this setting.
[b]Note:[/b] Some integrated GPUs have poor support for HDR output, even when they claim to support it. If you experience issues, try disabling this property.

or, this note could be kept more generic as it applies to a bunch of other descriptions as well:

Suggested change
[b]Note:[/b] Some integrated GPUs have poor support for HDR output, even when they claim to support it. If you experience issues, try disabling this setting.
[b]Note:[/b] Some integrated GPUs have poor support for HDR output, even when they claim to support it. If you experience issues, try setting this to [code]false[/code].

Or similar

Comment on lines +373 to +374
Returns [code]true[/code] if the window supports HDR output.
This depends on the platform, display capabilities, system settings, and the display the window is currently on.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Returns [code]true[/code] if the window supports HDR output.
This depends on the platform, display capabilities, system settings, and the display the window is currently on.
Returns [code]true[/code] if the window supports HDR output. This depends on the platform, display capabilities, system settings, and the display the window is currently on.

Comment on lines +2413 to +2419
Sets the SDR reference luminance in nits (cd/m²) for HDR content for the window specified by [param window_id].
Set to a negative value to automatically adjust to the reference level set by the OS or window manager.
By default, this is set to [code]-1[/code].
This controls the brightness of SDR content (such as UI) when HDR is enabled.
[b]Note:[/b] Requires support for [constant FEATURE_HDR_OUTPUT].
[b]Note:[/b] Requires support by the rendering device.
[b]Note:[/b] On some platforms, setting a custom reference luminance is not supported and will always be auto adjusted based on the display's capabilities.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although I personally sympathize with the need to keep sentences spread more nicely, please keep in mind that each new line in the class reference generates a whole new paragraph. This description, as well as others in this PR, take up a huge amount of vertical space for very few sentences.

"when HDR is enabled." but how is HDR enabled? I presume the following.

"On some platforms"? Is it possible to elaborate on what platforms these are?

Suggested change
Sets the SDR reference luminance in nits (cd/m²) for HDR content for the window specified by [param window_id].
Set to a negative value to automatically adjust to the reference level set by the OS or window manager.
By default, this is set to [code]-1[/code].
This controls the brightness of SDR content (such as UI) when HDR is enabled.
[b]Note:[/b] Requires support for [constant FEATURE_HDR_OUTPUT].
[b]Note:[/b] Requires support by the rendering device.
[b]Note:[/b] On some platforms, setting a custom reference luminance is not supported and will always be auto adjusted based on the display's capabilities.
Sets the SDR reference luminance in nits (cd/m²) for HDR content for the window specified by [param window_id]. If [param reference_luminance] is negative, the window automatically adjusts to the reference level set by the OS or window manager. By default, this luminance is set to [code]-1.0[/code] for every window.
When HDR is enabled via [method window_request_hdr_output], this controls the brightness of SDR content (such as UI).
[b]Note:[/b] Requires support for [constant FEATURE_HDR_OUTPUT], as well as support for the rendering device ([constant RenderingDevice.SUPPORTS_HDR_OUTPUT]).
[b]Note:[/b] On some platforms, setting a custom reference luminance is not supported and will always be automatically adjusted based on the display's capabilities.

<return type="bool" />
<param index="0" name="window_id" type="int" default="0" />
<description>
Returns whether HDR output is requested for the window specified by [param window_id].
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Returns whether HDR output is requested for the window specified by [param window_id].
Returns [code]true[/code] if HDR output is requested for the window specified by [param window_id].

Comment on lines +2138 to +2141
Returns the current maximum luminance in nits (cd/m²) for HDR content for the window specified by [param window_id].
If max luminance is being auto adjusted based on the display's capabilities, this will return that value.
Otherwise, it will return the value set by [method window_set_hdr_output_max_luminance].
[b]Note:[/b] Requires support for [constant FEATURE_HDR_OUTPUT].
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Returns the current maximum luminance in nits (cd/m²) for HDR content for the window specified by [param window_id].
If max luminance is being auto adjusted based on the display's capabilities, this will return that value.
Otherwise, it will return the value set by [method window_set_hdr_output_max_luminance].
[b]Note:[/b] Requires support for [constant FEATURE_HDR_OUTPUT].
Returns the current maximum luminance in nits (cd/m²) for HDR content for the window specified by [param window_id]. If the maximum luminance is being automatically adjusted based on the display's capabilities, this method will return that value. Otherwise, it will return the value set by [method window_set_hdr_output_max_luminance].
[b]Note:[/b] Requires support for [constant FEATURE_HDR_OUTPUT].

Comment on lines +2148 to +2150
Returns the current reference luminance in nits (cd/m²) for HDR content for the window specified by [param window_id].
If reference luminance is being auto adjusted based on the display's capabilities, this will return that value.
Otherwise, it will return the value set by [method window_set_hdr_output_reference_luminance].
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Returns the current reference luminance in nits (cd/m²) for HDR content for the window specified by [param window_id].
If reference luminance is being auto adjusted based on the display's capabilities, this will return that value.
Otherwise, it will return the value set by [method window_set_hdr_output_reference_luminance].
Returns the current reference luminance in nits (cd/m²) for HDR content for the window specified by [param window_id]. If the reference luminance is being automatically adjusted based on the display's capabilities, this will return that value. Otherwise, it will return the value set by [method window_set_hdr_output_reference_luminance].

Comment on lines +2158 to +2160
Returns the maximum luminance in nits (cd/m²) set for HDR content for the window specified by [param window_id].
Negative values indicate that the value is being auto adjusted based on the display's capabilities.
[b]Note:[/b] Requires support for [constant FEATURE_HDR_OUTPUT].
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Returns the maximum luminance in nits (cd/m²) set for HDR content for the window specified by [param window_id].
Negative values indicate that the value is being auto adjusted based on the display's capabilities.
[b]Note:[/b] Requires support for [constant FEATURE_HDR_OUTPUT].
Returns the maximum luminance in nits (cd/m²) set for HDR content for the window specified by [param window_id]. Negative values indicate that the value is being automatically adjusted based on the display's capabilities.
[b]Note:[/b] Requires support for [constant FEATURE_HDR_OUTPUT].

Comment on lines +2167 to +2168
Returns the SDR reference luminance in nits (cd/m²) set for HDR content for the window specified by [param window_id].
Negative values indicate that the value is being auto adjusted based on the display's capabilities.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Returns the SDR reference luminance in nits (cd/m²) set for HDR content for the window specified by [param window_id].
Negative values indicate that the value is being auto adjusted based on the display's capabilities.
Returns the SDR reference luminance in nits (cd/m²) set for HDR content for the window specified by [param window_id]. Negative values indicate that the value is being automatically adjusted based on the display's capabilities.

@DarkKilauea
Copy link
Contributor Author

@DarkKilauea May I know which steps you took to mitigate the issue with Proton not returning a reference luminance? I found this in my working copy of your PR in the display_server_windows.cpp file:

I updated the default values in the rendering contexts, for example: rendering_context_driver_d3d12.h:124. This should resolve the values starting out as zero.

The auto-adjustment logic in _update_hdr_output_for_window intentionally does not set a default on failure to get the display capabilities because I wanted to avoid any possibility of flickering from temporary failures to get those values.

I tested the fallback by updating _get_screen_hdr_data to return zero for all luminance values to simulate the failure you were seeing.

@iuymatiao
Copy link

Just tested the latest rebase. HDR Output test project now works out-of-the-box on Steam Deck OLED without additional modifications required.

Co-authored-by: Alvin Wong <[email protected]>
Co-authored-by: Allen Pestaluky <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.