Windows 上用 EnumDisplaySettings 获取当前显示器刷新率最可靠,需传 ENUM_CURRENT_SETTINGS、初始化 DEVMODE.dmSize,读取 dmDisplayFrequency 字段(单位 Hz);Linux X11 用 xrandr --current 解析或 XRR API 计算;macOS 调 CGDisplayModeGetRefreshRate。

Windows 上用 EnumDisplaySettings 查当前刷新率
Windows 没有直接暴露“V-Sync 频率”的 API,它实际就是显示器当前设置的垂直刷新率(Vertical Refresh Rate),而这个值由显卡驱动在 EnumDisplaySettings 中返回。你得先拿到当前活动显示器的模式信息:
关键点:必须传 ENUM_CURRENT_SETTINGS(不是 0 或 -1),否则可能返回默认/备用模式;DEVMODE.dmDisplayFrequency 字段才是你要的数值(单位:Hz)。
常见错误:调用前没初始化 DEVMODE 结构体的 dmSize 字段,导致返回失败或垃圾值;或者误用 EnumDisplayDevices 后没正确拼接设备名就调 EnumDisplaySettings。
示例片段:
立即学习“C++免费学习笔记(深入)”;
DEVMODE dm = {};
dm.dmSize = sizeof(dm);
if (EnumDisplaySettings(nullptr, ENUM_CURRENT_SETTINGS, &dm)) {
int vsync_hz = dm.dmDisplayFrequency; // 通常是 60、75、120、144、165、240 等
}Linux X11 下读取 xrandr 输出或调 XRRGetScreenInfo
X11 没有内建 V-Sync 抽象,但刷新率来自当前激活的视频模式,可通过命令行或 XRandR 扩展获取。最可靠的是用 XRRGetScreenInfo + XRRAllocGamma 配合遍历 XRRModeInfo,但更常用且轻量的做法是解析 xrandr --verbose 的输出——因为它的 clock 和 HDisplay/VDisplay 可算出理论刷新率,而带 + 标记的当前模式行会直接显示 60.00*+ 这样的字段。
注意:XRRGetScreenInfo 已被标记为 deprecated,新代码应优先用 XRRGetOutputInfo + XRRListOutputModes;而且必须确认当前 mode 的 mode->dotClock、mode->hTotal、mode->vTotal 都非零再计算,否则除零崩溃。
计算公式(仅作验证):refresh = dotClock * 1000.0 / (hTotal * vTotal),但实际应以 xrandr 显示的 * 行为准——驱动可能做了 CVT/GTF 微调。
macOS 上通过 CGDisplayModeGetRefreshRate 获取
macOS 提供了最干净的接口:CGDisplayModeGetRefreshRate 直接返回当前 display mode 的刷新率(float)。前提是先拿到当前主屏或目标屏的 CGDirectDisplayID,再用 CGDisplayCopyDisplayMode 获取当前 mode 对象。
容易忽略的细节:CGDisplayModeGetRefreshRate 在某些外接显示器或缩放模式下可能返回 0.0f,此时应 fallback 到 CGDisplayModeGetIOFlags 检查是否含 kCGDisplayModeIsSafeForHardware,或尝试枚举所有 mode 并选 CGDisplayModeGetRefreshRate > 0 的最高值。
简例:
CGDirectDisplayID display = CGMainDisplayID(); CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display); float rate = CGDisplayModeGetRefreshRate(mode); CFRelease(mode); // 必须释放
V-Sync 频率 ≠ 应用帧率,别混淆驱动层与应用层控制
获取到的刷新率只是硬件能力上限,不代表你的 OpenGL/Vulkan/DX 应用真能锁到该频率。真正启用 V-Sync 是靠图形 API 的交换链配置:wglSwapIntervalEXT(1)、vkQueuePresentKHR 前设 VkPresentInfoKHR::pWaitSemaphores、或 SDL_GL_SetSwapInterval(1)。这些调用失败时(比如驱动禁用了垂直同步),即使显示器是 144Hz,你的帧率也可能飙到 300+ 且撕裂。
跨平台项目里最容易出问题的是:只读了系统刷新率就认定“V-Sync 已启用”,结果用户关掉驱动面板里的 G-Sync/FreeSync,或笔记本独显/核显切换导致 SwapInterval 实际失效。务必在运行时检查图形 API 的返回值,并提供手动开关选项。
没有统一跨平台 API 能“获取当前是否启用了 V-Sync”,只有“获取显示器能力”和“尝试启用”两步,中间那层是驱动私有的。


















