Skip to content

[LinuxBSD] Add support for HDR output (Wayland)#102987

Merged
Repiteo merged 1 commit into
godotengine:masterfrom
ArchercatNEO:wayland-hdr
Mar 16, 2026
Merged

[LinuxBSD] Add support for HDR output (Wayland)#102987
Repiteo merged 1 commit into
godotengine:masterfrom
ArchercatNEO:wayland-hdr

Conversation

@ArchercatNEO
Copy link
Copy Markdown
Contributor

@ArchercatNEO ArchercatNEO commented Feb 18, 2025

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_wayland must be enabled.
For project: display/display_server/driver.linuxbsd set to "wayland" (X11 is still set chosen when "deafault" is selected).

Comment thread platform/linuxbsd/wayland/display_server_wayland.cpp Outdated
@DarkKilauea
Copy link
Copy Markdown
Contributor

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:

  1. Declaring its support for HDR (already done).
  2. Getting HDR support and luminance data from the display (you mostly have this).
  3. Telling the RenderDevice to use HDR and passing the parameters for precision and luminance. (you have most of the methods implemented).
  4. Automatically responding to changes in HDR support and movement of windows between displays.
  5. Automatically mapping the window to the display's luminance capabilities if use_screen_luminance is enabled.
  6. Preventing common errors like:
    • Trying to change luminance on a window if use_screen_luminance is enabled
    • Trying to enable HDR on a screen that does not support it, or if the RenderDevice does not support it.
    • Remembering if the user tried to enable HDR and automatically enabling it if the screen starts supporting it (or the window moves to an HDR capable screen).
    • Preventing lag by not setting hdr_output_enabled or hdr_output_prefer_high_precision if they are already match the requested value.

@ArchercatNEO ArchercatNEO force-pushed the wayland-hdr branch 2 times, most recently from e522785 to b67a8c6 Compare February 19, 2025 17:52
@ArchercatNEO
Copy link
Copy Markdown
Contributor Author

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?

  • If the Compositor implements color-management-v1 then yes.
  • If the Compositor doesn't implement color-management then vulkan APIs may still be able to handle it but unless it's far easier than I think to get information from Vulkan it doesn't seem practical.
  • Related APIs: color-management-v1

Does the Screen (Wayland output, PC monitor) support HDR? And if so, what is the luminance/primaries/tf/etc?

  • First obtain a wp_color_management_output. This (after a few layers of indirection) will give the screen's ICC profile
  • From this profile if the primaries_named and tf_named combination is a known HDR profile that godot supports, yes.
  • If the profile is an SDR profile there is no HDR. If it is an unsupported HDR profile probably raise a warning.
  • The luminance of the screen itself I am assuming to be from the luminaries event.
  • The target_* events I assume to refer to window values so they will be used for use_screen_luminance later
  • The rest of the events may be helpful for a full wayland ICC implementation but again that is outside the scope
  • Related APIs: wp_color_manager_v1::get_output, wp_image_description_info

How to manipulate HDR values of this Window (Wayland surface)?

  • This seems largely a Vulkan (or RenderingDriver) API which was already implemented so just defer to RenderingDriver.

What is the preferred screen luminance (for use_screen_luminance)?

On the concrete impl side of things

  • Screen luminance and descriptor_params are still unimplemented. I believe using the supports_* flags will be neccesary to coordinate what profile godot will actually use
  • Most of the relevant APIs are events which should make automatically responding more transparent
  • Object destruction needs to happen to prevent memory leaks
  • Docs/Warns/Errors will likely be handled last after I get more advice on where this state should really go

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.

@deralmas
Copy link
Copy Markdown
Member

deralmas commented Feb 19, 2025

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 *State class, which you'll need to bind anyways to the object so that it can be accessed by the handler. Even the "global" data you're talking about is still bound to an object, so it becomes quite easy to see where I'm going.

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 malloc their state in the user_data. See the *_get_*_state classes and the way their objects are handled.

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 whatever to not be null and whether it's properly "tagged" (a concept we use to signal that our objects are, well, ours and with our data attached to them) thanks to wl_proxy_tag_godot.

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.

@Zamundaaa
Copy link
Copy Markdown

If the Compositor implements color-management-v1 then yes

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.

