From 7485d7ce8c5234c756364215536b993cd30d02d2 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Fri, 20 Mar 2026 23:52:00 +1000 Subject: [PATCH] WindowInfo: Remove QueryRefreshRateForWindow() No longer needed. --- CMakeModules/DuckStationDependencies.cmake | 4 +- src/common/cocoa_tools.h | 3 - src/common/cocoa_tools.mm | 56 ------ src/util/CMakeLists.txt | 6 +- src/util/window_info.cpp | 210 +------------------- src/util/window_info.h | 6 - src/util/x11_tools.cpp | 215 +-------------------- src/util/x11_tools.h | 4 +- 8 files changed, 7 insertions(+), 497 deletions(-) diff --git a/CMakeModules/DuckStationDependencies.cmake b/CMakeModules/DuckStationDependencies.cmake index 390de8217..86fcfece8 100644 --- a/CMakeModules/DuckStationDependencies.cmake +++ b/CMakeModules/DuckStationDependencies.cmake @@ -124,8 +124,8 @@ if(NOT WIN32) if(NOT APPLE) if(ENABLE_X11) find_package(X11 REQUIRED) - if (NOT X11_xcb_FOUND OR NOT X11_xcb_randr_FOUND OR NOT X11_X11_xcb_FOUND) - message(FATAL_ERROR "XCB, XCB-randr and X11-xcb are required") + if (NOT X11_xcb_FOUND) + message(FATAL_ERROR "XCB is required") endif() endif() diff --git a/src/common/cocoa_tools.h b/src/common/cocoa_tools.h index c140cdb49..6ee24dd3b 100644 --- a/src/common/cocoa_tools.h +++ b/src/common/cocoa_tools.h @@ -55,9 +55,6 @@ std::optional> GetViewSizeInPixels(const void* view); /// Returns the "real" scaling factor for a given view, on its current display. std::optional GetViewRealScalingFactor(const void* view); -/// Returns the refresh rate of the display the window is placed on. -std::optional GetViewRefreshRate(const void* view, Error* error); - /// Creates metal layer on specified window surface. void* CreateMetalLayer(void* view, Error* error); diff --git a/src/common/cocoa_tools.mm b/src/common/cocoa_tools.mm index ec8e69f9e..53a3a83f1 100644 --- a/src/common/cocoa_tools.mm +++ b/src/common/cocoa_tools.mm @@ -210,62 +210,6 @@ std::optional CocoaTools::GetViewRealScalingFactor(const void* view) return static_cast(scale); } -std::optional CocoaTools::GetViewRefreshRate(const void* view, Error* error) -{ - if (!view) - return std::nullopt; - - if (![NSThread isMainThread]) - { - std::optional ret; - dispatch_sync(dispatch_get_main_queue(), [&ret, view, error] { ret = GetViewRefreshRate(view, error); }); - return ret; - } - - std::optional ret; - NSView* const nsview = (__bridge NSView*)view; - const u32 did = [[[[[nsview window] screen] deviceDescription] valueForKey:@"NSScreenNumber"] unsignedIntValue]; - if (CGDisplayModeRef mode = CGDisplayCopyDisplayMode(did)) - { - ret = CGDisplayModeGetRefreshRate(mode); - if (ret.value() <= 0.0f) - { - ret.reset(); - - // Ignore deprecration warnings here. The new APIs don't seem to have something that matches the semantics. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - - CVDisplayLinkRef link = nullptr; - if (CVDisplayLinkCreateWithCGDisplay(did, &link) == 0) - { - const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link); - if (!(time.flags & kCVTimeIsIndefinite) && time.timeValue != 0) - { - ret = static_cast(static_cast(time.timeScale) / static_cast(time.timeValue)); - } - else - { - Error::SetStringFmt(error, "Refresh period is invalid (flags=0x{:X}, timeValue={}, timeScale={})", - static_cast(time.flags), time.timeValue, time.timeScale); - } - } - else - { - Error::SetStringView(error, "CVDisplayLinkCreateWithCGDisplay() failed"); - } -#pragma clang diagnostic pop - } - CGDisplayModeRelease(mode); - } - else - { - Error::SetStringView(error, "CGDisplayCopyDisplayMode() failed"); - } - - return ret; -} - void* CocoaTools::CreateMetalLayer(void* view, Error* error) { // Punt off to main thread if we're not calling from it already. diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 0eead48d9..c8a9ab860 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -94,11 +94,7 @@ if(ENABLE_X11) x11_tools.h ) target_compile_definitions(util PRIVATE "-DENABLE_X11=1") - target_include_directories(util PRIVATE - "${X11_xcb_INCLUDE_PATH}" - "${X11_xcb_randr_INCLUDE_PATH}" - "${X11_X11_xcb_INCLUDE_PATH}" - ) + target_include_directories(util PRIVATE "${X11_xcb_INCLUDE_PATH}") endif() if(ENABLE_WAYLAND) diff --git a/src/util/window_info.cpp b/src/util/window_info.cpp index c79d1f161..874fd80f9 100644 --- a/src/util/window_info.cpp +++ b/src/util/window_info.cpp @@ -4,21 +4,12 @@ #include "window_info.h" #include "gpu_types.h" -#include "common/assert.h" -#include "common/error.h" -#include "common/heap_array.h" -#include "common/log.h" -#include "common/scoped_guard.h" - #include -#include - -LOG_CHANNEL(WindowInfo); WindowInfo::WindowInfo() : type(WindowInfoType::Surfaceless), surface_format(GPUTextureFormat::Unknown), - surface_prerotation(WindowInfoPrerotation::Identity), surface_width(0), surface_height(0), surface_refresh_rate(0.0f), - surface_scale(1.0f), display_connection(nullptr), window_handle(nullptr) + surface_prerotation(WindowInfoPrerotation::Identity), surface_width(0), surface_height(0), + surface_refresh_rate(0.0f), surface_scale(1.0f), display_connection(nullptr), window_handle(nullptr) { } @@ -33,200 +24,3 @@ float WindowInfo::GetZRotationForPreRotation(WindowInfoPrerotation prerotation) return rotation_radians[static_cast(prerotation)]; } - -#if defined(_WIN32) - -#include "common/windows_headers.h" -#include - -static std::optional GetRefreshRateFromDisplayConfig(HWND hwnd, Error* error) -{ - // Partially based on Chromium ui/display/win/display_config_helper.cc. - const HMONITOR monitor = MonitorFromWindow(hwnd, 0); - if (!monitor) [[unlikely]] - { - Error::SetWin32(error, "MonitorFromWindow() failed: ", GetLastError()); - return std::nullopt; - } - - MONITORINFOEXW mi = {}; - mi.cbSize = sizeof(mi); - if (!GetMonitorInfoW(monitor, &mi)) - { - Error::SetWin32(error, "GetMonitorInfoW() failed: ", GetLastError()); - return std::nullopt; - } - - DynamicHeapArray path_info; - DynamicHeapArray mode_info; - - // I guess this could fail if it changes inbetween two calls... unlikely. - for (;;) - { - UINT32 path_size = 0, mode_size = 0; - LONG res = GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &path_size, &mode_size); - if (res != ERROR_SUCCESS) - { - Error::SetWin32(error, "GetDisplayConfigBufferSizes() failed: ", res); - return std::nullopt; - } - - path_info.resize(path_size); - mode_info.resize(mode_size); - res = - QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &path_size, path_info.data(), &mode_size, mode_info.data(), nullptr); - if (res == ERROR_SUCCESS) - break; - if (res != ERROR_INSUFFICIENT_BUFFER) - { - Error::SetWin32(error, "QueryDisplayConfig() failed: ", res); - return std::nullopt; - } - } - - for (const DISPLAYCONFIG_PATH_INFO& pi : path_info) - { - DISPLAYCONFIG_SOURCE_DEVICE_NAME sdn = {.header = {.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME, - .size = sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME), - .adapterId = pi.sourceInfo.adapterId, - .id = pi.sourceInfo.id}, - .viewGdiDeviceName = {}}; - LONG res = DisplayConfigGetDeviceInfo(&sdn.header); - if (res != ERROR_SUCCESS) - { - Error::SetWin32(error, "DisplayConfigGetDeviceInfo() failed: ", res); - continue; - } - - if (std::wcscmp(sdn.viewGdiDeviceName, mi.szDevice) == 0) - { - // Found the monitor! - return static_cast(static_cast(pi.targetInfo.refreshRate.Numerator) / - static_cast(pi.targetInfo.refreshRate.Denominator)); - } - } - - return std::nullopt; -} - -static std::optional GetRefreshRateFromDWM(HWND hwnd, Error* error) -{ - BOOL composition_enabled; - HRESULT hr = DwmIsCompositionEnabled(&composition_enabled); - if (FAILED(hr)) - { - Error::SetHResult(error, "DwmIsCompositionEnabled() failed: ", hr); - return std::nullopt; - } - - DWM_TIMING_INFO ti = {}; - ti.cbSize = sizeof(ti); - hr = DwmGetCompositionTimingInfo(nullptr, &ti); - if (SUCCEEDED(hr)) - { - if (ti.rateRefresh.uiNumerator == 0 || ti.rateRefresh.uiDenominator == 0) - return std::nullopt; - - return static_cast(ti.rateRefresh.uiNumerator) / static_cast(ti.rateRefresh.uiDenominator); - } - else - { - Error::SetHResult(error, "DwmGetCompositionTimingInfo() failed: ", hr); - return std::nullopt; - } -} - -static std::optional GetRefreshRateFromMonitor(HWND hwnd, Error* error) -{ - HMONITOR mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); - if (!mon) - { - Error::SetWin32(error, "MonitorFromWindow() failed: ", GetLastError()); - return std::nullopt; - } - - MONITORINFOEXW mi = {}; - mi.cbSize = sizeof(mi); - if (GetMonitorInfoW(mon, &mi)) - { - DEVMODEW dm = {}; - dm.dmSize = sizeof(dm); - - // 0/1 are reserved for "defaults". - if (EnumDisplaySettingsW(mi.szDevice, ENUM_CURRENT_SETTINGS, &dm) && dm.dmDisplayFrequency > 1) - { - return static_cast(dm.dmDisplayFrequency); - } - else - { - Error::SetWin32(error, "EnumDisplaySettingsW() failed: ", GetLastError()); - return std::nullopt; - } - } - else - { - Error::SetWin32(error, "GetMonitorInfoW() failed: ", GetLastError()); - return std::nullopt; - } -} - -std::optional WindowInfo::QueryRefreshRateForWindow(const WindowInfo& wi, Error* error) -{ - std::optional ret; - if (wi.type != WindowInfoType::Win32 || !wi.window_handle) - { - Error::SetStringView(error, "Invalid window type."); - return ret; - } - - // Try DWM first, then fall back to integer values. - const HWND hwnd = static_cast(wi.window_handle); - Error local_error; - ret = GetRefreshRateFromDisplayConfig(hwnd, &local_error); - if (!ret.has_value()) - { - WARNING_LOG("GetRefreshRateFromDisplayConfig() failed: {}", local_error.GetDescription()); - - ret = GetRefreshRateFromDWM(hwnd, &local_error); - if (!ret.has_value()) - { - WARNING_LOG("GetRefreshRateFromDWM() failed: {}", local_error.GetDescription()); - - ret = GetRefreshRateFromMonitor(hwnd, error); - } - } - - return ret; -} - -#elif defined(__APPLE__) - -#include "common/cocoa_tools.h" - -std::optional WindowInfo::QueryRefreshRateForWindow(const WindowInfo& wi, Error* error) -{ - if (wi.type == WindowInfoType::MacOS) - return CocoaTools::GetViewRefreshRate(wi.window_handle, error); - - Error::SetStringView(error, "Invalid window type."); - return std::nullopt; -} - -#else - -#ifdef ENABLE_X11 -#include "x11_tools.h" -#endif - -std::optional WindowInfo::QueryRefreshRateForWindow(const WindowInfo& wi, Error* error) -{ -#if defined(ENABLE_X11) - if (wi.type == WindowInfoType::Xlib || wi.type == WindowInfoType::XCB) - return GetRefreshRateFromXRandR(wi, error); -#endif - - Error::SetStringView(error, "Invalid window type."); - return std::nullopt; -} - -#endif diff --git a/src/util/window_info.h b/src/util/window_info.h index 14c075afd..20c4541d9 100644 --- a/src/util/window_info.h +++ b/src/util/window_info.h @@ -5,10 +5,6 @@ #include "common/types.h" -#include - -class Error; - enum class GPUTextureFormat : u8; enum class WindowInfoType : u8 @@ -63,6 +59,4 @@ struct WindowInfo } static float GetZRotationForPreRotation(WindowInfoPrerotation prerotation); - - static std::optional QueryRefreshRateForWindow(const WindowInfo& wi, Error* error = nullptr); }; diff --git a/src/util/x11_tools.cpp b/src/util/x11_tools.cpp index cd094e7bf..53d2e7e26 100644 --- a/src/util/x11_tools.cpp +++ b/src/util/x11_tools.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin // SPDX-License-Identifier: CC-BY-NC-ND-4.0 #include "x11_tools.h" @@ -8,10 +8,7 @@ #include "common/dynamic_library.h" #include "common/error.h" #include "common/log.h" -#include "common/scoped_guard.h" -#include -#include #include #include @@ -42,39 +39,16 @@ namespace dyn_libs { X(xcb_free_colormap_checked) \ X(xcb_configure_window_checked) -#define XCB_RANDR_FUNCTIONS(X) \ - X(xcb_randr_get_screen_resources_reply) \ - X(xcb_randr_get_screen_resources) \ - X(xcb_randr_get_monitors_reply) \ - X(xcb_randr_get_monitors) \ - X(xcb_randr_get_monitors_monitors_iterator) \ - X(xcb_randr_monitor_info_outputs) \ - X(xcb_randr_get_output_info_reply) \ - X(xcb_randr_get_output_info) \ - X(xcb_randr_get_crtc_info_reply) \ - X(xcb_randr_get_crtc_info) \ - X(xcb_randr_get_screen_resources_modes_iterator) \ - X(xcb_randr_mode_info_next) - -#define X11XCB_FUNCTIONS(X) X(XGetXCBConnection) - static bool OpenXcb(Error* error); static void CloseXcb(); -static bool OpenXcbRandR(Error* error); -static void CloseXcbRandR(); -static bool OpenX11Xcb(Error* error); -static void CloseX11Xcb(); static void CloseAll(); static DynamicLibrary s_xcb_library; -static DynamicLibrary s_xcb_randr_library; static DynamicLibrary s_x11xcb_library; static bool s_close_registered = false; #define ADD_FUNC(F) static decltype(&::F) F; XCB_FUNCTIONS(ADD_FUNC); -XCB_RANDR_FUNCTIONS(ADD_FUNC); -X11XCB_FUNCTIONS(ADD_FUNC); #undef ADD_FUNC } // namespace dyn_libs @@ -131,92 +105,8 @@ void dyn_libs::CloseXcb() s_xcb_library.Close(); } -bool dyn_libs::OpenXcbRandR(Error* error) -{ - if (s_xcb_randr_library.IsOpen()) - return true; - - const std::string libname = DynamicLibrary::GetVersionedFilename("xcb-randr", 0); - if (!s_xcb_randr_library.Open(libname.c_str(), error)) - { - Error::AddPrefix(error, "Failed to load xcb-randr: "); - return false; - } - -#define LOAD_FUNC(F) \ - if (!s_xcb_randr_library.GetSymbol(#F, &F)) \ - { \ - Error::SetStringFmt(error, "Failed to find function {}", #F); \ - CloseXcb(); \ - return false; \ - } - - XCB_RANDR_FUNCTIONS(LOAD_FUNC) -#undef LOAD_FUNC - - if (!s_close_registered) - { - s_close_registered = true; - std::atexit(&dyn_libs::CloseAll); - } - - return true; -} - -void dyn_libs::CloseXcbRandR() -{ -#define UNLOAD_FUNC(F) F = nullptr; - XCB_RANDR_FUNCTIONS(UNLOAD_FUNC) -#undef UNLOAD_FUNC - - s_xcb_randr_library.Close(); -} - -bool dyn_libs::OpenX11Xcb(Error* error) -{ - if (s_x11xcb_library.IsOpen()) - return true; - - const std::string libname = DynamicLibrary::GetVersionedFilename("X11-xcb", 1); - if (!s_x11xcb_library.Open(libname.c_str(), error)) - { - Error::AddPrefix(error, "Failed to load X11-xcb: "); - return false; - } - -#define LOAD_FUNC(F) \ - if (!s_x11xcb_library.GetSymbol(#F, &F)) \ - { \ - Error::SetStringFmt(error, "Failed to find function {}", #F); \ - CloseXcb(); \ - return false; \ - } - - X11XCB_FUNCTIONS(LOAD_FUNC) -#undef LOAD_FUNC - - if (!s_close_registered) - { - s_close_registered = true; - std::atexit(&dyn_libs::CloseAll); - } - - return true; -} - -void dyn_libs::CloseX11Xcb() -{ -#define UNLOAD_FUNC(F) F = nullptr; - X11XCB_FUNCTIONS(UNLOAD_FUNC) -#undef UNLOAD_FUNC - - s_x11xcb_library.Close(); -} - void dyn_libs::CloseAll() { - CloseX11Xcb(); - CloseXcbRandR(); CloseXcb(); } @@ -427,106 +317,3 @@ void X11Window::Resize(u16 width, u16 height) ERROR_LOG(error.GetDescription()); } } - -std::optional GetRefreshRateFromXRandR(const WindowInfo& wi, Error* error) -{ - xcb_connection_t* connection = nullptr; - if (wi.type == WindowInfoType::Xlib) - { - if (!dyn_libs::OpenX11Xcb(error)) - return std::nullopt; - - connection = dyn_libs::XGetXCBConnection(static_cast(wi.display_connection)); - } - else if (wi.type == WindowInfoType::XCB) - { - connection = static_cast(wi.display_connection); - } - - xcb_window_t window = static_cast(reinterpret_cast(wi.window_handle)); - if (!connection || window == XCB_NONE) - { - Error::SetStringView(error, "Invalid window handle."); - return std::nullopt; - } - - if (!dyn_libs::OpenXcb(error) || !dyn_libs::OpenXcbRandR(error)) - return std::nullopt; - - xcb_generic_error_t* xerror; - XCBPointer gsr(dyn_libs::xcb_randr_get_screen_resources_reply( - connection, dyn_libs::xcb_randr_get_screen_resources(connection, window), &xerror)); - if (xerror) - { - SetErrorObject(error, "xcb_randr_get_screen_resources() failed: ", xerror); - return std::nullopt; - } - - XCBPointer gm(dyn_libs::xcb_randr_get_monitors_reply( - connection, dyn_libs::xcb_randr_get_monitors(connection, window, true), &xerror)); - if (xerror || gm->nMonitors < 0) - { - SetErrorObject(error, "xcb_randr_get_screen_resources() failed: ", xerror); - return std::nullopt; - } - - if (gm->nMonitors > 1) - WARNING_LOG("xcb_randr_get_monitors() returned {} monitors, using first", gm->nMonitors); - - if (gm->nOutputs <= 0) - { - Error::SetStringView(error, "Monitor has no outputs"); - return std::nullopt; - } - else if (gm->nOutputs > 1) - { - WARNING_LOG("Monitor has {} outputs, using first", gm->nOutputs); - } - - xcb_randr_monitor_info_t* monitor_info = dyn_libs::xcb_randr_get_monitors_monitors_iterator(gm.get()).data; - DebugAssert(monitor_info); - - xcb_randr_output_t* monitor_outputs = dyn_libs::xcb_randr_monitor_info_outputs(monitor_info); - DebugAssert(monitor_outputs); - - XCBPointer goi(dyn_libs::xcb_randr_get_output_info_reply( - connection, dyn_libs::xcb_randr_get_output_info(connection, monitor_outputs[0], 0), &xerror)); - if (xerror) - { - SetErrorObject(error, "xcb_randr_get_output_info() failed: ", xerror); - return std::nullopt; - } - - XCBPointer gci(dyn_libs::xcb_randr_get_crtc_info_reply( - connection, dyn_libs::xcb_randr_get_crtc_info(connection, goi->crtc, 0), &xerror)); - if (xerror) - { - SetErrorObject(error, "xcb_randr_get_crtc_info_reply() failed: ", xerror); - return std::nullopt; - } - - xcb_randr_mode_info_t* mode = nullptr; - for (xcb_randr_mode_info_iterator_t it = dyn_libs::xcb_randr_get_screen_resources_modes_iterator(gsr.get()); - it.rem != 0; dyn_libs::xcb_randr_mode_info_next(&it)) - { - if (it.data->id == gci->mode) - { - mode = it.data; - break; - } - } - if (!mode) - { - Error::SetStringFmt(error, "Failed to look up mode ID {}", static_cast(gci->mode)); - return std::nullopt; - } - - if (mode->dot_clock == 0 || mode->htotal == 0 || mode->vtotal == 0) - { - ERROR_LOG("Modeline is invalid: {}/{}/{}", mode->dot_clock, mode->htotal, mode->vtotal); - return std::nullopt; - } - - return static_cast(static_cast(mode->dot_clock) / - (static_cast(mode->htotal) * static_cast(mode->vtotal))); -} diff --git a/src/util/x11_tools.h b/src/util/x11_tools.h index 24dfad6e3..1323fd6c7 100644 --- a/src/util/x11_tools.h +++ b/src/util/x11_tools.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2026 Connor McLaughlin // SPDX-License-Identifier: CC-BY-NC-ND-4.0 #pragma once @@ -41,5 +41,3 @@ private: u16 m_width = 0; u16 m_height = 0; }; - -std::optional GetRefreshRateFromXRandR(const WindowInfo& wi, Error* error);