2、帧率与刷新率:深入理解VSync、帧生成时间与显示延迟
好,咱们进入第二章。上一章我们聊了高刷屏到底是不是智商税,结论是:硬件到位了,软件跟不上,照样卡。那这一章,我们就深入底层,把「帧率」和「刷新率」这两个看似简单、实则坑极多的概念彻底讲透。
我个人习惯,在讲任何优化之前,先搞清楚「敌人」长什么样。显示卡顿的敌人,就是VSync、帧生成时间和显示延迟这三兄弟。你搞懂了它们,优化思路自然就出来了。
2.1 刷新率 vs 帧率:别再傻傻分不清
很多同学觉得,刷新率60Hz,帧率60fps,这不就完美匹配了吗?嗯,理论上没错,但实际远没那么简单。
| 概念 | 定义 | 谁决定的 | 单位 |
|---|---|---|---|
| 刷新率 (Refresh Rate) | 显示器每秒重绘画面的次数 | 硬件(显示器面板) | Hz |
| 帧率 (Frame Rate) | GPU每秒渲染出多少帧画面 | 软件(游戏/应用 + GPU性能) | fps |
说白了,刷新率是显示器的「输出能力」,帧率是GPU的「生产能力」。一个负责往外倒水,一个负责往里灌水。两者节奏一旦错位,卡顿就来了。
核心认知: 高刷新率只是给了你一个「不卡」的潜力,真正决定流畅度的,是帧率能否稳定匹配刷新率,以及每一帧的生成时间是否均匀。
2.2 VSync:那个又爱又恨的同步开关
VSync,全称Vertical Synchronization(垂直同步)。它的作用,就是强制GPU的帧率与显示器的刷新率对齐。
你想想看,如果没有VSync,GPU拼命渲染,显示器还在慢慢刷新,会发生什么?——画面撕裂(Tearing)。上半部分还是上一帧,下半部分已经变成下一帧了,中间一条横线割裂感极强。
VSync的解决方案很简单:GPU渲染完一帧后,必须等显示器发出「垂直消隐信号」(VBlank),才能把帧缓冲区交换出去。这样,显示器每次刷新看到的都是完整的一帧。
但问题也来了。我在项目中遇到过不少案例,开了VSync后,帧率直接从60fps掉到30fps。为什么?因为GPU渲染一帧的时间超过了16.67ms(60Hz下的单帧时间),VSync会强制GPU等待下一个VBlank,导致实际帧率直接腰斩。
避坑指南: 我曾经调试一个赛车游戏,开了VSync后方向盘响应明显变肉。原因就是VSync引入了额外的输入延迟——你按下按键,要等到下一帧被显示器刷新出来,你才能看到反应。竞技类游戏,慎开VSync。
2.3 帧生成时间:比帧率更重要的指标
帧率是平均值,帧生成时间(Frame Time)才是「心电图」。它记录的是每一帧从开始渲染到完成所花费的毫秒数。
举个例子:
- 场景A: 帧率60fps,但帧生成时间分别是 10ms、20ms、10ms、20ms……
- 场景B: 帧率55fps,但帧生成时间稳定在 18ms、18ms、18ms……
哪个更流畅?答案是场景B。因为人眼对「卡顿」的感知,主要来自帧生成时间的突变,而不是平均帧率的高低。场景A虽然平均帧率高,但20ms那一帧明显「跳了一下」,体感就是一顿一顿的。
我习惯用Frame Time的「标准差」来衡量流畅度。标准差越小,画面越丝滑。这个指标,比任何跑分软件都靠谱。
// 伪代码:计算帧生成时间的标准差
float[] frameTimes = {10, 20, 10, 20, 10, 20};
float mean = sum(frameTimes) / frameTimes.length;
float variance = 0;
for (float t : frameTimes) {
variance += (t - mean) * (t - mean);
}
float stdDev = sqrt(variance / frameTimes.length);
// stdDev 越大,卡顿感越强
2.4 显示延迟:从点击到像素的漫长旅程
显示延迟(Display Latency),也叫Motion-to-Photon Latency(动作到光子延迟)。它指的是从你手指触摸屏幕(或按下鼠标),到屏幕上显示出对应画面所经历的总时间。
这个延迟由三部分组成:
- 输入延迟: 触摸/鼠标信号传输到CPU的时间。
- 处理延迟: CPU/GPU渲染帧的时间。
- 显示延迟: 显示器从收到帧数据到像素实际发光的时间。
高刷屏主要降低的是「显示延迟」部分。比如60Hz显示器,显示延迟大约16.67ms;120Hz显示器,可以降到8.33ms。但如果你开了VSync,处理延迟可能会因为等待VBlank而增加,反而抵消了高刷的优势。
注意: 很多手机厂商宣传的「触控采样率」和「显示延迟」是两码事。触控采样率只影响输入延迟的第一阶段,而显示延迟是全程的总和。别被营销话术带偏了。
2.5 知识体系:VSync、帧生成时间与显示延迟的关系
下面这张图,是我自己梳理的。它把这三者的关系画清楚了。你盯着看一分钟,很多疑惑会迎刃而解。
2.6 实战:如何测量和优化这些指标
光说不练假把式。我分享几个我常用的工具和方法。
- 测量帧生成时间: 用
PresentMon(Windows)或PerfDog(移动端)。别只看平均帧率,盯着Frame Time曲线看。 - 判断VSync是否开启: 观察Frame Time曲线是否出现「阶梯状」——比如稳定在16.67ms,然后突然跳到33.33ms,大概率是VSync在作祟。
- 优化显示延迟: 关闭VSync + 开启NVIDIA Reflex / AMD Anti-Lag。这些技术本质上是让CPU和GPU更紧密地协作,减少渲染队列中的等待时间。
个人经验: 我调试一个120Hz平板时,发现滑动列表总感觉「粘手」。用PerfDog一测,帧生成时间在8ms到16ms之间剧烈波动。后来发现是某个后台动画线程抢占了主线程的CPU时间。把动画线程优先级调低后,Frame Time曲线瞬间变平了。你看,问题往往不在渲染本身,而在调度。