EnumDisplaySettings 是 Windows 下获取显示器刷新率最可靠的 API,需正确初始化 DEVMODE 并传入有效设备名,返回当前活动模式的 dmDisplayFrequency,为 0 时应视为未知而非硬编码 fallback。

Windows 下用 EnumDisplaySettings 获取刷新率最可靠
在 Windows 平台,EnumDisplaySettings 是获取当前显示器垂直同步频率(即刷新率)的首选 API,它直接读取显卡驱动上报的设置,比轮询或解析显示属性更准确。注意:它返回的是当前活动显示模式下的 dmDisplayFrequency,不是“理论最大值”或“自适应范围”。
常见错误是传入错误的设备名——必须用 ENUM_CURRENT_SETTINGS 或先调用 EnumDisplayDevices 获取主显示器名称(如 \\.\DISPLAY1),否则可能返回 0 或过时值。
- 使用
DEVMODE结构体时,务必把dmSize初始化为sizeof(DEVMODE),否则 API 可能拒绝填充数据 - 若程序运行在多显示器环境且未指定设备名,
EnumDisplaySettings(NULL, ...)默认操作主显示器,但行为依赖系统版本;建议显式传入EnumDisplayDevices返回的DeviceName -
dmDisplayFrequency为 0 表示驱动未报告刷新率(常见于虚拟显示器、某些远程桌面会话),此时不应 fallback 到硬编码值,而应视为未知
DEVMODE dm = {};
dm.dmSize = sizeof(dm);
if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm)) {
int hz = dm.dmDisplayFrequency; // 如 60、144、240
}Linux 下需区分 X11 和 Wayland
X11 环境可用 xrandr 命令行工具解析输出,但程序内调用推荐用 XRandR 扩展 API:XRRGetScreenInfo + XRRAllocGamma 不适用,真正该用的是 XRRGetCrtcInfo 配合 XRRGetOutputInfo 查当前 CRTC 的 mode,再从 XRRGetScreenResources 中匹配该 mode 的 dot_clock、h_total、v_total 手动计算: refresh = dot_clock / (h_total * v_total)。
Wayland 没有全局刷新率概念——每个 surface 可独立提交帧,合成器(如 wlroots)决定最终呈现时机。应用无法直接查“系统刷新率”,只能通过 wp_presentation 协议监听 clockid 或查询 surface 的 preferred_buffer_scale 和 preferred_refresh(若有),但这只是合成器建议值,非强制。
立即学习“C++免费学习笔记(深入)”;
- X11 下
xrandr --verbose输出里的Monitor name后紧跟的60.00*+中的*表示当前激活模式,+表示首选,但程序不能依赖字符串解析 - Linux 上没有跨桌面环境统一的刷新率 API,GNOME/KDE 的 D-Bus 接口(如
org.gnome.mutter.DisplayConfig)仅限特定版本且需权限,不推荐用于通用程序
macOS 用 CGDisplayModeGetRefreshRate 最简洁
macOS 提供了直接的 Core Graphics API:CGDisplayModeGetRefreshRate,输入当前主屏的 CGDirectDisplayID(可用 CGMainDisplayID() 获取)即可返回浮点数刷新率(如 60.0、120.0)。它支持 ProMotion 自适应刷新(返回实际当前值,非范围)。
注意:该函数在 macOS 10.15+ 返回真实值;旧版本(如 10.13)对某些外接显示器可能始终返回 0.0,此时需 fallback 到 CGDisplayModeGetIOFlags 检查是否含 kDisplayModeValidFlag,并结合 CGDisplayModeGetPixelWidth/Height 推断典型值(不精确但可降级)。
- 不要用
CGDisplayCopyAllDisplayModes遍历所有模式再找最高频——用户可能正运行 48Hz 的省电模式,而非列表里排第一的 120Hz - 如果应用启用了
NSHighResolutionCapable且运行在 Retina 屏上,刷新率仍由物理面板决定,与缩放比例无关
跨平台封装要注意刷新率动态变化
显示器刷新率可能被用户手动切换(如 Windows 显示设置、Linux xrandr -r)、系统节能策略触发(如 macOS 自动降低外接屏刷新率)、甚至游戏内垂直同步开关影响——这些都不是一次性查询能覆盖的。
真正健壮的做法是:首次初始化时查一次,之后注册系统事件监听(Windows 的 WM_DISPLAYCHANGE、X11 的 RandR ScreenChangeNotify、macOS 的 CGDisplayRegisterReconfigurationCallback),并在回调中重新获取。忽略这点会导致 vsync 逻辑错配、画面撕裂或输入延迟突增。
- 很多引擎(如 SDL2)的
SDL_GetDesktopDisplayMode只返回初始值,不响应运行时变更,需自行 hook 系统事件 - 即使查到刷新率为 144Hz,也不代表每帧都能稳定渲染——GPU 负载、驱动队列、复合器调度都会导致实际呈现间隔波动,应用层应以垂直同步信号(如
wglSwapIntervalEXT)为准,而非单纯信任查询结果


















