Skip to content

[Windows] Add support for AdvancedColorInfo info and change callback.#118339

Merged
Repiteo merged 1 commit into
godotengine:masterfrom
bruvzg:winrt_color
Apr 16, 2026
Merged

[Windows] Add support for AdvancedColorInfo info and change callback.#118339
Repiteo merged 1 commit into
godotengine:masterfrom
bruvzg:winrt_color

Conversation

@bruvzg
Copy link
Copy Markdown
Member

@bruvzg bruvzg commented Apr 9, 2026

See #117837 (comment)

Note: this will not work on Wine and some older Windows 10 versions (pre-1809 / Redstone 5), so we still need to keep polling code for this case.

Fixes #118618

Comment thread platform/windows/display_server_windows.cpp Outdated
@bruvzg bruvzg force-pushed the winrt_color branch 4 times, most recently from 7172109 to 5e06576 Compare April 9, 2026 10:57
@bruvzg bruvzg requested a review from allenwp April 9, 2026 11:10
@allenwp
Copy link
Copy Markdown
Contributor

allenwp commented Apr 9, 2026

🤩

but it can be conditionally skipped (using WinRTUtils::window_has_display_info).

Any chance this PR can be updated to include this? Although this PR does solve the problem of the reference luminance not updating until the window regains focus, the real high-priority impetus for this change is to improve performance significantly by not needing to poll for changes in colour space and max luminance.

It will also be critically important to test if the WM_DISPLAYCHANGE happening before DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 problem occurs with this approach. I'd like to test to see if the new advanced colour event happens before DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 100% of the time...

@allenwp allenwp mentioned this pull request Apr 9, 2026
34 tasks
@allenwp
Copy link
Copy Markdown
Contributor

allenwp commented Apr 9, 2026

Any chance this PR can be updated to include this?

Derp. My mistake! I think this PR already does this!

I'll give this a thorough test. It would be great to have this for 4.7...

@allenwp
Copy link
Copy Markdown
Contributor

allenwp commented Apr 14, 2026

I just tested this on my "problematic" computer now. I was able to produce a bug in this PR where the screen would be in HDR output mode (from pressing the Win + Alt + B shortcut), but Godot would think the Window did not support HDR output. This appears to be because a DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 colour space was still reported for the moments after the new _winrt_adv_color_info_cb was called. This is exactly what happens after the WM_DISPLAYCHANGE event, so it's not surprising that it would occur with AdvancedColorInfoChanged as well.

But, the new screen information includes a CurrentAdvancedColorKind, which can tell us if we should be in HDR mode and will let us fill out the ScreenHdrData struct! So I've made a modified version of this PR that fixes the bug. I tested this by running both this PR and my update at the same time to verify this.

https://github.com/allenwp/godot/tree/winrt_color

My branch has some remaining issues. Specifically, I needed to remove the const part of _get_screen_hdr_data. Not sure how to avoid this, so that needs some work.

Also, in this PR, I'd be fine only including the items we actually will use in the dictionary that window_get_advanced_color_info returns instead of filling in all of the other data we'll never use. But I'm not familiar with the preferred code style for this sort of thing.


After doing some more testing, I am now no longer able to reproduce the issue with this PR... but the commit just before this PR (master) is now entirely broken on my computer and the DXGI_OUTPUT_DESC1 is always reporting DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 until I adjust the SDR content brightness Windows setting or I start Godot with Windows in HDR mode. This doesn't happen with this PR or with my update, which makes no sense to me because I would expect this PR to also have the same issue... So I feel like I'm going a bit crazy here. Either way, I haven't yet seen an issue with my branch.

I'll continue trying to reproduce these two issues to firmly verify what is going on here and that the behaviour in my branch is the best approach for Godot...

@bruvzg
Copy link
Copy Markdown
Member Author

bruvzg commented Apr 15, 2026

Specifically, I needed to remove the const part of _get_screen_hdr_data. Not sure how to avoid this, so that needs some work.

What's causing it not to work with const, if it's window data access and non-const WinRTWindowData * in utils it should be changed to const in utils instead, has/get functions doesn't write to this pointer.

Also, in this PR, I'd be fine only including the items we actually will use in the dictionary

If we only need color type, max_luminance, and sdr_white_level it probably would make sense to use return args instead of Dictionary. This is unexposed internal API, so there's no specific requirements.

This doesn't happen with this PR or with my update, which makes no sense to me because I would expect this PR to also have the same issue...

No idea, but it's possible that working WinRT dispatcher queue for the window can result in DirectX getting some extra system events as well.

@bruvzg
Copy link
Copy Markdown
Member Author

