使用 std::chrono 限制 fps
Limiting fps with std::chrono
std::chrono::system_clock::time_point m_BeginFrame = std::chrono::system_clock::now();
std::chrono::system_clock::time_point m_EndFrame = std::chrono::system_clock::now();
std::chrono::nanoseconds m_WorkTime = std::chrono::nanoseconds::zero();
std::chrono::nanoseconds m_WaitTime = std::chrono::nanoseconds::zero();
auto invFpsLimit = std::chrono::nanoseconds(1e9 / fpsLimit());
// main loop
while (!glfwWindowShouldClose(m_pScreen->glfwWindow()))
{
m_WaitTime = m_BeginFrame - m_EndFrame;
m_EndFrame = std::chrono::system_clock::now();
m_WorkTime = m_EndFrame - m_BeginFrame;
// if need sleep
if (m_WorkTime < invFpsLimit)
{
std::this_thread::sleep_until(m_BeginFrame + invFpsLimit);
m_DeltaTime = invFpsLimit;
}
else
{
m_DeltaTime = m_WorkTime;
}
m_BeginFrame = std::chrono::system_clock::now();
TRACE(" %f %u %u %u",
((float)1e9 / (float)(m_WaitTime.count() + m_WorkTime.count())),
m_WorkTime.count(),
m_WaitTime.count(),
invFpsLimit.count());
// think and opengl stuff...
}
我试图用这段代码限制 fps,但 Fraps 显示大约 56-57 值
58.848454 3175500 13817300 16666666
55.259304 3314200 14782300 16666666
58.923698 2321700 14649400 16666666
56.200928 2167400 15625900 16666666
52.774071 3188200 15760500 16666666
50.600887 4899700 14862800 16666666
65.011055 2347500 13034500 16666666
54.966499 2611700 15581200 16666666
55.605911 2653400 15330300 16666666
56.476437 2386100 15320400 16666666
55.280689 2581400 15508100 16666666
56.437550 2355400 15363300 16666666
47.170700 5535900 15663700 16666666
64.713608 3039700 12413000 16666666
56.136570 2941100 14872600 16666666
53.444496 3624200 15086800 16666666
60.074493 2397500 14248500 16666666
51.737339 3777100 15551300 16666666
59.369026 3665800 13178000 16666666
59.355282 3543900 13303800 16666666
54.243759 3961000 14474300 16666666
45.764706 7823500 14027400 16666666
61.242237 6239400 10089200 16666666
73.396652 2013800 11610800 16666666
50.531849 3824000 15965500 16666666
62.895454 2796000 13103400 16666666
60.611572 2360500 14138000 16666666
56.074242 2241700 15591800 16666666
55.143208 2454800 15679800 16666666
我尝试将时钟更改为 system_clock,使用 sleep_for 而不是 sleep_untill,但没有任何效果
关于标准时钟或我看不到的工作代码,有什么我不知道的具体事情吗?
什么在偷我的 fps?
documentation of sleep_until
说:
The function also may block for longer than until after sleep_time has been reached due to scheduling or resource contention delays.
如果您确实需要精确的 fps,请使用 vSync,或将代码中的 if 块替换为以下循环,该循环在帧时间用完之前一直不执行任何操作:
while (m_WorkTime < invFpsLimit)
{
m_EndFrame = std::chrono::system_clock::now();
m_WorkTime = m_EndFrame - m_BeginFrame;
}
将 m_BeginFrame
和 m_EndFrame
更新为 invFpsLimit
而不是 system_clock::now()
可以做得更好。这可能看起来像:
#include <iostream>
#include <thread>
int fpsLimit() {return 60;}
int
main()
{
using namespace std::chrono;
using dsec = duration<double>;
auto invFpsLimit = duration_cast<system_clock::duration>(dsec{1./fpsLimit()});
auto m_BeginFrame = system_clock::now();
auto m_EndFrame = m_BeginFrame + invFpsLimit;
unsigned frame_count_per_second = 0;
auto prev_time_in_seconds = time_point_cast<seconds>(m_BeginFrame);
while (true)
{
// Do drawing work ...
// This part is just measuring if we're keeping the frame rate.
// It is not necessary to keep the frame rate.
auto time_in_seconds = time_point_cast<seconds>(system_clock::now());
++frame_count_per_second;
if (time_in_seconds > prev_time_in_seconds)
{
std::cerr << frame_count_per_second << " frames per second\n";
frame_count_per_second = 0;
prev_time_in_seconds = time_in_seconds;
}
// This part keeps the frame rate.
std::this_thread::sleep_until(m_EndFrame);
m_BeginFrame = m_EndFrame;
m_EndFrame = m_BeginFrame + invFpsLimit;
}
}
在 C++17 及更高版本中,我建议使用 round
构造 invFpsLimit
而不是 duration_cast
以获得更好的准确性:
auto invFpsLimit = round<system_clock::duration>(dsec{1./fpsLimit()});
要获得增量,您可以这样做:
unsgined deltaTime = 1000.0f / frame_count_per_fps; // In milliseconds
std::chrono::system_clock::time_point m_BeginFrame = std::chrono::system_clock::now();
std::chrono::system_clock::time_point m_EndFrame = std::chrono::system_clock::now();
std::chrono::nanoseconds m_WorkTime = std::chrono::nanoseconds::zero();
std::chrono::nanoseconds m_WaitTime = std::chrono::nanoseconds::zero();
auto invFpsLimit = std::chrono::nanoseconds(1e9 / fpsLimit());
// main loop
while (!glfwWindowShouldClose(m_pScreen->glfwWindow()))
{
m_WaitTime = m_BeginFrame - m_EndFrame;
m_EndFrame = std::chrono::system_clock::now();
m_WorkTime = m_EndFrame - m_BeginFrame;
// if need sleep
if (m_WorkTime < invFpsLimit)
{
std::this_thread::sleep_until(m_BeginFrame + invFpsLimit);
m_DeltaTime = invFpsLimit;
}
else
{
m_DeltaTime = m_WorkTime;
}
m_BeginFrame = std::chrono::system_clock::now();
TRACE(" %f %u %u %u",
((float)1e9 / (float)(m_WaitTime.count() + m_WorkTime.count())),
m_WorkTime.count(),
m_WaitTime.count(),
invFpsLimit.count());
// think and opengl stuff...
}
我试图用这段代码限制 fps,但 Fraps 显示大约 56-57 值
58.848454 3175500 13817300 16666666
55.259304 3314200 14782300 16666666
58.923698 2321700 14649400 16666666
56.200928 2167400 15625900 16666666
52.774071 3188200 15760500 16666666
50.600887 4899700 14862800 16666666
65.011055 2347500 13034500 16666666
54.966499 2611700 15581200 16666666
55.605911 2653400 15330300 16666666
56.476437 2386100 15320400 16666666
55.280689 2581400 15508100 16666666
56.437550 2355400 15363300 16666666
47.170700 5535900 15663700 16666666
64.713608 3039700 12413000 16666666
56.136570 2941100 14872600 16666666
53.444496 3624200 15086800 16666666
60.074493 2397500 14248500 16666666
51.737339 3777100 15551300 16666666
59.369026 3665800 13178000 16666666
59.355282 3543900 13303800 16666666
54.243759 3961000 14474300 16666666
45.764706 7823500 14027400 16666666
61.242237 6239400 10089200 16666666
73.396652 2013800 11610800 16666666
50.531849 3824000 15965500 16666666
62.895454 2796000 13103400 16666666
60.611572 2360500 14138000 16666666
56.074242 2241700 15591800 16666666
55.143208 2454800 15679800 16666666
我尝试将时钟更改为 system_clock,使用 sleep_for 而不是 sleep_untill,但没有任何效果
关于标准时钟或我看不到的工作代码,有什么我不知道的具体事情吗?
什么在偷我的 fps?
documentation of sleep_until
说:
The function also may block for longer than until after sleep_time has been reached due to scheduling or resource contention delays.
如果您确实需要精确的 fps,请使用 vSync,或将代码中的 if 块替换为以下循环,该循环在帧时间用完之前一直不执行任何操作:
while (m_WorkTime < invFpsLimit)
{
m_EndFrame = std::chrono::system_clock::now();
m_WorkTime = m_EndFrame - m_BeginFrame;
}
将 m_BeginFrame
和 m_EndFrame
更新为 invFpsLimit
而不是 system_clock::now()
可以做得更好。这可能看起来像:
#include <iostream>
#include <thread>
int fpsLimit() {return 60;}
int
main()
{
using namespace std::chrono;
using dsec = duration<double>;
auto invFpsLimit = duration_cast<system_clock::duration>(dsec{1./fpsLimit()});
auto m_BeginFrame = system_clock::now();
auto m_EndFrame = m_BeginFrame + invFpsLimit;
unsigned frame_count_per_second = 0;
auto prev_time_in_seconds = time_point_cast<seconds>(m_BeginFrame);
while (true)
{
// Do drawing work ...
// This part is just measuring if we're keeping the frame rate.
// It is not necessary to keep the frame rate.
auto time_in_seconds = time_point_cast<seconds>(system_clock::now());
++frame_count_per_second;
if (time_in_seconds > prev_time_in_seconds)
{
std::cerr << frame_count_per_second << " frames per second\n";
frame_count_per_second = 0;
prev_time_in_seconds = time_in_seconds;
}
// This part keeps the frame rate.
std::this_thread::sleep_until(m_EndFrame);
m_BeginFrame = m_EndFrame;
m_EndFrame = m_BeginFrame + invFpsLimit;
}
}
在 C++17 及更高版本中,我建议使用 round
构造 invFpsLimit
而不是 duration_cast
以获得更好的准确性:
auto invFpsLimit = round<system_clock::duration>(dsec{1./fpsLimit()});
要获得增量,您可以这样做:
unsgined deltaTime = 1000.0f / frame_count_per_fps; // In milliseconds