If the Compositor doesn't implement color-management then vulkan APIs may still be able to handle it but unless it's far easier than I think to get information from Vulkan it doesn't seem practical.

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.

Does the Screen (Wayland output, PC monitor) support HDR? First obtain a wp_color_management_output.

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 target_* events I assume to refer to window values so they will be used for use_screen_luminance later

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.

In all cases use wp_image_description_creator_params to tell the compositor what profile we have chosen so that it may perform it's job better

Note that while you can have multiple wp_color_management_surface_feedback_v1, you can only have one wp_color_management_surface_v1 per Wayland surface at a time. If Godot already uses Vulkan to set a colorspace and HDR metadata on the window, then you must not create a color management surface in addition, as the driver creates one too!

If you want to use the protocol directly, you can do that if you set VK_COLOR_SPACE_PASS_THROUGH_EXT as the colorspace with Vulkan, which tells the driver to not use the protocol.

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 set_luminances, but that's an optional feature and not every compositor currently supports it.

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 :)

@ArchercatNEO
Copy link
Copy Markdown
Contributor Author

@DarkKilauea should the screen_* APIs be implemented against the real profile of the wl_output or the reccomended profile of wl_surface_feedback? I am partial to @Zamundaaa since the intention of using the screen profile I expect is for performance/efficiency/power but the feedback is the one that gives the most optimal profile not the output.

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 feedback seems more fitting but in the (I think quite esoteric) case of enumerating screens to see which one is most fitting for custom HDR output. Next update will likely be using feedback and just dropping output entirely but clarification on this would be helpful.

@DarkKilauea
Copy link
Copy Markdown
Contributor

@ArchercatNEO The screen APIs should return the characteristics of the display that Godot should be tonemapping to. I would bias towards returning the actual capabilities of the display instead of asking the compositor to perform some of the mapping itself.

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.

@ArchercatNEO
Copy link
Copy Markdown
Contributor Author

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.

  1. Use output for everything and ignore feedback. I hesitate on this one because it assumes the compositor a bad implementation of the protocol and cannot be trusted.
  2. Use output for screen APIs and feedback for screen_luminance. My greatest hesitation on this is just the inconsistency. Since I haven’t seen useage of the screen APIs I’m not aware if the inconsistency is significant
  3. Use feedback for everything. This assumes the compositor behaves well (which could include doing no transformation at all) which seems like a reasonable assumption. It means we can’t actually enumerate the properties of screens the main window is not on but this doesn’t seem too large an issue for me. It also maintains consistency between screen and screen_luminance APIs

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 feedback would make 1 my preferred option.

@ArchercatNEO
Copy link
Copy Markdown
Contributor Author

Finally got round to a screen_luminance implementation.

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 feedback for everything because trusting the compositor felt right (and I checked the mesa PR, there you can see that the vulkan impl does actually use this protocol too so the system does get metadata) and consistency between screen and screen_luminance felt important. If we decide to go in another direction it probably won't be too hard to just add an IccProfile to ScreenData and do something similar to what we already do except instead of using the window's intrinsic feedback profile we just look for which screen the window is on and use its profile

@Zamundaaa
Copy link
Copy Markdown

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

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 is the primary reason my PR does not provide HDR10 metadata to the system. We should avoid doing the same for Wayland.

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.

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.

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.

For people with more experience with wayland: when a compositor implements a protocol, is assuming a correct implementation reasonable?

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.

Comment thread platform/linuxbsd/wayland/wayland_thread.cpp Outdated
Comment thread platform/linuxbsd/wayland/wayland_thread.h Outdated
Comment thread platform/linuxbsd/wayland/wayland_thread.h Outdated
Comment thread platform/linuxbsd/wayland/wayland_thread.cpp
Comment thread platform/linuxbsd/wayland/wayland_thread.cpp Outdated
Comment thread platform/linuxbsd/wayland/wayland_thread.cpp Outdated
Comment thread platform/linuxbsd/wayland/wayland_thread.cpp Outdated
@DarkKilauea
Copy link
Copy Markdown
Contributor

That is the primary reason my PR does not provide HDR10 metadata to the system. We should avoid doing the same for Wayland.

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.

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?