bruvzg commented Apr 15, 2026

I'll apply your changes (+ const fix and change from dict to return args) and retest in a bit later today.

Co-authored-by: Allen Pestaluky <allenpestaluky@gmail.com>
@bruvzg
Copy link
Copy Markdown
Member Author

bruvzg commented Apr 15, 2026

Updated it and it seems to be working fine. I was not able to reproduce issue with Win + Alt + B switching, all HDR data for new and old method is always the same.

@allenwp
Copy link
Copy Markdown
Contributor

allenwp commented Apr 15, 2026

Thanks, if my computer is still producing the weird bug with the dev releases, I’ll post an issue and demonstrate that this PR fixes it. Yesterday, at least, it became very consistent. I must have some funny NVIDIA drivers or something for my 5070 Ti…

@allenwp
Copy link
Copy Markdown
Contributor

allenwp commented Apr 15, 2026

I've created a bug report. This PR fixes the bug: #118618

@allenwp
Copy link
Copy Markdown
Contributor

allenwp commented Apr 15, 2026

I've requested review from blueskythlikesclouds, also cc @DarkKilauea. You two are both familiar with this code, so I figure you might want to take a look.

In short, this PR should prevent any of the "legacy" HDR screen info functions from running and instead exclusively use the new WinRT advanced colour info functions and event when they are available. This should improve performance by not needing to poll anything and also seems to fix two bugs that I had been experiencing relating to the colour space that DXGI_OUTPUT_DESC1 was reporting. Windows emulation and older versions of Windows can use the old legacy method, since this is the only option to make these work.

I have reviewed the changes to DisplayServerWindows and they look good to me, but I can't comment on the rest of the files, since I'm not familiar with those. I have not approved this PR yet because it will take quite a bit of testing over the next few days on systems with different configurations before I'm confident that there aren't any unexpected bugs. I'll report back when I've built and exported with MinGW and tested on computers like laptops with built-in HDR screens.

Copy link
Copy Markdown
Member

@Calinou Calinou left a comment

Choose a reason for hiding this comment

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

Tested locally on Windows 11 24H2, it works as expected.

I've tested changes to the SDR content brightness slider at runtime, as well as toggling HDR on the system while the project is running (on -> off, or off -> on). Everything updates in real-time (no more need to focus the window to update SDR content brightness).

Comment thread platform/windows/winrt_utils.cpp
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.

Looks good to me. The CPU cost is also basically gone.

@Repiteo Repiteo merged commit a6dccbf into godotengine:master Apr 16, 2026
20 checks passed
@Repiteo
Copy link
Copy Markdown
Contributor

Repiteo commented Apr 16, 2026

Thanks!

shaun0927 added a commit to shaun0927/godot that referenced this pull request Apr 17, 2026
…RT queue on shutdown

Follow-up on godotengine#118339. Two correctness fixes in the WinRT
AdvancedColorInfo path:

1. _winrt_adv_color_info_cb and _get_screen_hdr_data access
   windows[p_window] without the windows.has(...) guard that every
   other entry point on this class already uses. The WinRT event is
   delivered via call_deferred, so a window can be closed between the
   event firing and the deferred call running. HashMap::operator[]
   then auto-inserts a default WindowData (non-const) or hits UB
   (const), neither of which is intended.

2. WinRTUtils::destroy_queue calls controller.ShutdownQueueAsync()
   without awaiting the returned IAsyncAction. If an
   AdvancedColorInfoChanged callback is in flight when
   ~DisplayServerWindows runs, it can execute against partially
   destroyed members. Block on .get() during shutdown so teardown
   waits for in-flight events to drain.
shaun0927 added a commit to shaun0927/godot that referenced this pull request Apr 17, 2026
Follow-up on godotengine#118339, addressing review feedback on godotengine#118669.

Move the windows.has(...) guard from the internal _get_screen_hdr_data
helper to the public HDR methods that own the WindowID lookup, so the
check sits at the API boundary like every other public method on
DisplayServerWindows. Also keep the guard on the WinRT-deferred
callback _winrt_adv_color_info_cb, where the callback can fire after
the window is gone.

Public methods guarded:
 - window_is_hdr_output_supported
 - window_request_hdr_output
 - window_set_hdr_output_reference_luminance
 - window_set_hdr_output_max_luminance

The previously proposed controller.ShutdownQueueAsync().get() change
in winrt_utils.cpp was dropped: bruvzg confirmed it would deadlock,
since destroy_queue runs on the main thread after the event pump has
already stopped, so .get() would never return.
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.

HDR output not activated when enabling HDR mode in Windows

6 participants