-
-
Notifications
You must be signed in to change notification settings - Fork 24k
[Windows] Support output to HDR monitors #94496
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
|
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:
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.mp4Interesting, 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. |
88beb60 to
8df131d
Compare
Thanks for taking a look!
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.
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.
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.
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.
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.
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. |
b89985a to
e9742ba
Compare
e9742ba to
b2bd1a1
Compare
|
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 |
|
I recently got a monitor that supports 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. |
|
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. |
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. |
b2bd1a1 to
728912f
Compare
|
Here are the changes to get Rec. 2020 HDR output on D3D12: master...alvinhochun:godot:hdr-output-d3d12 |
|
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: 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));
}
|
728912f to
56d27a6
Compare
|
Rebased after the recent D3D and AgX changes. This one was a little hairy, so I'd appreciate some retesting to ensure nothing broke. Everything looked ok in my sanity checks. I also changed the default reference luminance (when it cannot be queried from the OS) to 200 nits to match @allenwp's observations. |
I believe if we do any clipping that it should be done in |
fde15b3 to
ba867e9
Compare
Latest rebaseThis mostly looked good! Thanks for doing this!! I've pushed a commit to fix up a couple of things so that my big overhaul to tonemapping and AgX with HDR is now complete. I did another trivial rebase while I was at it, since I needed for force push anyway. Comments and minor changesI've added a number of comments to document our rationale; normally a developer would be able to look at the PR to determine this, but there's no way anyone in the future will be searching through the hundreds of comments of this PR to find this information, so it's important for these notes to be presented in code comments. I've fully removed the ClippingI've added clipping to Docs changesI've done a second pass on the docs for func _process(_delta: float):
# output_max_linear_value may change often, so do this every frame.
# max_linear_value is only valid when using no tonemapping or the
# Linear tonemapper.
var max_linear_value = get_window().get_output_max_linear_value()
# Replace this with your color:
var original_color = Color.PURPLE
# Normalize to max_linear_value to produce the brightest color possible,
# regardless of SDR or HDR output:
var bright_color = normalize_color(original_color, max_linear_value)
func normalize_color(srgb_color, max_linear_value = 1.0):
# Color must be linear-encoded to use math operations.
var linear_color = srgb_color.srgb_to_linear()
var max_rgb_value = maxf(linear_color.r, maxf(linear_color.g, linear_color.b))
var brightness_scale = max_linear_value / max_rgb_value
linear_color *= brightness_scale
# Undo changes to the alpha channel, which should not be modified.
linear_color.a = srgb_color.a
# Convert back to nonlinear sRGB encoding, which is required for Color in
# Godot unless stated otherwise.
return linear_color.linear_to_srgb()Editor changesI noticed the I believe the "Enable HDR for editor previews when HDR output is enabled" commit should be separated into its own followup PR (similar to the Android HDR PR) in order to improve the review process: This way, members who are experts in reviewing editor changes will be able to focus on editor changes, rather than needing to wade through the vast number of changes of this PR that are not related to the editor. Besides that commit, this PR has almost zero changes to the editor, and I think this is a good thing for the review process. This "[HDR output] editor enhancements" PR that adds all of the non-critical editor changes can be used to track other things that come up, like the As another benefit, it means we can keep this PR in a "ready to merge" state so we can get it into 4.7 dev 1 without risk of editor enhancements blocking it :) SquashingAs always, go ahead and squash my commits when you've reviewed them; I simply left them separate for it to be easier to see what I've changed. |
ba867e9 to
14268ef
Compare
Thanks for that! Squashed in most of the changes.
I ended up removing the change in logic here for a couple reasons:
This is likely a quick change to enable
Yea, that makes sense, assuming we plan to actually merge the editor changes in 4.7. Without them, the editor looks strange in places with HDR on, which is not a great experience. I requested another review since all suggestions have been completed, would love to see another approval to unblock merging. |
Oh, good catch; thanks for having my back. I thought I did a thorough search of references to it, but I must have overlooked a scenario.
Yep, for sure. I want to make sure this PR gets into 4.7 dev 1, so long as no issues are discovered with it. Editor enhancements can easily make it in shortly afterwards, but if they end up being in a different dev release, it's no big deal.
Done! I don't know of any remaining issues with this PR. I'll keep testing on Steam Deck/Wine to verify that things don't look problematically dark with the 200 nits reference luminance... |
|
While testing, I was connecting and disconnecting monitors a fair bit and got into a situation where Godot reported this error: And then stopped responding entirely to changes in I've committed and squashed a change to only stop reporting error messages instead of permanently giving up on reading |
14268ef to
1df5b65
Compare
1df5b65 to
05f5ca1
Compare
|
Another rebase to bring in the beta 1 bits. No other changes. |
|
I've made a draft for a new HDR output manual page along with a draft for an official HDR output demo project. Please give those a look and provide feedback! I'm sure many of us have had some thoughts about how best to instruct HDR output usage and how it can be demonstrated to new users, so I'd like to hear if I've captured the key points or have introduced anything that may only add confusion. I've also renamed my old test project to be a "Godot HDR output porting test project ". This older test project is designed solely for implementing the HDR output feature on new platforms. The official HDR output demo project supersedes it for general demonstration purposes. Finally, I've created trackers for HDR output-related proposals and issues & PRs. Please feel free to post on those threads whenever you create a new item that should be added to one of those trackers. @DarkKilauea Would you mind updating the description of this PR to include some of those links if you have time? (Also, I'm not sure if your old test project is entirely suitable anymore: I notice that it has the old Rec. 2020 colour triangle, but this is entirely clipped to Rec. 709 now...) No rush, of course, and thanks as always! |
05f5ca1 to
152ec0b
Compare
0e222a4 to
c373143
Compare
Co-authored-by: Alvin Wong <[email protected]> Co-authored-by: Allen Pestaluky <[email protected]>
c373143 to
e0c6478
Compare
Thanks for that! I've added links to the description.
Links have been updated. I also updated the screenshots and getting started guide. Thanks again for all the help! |
|
Thanks! From the description:
Most of these are no longer the case. I implemented fixes in 4.6 to correct this behaviour: now only blending is different when hdr_2d is enabled. Also, I'm not sure that the advice in the Getting Started -> runtime is a good idea. Setting request HDR output is something that should be done independently of whether the window currently supports HDR output. I expect this approach of checking to see if the window currently supports HDR output should only be used for determining how player-facing settings are presented, which doesn't appear to be what this section of getting started is demonstrating. |



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:
Examples (converted to SDR to work on all browsers):
Examples (HDR images, may not display correctly on all browsers):
Supported Platforms:
Supported Graphics APIs:
Supported HDR Formats:
Supported Tonemappers:
Features:
Limitations:
hdr_2dto output the additional dynamic range needed for HDR displays. Blending, glow, color correction, brightness, contrast, and saturation adjustments may look different whenhdr_2dis enabled.hdr_2dwill 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 withhdr_2denabled, even when HDR output is disabled. Future PRs may resolve some of these remaining differences.Follow up work:
white,contrast, and future HDR support to the AgX tonemapper. #106940Trackers:
Getting Started
Project Settings
display/window/hdr/enabled(you may need to enable Advanced Settings first):rendering/viewport/hdr_2d:Runtime
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.
Remaining Work / Issues
SDRWhiteLevel: [Windows] Support output to HDR monitors #94496 (comment)