C ++如何制定精确的帧率限制?

我正在尝试使用C ++创建游戏,我想为fps设置限制,但是我总是得到比我想要的更多或更少的fps。当我查看具有fps限制的游戏时,始终是精确的帧频。使用Sleep()std :: this_thread :: sleep_for(sleep_untill)进行了尝试。例如,Sleep(0.01-deltaTime)可获得100fps,但最终却变为+ -90fps。 这些游戏如何处理fps,以至于任何睡眠都不准确? 我知道我可以使用无限循环来检查时间是否已过去,但是它正在使用cpu的全部功能,但是我想通过此限制来减少cpu的使用而无需VSync

Jason82918 回答:C ++如何制定精确的帧率限制?

在执行基于调度程序睡眠的任何等待时要非常小心。

大多数OS调度程序的等待等待时间更长,没有明确定义的时间间隔或信号使线程回到就绪状态。

睡眠本身并不是不正确的,您只是在错误地解决问题。如果您可以访问DXGI的“等待交换链”之类的内容,则可以同步到DWM的当前队列,并获得真正可靠的低延迟时间。

您无需忙于等待即可获得准确的时间,可等待的计时器将为您提供一个同步对象来重新安排线程。

无论您做什么,都不要在生产代码中使用当前接受的答案。您想避免这种情况,在这种情况下,睡眠(0)不会将CPU时间浪费在优先级更高的线程上。我已经看到很多游戏开发人员尝试使用Sleep(0),这会给您带来重大问题。

,

您可以记录开始时的时间点,为其添加固定的持续时间,然后休眠直到计算出的时间点出现在每个循环的末尾(或开始)为止。示例:

#include <chrono>
#include <iostream>
#include <ratio>
#include <thread>

template<std::intmax_t FPS>
class frame_rater {
public:
    frame_rater() :                 // initialize the object keeping the pace
        time_between_frames{1},// std::ratio<1,FPS> seconds
        tp{std::chrono::steady_clock::now()}
    {}

    void sleep() {
        // add to time point
        tp += time_between_frames;

        // and sleep until that time point
        std::this_thread::sleep_until(tp);
    }

private:
    // a duration with a length of 1/FPS seconds
    std::chrono::duration<double,std::ratio<1,FPS>> time_between_frames;

    // the time point we'll add to in every loop
    std::chrono::time_point<std::chrono::steady_clock,decltype(time_between_frames)> tp;
};

// this should print ~10 times per second pretty accurately
int main() {
    frame_rater<10> fr; // 10 FPS
    while(true) {
        std::cout << "Hello world\n";
        fr.sleep();                   // let it sleep any time remaining
    }
}
,

您可以将const fps变量设置为所需的帧速率,然后,如果自上次更新起经过的时间等于或大于1 /期望的fps,则可以更新游戏。 这可能会起作用。 示例:

const /*or constexpr*/ int fps{60};

// then at update loop.
while(running)
{
    // update the game timer.
    timer->update();

    // check for any events.

    if(timer->ElapsedTime() >= 1 / fps)
    {
        // do your updates and THEN renderer.
    }
}

,

是的,睡眠通常不准确。因此,您的睡眠时间少于完成帧所需的实际时间。例如,如果您还需要5毫秒来完成帧,则请休眠4毫秒。睡觉后,只需对其余的框架进行自旋锁即可。像

float TimeRemaining = NextFrameTime - GetCurrentTime();
Sleep(ConvertToMilliseconds(TimeRemaining) - 1);
while (GetCurrentTime() < NextFrameTime) {};
,

使用计时器。
某些OS可以提供​​特殊功能。例如,对于Windows,您可以使用SetTimer并处理其WM_TIMER消息。

然后计算计时器的频率。 100 fps表示计时器必须每0.01秒触发一次事件。

在此计时器事件的事件处理程序中,您可以进行渲染。

如果渲染速度慢于所需频率,则使用同步标记OpenGL sync,如果先前的渲染未完成,则丢弃计时器事件。

,

被接受的答案听起来真的很糟糕。这可能不准确,并且会烧毁CPU!

Thread.Sleep不准确,因为您必须告诉它准确(默认情况下大约为15ms准确-这意味着如果您告诉它休眠1ms,则可能休眠15ms)。

您可以使用Win32 API调用timeBeginPeriod和timeEndPeriod函数来完成此操作。

检查MSDN了解更多详细信息-> https://docs.microsoft.com/en-us/windows/win32/api/timeapi/nf-timeapi-timebeginperiod

(我会在接受的答案上发表评论,但仍然没有50个声誉)

本文链接:https://www.f2er.com/2982377.html

大家都在问