diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 085691c635b..6ed55b98afe 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -3385,7 +3385,7 @@ HWND DisplayServerWindows::_find_window_from_process_id(ProcessID p_pid, HWND p_ } // Get screen HDR capabilities for internal use only. -DisplayServerWindows::ScreenHdrData DisplayServerWindows::_get_screen_hdr_data(int p_screen) const { +DisplayServerWindows::ScreenHdrData DisplayServerWindows::_get_screen_hdr_data(int p_screen, bool p_include_sdr_white_level) const { ScreenHdrData data; HMONITOR monitor = _get_hmonitor_of_screen(p_screen); if (!monitor) { @@ -3408,17 +3408,19 @@ DisplayServerWindows::ScreenHdrData DisplayServerWindows::_get_screen_hdr_data(i } #endif // D3D12_ENABLED - uint32_t path_count = 0; - uint32_t mode_count = 0; + if (p_include_sdr_white_level) { + uint32_t path_count = 0; + uint32_t mode_count = 0; - if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &path_count, &mode_count) == ERROR_SUCCESS) { - LocalVector paths; - LocalVector modes; - paths.resize(path_count); - modes.resize(mode_count); + if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &path_count, &mode_count) == ERROR_SUCCESS) { + LocalVector paths; + LocalVector modes; + paths.resize(path_count); + modes.resize(mode_count); - if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &path_count, paths.ptr(), &mode_count, modes.ptr(), nullptr) == ERROR_SUCCESS) { - data.sdr_white_level = _get_sdr_white_level_for_hmonitor(monitor, paths); + if (QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &path_count, paths.ptr(), &mode_count, modes.ptr(), nullptr) == ERROR_SUCCESS) { + data.sdr_white_level = _get_sdr_white_level_for_hmonitor(monitor, paths); + } } } @@ -3455,7 +3457,7 @@ void DisplayServerWindows::_update_hdr_output_for_window(DisplayServerEnums::Win #endif // RD_ENABLED } -void DisplayServerWindows::_update_hdr_output_for_tracked_windows() { +void DisplayServerWindows::_update_hdr_output_for_tracked_windows(bool p_include_sdr_white_level) { hdr_output_cache.clear(); for (const KeyValue &E : windows) { if (E.value.hdr_output_requested) { @@ -3463,7 +3465,7 @@ void DisplayServerWindows::_update_hdr_output_for_tracked_windows() { ScreenHdrData data; if (!hdr_output_cache.has(screen)) { - data = _get_screen_hdr_data(screen); + data = _get_screen_hdr_data(screen, p_include_sdr_white_level); hdr_output_cache.insert(screen, data); } else { data = hdr_output_cache[screen]; @@ -4161,7 +4163,16 @@ void DisplayServerWindows::process_events() { // Poll HDR output state for windows that have requested it. // Needed to detect changes in luminance values due to a lack of Windows events for such changes. - _update_hdr_output_for_tracked_windows(); + // System-reported max luminance changes when the user adjust the screen brightness of a laptop + // with a built-in HDR screen. Additionally, some computers may continue to report a + // DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 color space for a period of time after the + // WM_DISPLAYCHANGE event is received by Godot which means we must poll this regularly to + // capture this change in HDR capabilities of the screen triggered by the Win + Alt + B shortcut. + // The SDR white level (reference white luminance) does not need to be polled every frame + // because the only way to adjust this is to leave the Godot Window and adjust the SDR/HDR + // Content Brightness Windows display setting. This means the user must return to the Godot + // window, which triggers a WM_WINDOWPOSCHANGED event. + _update_hdr_output_for_tracked_windows(false); LocalVector::Element *> to_remove; for (List::Element *E = file_dialogs.front(); E; E = E->next()) { @@ -4633,7 +4644,7 @@ bool DisplayServerWindows::window_is_hdr_output_supported(DisplayServerEnums::Wi // The window supports HDR if the screen it is on supports HDR. int screen = window_get_current_screen(p_window); - DisplayServerWindows::ScreenHdrData data = _get_screen_hdr_data(screen); + DisplayServerWindows::ScreenHdrData data = _get_screen_hdr_data(screen, false); return data.hdr_supported; } @@ -4648,7 +4659,7 @@ void DisplayServerWindows::window_request_hdr_output(const bool p_enable, Displa wd.hdr_output_requested = p_enable; int screen = window_get_current_screen(p_window); - DisplayServerWindows::ScreenHdrData data = _get_screen_hdr_data(screen); + DisplayServerWindows::ScreenHdrData data = _get_screen_hdr_data(screen, true); _update_hdr_output_for_window(p_window, wd, data); } @@ -4685,7 +4696,7 @@ void DisplayServerWindows::window_set_hdr_output_reference_luminance(const float // Negative luminance means auto-adjust if (wd.hdr_output_reference_luminance < 0.0f) { int screen = window_get_current_screen(p_window); - DisplayServerWindows::ScreenHdrData data = _get_screen_hdr_data(screen); + DisplayServerWindows::ScreenHdrData data = _get_screen_hdr_data(screen, true); _update_hdr_output_for_window(p_window, wd, data); } else { // Otherwise, apply the requested luminance @@ -4730,7 +4741,7 @@ void DisplayServerWindows::window_set_hdr_output_max_luminance(const float p_max // Negative luminance means auto-adjust if (wd.hdr_output_max_luminance < 0.0f) { int screen = window_get_current_screen(p_window); - DisplayServerWindows::ScreenHdrData data = _get_screen_hdr_data(screen); + DisplayServerWindows::ScreenHdrData data = _get_screen_hdr_data(screen, true); _update_hdr_output_for_window(p_window, wd, data); } else { // Otherwise, apply the requested luminance @@ -6249,7 +6260,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA case WM_DISPLAYCHANGE: { // Update HDR capabilities and reference luminance when display changes. - _update_hdr_output_for_tracked_windows(); + _update_hdr_output_for_tracked_windows(true); } break; case WM_WINDOWPOSCHANGED: { @@ -6347,9 +6358,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA window.rect_changed_callback.call(Rect2i(window.last_pos.x, window.last_pos.y, window.width, window.height)); } - // Update HDR capabilities and reference luminance when window moves to different screen. - _update_hdr_output_for_tracked_windows(); - // Update cursor clip region after window rect has changed. if (mouse_mode == DisplayServerEnums::MOUSE_MODE_CAPTURED || mouse_mode == DisplayServerEnums::MOUSE_MODE_CONFINED || mouse_mode == DisplayServerEnums::MOUSE_MODE_CONFINED_HIDDEN) { RECT crect; @@ -6388,6 +6396,11 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } } + // Update HDR capabilities and reference luminance when window moves to different screen. + // Also update when Godot has regained focus because the user may have adjusted their SDR white + // level while Godot was not in focus. + _update_hdr_output_for_tracked_windows(true); + // Return here to prevent WM_MOVE and WM_SIZE from being sent // See: https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-windowposchanged#remarks return 0; diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 55c6c264a34..2041104270f 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -548,9 +548,9 @@ class DisplayServerWindows : public DisplayServer { }; AHashMap hdr_output_cache; - ScreenHdrData _get_screen_hdr_data(int p_screen) const; + ScreenHdrData _get_screen_hdr_data(int p_screen, bool p_include_sdr_white_level) const; void _update_hdr_output_for_window(DisplayServerEnums::WindowID p_window, const WindowData &p_window_data, ScreenHdrData p_screen_data); - void _update_hdr_output_for_tracked_windows(); + void _update_hdr_output_for_tracked_windows(bool p_include_sdr_white_level); public: LRESULT WndProcFileDialog(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);