C ++:哪里可以获得不使用v-sync的帧速率限制器?

这似乎是程序员之间的一个巨大的秘密,没有人想分享他们的代码。 为什么?

我找不到一个工作的FPS限制器,可以将FPS限制在至less60,而不使用v-sync。

当然,我想要正确的做法。 所以我还没有做出自己的,因为他们都说,花了一年的时间来学习fps限制器中的所有技巧…

编辑:这是我的fps限制器代码,这是不完美的,但它最好的,我可以做,但仍然stream泪:

timeBeginPeriod(1); frame_start_time = TimerGetTime(); while(!done){ if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){ if(msg.message == WM_QUIT){ done = 1; }else{ TranslateMessage(&msg); DispatchMessage(&msg); } }else if(active){ draw_everything(); SwapBuffers(hDC); // fps limiter: one_frame_limit = 1000.0f/(float)framerate_limit; // 16.666 ms while((time_left = one_frame_limit-(TimerGetTime()-frame_start_time)) > 0){ if(time_left >= 6.0f){ Sleep((int)(time_left/6.0f)); }else{ Sleep(0); // sleep less than 1ms } } frame_start_time = TimerGetTime(); } } 

编辑2:inheritance人我第二次尝试,使用等待定时器build议:

 float one_frame_limit = 1000.0f/(float)framerate_limit; float time_left = one_frame_limit-(TimerGetTime()-frame_start_time); // 4.7432ms liDueTime.QuadPart = -(LONGLONG)(time_left*10000.0f); if(SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, 0)){ WaitForSingleObject(hTimer, INFINITE); } while((time_left = one_frame_limit-(TimerGetTime()-frame_start_time)) > 0.003f){ Sleep(0); } frame_start_time = TimerGetTime(); 

我认为更好地工作。 但仍然撕裂…请注意,我在那里添加了while循环,因为它比没有它更撕裂。

另一个问题:这是初始化安全吗?

 HANDLE hTimer = NULL; LARGE_INTEGER liDueTime; liDueTime.QuadPart = -100000LL; // testing timer: wait for 10ms hTimer = CreateWaitableTimer(NULL, TRUE, NULL); if(hTimer == NULL){ waitable_timer_supported = 0; }else if(!SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, 0)){ waitable_timer_supported = 0; }else if(WaitForSingleObject(hTimer, INFINITE) != WAIT_OBJECT_0){ waitable_timer_supported = 0; } 

恐怕即使支持等待定时器,最后2次检查也可能失败…迄今为止它没有失败。 这是检查其支持的正确方法吗?

设置一个系统计时器,每隔16.6666ms关闭一次,并在该事件上进行渲染。 更好的方法是,在定时器上进行渲染和页面翻转,然后开始渲染下一帧。 这不是一个很大的秘密,你可以使用高分辨率定时器在windows中进行。

一旦你得到这个工作,你会看到撕裂,并决定等待v-同步,而不是一些任意的计时器。

在DirectX中,只需将参数传递给Present()即可使当前线程空闲,直到它返回,这将以某个刷新率的倍数来限制FPS。 我用过它,可以说我的系统通过使用这个系统达到了大约1%的CPU使用率。 你现在的代码基本上是错误的,因为睡眠是最不可靠的功能,总之,你几乎不应该用非零参数来使用它。

你可以尝试使用QueryPerformanceCounter和Sleep()。

 LARGE_INTEGER freq, begin, end; QueryPerformanceFrequency(&freq); QueryPerformanceCounter(&begin); QueryPerformanceCounter(&end); const unsigned __int64 waitinticks = static_cast<unsigned __int64>(static_cast<double>(1000)/60)); while(end.QuadPart - begin.QuadPart < waitinticks) { Sleep(0); // If someone else wants to run, let them. QueryPerformanceCounter(&end); } 

最好的办法是使用一个等待定时器 – http://msdn.microsoft.com/en-us/library/ms682492(v=VS.85).aspx 。 这将睡眠你的线程,直到定时器提醒它。

对不起,如果有一些让我误会的魔法,但据我所知,VSync和撕裂是相辅相成的。 不管帧的限制是什么,如果帧缓冲区在帧中间翻转,你仍然会撕裂。 这是VSync的用途。

至于帧限制码,下面是一些做生产者/消费者时间步的技巧:

http://gafferongames.com/game-physics/fix-your-timestep/

他的理由似乎集中在物理上,但它也完全适用于帧限制。