2023-02-23 17:00:06 +00:00
|
|
|
#include "std_chrono_throttle.hpp"
|
|
|
|
#include <thread>
|
|
|
|
|
|
|
|
using namespace std::chrono;
|
|
|
|
|
|
|
|
void Throttle::set_frame_rate(double frame_rate)
|
|
|
|
{
|
|
|
|
max_frame_rate = frame_rate;
|
|
|
|
frame_duration = 1.0 / max_frame_rate;
|
|
|
|
frame_duration_us = microseconds(int64_t(frame_duration * 1000000.0));
|
|
|
|
}
|
|
|
|
|
|
|
|
microseconds Throttle::remaining()
|
|
|
|
{
|
|
|
|
auto now = time_point_cast<microseconds>(steady_clock::now());
|
|
|
|
auto diff = (now - then);
|
|
|
|
return frame_duration_us - diff;
|
|
|
|
}
|
|
|
|
|
2023-07-07 18:38:58 +00:00
|
|
|
#if defined(_WIN32)
|
2023-07-06 19:53:07 +00:00
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
|
|
#include <windows.h>
|
2023-07-07 18:38:58 +00:00
|
|
|
void Throttle::wait_for_frame()
|
2023-02-23 21:24:01 +00:00
|
|
|
{
|
2023-07-07 18:38:58 +00:00
|
|
|
static HANDLE timer = nullptr;
|
2023-07-06 19:53:07 +00:00
|
|
|
|
|
|
|
if (timer == nullptr)
|
|
|
|
timer = CreateWaitableTimer(nullptr, true, nullptr);
|
|
|
|
|
2023-02-23 21:24:01 +00:00
|
|
|
auto time_to_wait = remaining();
|
|
|
|
|
|
|
|
if (time_to_wait < -frame_duration_us / 10)
|
2023-07-07 18:49:10 +00:00
|
|
|
{
|
2023-02-23 21:24:01 +00:00
|
|
|
reset();
|
2023-07-07 18:49:10 +00:00
|
|
|
return;
|
|
|
|
}
|
2023-02-23 21:24:01 +00:00
|
|
|
|
2023-07-07 18:38:58 +00:00
|
|
|
if (time_to_wait.count() > 2000)
|
2023-02-23 21:24:01 +00:00
|
|
|
{
|
2023-07-06 19:53:07 +00:00
|
|
|
LARGE_INTEGER li;
|
2023-07-07 18:38:58 +00:00
|
|
|
li.QuadPart = -(time_to_wait.count() - 2000) * 10;
|
|
|
|
SetWaitableTimer(timer, &li, 0, nullptr, nullptr, false);
|
|
|
|
WaitForSingleObject(timer, INFINITE);
|
|
|
|
}
|
|
|
|
|
|
|
|
time_to_wait = remaining();
|
|
|
|
while (time_to_wait.count() > 0)
|
|
|
|
{
|
|
|
|
std::this_thread::yield();
|
|
|
|
time_to_wait = remaining();
|
2023-02-23 21:24:01 +00:00
|
|
|
}
|
2023-07-07 18:38:58 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !defined(_WIN32)
|
|
|
|
void Throttle::wait_for_frame()
|
|
|
|
{
|
|
|
|
auto time_to_wait = remaining();
|
|
|
|
|
|
|
|
if (time_to_wait < -frame_duration_us / 10)
|
2023-07-07 18:49:10 +00:00
|
|
|
{
|
2023-07-07 18:38:58 +00:00
|
|
|
reset();
|
2023-07-07 18:49:10 +00:00
|
|
|
return;
|
|
|
|
}
|
2023-07-07 18:38:58 +00:00
|
|
|
|
|
|
|
if (time_to_wait.count() > 1000)
|
|
|
|
std::this_thread::sleep_for(time_to_wait - 1ms);
|
2023-07-06 19:53:07 +00:00
|
|
|
|
|
|
|
time_to_wait = remaining();
|
|
|
|
while (time_to_wait.count() > 0)
|
|
|
|
{
|
|
|
|
std::this_thread::yield();
|
|
|
|
time_to_wait = remaining();
|
|
|
|
}
|
2023-07-07 18:38:58 +00:00
|
|
|
}
|
|
|
|
#endif
|
2023-07-06 19:53:07 +00:00
|
|
|
|
2023-07-07 18:38:58 +00:00
|
|
|
void Throttle::wait_for_frame_and_rebase_time()
|
|
|
|
{
|
|
|
|
wait_for_frame();
|
2023-07-06 19:53:07 +00:00
|
|
|
advance();
|
2023-02-23 21:24:01 +00:00
|
|
|
}
|
|
|
|
|
2023-02-23 17:00:06 +00:00
|
|
|
void Throttle::advance()
|
|
|
|
{
|
|
|
|
then += frame_duration_us;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Throttle::reset()
|
|
|
|
{
|
|
|
|
auto now = time_point_cast<microseconds>(steady_clock::now());
|
|
|
|
then = now;
|
|
|
|
}
|