@ArchercatNEO
Copy link
Copy Markdown
Contributor Author

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”

  • Applications that do not supply metadata (most likely just apps with old libraries seeing as how mesa drivers themselves implement this protocol) are assumed to be using sRGB and the compositor should transform it as such
  • Applications that supply metadata (maybe because it’s the only one they can render in) are to be transformed by the compositor in whichever way it sees fit to render on the monitor
  • Applications that can render in many color spaces (like us) should render in the preferred profile as given by surface_feedback. It should also tell the compositor it is doing so (which is handled by vulkan)

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

Comment thread platform/linuxbsd/wayland/display_server_wayland.cpp Outdated
Comment thread platform/linuxbsd/wayland/display_server_wayland.cpp Outdated
Comment thread platform/linuxbsd/wayland/display_server_wayland.cpp Outdated
Comment thread platform/linuxbsd/wayland/wayland_thread.cpp Outdated
@Zamundaaa
Copy link
Copy Markdown

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.

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.

I wonder if gamescope works the same way?

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.

@ArchercatNEO
Copy link
Copy Markdown
Contributor Author

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 use_hdr = true and use_screen_luminance = true as far as I can tell. Since we are ignoring the physical capabilities of the screen this means that if the compositor is asking for an HDR format in surface_feedback then likely this is an HDR monitor. If this is the case then internally we should collaborate with the compositor to render in an HDR format and this should be transparent to the user.

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 use_hdr has been enabled then we are rendering in an HDR format. If use_screen_luminance is also enabled perhaps what would make more sense is to disable hdr if the compositor prefers an srgb colorspace and then perform whatever transformation we require to clip our HDR content. If use_hdr is enabled and use_screen_luminance is disabled, then we will render output HDR content on a potentially SDR display.

So then to avoid outputting HDR content on a potentially SDR monitor we should make use_screen_luminance be independent from use_hdr. If it is enabled then we will internally decide all colorspace values including whether we use an SDR or HDR format. On wayland this will mean adopting surface_feedback to the best of our ability. On other systems it may mean adopting the physical screen profile to the best of our ability. If use_screen_luminance is disabled then it is up to the user to decide upon SDR/HDR with use_hdr and their values which may or may not be efficient.

I believe we should aim for as much transparency as possible when implementing this feature and this implementation of use_screen_luminace seems to me quite transparent as ideally it should require no configuration on the part of the developer or the end user, it can simply be enabled to allow for efficient transformation of SDR content on HDR screens or graceful clipping of HDR content on SDR screens. This could be by either godot internally (if use_screen_luminance is enabled) or the os/compositor/screen (if both use_screen_luminance is disabled and use_hdr is enabled). On systems where external clipping is known to be faulty (e.g. windows, mac) this can be restricted however you best see fit (e.g. complete failure, warnings, errors, etc.) however since I know of no such faults on wayland I see no reason to disallow outputting HDR content on SDR screens as long as both use_screen_luminance is disabled and use_hdr is enabled.

@ArchercatNEO
Copy link
Copy Markdown
Contributor Author

Without a change to how the display/window/hdr/enabled works we can't really implement "implicit" hdr and using the preferred profile with screen_luminance consistently. If we say screen_supports_hdr is "unconditionally" true (depends on compositor supports) but then check for max_luminance > sdr_white to actually enable it we're going to get bug reports. If the project setting didn't just enable hdr on all windows it's a simple fix.

bool enable_hdr = (GLOBAL_GET("display/window/hdr/enabled") && max_luminance > sdr_white) || window->hdr_enabled)

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 screen_luminance in docs will have to suffice. If they implement an hdr settings menu they're already not doing the preferred profile so that's really beyond attempting to optimise engine side (as far as this pr is concerned).

@Zamundaaa
Copy link
Copy Markdown

Without a change to how the display/window/hdr/enabled works we can't really implement "implicit" hdr and using the preferred profile with screen_luminance consistently.

I thought there was a preferred vs. supported distinction?

But if not, just setting supported only to true if the image description has max luminance > reference luminance would be totally fine. Like I wrote in #94496, letting the compositor tonemap in that situation is a really niche thing that you don't have to put any effort in for.

@ArchercatNEO
Copy link
Copy Markdown
Contributor Author

As per a recommendation by riteo: now the color state of screens is in ScreenState instead of ScreenData. I did have to expose a new method to actually get ScreenState from the DisplayServer so I hope that's okay. Good news is with this change the wp_color_management_output_v1s actually get destroyed now so less memory leaks.

