[LinuxBSD] Add support for HDR output (Wayland)#102987
Conversation
|
This looks like a good start, I had no idea HDR support in Wayland was this far along. Unfortunately I can't speak to the correctness of the Wayland code as I don't have experience with it. You may want to look at the latest commit for Windows support and gradually implement the remaining methods and features. Generally I'd expect a full implementation to support:
|
e522785 to
b67a8c6
Compare
|
Update on what I have understood each bit of the protocol to mean and what I'm trying to work with: Does the DisplayServer support HDR?
Does the Screen (Wayland
How to manipulate HDR values of this Window (Wayland
What is the preferred screen luminance (for
On the concrete impl side of things
If I got the relation between wayland API and godot hdr rendering stuff correct then it seems like what's left is largely state management in wayland. If you don't mind @riteo I'd also like to get your feedback on this specially with where to put the more stateful stuff like the compositors prefered icc profile. |
Yea sure! :D I'm currently very busy with a thing I'm working on but I could not resist taking a very quick look at the protocol. I can't really comment on the feature itself as I have very little experience with HDR. That said, the logic you're describing seems great! My only concern is how much the godot-side API depends on the screen since 99% of Wayland stuff revolves around windows, with the screen being a way smaller piece of context compared to traditional servers. Regarding the data layout, the general rule of thumb is to put all state for an object in an aptly-named Actually, you don't even need to make a "global" variable in the thread class; a common approach I've chosen is to consider the objects themselves... objects, and just So you could just do an: ColorManagerState *state = wp_color_manager_get_state(the_actual_color_manager_proxy);
if (state) {
// Stuff!
}And always have a valid state reference. If you implement it like the other methods, it will also automatically check for Crap, this was supposed to be a quick message. There's a lot of similar things I have to document somewhere. I hope that was not too much. If you need some further clarifications feel free to tell me. |
It also needs to support parametric image descriptions, and the primaries and transfer function you want to use. Ofc if you use Vulkan to set the colorspace and HDR metadata, the Vulkan driver also has to support them.
You can output HDR content with Vulkan, but it doesn't (yet) actually have any API to figure out what the compositor is asking for / what the display is capable of.
Please don't do that. Outside of special cases, the color management output should not be used. HDR support should only be determined by whether or not the compositor supports it, the display isn't really relevant beyond the luminance ranges (which you can get from the preferred image description). If you output scRGB or BT2020PQ, the compositor will do the needed transformations to make it work on any display. KWin for example does proper HDR on SDR laptops (as proper as the displays can do at least); while the primary use case for that is HDR videos, it would be cool if that would work with games too. If you want to ensure that you don't waste power presenting HDR content when it's not necessary, you can instead check if the preferred image description has a maximum target luminance that's higher than the reference luminance. If it is higher, displaying HDR makes sense, if it isn't, then it's probably not useful.
The image description just describes what you get it from, so they're about the screen if you get it from the color management output, or about the window if you get the preferred image description from the surface feedback.
Note that while you can have multiple If you want to use the protocol directly, you can do that if you set You can use https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/32038 for testing either approach. There's one more important topic I want to touch on: Reference luminance / paper white. Does Godot already have a centralized setting for it? With Vulkan, the assumption on Wayland is that the paper white is 203 cd/m² with PQ, and 80cd/m² with scRGB, and the compositor will map that to the system wide user setting - so using anything else as the paper white will cause undesired outcomes. With the protocol directly, you can set the reference luminance with Ideally, games would either always use the reference luminance for the transfer function they use, or use the same reference luminance the compositor would like to have, and the preference for this would be completely hidden on Wayland. Same with maximum luminance, it should just be read from the compositor, so that it can automatically adjust to brightness settings changes and to different displays without the user having to change the settings of each game. I'm not sure how you handle that on Windows - technically it also has such settings, but I know the very vast majority of games just ignore them completely. This has already caused some user confusion on Plasma, as the Windows game settings don't necessarily directly translate to the brightness values of the screen, so it would be really great if we could avoid that mess and always have them configure things system wide instead. Sorry for the wall of text, after working on it so long I'm really exited for some great HDR experiences on Linux :) |
|
@DarkKilauea should the Just doing ctrl + shift + f gives no places where these methods are called so I can't tell what the expected use is. In efficiency scenarios |
|
@ArchercatNEO The The general recommendation for games is to avoid the display or compositor performing a conversion to the final values, due to poor results on many displays (if the display/compositor even bothers). That is the primary reason my PR does not provide HDR10 metadata to the system. We should avoid doing the same for Wayland. |
|
The surface feedback is simply the profile the compositor would like us to use according to docs. There is no reason why if the compositor is not able to transform values itself it shouldn’t return the actual profile of the screen and perform no transformation on the incoming data. My fear with not using the feedback and using the screen format is that a compositor may then transform it into its preferred format to do processing and then back into the screens native format when we could have used the compositors format from the beginning. The way I see it there are 3 ways we could do this.
As of now I have no reason to believe compositors would implement a buggy transformation instead of performing no transformation at all which makes me partial to 3. If enumerating screens is a desirable property I would go with 2 because assuming the compositor is buggy and will not perform transformations on its preferred format correctly (as 1 assumes) does not seem that reasonable. For people with more experience with wayland: when a compositor implements a protocol, is assuming a correct implementation reasonable? I don’t have much experience with the reliability of different compositors beyond knowing mutter doesn’t support SSD so knowing if they are so unreliable we should not rely on |
b67a8c6 to
95411c9
Compare
|
Finally got round to a In terms of what I think has to be done before this stops being a draft I think the most important is making sure that if the preferred profile changes (whether that be from the screen itself or from the compositor) and screen_luminance is enabled we set the window luminances. We should also destroy all the wayland objects that we aren't already destroying. After that I think just cleaning up error messages and state management (not setting values that are already equal, remembering whether we tried to enable hdr, etc) are the main things for a mergable PR. I went with |
That's definitely sensible, you don't want to stack multiple tone mapping processes on top of each other if it can be avoided. Even if the compositor does really good tone mapping, it may have a performance cost, so if you do tone mapping either way, you should do all of it in one go. That does not mean you should use the output image description though, as that could require additional conversions. The preferred image description is the most optimal one for the window.
That won't work. Wayland is not like Windows, where HDR metadata at best does nothing and at worst causes issues. If you don't provide HDR metadata, the compositor may (and KWin always does) clip the image to SDR range.
Indeed, that is a likely scenario. If a compositor does blending in linear, if the game renders in linear, converts to BT2020PQ and sends that to the compositor, it'll convert back to linear, then do its compositing, and then convert to BT2020PQ for the display. The first two conversions could be optimized out by providing the compositor with scRGB instead of BT2020PQ for example.
Yes. If you can't trust a compositor far enough to provide an optimal image description for the window, why would you trust it with the output image description? The minimal implementation for the protocol just returns the image description of the output the window is on anyways. |
That's a little concerning and would suggest a project setting is needed to control whether Godot outputs HDR10 metadata to the system. Neither macOS nor Windows seems to require this, so it is odd that Wayland does. It is a new protocol though, so this may change as compositors run into programs that don't provide the required metadata. I wonder if gamescope works the same way? |
|
The mesa drivers for vulkan make use of this protocol. Unless we explicitly tell the vulkan driver to not give the compositor the information it needs (in which case we’d have to do so ourselves) then the compositor will receive the metadata. I read through some of the “what this protocol is and what it isn’t”
In all situations it is better to supply metadata (or just let vulkan do it for us) because otherwise every compositor that implements this protocol will assume we are using sRGB and attempt to fix our rendering. https://gitlab.freedesktop.org/pq/color-and-hdr/-/blob/main/doc/design_goals.md |
It won't change. Proper HDR metadata is fundamental to good HDR support, and without it you will always get a suboptimal experience. KWin does have a fallback for existing but obviously crazy HDR metadata (many Windows games claim to have 10 million nits max_cll, because some engine has really broken HDR support) - but that fallback makes assumptions that may cause tone mapping to be applied when the game wouldn't need it. You do not want that to be applied to Godot. MacOS does need HDR metadata too afaik. It might not clip in all situations, but for example their equivalent of HDR on SDR laptop displays can't really work without it.
Gamescope does Windows behavior as far as it can. Afaik it completely ignores HDR metadata and doesn't do anything in regard to reference luminance. |
|
We seem to be talking past each other a lot. You seem very persistent is asking whether or not the screen our window is on supports HDR or not. As far as I can tell this question does not make sense under Wayland (even if it may make sense in other systems). According to the above link KWin (and I suspect other compositors too) are able to render HDR content on SDR displays and do so in a way that somewhat preserves the HDR nature of the content. The question of SDR/HDR then needs to move on from does the screen support HDR. If we are outputting standard SDR content on an HDR monitor we should default to If we are outputting HDR content on an SDR screen then things may be more complex. Since on wayland the capabilities of the physical screen do not seem relevant we will not use them. If So then to avoid outputting HDR content on a potentially SDR monitor we should make I believe we should aim for as much transparency as possible when implementing this feature and this implementation of |
95411c9 to
321826a
Compare
|
Without a change to how the
But there's a bit more I could do without that so that's this. I'd like it if there was more consistency but I think just pushing developers towards |
I thought there was a preferred vs. supported distinction? But if not, just setting supported only to true if the image description has |
321826a to
0951581
Compare
|
As per a recommendation by riteo: now the color state of screens is in |
|
@ArchercatNEO Would you mind updating this PR's description with details about what is required for HDR output? Without considering Linux, this is what I have so far: Steps to enable HDR output in your project:
Does there need to be something about the |
|
For HDR output we need the Wayland display server, "default" for Linux is still X11 so we need to explicitly enable it. For the project you need to set The editor uses a different method for choosing a display server ( I will update main PR description, though do I need to mention any of this in actual doc changes in this PR? |
|
Thanks!
I see you already have this in the changes to
Hmm. I'm curious why there is a separate editor setting at all, it sounds like a recipe for problems and also adds complexity to things like the documentation I'm writing for HDR output. Might be worth revisiting this in a separate proposal/PR and removing the editor setting entirely so the editor just follows the project settings if there isn't a good reason that still exists to have a separate editor setting. |
The main rationale is that people might want to use the editor through Wayland but still export with the default display driver order (X11, Wayland) for stability. This was especially relevant when the Wayland backend was still single-window only, but I think that it's still useful to have this distinction until it becomes the default. |
|
Alongside the rebase I pre-emptively removed support for llvmpipe to just have the PR in a mergeable state. From my testing the banding was pretty severe but if other testing has different results I can add it back in. |
|
Since there are some compositor developers in this thread, we were discussing about ways of getting rid of If we were to replace this flag with |
allenwp
left a comment
There was a problem hiding this comment.
I finally got a computer set up with Fedora KDE plasma! There aren't any major glaring issues that I experienced right out the gate -- great job!
I've added some comments for things that should be adjusted.
It should be very safe, X11 doesn't do color management for you either way. |
|
Thanks for all the feedback! One thing I was wandering was about llvmpipe. Where you able to test it? There may be old github action builds you could use, since I removed the support. It would be nice to close the last of Calinou's thread which don't require his feedback. |
|
Squashed the error message and HDR format selection into one commit as well as dropping the HDR supported commit. Unresolved issues I am aware of
If there are any other unresolved threads I missed feel free to remind me, but it seems we're getting very close to covering the reviews of all relevant maintainers. Soon! |
allenwp
left a comment
There was a problem hiding this comment.
Trying to put
get_colorspace_externally_managedsomewhere better (my only idea is replacing the check with#ifdef WAYLANDand just hoping that nothing breaks on X11 or compositors that don't implement wp-color-management. Personally, I can't think of a way that this could break but that doesn't mean such a situation does not exist).
I apologize, but it's possible that RenderingDeviceDriver is actually the best place for this. Upon further reflection, I have realized that I have no expressible reason to believe that this is the incorrect place for this. It's just a gut feeling.
Skyth mentioned in RocketChat that maybe get_colorspace_externally_managed() could maybe be moved to the RenderingContextDriverVulkan and then the device driver can query it. There's also an option of the logic to set this flag to true being in RenderingContextDriverVulkanWayland, but I'm not sure if it will be able to access the wayland thread reasonably to query wayland_thread.supports_hdr().
I'm fine with whichever approach, so long as it keeps the code clean and simple.
If there are any other unresolved threads I missed feel free to remind me, but it seems we're getting very close to covering the reviews of all relevant maintainers. Soon!
I also have added a few small change suggestions that I believe should be made before further review and merge.
P.S. I'm getting a hang when I try and close either the Godot editor or Godot game. I have no idea if this is related to this PR because this is my first time using Linux at all, so it's possible it has to do with my local build or something in master.
|
Applied the low-hanging fruit changes, and like I mentioned I will try to work on |
As I understand it, we are OK with using C++20 in the Wayland code as it's only used for Linux builds. It's not compiled for any other platform where requiring C++20 might be a problem. The build toolchain used for official binaries already supports C++20 (even outside Linux). |
allenwp
left a comment
There was a problem hiding this comment.
I made a bigger deal about where get_colorspace_externally_managed() should live than was needed given that I don't have a better place to put it off-hand.
From my perspective, so long as the #ifdef WAYLAND_ENABLED is switched back to context_driver->get_colorspace_externally_managed() as descried in my previous review comment, I'm happy with how this PR is right now.
I'll leave the final resting place of get_colorspace_externally_managed() up to you and whoever else cares about this! I'll request a review from @blueskythlikesclouds to give a final sign off from someone on the rendering team.
Thanks for your work on this!
|
To add to the I think that, in general, we should allow third party platforms to be as "plug-n-play" as possible. |
Replaced HDMI cable with DP-to-HDMI, and now HDR is working on Linux. I have tested current version, and it seems to be working fine, except initial HDR status detection.
|
There was a problem hiding this comment.
Rendering code looks good to me.
Like I mentioned in RC, I think get_colorspace_externally_managed can be moved to RenderingContextDriverVulkan without a backing field. RenderingContextDriverVulkanWayland would override it and return true.
Since this appears to be Vulkan specific, it doesn't feel right to me to have this in the abstract rendering context driver class.
Adding listened early seems to fix it: diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp
index 57ce7d4aa6..44fecb7945 100644
--- a/platform/linuxbsd/wayland/wayland_thread.cpp
+++ b/platform/linuxbsd/wayland/wayland_thread.cpp
@@ -4054,6 +4054,9 @@ void WaylandThread::window_create(DisplayServerEnums::WindowID p_window_id, cons
ws.wp_color_management_surface_feedback = wp_color_manager_v1_get_surface_feedback(registry.wp_color_manager, ws.wl_surface);
wp_color_management_surface_feedback_v1_add_listener(ws.wp_color_management_surface_feedback, &wp_color_management_surface_feedback_listener, &ws);
+ struct wp_image_description_v1 *image_description = wp_color_management_surface_feedback_v1_get_preferred_parametric(ws.wp_color_management_surface_feedback);
+ wp_image_description_v1_add_listener(image_description, &wp_image_description_listener, &ws);
+
//NOTE: requires vulkan to use the VK_COLOR_SPACE_PASSTHROUGH_EXT colorspace to not raise protocol errors
ws.wp_color_management_surface = wp_color_manager_v1_get_surface(registry.wp_color_manager, ws.wl_surface);
} |
|
I have applied bruvzg's suggestion and moved Since I want this PR to be in a mergable state I have reverted to the agreed interface, the condition is also now simply that we are on Wayland. This is more correct than asking whether the compositor supports HDR because previously if the compositor supported wp-color-management but not the ext_linear transfer function, we would manage the colorspace externally but not report it to the driver. If wp-color-management is not supported there's nothing the driver could do even if we used a real vk colorspace. I will make a suggestion on the Android PR to move all of the colorspace priority logic into a platform-dependant virtual method, but that will be in the Android PR. |
blueskythlikesclouds
left a comment
There was a problem hiding this comment.
Code looks good to me! I can't test this though so I hope nothing was missed.
|
Thanks! Great work getting everything together! |
Description updated for 2026/02/23.
Based on #94496 (merged to master)
Implements godotengine/godot-proposals#10817 for Wayland
Testing/Sample project: https://github.com/DarkKilauea/godot-hdr-output
This PR implements the luminance based features of the wp-color-management protocol as well as the minimum amount of colorspace + transfer function features necessary for HDR output.
Due to the unreliability of HDR applying glare compensation or not, SDR over HDR is assumed to be performed against a monitor which does not apply glare compensation which differs from the assumptions made in the Windows and Mac implementations for HDR. The Wayland protocol was made with this assumption so we will not deviate from it despite having the possibility to do so.
Since this feature is exclusive to Wayland, the display server must be set to Wayland in both project settings and editor settings (not setting both to Wayland leads to inconsistencies in display server selection).
For editor:
run/platforms/linuxbsd/prefer_waylandmust be enabled.For project:
display/display_server/driver.linuxbsdset to "wayland" (X11 is still set chosen when "deafault" is selected).