2021-02-18 13:18:41 -05:00
|
|
|
#include "FrameLimiter.h"
|
2021-02-24 12:53:04 -05:00
|
|
|
#include <cassert>
|
|
|
|
#include <thread>
|
2021-02-18 13:18:41 -05:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
#include <Windows.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
CFrameLimiter::CFrameLimiter()
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
timeBeginPeriod(1);
|
|
|
|
#endif
|
2021-12-16 13:24:47 -05:00
|
|
|
for(uint32 i = 0; i < MAX_FRAMETIMES; i++)
|
2021-12-15 17:28:48 -05:00
|
|
|
{
|
|
|
|
m_frameTimes[i] = std::chrono::microseconds(0);
|
|
|
|
}
|
2021-02-18 13:18:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
CFrameLimiter::~CFrameLimiter()
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
timeEndPeriod(1);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void CFrameLimiter::BeginFrame()
|
|
|
|
{
|
|
|
|
assert(!m_frameStarted);
|
|
|
|
m_lastFrameTime = std::chrono::high_resolution_clock::now();
|
|
|
|
m_frameStarted = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CFrameLimiter::EndFrame()
|
|
|
|
{
|
|
|
|
assert(m_frameStarted);
|
2021-12-16 11:23:04 -05:00
|
|
|
|
|
|
|
//Add current frame time to array
|
|
|
|
{
|
|
|
|
auto currentFrameTime = std::chrono::high_resolution_clock::now();
|
|
|
|
auto frameDuration = std::chrono::duration_cast<std::chrono::microseconds>(currentFrameTime - m_lastFrameTime);
|
|
|
|
m_frameTimes[m_frameTimeIndex++] = frameDuration;
|
|
|
|
m_frameTimeIndex %= MAX_FRAMETIMES;
|
|
|
|
}
|
2021-12-16 13:24:47 -05:00
|
|
|
|
2021-12-16 11:23:04 -05:00
|
|
|
//Compute average frame time
|
2021-12-15 17:28:48 -05:00
|
|
|
std::chrono::microseconds averageFrameTime = std::chrono::microseconds(0);
|
|
|
|
for(uint32 i = 0; i < MAX_FRAMETIMES; i++)
|
|
|
|
{
|
|
|
|
averageFrameTime += m_frameTimes[i];
|
|
|
|
}
|
|
|
|
averageFrameTime /= MAX_FRAMETIMES;
|
2021-12-16 11:23:04 -05:00
|
|
|
|
2021-12-15 17:28:48 -05:00
|
|
|
if(averageFrameTime < m_minFrameDuration)
|
2021-02-18 13:18:41 -05:00
|
|
|
{
|
2021-12-15 17:28:48 -05:00
|
|
|
auto delay = m_minFrameDuration - averageFrameTime;
|
2021-02-18 13:18:41 -05:00
|
|
|
#ifdef _WIN32
|
|
|
|
{
|
|
|
|
LARGE_INTEGER ft = {};
|
|
|
|
ft.QuadPart = -static_cast<int64>(delay.count() * 10);
|
|
|
|
|
|
|
|
HANDLE timer = CreateWaitableTimer(NULL, TRUE, NULL);
|
|
|
|
SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
|
|
|
|
WaitForSingleObject(timer, INFINITE);
|
|
|
|
CloseHandle(timer);
|
|
|
|
}
|
2025-02-10 11:37:50 -05:00
|
|
|
#elif defined(__APPLE__) || defined(__EMSCRIPTEN__)
|
|
|
|
//Sleeping for the whole delay on some platforms doesn't provide a good enough resolution
|
2021-12-16 11:23:04 -05:00
|
|
|
auto currentTime = std::chrono::high_resolution_clock::now();
|
|
|
|
auto targetTime = currentTime + delay;
|
|
|
|
while(currentTime < targetTime)
|
2021-02-25 15:34:32 -05:00
|
|
|
{
|
|
|
|
std::this_thread::sleep_for(std::chrono::microseconds(250));
|
2021-12-16 11:23:04 -05:00
|
|
|
currentTime = std::chrono::high_resolution_clock::now();
|
2021-02-25 15:34:32 -05:00
|
|
|
}
|
2021-02-18 13:18:41 -05:00
|
|
|
#else
|
|
|
|
std::this_thread::sleep_for(delay);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
m_frameStarted = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CFrameLimiter::SetFrameRate(uint32 fps)
|
|
|
|
{
|
|
|
|
if(fps == 0)
|
|
|
|
{
|
|
|
|
m_minFrameDuration = std::chrono::microseconds(0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_minFrameDuration = std::chrono::microseconds(1000000 / fps);
|
|
|
|
}
|
|
|
|
}
|