在循环 C++ 中限制 fps
Limit fps in loop c++
我有一个简单的 fps 限制器,它可以工作:
Clock.h
#include <chrono>
using namespace std::chrono;
class Clock
{
high_resolution_clock::time_point startTime;
public:
Clock();
duration<double> restart();
};
Clock.cpp
#include "Clock.h"
Clock::Clock()
: startTime(high_resolution_clock::now())
{
}
duration<double> Clock::restart()
{
high_resolution_clock::time_point now = high_resolution_clock::now();
duration<double> elapsed = now - startTime;
startTime = now;
return elapsed;
}
main.cpp
duration<double> stepInterval(1.f / 60.f);
duration<double> deltaTime(0);
Clock clock;
while(isRunning)
{
deltaTime += clock.restart();
if(deltaTime > stepInterval)
{
std::cout << deltaTime.count() * 1000 << std::endl;
deltaTime = seconds(0);
}
}
但在这种情况下 CPU 负载很高。我用 std::this_thread::sleep_for 尝试了另一种解决方案,但它们不适用于小间隔(如 16 毫秒)。关于实施 std::this_thread::sleep_for 有什么想法吗?
此代码可能对您有所帮助。它对我来说效果很好(精度高):
#include <iostream>
#include <thread>
#include <chrono>
int main()
{
std::chrono::high_resolution_clock::time_point prev =
std::chrono::high_resolution_clock::now();
std::chrono::high_resolution_clock::time_point current =
std::chrono::high_resolution_clock::now();
int i = 0;
while (true) {
current = std::chrono::high_resolution_clock::now();
if (std::chrono::duration_cast<std::chrono::microseconds>(current - prev).count() >= 16000) {
prev = current;
i++;
std::cout << i << std::endl;
} else {
std::this_thread::sleep_for(std::chrono::microseconds(1));
}
}
return 0;
}
```
不要使用 sleep_for
。请改用 sleep_until
。这将使您从所需帧速率的漂移平均为零。这是通过休眠 直到 当前帧的开始加上所需的帧持续时间来完成的。
使用 system_clock
可以让您的帧速率在很长一段时间内保持准确。没有时钟是完美的。但是 system_clock
偶尔会被少量调整到正确的时间。这将影响您的帧速率在电影长度内符合所需的速率。如果您担心具有管理员权限的进程按总量调整系统时钟,请不要遵循此建议。在这种情况下,请改用 steady_clock
。
创建一个 1/60 秒的持续时间类型以消除浮点舍入误差。
消除代码中的转换常量,例如 1000
,以减少出现逻辑错误的可能性。
在你的 sleep_until
中,早点起床然后 busy-loop 直到所需的时间。你必须提前试验多少。太早你会消耗太多 CPU(和电池)。太少了,而且sleep_until
偶尔会在CPU高负载的时候醒得太晚。
总的来说,这可能看起来像:
template <class Clock, class Duration>
void
sleep_until(std::chrono::time_point<Clock, Duration> tp)
{
using namespace std::chrono;
std::this_thread::sleep_until(tp - 10us);
while (tp >= Clock::now())
;
}
int
main()
{
using namespace std;
using namespace std::chrono;
using framerate = duration<int, ratio<1, 60>>;
auto tp = system_clock::now() + framerate{1};
while (isRunning)
{
// do drawing
::sleep_until(tp);
tp += framerate{1};
}
}
这里有一个更详细的想法草图,其中包括“绘制”每帧的当前帧速率和平均帧速率。它使用 C++17 的 chrono::round
函数和这个 free, open-source C++20 chrono preview library 用于“绘图”。
#include "date/date.h"
#include <chrono>
#include <iostream>
#include <thread>
template <class Clock, class Duration>
void
sleep_until(std::chrono::time_point<Clock, Duration> tp)
{
using namespace std::chrono;
std::this_thread::sleep_until(tp - 10us);
while (tp >= Clock::now())
;
}
int
main()
{
using namespace std;
using namespace std::chrono;
using framerate = duration<int, ratio<1, 60>>;
auto prev = system_clock::now();
auto next = prev + framerate{1};
int N = 0;
system_clock::duration sum{0};
while (true)
{
::sleep_until(next);
next += framerate{1};
// do drawing
using namespace date;
auto now = system_clock::now();
sum += now - prev;
++N;
cerr << "This frame: " << round<milliseconds>(now-prev)
<< " average: " << round<milliseconds>(sum/N) << '\n';
prev = now;
}
}
我的输出:
...
This frame: 16ms average: 17ms
This frame: 15ms average: 17ms
This frame: 19ms average: 17ms
This frame: 16ms average: 17ms
This frame: 17ms average: 17ms
This frame: 16ms average: 17ms
This frame: 17ms average: 17ms
This frame: 17ms average: 17ms
This frame: 16ms average: 17ms
This frame: 16ms average: 17ms
This frame: 16ms average: 17ms
This frame: 18ms average: 17ms
This frame: 16ms average: 17ms
我有一个简单的 fps 限制器,它可以工作:
Clock.h
#include <chrono>
using namespace std::chrono;
class Clock
{
high_resolution_clock::time_point startTime;
public:
Clock();
duration<double> restart();
};
Clock.cpp
#include "Clock.h"
Clock::Clock()
: startTime(high_resolution_clock::now())
{
}
duration<double> Clock::restart()
{
high_resolution_clock::time_point now = high_resolution_clock::now();
duration<double> elapsed = now - startTime;
startTime = now;
return elapsed;
}
main.cpp
duration<double> stepInterval(1.f / 60.f);
duration<double> deltaTime(0);
Clock clock;
while(isRunning)
{
deltaTime += clock.restart();
if(deltaTime > stepInterval)
{
std::cout << deltaTime.count() * 1000 << std::endl;
deltaTime = seconds(0);
}
}
但在这种情况下 CPU 负载很高。我用 std::this_thread::sleep_for 尝试了另一种解决方案,但它们不适用于小间隔(如 16 毫秒)。关于实施 std::this_thread::sleep_for 有什么想法吗?
此代码可能对您有所帮助。它对我来说效果很好(精度高):
#include <iostream>
#include <thread>
#include <chrono>
int main()
{
std::chrono::high_resolution_clock::time_point prev =
std::chrono::high_resolution_clock::now();
std::chrono::high_resolution_clock::time_point current =
std::chrono::high_resolution_clock::now();
int i = 0;
while (true) {
current = std::chrono::high_resolution_clock::now();
if (std::chrono::duration_cast<std::chrono::microseconds>(current - prev).count() >= 16000) {
prev = current;
i++;
std::cout << i << std::endl;
} else {
std::this_thread::sleep_for(std::chrono::microseconds(1));
}
}
return 0;
}
```
不要使用
sleep_for
。请改用sleep_until
。这将使您从所需帧速率的漂移平均为零。这是通过休眠 直到 当前帧的开始加上所需的帧持续时间来完成的。使用
system_clock
可以让您的帧速率在很长一段时间内保持准确。没有时钟是完美的。但是system_clock
偶尔会被少量调整到正确的时间。这将影响您的帧速率在电影长度内符合所需的速率。如果您担心具有管理员权限的进程按总量调整系统时钟,请不要遵循此建议。在这种情况下,请改用steady_clock
。创建一个 1/60 秒的持续时间类型以消除浮点舍入误差。
消除代码中的转换常量,例如
1000
,以减少出现逻辑错误的可能性。在你的
sleep_until
中,早点起床然后 busy-loop 直到所需的时间。你必须提前试验多少。太早你会消耗太多 CPU(和电池)。太少了,而且sleep_until
偶尔会在CPU高负载的时候醒得太晚。
总的来说,这可能看起来像:
template <class Clock, class Duration>
void
sleep_until(std::chrono::time_point<Clock, Duration> tp)
{
using namespace std::chrono;
std::this_thread::sleep_until(tp - 10us);
while (tp >= Clock::now())
;
}
int
main()
{
using namespace std;
using namespace std::chrono;
using framerate = duration<int, ratio<1, 60>>;
auto tp = system_clock::now() + framerate{1};
while (isRunning)
{
// do drawing
::sleep_until(tp);
tp += framerate{1};
}
}
这里有一个更详细的想法草图,其中包括“绘制”每帧的当前帧速率和平均帧速率。它使用 C++17 的 chrono::round
函数和这个 free, open-source C++20 chrono preview library 用于“绘图”。
#include "date/date.h"
#include <chrono>
#include <iostream>
#include <thread>
template <class Clock, class Duration>
void
sleep_until(std::chrono::time_point<Clock, Duration> tp)
{
using namespace std::chrono;
std::this_thread::sleep_until(tp - 10us);
while (tp >= Clock::now())
;
}
int
main()
{
using namespace std;
using namespace std::chrono;
using framerate = duration<int, ratio<1, 60>>;
auto prev = system_clock::now();
auto next = prev + framerate{1};
int N = 0;
system_clock::duration sum{0};
while (true)
{
::sleep_until(next);
next += framerate{1};
// do drawing
using namespace date;
auto now = system_clock::now();
sum += now - prev;
++N;
cerr << "This frame: " << round<milliseconds>(now-prev)
<< " average: " << round<milliseconds>(sum/N) << '\n';
prev = now;
}
}
我的输出:
...
This frame: 16ms average: 17ms
This frame: 15ms average: 17ms
This frame: 19ms average: 17ms
This frame: 16ms average: 17ms
This frame: 17ms average: 17ms
This frame: 16ms average: 17ms
This frame: 17ms average: 17ms
This frame: 17ms average: 17ms
This frame: 16ms average: 17ms
This frame: 16ms average: 17ms
This frame: 16ms average: 17ms
This frame: 18ms average: 17ms
This frame: 16ms average: 17ms