From dcd0f8d3f69b5918d3bd23f2da06916319973b28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 22 Mar 2023 14:59:24 +0800 Subject: [PATCH] DisplayServer (Windows): support precise refresh rate --- src/detection/displayserver/displayserver.c | 20 +---- src/detection/displayserver/displayserver.h | 7 +- .../displayserver/displayserver_apple.c | 2 +- .../displayserver/displayserver_windows.c | 74 +++++++++++++++---- src/detection/displayserver/linux/wayland.c | 2 +- src/detection/displayserver/linux/xcb.c | 4 +- src/detection/displayserver/linux/xlib.c | 4 +- src/modules/display.c | 4 +- 8 files changed, 68 insertions(+), 49 deletions(-) diff --git a/src/detection/displayserver/displayserver.c b/src/detection/displayserver/displayserver.c index 3bc47c345..d727e8bfa 100644 --- a/src/detection/displayserver/displayserver.c +++ b/src/detection/displayserver/displayserver.c @@ -1,25 +1,7 @@ #include "displayserver.h" #include "detection/internal.h" -uint32_t ffdsParseRefreshRate(int32_t refreshRate) -{ - if(refreshRate <= 0) - return 0; - - int remainder = refreshRate % 5; - if(remainder >= 3) - refreshRate += (5 - remainder); - else - refreshRate -= remainder; - - //All other typicall refresh rates are dividable by 5 - if(refreshRate == 145) - refreshRate = 144; - - return (uint32_t) refreshRate; -} - -bool ffdsAppendDisplay(FFDisplayServerResult* result, uint32_t width, uint32_t height, uint32_t refreshRate, uint32_t scaledWidth, uint32_t scaledHeight) +bool ffdsAppendDisplay(FFDisplayServerResult* result, uint32_t width, uint32_t height, double refreshRate, uint32_t scaledWidth, uint32_t scaledHeight) { if(width == 0 || height == 0) return false; diff --git a/src/detection/displayserver/displayserver.h b/src/detection/displayserver/displayserver.h index 271a35085..55c268919 100644 --- a/src/detection/displayserver/displayserver.h +++ b/src/detection/displayserver/displayserver.h @@ -38,7 +38,7 @@ typedef struct FFDisplayResult { uint32_t width; uint32_t height; - uint32_t refreshRate; + double refreshRate; uint32_t scaledWidth; uint32_t scaledHeight; } FFDisplayResult; @@ -55,9 +55,6 @@ typedef struct FFDisplayServerResult } FFDisplayServerResult; const FFDisplayServerResult* ffConnectDisplayServer(const FFinstance* instance); - -//Used internal -uint32_t ffdsParseRefreshRate(int32_t refreshRate); -bool ffdsAppendDisplay(FFDisplayServerResult* result, uint32_t width, uint32_t height, uint32_t refreshRate, uint32_t scaledWidth, uint32_t scaledHeight); +bool ffdsAppendDisplay(FFDisplayServerResult* result, uint32_t width, uint32_t height, double refreshRate, uint32_t scaledWidth, uint32_t scaledHeight); #endif diff --git a/src/detection/displayserver/displayserver_apple.c b/src/detection/displayserver/displayserver_apple.c index b904f4cb2..e13e925e7 100644 --- a/src/detection/displayserver/displayserver_apple.c +++ b/src/detection/displayserver/displayserver_apple.c @@ -39,7 +39,7 @@ static void detectDisplays(FFDisplayServerResult* ds) ffdsAppendDisplay(ds, (uint32_t)CGDisplayModeGetPixelWidth(mode), (uint32_t)CGDisplayModeGetPixelHeight(mode), - (uint32_t)refreshRate, + refreshRate, (uint32_t)CGDisplayModeGetWidth(mode), (uint32_t)CGDisplayModeGetHeight(mode) ); diff --git a/src/detection/displayserver/displayserver_windows.c b/src/detection/displayserver/displayserver_windows.c index e049a5c5b..71df5da61 100644 --- a/src/detection/displayserver/displayserver_windows.c +++ b/src/detection/displayserver/displayserver_windows.c @@ -1,5 +1,6 @@ #include "displayserver.h" #include "detection/os/os.h" +#include "util/windows/unicode.h" #include #include @@ -11,6 +12,7 @@ typedef struct uint32_t height; } DataBundle; + static CALLBACK WINBOOL enumMonitorProc(HMONITOR hMonitor, FF_MAYBE_UNUSED HDC hDC, FF_MAYBE_UNUSED LPRECT rc, LPARAM lparam) { MONITORINFOEXW mi = { .cbSize = sizeof(mi) }; @@ -45,22 +47,64 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds, const FFinstance* ins ffStrbufInit(&ds->deVersion); ffListInit(&ds->displays, sizeof(FFDisplayResult)); - DISPLAY_DEVICEW displayDevice = { .cb = sizeof(DISPLAY_DEVICEW) }; - for(DWORD devNum = 0; EnumDisplayDevicesW(NULL, devNum, &displayDevice, 0) != 0; ++devNum) - { - if(!(displayDevice.StateFlags & DISPLAY_DEVICE_ACTIVE)) - continue; - DEVMODEW devMode = { .dmSize = sizeof(DEVMODEW) }; - if(EnumDisplaySettingsW(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &devMode) == 0) - continue; + 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]); - DataBundle data = { - .deviceName = displayDevice.DeviceName, - .width = 0, - .height = 0, - }; - EnumDisplayMonitors(NULL, NULL, enumMonitorProc, (LPARAM)&data); - ffdsAppendDisplay(ds, devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmDisplayFrequency, data.width, data.height); + if (SUCCEEDED(QueryDisplayConfig( + QDC_ONLY_ACTIVE_PATHS | QDC_VIRTUAL_MODE_AWARE | 0x00000040 /*QDC_VIRTUAL_REFRESH_RATE_AWARE*/, + &pathCount, + paths, + &modeCount, + modes, + NULL))) + { + for (uint32_t i = 0; i < modeCount; ++i) + { + DISPLAYCONFIG_MODE_INFO* mode = &modes[i]; + if(mode->infoType != DISPLAYCONFIG_MODE_INFO_TYPE_TARGET) + continue; + + DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName = { + .header = { + .type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME, + .size = sizeof(sourceName), + .adapterId = mode->adapterId, + .id = mode->id, + }, + }; + + DataBundle data = {}; + if(SUCCEEDED(DisplayConfigGetDeviceInfo(&sourceName.header))) + { + data.deviceName = sourceName.viewGdiDeviceName; + EnumDisplayMonitors(NULL, NULL, enumMonitorProc, (LPARAM) &data); + } + + // Find the target (monitor) friendly name + DISPLAYCONFIG_TARGET_DEVICE_NAME targetName = { + .header = { + .type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME, + .size = sizeof(targetName), + .adapterId = mode->adapterId, + .id = mode->id, + }, + }; + + FFstrbuf name; + ffStrbufInit(&name); + if(SUCCEEDED(DisplayConfigGetDeviceInfo(&targetName.header)) && targetName.flags.friendlyNameFromEdid) + ffStrbufSetWS(&name, targetName.monitorFriendlyDeviceName); + + ffdsAppendDisplay( + ds, + mode->targetMode.targetVideoSignalInfo.totalSize.cx, + mode->targetMode.targetVideoSignalInfo.totalSize.cy, + mode->targetMode.targetVideoSignalInfo.vSyncFreq.Numerator / (double) mode->targetMode.targetVideoSignalInfo.vSyncFreq.Denominator, + data.width, + data.height); + } } //https://github.com/hykilpikonna/hyfetch/blob/master/neofetch#L2067 diff --git a/src/detection/displayserver/linux/wayland.c b/src/detection/displayserver/linux/wayland.c index fce97c8f2..938d46b3c 100644 --- a/src/detection/displayserver/linux/wayland.c +++ b/src/detection/displayserver/linux/wayland.c @@ -123,7 +123,7 @@ static void waylandOutputHandler(WaylandData* wldata, struct wl_registry* regist ffdsAppendDisplay(wldata->result, (uint32_t) display.width, (uint32_t) display.height, - ffdsParseRefreshRate(display.refreshRate / 1000), + display.refreshRate / 1000.0, (uint32_t) (display.width / display.scale), (uint32_t) (display.height / display.scale) ); diff --git a/src/detection/displayserver/linux/xcb.c b/src/detection/displayserver/linux/xcb.c index c31803286..3b9680301 100644 --- a/src/detection/displayserver/linux/xcb.c +++ b/src/detection/displayserver/linux/xcb.c @@ -174,9 +174,7 @@ typedef struct XcbRandrData static bool xcbRandrHandleModeInfo(XcbRandrData* data, xcb_randr_mode_info_t* modeInfo) { - uint32_t refreshRate = ffdsParseRefreshRate((int32_t) ( - modeInfo->dot_clock / (uint32_t) (modeInfo->htotal * modeInfo->vtotal) - )); + double refreshRate = modeInfo->dot_clock / (double) (modeInfo->htotal * modeInfo->vtotal); return ffdsAppendDisplay( data->result, diff --git a/src/detection/displayserver/linux/xlib.c b/src/detection/displayserver/linux/xlib.c index 241db5e87..bcce80f52 100644 --- a/src/detection/displayserver/linux/xlib.c +++ b/src/detection/displayserver/linux/xlib.c @@ -133,9 +133,7 @@ typedef struct XrandrData static bool xrandrHandleModeInfo(XrandrData* data, XRRModeInfo* modeInfo) { - uint32_t refreshRate = ffdsParseRefreshRate((int32_t) ( - modeInfo->dotClock / (modeInfo->hTotal * modeInfo->vTotal) - )); + double refreshRate = modeInfo->dotClock / (double) (modeInfo->hTotal * modeInfo->vTotal); return ffdsAppendDisplay( data->result, diff --git a/src/modules/display.c b/src/modules/display.c index cc6971f1a..a129b4077 100644 --- a/src/modules/display.c +++ b/src/modules/display.c @@ -25,7 +25,7 @@ void ffPrintDisplay(FFinstance* instance) printf("%ix%i", result->width, result->height); if(result->refreshRate > 0) - printf(" @ %iHz", result->refreshRate); + printf(" @ %iHz", (uint32_t) (result->refreshRate + 0.5)); if( result->scaledWidth > 0 && result->scaledWidth != result->width && @@ -39,7 +39,7 @@ void ffPrintDisplay(FFinstance* instance) ffPrintFormat(instance, FF_RESOLUTION_MODULE_NAME, moduleIndex, &instance->config.display, FF_RESOLUTION_NUM_FORMAT_ARGS, (FFformatarg[]) { {FF_FORMAT_ARG_TYPE_UINT, &result->width}, {FF_FORMAT_ARG_TYPE_UINT, &result->height}, - {FF_FORMAT_ARG_TYPE_UINT, &result->refreshRate}, + {FF_FORMAT_ARG_TYPE_DOUBLE, &result->refreshRate}, {FF_FORMAT_ARG_TYPE_UINT, &result->scaledWidth}, {FF_FORMAT_ARG_TYPE_UINT, &result->scaledHeight} });