@allenwp
Copy link
Copy Markdown
Contributor

allenwp commented Feb 23, 2026

@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:

  1. Ensure no Environment resources use SDR-only features:
    • Tonemap Mode: Filmic or ACES
    • Glow Blend Mode: Soft Light
    • Adjustments: Color Correction
  2. Configure the rendering/rendering_device/driver project setting to the following:
    • macOS: metal
    • iOS: metal
    • Windows: d3d12
  3. Turn on the rendering/viewport/hdr_2d project setting and enable use_hdr_2d for all Subviewports and Windows that should support HDR output.
  4. Turn on the display/window/hdr/request_hdr_output project setting and enable hdr_output_requested for all other Windows that should support HDR output.
  5. [Optional] Provide in-game settings for the player to adjust HDR brightness and maximum luminance by copying in_game_hdr_settings from this demo to your project.

Does there need to be something about the display/display_server/driver.linuxbsd project setting? (Does this need to be set to default or wayland?) Also, does the run/platforms/linuxbsd/prefer_wayland editor setting also need to set to On or can this be on or off to get HDR output in the editor?

@ArchercatNEO
Copy link
Copy Markdown
Contributor Author

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 display/display_server/driver.linuxbsd to wayland (again because "default" is still X11). Projects don't look at editor settings so unless users are using command line arguments to run the games they will get X11/XWayland.

The editor uses a different method for choosing a display server (run/platforms/linuxbsd/prefer_wayland) and fully ignores the project setting. If the project is embedded in the editor it will inherit the display server that the editor uses instead of using the project setting which means it's possible to get weird behaviour where embedded and exported games behave differently.

I will update main PR description, though do I need to mention any of this in actual doc changes in this PR?

@allenwp
Copy link
Copy Markdown
Contributor

allenwp commented Feb 23, 2026

Thanks!

I will update main PR description, though do I need to mention any of this in actual doc changes in this PR?

I see you already have this in the changes to doc/classes/DisplayServer.xml

The editor uses a different method for choosing a display server (run/platforms/linuxbsd/prefer_wayland) and fully ignores the project setting. If the project is embedded in the editor it will inherit the display server that the editor uses instead of using the project setting which means it's possible to get weird behaviour where embedded and exported games behave differently.

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.

@deralmas
Copy link
Copy Markdown
Member

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.

Comment thread drivers/vulkan/rendering_device_driver_vulkan.cpp Outdated
@ArchercatNEO
Copy link
Copy Markdown
Contributor Author

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.

@ArchercatNEO
Copy link
Copy Markdown
Contributor Author

Since there are some compositor developers in this thread, we were discussing about ways of getting rid of get_colorspace_externally_managed which is effectively just a flag that determines whether we're using a wayland compositor or not.

If we were to replace this flag with #ifdef WAYLAND_ENABLED then all godot games, including those using X11, would request VK_COLOR_SPACE_PASS_THROUGH_EXT when performing HDR (if the driver supports it). We are very cautious about doing this because we believe this could affect some X11 configuration out there. Is there a reason for us to be cautious or is using VK_COLOR_SPACE_PASS_THROUGH_EXT with the X11 display server safe?

Copy link
Copy Markdown
Contributor

@allenwp allenwp left a comment

Choose a reason for hiding this comment

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

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.

Comment thread platform/linuxbsd/wayland/display_server_wayland.cpp
Comment thread platform/linuxbsd/wayland/display_server_wayland.cpp Outdated
Comment thread platform/linuxbsd/wayland/display_server_wayland.cpp Outdated
Comment thread drivers/vulkan/rendering_device_driver_vulkan.cpp
Comment thread drivers/vulkan/rendering_device_driver_vulkan.cpp
Comment thread drivers/vulkan/rendering_device_driver_vulkan.cpp Outdated
@Zamundaaa
Copy link
Copy Markdown

If we were to replace this flag with #ifdef WAYLAND_ENABLED then all godot games, including those using X11, would request VK_COLOR_SPACE_PASS_THROUGH_EXT when performing HDR (if the driver supports it). We are very cautious about doing this because we believe this could affect some X11 configuration out there. Is there a reason for us to be cautious or is using VK_COLOR_SPACE_PASS_THROUGH_EXT with the X11 display server safe?

