基于WIN32 API同步游戏循环至60TPS遇33FPS异常求助
游戏循环FPS不达目标的原因及解决方法
问题出在Windows系统的Sleep函数精度限制上:
- Windows默认的系统定时器分辨率是15.625ms(对应64Hz),Sleep的实际休眠时间会强制对齐到这个分辨率的整数倍。
- 你的目标是每帧耗时≈16.666ms(1/60秒),当渲染耗时可以忽略时,计算出的delay≈16.666ms,转换成整数是16ms。但Sleep(16)会被系统向上对齐到下一个完整的定时器周期,也就是31.25ms(15.625×2),直接导致每帧耗时接近31ms,最终FPS约为33。
修复步骤
提升系统定时器分辨率
使用timeBeginPeriod和timeEndPeriod函数(需链接winmm.lib),将系统定时器分辨率临时提升到1ms,大幅提高Sleep的精度。注意程序退出时必须恢复原分辨率,避免影响系统其他进程。优化休眠逻辑
对于小于1ms的剩余延迟,采用忙等(循环查询时间)来补充,避免Sleep的最小单位误差。优化时钟类
QueryPerformanceFrequency无需每次调用,系统启动后频率就固定了,可以在Clock类初始化时只查询一次,减少冗余计算。
修改后的代码示例
#include <iostream> #include <Windows.h> #include <mmsystem.h> // 用于timeBeginPeriod #pragma comment(lib, "winmm.lib") // 链接winmm库 class Clock { public: Clock() : m_Start(0.0), m_Elapsed(0.0) { // 只查询一次性能计数器频率 LARGE_INTEGER frequency; QueryPerformanceFrequency(&frequency); m_Frequency = static_cast<double>(frequency.QuadPart); } double AbsoluteTime() { LARGE_INTEGER current_time; QueryPerformanceCounter(¤t_time); return static_cast<double>(current_time.QuadPart) / m_Frequency; } void Start() { m_Start = AbsoluteTime(); } double GetElapsed() { double current_time = AbsoluteTime(); m_Elapsed = current_time - m_Start; return m_Elapsed; } private: double m_Start; double m_Elapsed; double m_Frequency; // 缓存性能计数器频率 }; int main() { // 提升定时器分辨率到1ms timeBeginPeriod(1); Clock clock; Clock fpsClock; int frameCount = 0; while (true) { clock.Start(); // 模拟渲染操作(可替换为实际渲染代码) // ... double elapsed = clock.GetElapsed(); const double targetFrameTime = 1.0 / 60.0; double delay = targetFrameTime - elapsed; if (delay > 0) { if (delay >= 0.001) { // 大于等于1ms时用Sleep Sleep(static_cast<DWORD>(delay * 1000)); } // 剩余不足1ms的时间用忙等补充,同时让出CPU给其他线程 while (clock.GetElapsed() < targetFrameTime) { YieldProcessor(); } } frameCount++; if (fpsClock.GetElapsed() > 1.0) { std::cout << "FPS: " << frameCount << std::endl; fpsClock.Start(); frameCount = 0; } } // 恢复定时器分辨率(无限循环场景下可在退出分支调用) timeEndPeriod(1); return 0; }
补充说明
YieldProcessor()可以在忙等时让出CPU给其他线程,避免独占核心资源。- 提升系统定时器分辨率会增加系统功耗,因此仅在游戏运行期间开启,退出时务必恢复原设置。
内容的提问来源于stack exchange,提问作者Nicky
相关产品推荐
相关产品推荐

