EnumDisplaySettings是Windows平台获取当前显示器刷新率最直接的方式,通过传入NULL设备名和ENUM_CURRENT_SETTINGS索引,读取DEVMODE结构体中dmDisplayFrequency字段(单位Hz),但需正确初始化dmSize且检查返回值。

Windows平台用 EnumDisplaySettings 获取当前显示器刷新率
在 Windows 上,EnumDisplaySettings 是最直接、无需额外依赖的方式。它读取当前活动显示设备的 DevMode 结构体,其中 dmDisplayFrequency 字段就是垂直刷新率(单位:Hz)。
常见错误是传入错误的设备名或未初始化 DEVMODE 结构体的 dmSize 字段——这会导致函数返回 FALSE 且不填充数据。
- 设备名用
NULL或空字符串表示主显示器;多显示器需先用EnumDisplayDevices枚举设备名 -
DEVMODE必须用sizeof(DEVMODE)初始化dmSize,否则调用失败 - 返回值为
FALSE时,不要假设dmDisplayFrequency有有效值,应检查 GetLastError()
DEVMODE dm = {};
dm.dmSize = sizeof(dm);
if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm)) {
int refreshRate = dm.dmDisplayFrequency; // 如 60、144、240
}
macOS 用 CGDisplayModeCopyDisplayMode 和 CGDisplayModeGetRefreshRate
macOS 不暴露“刷新率”为独立属性,而是通过当前显示模式(CGDisplayModeRef)查询。注意:只有部分模式支持可变刷新率(如 ProMotion),且系统可能返回 0.0 表示“未指定”或“动态切换中”。
容易忽略的是内存管理——CGDisplayModeCopyDisplayMode 返回的对象需手动释放,否则泄漏。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 用
CGMainDisplayID()获取主屏 ID;多屏需遍历CGGetActiveDisplayList -
CGDisplayModeGetRefreshRate在某些旧 macOS 版本(如 10.13 之前)可能始终返回 0.0 - 若返回 0.0,可 fallback 到
CGDisplayModeGetPixelHeight/Width+ 定时器估算,但精度差
CGDirectDisplayID display = CGMainDisplayID(); CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display); float rate = CGDisplayModeGetRefreshRate(mode); CFRelease(mode); // 必须释放
Linux(X11)用 xrandr 命令解析或 XRRGetScreenInfo
X11 下没有统一 API,推荐优先解析 xrandr --verbose 输出,比调用 XRandR 扩展更稳定。XRRGetScreenInfo 已被标记为 deprecated,且在现代 compositor(如 Wayland 会话下的 Xwayland)中行为不可靠。
常见坑是没处理多输出(output)场景:一个屏幕可能对应多个 output(如 eDP-1、HDMI-1),需匹配当前激活的 current 标记。
-
xrandr --verbose输出中找 “*” 标记的行(如1920x1080 60.00*+),星号表示当前激活模式 - 正则匹配建议用
(\d+\.\d+)\s*\*,避免误抓非当前模式的数值 - 若程序运行在无图形环境(如 SSH 无 DISPLAY),
xrandr会失败,需提前检查getenv("DISPLAY")
跨平台封装要注意刷新率是否“真实可用”
获取到的数值不等于游戏/渲染循环能稳定维持的帧率。尤其在 macOS 的 ProMotion 屏、Windows 的 Adaptive Sync(G-Sync/FreeSync)显示器上,报告值可能是最大值或标称值,实际刷新率动态变化。
真正影响 VSync 行为的是底层图形 API(如 Vulkan 的 VK_PRESENT_MODE_FIFO_KHR、OpenGL 的 wglSwapIntervalEXT)与驱动协同结果,系统报告值仅作参考。
别把 dmDisplayFrequency 或 CGDisplayModeGetRefreshRate 当作硬性帧率上限去设定时器——它不反映当前负载下的实际能力,也不包含 vsync 偏移、扫描延迟等关键信息。

