It should be very safe, X11 doesn't do color management for you either way.

@ArchercatNEO
Copy link
Copy Markdown
Contributor Author

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.

@ArchercatNEO
Copy link
Copy Markdown
Contributor Author

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

  • Using C++20 features (waiting on Calinou for this)
  • Support for llvmpipe/16-bit ints (I though the banding was pretty bad but I'm only one person)
  • Trying to put get_colorspace_externally_managed somewhere better (my only idea is replacing the check with #ifdef WAYLAND and 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).

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!

Copy link
Copy Markdown
Contributor

@allenwp allenwp left a comment

Choose a reason for hiding this comment

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

Trying to put get_colorspace_externally_managed somewhere better (my only idea is replacing the check with #ifdef WAYLAND and 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.

Comment thread drivers/vulkan/rendering_device_driver_vulkan.cpp Outdated
Comment thread drivers/vulkan/rendering_device_driver_vulkan.cpp
Comment thread platform/linuxbsd/wayland/wayland_thread.h Outdated
Comment thread platform/linuxbsd/wayland/wayland_embedder.h
Comment thread platform/linuxbsd/wayland/wayland_thread.cpp
Comment thread platform/linuxbsd/wayland/wayland_thread.h
Comment thread platform/linuxbsd/wayland/wayland_thread.h
Comment thread platform/linuxbsd/wayland/display_server_wayland.cpp
Comment thread drivers/vulkan/rendering_device_driver_vulkan.cpp Outdated
Comment thread platform/linuxbsd/wayland/wayland_thread.h
@ArchercatNEO
Copy link
Copy Markdown
Contributor Author

Applied the low-hanging fruit changes, and like I mentioned I will try to work on get_colorspace_externally_managed in a bit. Hopefully dery can get back to us with the embedder file, but thanks for the final round of comments!

@Calinou
Copy link
Copy Markdown
Member

Calinou commented Mar 11, 2026

  • Using C++20 features (waiting on Calinou for this)

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).

Copy link
Copy Markdown
Contributor

@allenwp allenwp left a comment

Choose a reason for hiding this comment

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

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!

@deralmas
Copy link
Copy Markdown
Member

To add to the get_colorspace_externally_managed discourse, I personally agree that it should not be gated under the Wayland #ifdef, as other (third-party) platforms might want to use the same (AFAICT) standard Vulkan feature.

I think that, in general, we should allow third party platforms to be as "plug-n-play" as possible.

@bruvzg
Copy link
Copy Markdown
Member

bruvzg commented Mar 12, 2026

Code looks good. I was not able to test it, my Fedora install refuse to detect HDR monitor (which works fine on Windows on the same system).

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.

  • When project is started (on an HDR display), it is showing that HDR is not supported for the window.
  • After dragging window to the non-HDR display and back it is correctly detected, and everything seems to be working as expected.

Copy link
Copy Markdown
Member

@blueskythlikesclouds blueskythlikesclouds left a comment

Choose a reason for hiding this comment

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

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.

@bruvzg
Copy link
Copy Markdown
Member

bruvzg commented Mar 12, 2026

When project is started (on an HDR display), it is showing that HDR is not supported for the window.
After dragging window to the non-HDR display and back it is correctly detected, and everything seems to be working as expected.

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);
 	}

@ArchercatNEO
Copy link
Copy Markdown
Contributor Author

I have applied bruvzg's suggestion and moved get_colorspace_externally_managed (now is_colorspace_externally_managed) to a virtual method in RenderingContextDriver. The reasoning for this is that as far as I am aware, the platforms on which we can perform HDR with Vulkan (Linux, Android, and perhaps someday Mac and Windows) all have different preferences for colorspace selection.

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.

Comment thread platform/linuxbsd/wayland/display_server_wayland.h Outdated
Copy link
Copy Markdown
Member

@blueskythlikesclouds blueskythlikesclouds left a comment

Choose a reason for hiding this comment

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

Code looks good to me! I can't test this though so I hope nothing was missed.

@Repiteo
Copy link
Copy Markdown
Contributor

Repiteo commented Mar 16, 2026

Thanks! Great work getting everything together!

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.