From 121cbde661869ee4ca9de9e0f96381db13f7e307 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 18 Jul 2024 15:09:04 +0800 Subject: [PATCH] Monitor (Windows): detect maximum refresh rate --- src/detection/monitor/monitor_windows.c | 128 +++++++++++++++++------- 1 file changed, 91 insertions(+), 37 deletions(-) diff --git a/src/detection/monitor/monitor_windows.c b/src/detection/monitor/monitor_windows.c index 6bd7788ba..03cc56878 100644 --- a/src/detection/monitor/monitor_windows.c +++ b/src/detection/monitor/monitor_windows.c @@ -1,55 +1,109 @@ #include "monitor.h" -#include "common/io/io.h" #include "util/edidHelper.h" -#include "util/mallocHelper.h" -#include "util/stringUtils.h" #include "util/windows/registry.h" -#include "util/windows/unicode.h" #include -#include -#include - -static inline void wrapSetupDiDestroyDeviceInfoList(HDEVINFO* hdev) -{ - if(*hdev) - SetupDiDestroyDeviceInfoList(*hdev); -} const char* ffDetectMonitor(FFlist* results) { - //https://learn.microsoft.com/en-us/windows/win32/power/enumerating-battery-devices - HDEVINFO hdev __attribute__((__cleanup__(wrapSetupDiDestroyDeviceInfoList))) = - SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR, 0, 0, DIGCF_PRESENT); - if(hdev == INVALID_HANDLE_VALUE) - return "SetupDiGetClassDevsW(&GUID_DEVCLASS_MONITOR) failed"; + DISPLAYCONFIG_PATH_INFO paths[128]; + uint32_t pathCount = sizeof(paths) / sizeof(paths[0]); + DISPLAYCONFIG_MODE_INFO modes[256]; + uint32_t modeCount = sizeof(modes) / sizeof(modes[0]); - SP_DEVINFO_DATA did = { .cbSize = sizeof(did) }; - for (DWORD idev = 0; SetupDiEnumDeviceInfo(hdev, idev, &did); ++idev) + if (QueryDisplayConfig( + QDC_ONLY_ACTIVE_PATHS, + &pathCount, + paths, + &modeCount, + modes, + NULL) != ERROR_SUCCESS) + return "QueryDisplayConfig() failed"; + + if (pathCount == 0) + return "QueryDisplayConfig() returns 0 paths"; + + for (uint32_t i = 0; i < pathCount; ++i) { - FF_HKEY_AUTO_DESTROY hKey = SetupDiOpenDevRegKey(hdev, &did, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE); - if (!hKey) continue; + DISPLAYCONFIG_PATH_INFO* path = &paths[i]; - FF_AUTO_FREE uint8_t* edidData = NULL; - uint32_t edidLength = 0; - if (!ffRegReadData(hKey, L"EDID", &edidData, &edidLength, NULL)) continue; - if (edidLength == 0 || edidLength % 128 != 0) + DISPLAYCONFIG_TARGET_DEVICE_NAME targetName = { + .header = { + .type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME, + .size = sizeof(targetName), + .adapterId = path->targetInfo.adapterId, + .id = path->targetInfo.id, + }, + }; + if (DisplayConfigGetDeviceInfo(&targetName.header) != ERROR_SUCCESS) continue; - uint32_t width, height; - ffEdidGetPhysicalResolution(edidData, &width, &height); - if (width == 0 || height == 0) continue; + wchar_t regPath[256] = L"SYSTEM\\CurrentControlSet\\Enum"; + wchar_t* pRegPath = regPath + strlen("SYSTEM\\CurrentControlSet\\Enum"); + wchar_t* pDevPath = targetName.monitorDevicePath + strlen("\\\\?"); + while (*pDevPath && *pDevPath != L'{') + { + if (*pDevPath == L'#') + *pRegPath = L'\\'; + else + *pRegPath = *pDevPath; + ++pRegPath; + ++pDevPath; + assert(pRegPath < regPath + sizeof(regPath) / sizeof(wchar_t) + strlen("Device Parameters")); + } + wcscpy(pRegPath, L"Device Parameters"); - FFMonitorResult* display = (FFMonitorResult*) ffListAdd(results); - display->width = width; - display->height = height; - ffEdidGetSerialAndManufactureDate(edidData, &display->serial, &display->manufactureYear, &display->manufactureWeek); - display->hdrCompatible = ffEdidGetHdrCompatible(edidData, edidLength); // Doesn't work. edidLength is always 128 - ffStrbufInit(&display->name); - ffEdidGetName(edidData, &display->name); - ffEdidGetPhysicalSize(edidData, &display->physicalWidth, &display->physicalHeight); - display->refreshRate = 0; + uint8_t edidData[1024]; + DWORD edidLength = sizeof(edidData); + + if (RegGetValueW(HKEY_LOCAL_MACHINE, regPath, L"EDID", RRF_RT_REG_BINARY, NULL, edidData, &edidLength) == ERROR_SUCCESS && + edidLength > 0 && edidLength % 128 == 0) + { + uint32_t width, height; + ffEdidGetPhysicalResolution(edidData, &width, &height); + if (width == 0 || height == 0) continue; + + FFMonitorResult* display = (FFMonitorResult*) ffListAdd(results); + display->width = width; + display->height = height; + ffEdidGetSerialAndManufactureDate(edidData, &display->serial, &display->manufactureYear, &display->manufactureWeek); + ffStrbufInit(&display->name); + ffEdidGetName(edidData, &display->name); + ffEdidGetPhysicalSize(edidData, &display->physicalWidth, &display->physicalHeight); + display->refreshRate = 0; + display->hdrCompatible = false; + + DISPLAYCONFIG_GET_ADVANCED_COLOR_INFO advColorInfo = { + .header = { + .type = DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO, + .size = sizeof(advColorInfo), + .adapterId = path->targetInfo.adapterId, + .id = path->targetInfo.id, + } + }; + if (DisplayConfigGetDeviceInfo(&advColorInfo.header) == ERROR_SUCCESS) + display->hdrCompatible = !!advColorInfo.advancedColorSupported; + else + display->hdrCompatible = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength); + + DISPLAYCONFIG_TARGET_PREFERRED_MODE preferredMode = { + .header = { + .type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE, + .size = sizeof(preferredMode), + .adapterId = path->targetInfo.adapterId, + .id = path->targetInfo.id, + } + }; + if (DisplayConfigGetDeviceInfo(&preferredMode.header) == ERROR_SUCCESS) + { + if (preferredMode.width == width && preferredMode.height == height) + { + DISPLAYCONFIG_RATIONAL freq = preferredMode.targetMode.targetVideoSignalInfo.vSyncFreq; + display->refreshRate = freq.Numerator / (double) freq.Denominator; + } + } + } } return NULL; }