Monitor (Windows): detect maximum refresh rate

This commit is contained in:
李通洲
2024-07-18 15:09:04 +08:00
parent 0d71ae7f97
commit 121cbde661
+91 -37
View File
@@ -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 <windows.h>
#include <setupapi.h>
#include <devguid.h>
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;
}