Play-/Source/FrameLimiter.cpp

94 lines
2.1 KiB
C++
Raw Normal View History

#include "FrameLimiter.h"
2021-02-24 12:53:04 -05:00
#include <cassert>
#include <thread>
#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++)
{
m_frameTimes[i] = std::chrono::microseconds(0);
}
}
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
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
if(averageFrameTime < m_minFrameDuration)
{
auto delay = m_minFrameDuration - averageFrameTime;
#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)
{
std::this_thread::sleep_for(std::chrono::microseconds(250));
2021-12-16 11:23:04 -05:00
currentTime = std::chrono::high_resolution_clock::now();
}
#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);
}
}