1. 帧率基础概念
1.1 帧率定义
帧率(FPS,Frames Per Second)表示图形渲染系统每秒能够输出到显示器的画面数量。例如 60 FPS 意味着每秒钟生成 60 帧画面。帧率直接决定了画面的流畅度:帧率越高,相邻帧之间的视觉差异越小,人眼感知到的运动越平滑。
在技术实现中,帧率的计算通常通过统计一段时间内的帧数来完成:
FPS = 总渲染帧数 / 测量时间窗口(秒)
例如,如果在 2 秒内渲染了 120 帧,则平均 FPS = 120 / 2 = 60。但平均帧率可能掩盖瞬间卡顿,因此实际性能分析更关注 帧生成时间(见 1.4 节)。
1.2 刷新率与帧率关系
显示器刷新率(Hz)是指显示器每秒能够更新画面的次数,常见的刷新率有 60Hz、120Hz、144Hz、240Hz 等。帧率与刷新率的关系决定了画面是否会出现 画面撕裂(Tearing)、卡顿(Stutter) 或 输入延迟(Input Lag)。
| 帧率 vs 刷新率 | 现象 | 常见解决方法 |
|---|---|---|
| 帧率 < 刷新率 | 画面重复显示同一帧,感知卡顿 | 降低画质、开启 V-Sync(垂直同步) |
| 帧率 = 刷新率 | 理想状态,画面流畅无撕裂 | 维持稳定帧率 |
| 帧率 > 刷新率 | 多余帧无法显示,产生撕裂 | 开启 V-Sync 或使用自适应同步(FreeSync/G-Sync) |
| 帧率波动剧烈 | 帧生成时间不均,主观感觉不流畅 | 限制帧率上限、优化渲染管线 |
关键概念:垂直同步(V-Sync)会将帧率强制同步到刷新率整数倍,消除撕裂但可能增加输入延迟。自适应同步技术(AMD FreeSync / NVIDIA G-Sync)允许显示器动态调整刷新率匹配帧率,兼顾流畅与低延迟。
1.3 常见帧率标准
不同应用场景对帧率的要求差异很大。以下为行业通行的帧率标准及其对应的帧生成时间:
| 目标帧率 | 典型场景 | 每帧生成时间 | 备注 |
|---|---|---|---|
| 24 FPS | 电影、动画 | 41.67 ms | 人眼可感知运动模糊,符合电影质感 |
| 30 FPS | 家用机游戏、低端移动设备 | 33.33 ms | 可接受但不够顺滑 |
| 60 FPS | 主流 PC 游戏、视频 | 16.67 ms | 流畅与性能的平衡点 |
| 90 FPS | VR 头显 | 11.11 ms | 降低 VR 晕动症风险 |
| 120 FPS | 高刷新率显示器、电竞 | 8.33 ms | 竞技游戏追求的最低标准 |
| 144 FPS | 144Hz 显示器、FPS 电竞 | 6.94 ms | 专业电竞配置 |
| 240 FPS | 240Hz 极速显示器 | 4.17 ms | 极限响应需求 |
注意:帧生成时间 = 1000 ms / FPS。过高帧率会导致 GPU 负载增加、发热和功耗上升,同时人眼对 240 FPS 以上的提升感知减弱,需根据硬件和应用场景权衡。
1.4 帧生成时间(Frame Time)
帧生成时间是指从开始渲染一帧到渲染完成并提交到显示队列所花费的时间,单位通常为毫秒(ms)。它是比 FPS 更敏感的性能指标——即使平均 FPS 很高,如果某一帧的生成时间突然飙升(如 100 ms),就会造成明显的卡顿(掉帧)。
测量帧生成时间通常使用高精度计时器(例如 std::chrono::high_resolution_clock 或 QueryPerformanceCounter):
// C++ 伪代码示例:逐帧帧生成时间采样
auto lastTime = std::chrono::high_resolution_clock::now();
while (running) {
// 渲染一帧
renderFrame();
auto currentTime = std::chrono::high_resolution_clock::now();
float frameTime = std::chrono::duration<float, std::milli>(currentTime - lastTime).count();
// 记录 frameTime 到历史缓冲区
lastTime = currentTime;
// 可计算 FPS = 1000.0f / frameTime;
}
在实际调试中,常用 Percentile 统计 来衡量帧生成时间的稳定性:
- 1% Low:所有帧生成时间中最差的 1% 的平均值,反映卡顿严重程度。
- 0.1% Low:更极端的卡顿指标。
- Frame Time Variance:帧时间标准差,越大表示抖动越严重。
性能优化核心原则:帧率监控不应只看平均 FPS,而应持续追踪帧生成时间的分布。当 1% Low 远低于平均 FPS 时,说明存在明显掉帧,需要定位导致长帧的渲染阶段(如 draw call 过多、纹理加载阻塞、物理计算突发等)。
1.5 内联 SVG:帧率与帧生成时间关系图
下图展示了在稳定 60 FPS 以及出现掉帧(长帧)时的帧生成时间序列对比:
1.6 帧率监控实战入门
在本课程中,你将逐步学习如何通过代码和工具实时监控帧率并定位掉帧原因。以下是本章可立即实践的两个基础命令:
- 使用 PresentMon(Windows): 从 GitHub 下载 PresentMon,运行以下命令获取进程的帧时间日志:
PresentMon.exe -process_name "YourGame.exe" -output_file frametimes.csv -timed 60
- 使用 CLI 工具 GPU-Z 或 MSI Afterburner: 开启帧率/帧时间 OSD 显示,可以直观观察稳定性和掉帧。
在下章(第 2 章)开始前,建议你使用上述工具记录一段游戏实况的帧时间数据,为后续分析和定位掉帧源头做好准备。