Skip to content

Commit

Permalink
frame rate limiter
Browse files Browse the repository at this point in the history
  • Loading branch information
beaumanvienna committed Oct 13, 2024
1 parent 2038197 commit 0040106
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 29 deletions.
3 changes: 2 additions & 1 deletion engine/core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,10 @@ namespace GfxRenderEngine
}
m_EventQueue.clear();
}
m_StartTime = GetTime();
}

void Engine::OnRender() { m_GraphicsContext->SwapBuffers(); }
void Engine::PostRender() { m_GraphicsContext->LimitFrameRate(m_StartTime); }

void Engine::SignalHandler(int signal)
{
Expand Down
5 changes: 3 additions & 2 deletions engine/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ namespace GfxRenderEngine
bool Start();
void WaitInitialized();
void OnUpdate();
void OnRender();
void OnEvent(Event& event);
void PostRender();
void QueueEvent(std::unique_ptr<Event>& event);
void Shutdown(bool switchOffComputer = false);
void Quit();
Expand Down Expand Up @@ -141,7 +141,8 @@ namespace GfxRenderEngine
LayerStack m_LayerStack;

Timestep m_Timestep;
std::chrono::time_point<std::chrono::high_resolution_clock> m_TimeLastFrame;
Chrono::TimePoint m_TimeLastFrame;
Chrono::TimePoint m_StartTime;

bool m_Running, m_Paused, m_GraphicsContextInitialized;
std::vector<std::unique_ptr<Event>> m_EventQueue;
Expand Down
4 changes: 2 additions & 2 deletions engine/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ int engine(int argc, char* argv[])
engine->RunScripts(application.get());
}
{
ZoneScopedN("engine->OnRender()");
engine->OnRender();
ZoneScopedN("engine->PostRender()");
engine->PostRender();
}
}
else
Expand Down
25 changes: 6 additions & 19 deletions engine/platform/Vulkan/VKgraphicsContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
namespace GfxRenderEngine
{
VK_Context::VK_Context(VK_Window* window, ThreadPool& threadPoolPrimary, ThreadPool& threadPoolSecondary)
: m_Window{window}, m_FrameDuration{16.667ms}, m_VSyncIsWorking{10}, m_Initialized{false}
: m_Window{window}, m_Initialized{false}
{
// create a device
m_Device = std::make_unique<VK_Device>(window, threadPoolPrimary, threadPoolSecondary);
Expand All @@ -55,30 +55,17 @@ namespace GfxRenderEngine

void VK_Context::SetVSync(int interval) {}

void VK_Context::SwapBuffers()
void VK_Context::LimitFrameRate(Chrono::TimePoint startTime)
{
ZoneScopedN("SwapBuffers");
ZoneScopedN("LimitFrameRate");
#ifndef MACOSX
auto diffTime = Engine::m_Engine->GetTime() - m_StartTime;
auto sleepTime = m_FrameDuration - diffTime - 150us;
if (sleepTime < 0s)
sleepTime = 0s;
auto diffTime = Engine::m_Engine->GetTime() - startTime;
auto sleepTime = m_MinFrameDuration - diffTime;

// here ends the frame
if (m_VSyncIsWorking)
{
if (diffTime < (m_FrameDuration / 2))
{
// time difference too short
m_VSyncIsWorking--;
}
}
else
if (sleepTime > 0s)
{
std::this_thread::sleep_for(sleepTime);
}
// here starts the new frame
m_StartTime = Engine::m_Engine->GetTime();
#else
std::this_thread::sleep_for(10ms);
auto oldStartTime = m_StartTime;
Expand Down
15 changes: 11 additions & 4 deletions engine/platform/Vulkan/VKgraphicsContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ namespace GfxRenderEngine

virtual bool Init() override;
virtual void SetVSync(int interval) override;
virtual void SwapBuffers() override;
virtual void LimitFrameRate(Chrono::TimePoint) override;
virtual bool IsInitialized() const override { return m_Initialized; }

virtual Renderer* GetRenderer() const override { return m_Renderer.get(); }
Expand All @@ -68,8 +68,15 @@ namespace GfxRenderEngine
std::unique_ptr<VK_Device> m_Device;
std::unique_ptr<VK_Renderer> m_Renderer;

std::chrono::time_point<std::chrono::high_resolution_clock> m_StartTime;
std::chrono::duration<float, std::chrono::seconds::period> m_FrameDuration;
int m_VSyncIsWorking;
Chrono::TimePoint m_StartTime;

// *** m_MinFrameDuration ***
// The main thread must use at least m_MinFrameDuration of CPU time.
// If the app is using less, LimitFrameRate() pads the remainder via sleep().
// Without the frame limiter, vkQueuesubmit() would pad the remainder,
// and we don't want that:
// vkQueuesubmit() is blocking the acces mutex and thus background operations
// on the queue (such as resource loading) are blocked as well.
Chrono::Duration m_MinFrameDuration{16.0ms};
};
} // namespace GfxRenderEngine
8 changes: 8 additions & 0 deletions engine/platform/Vulkan/VKswapChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,14 @@ namespace GfxRenderEngine

VkPresentModeKHR VK_SwapChain::ChooseSwapPresentMode(const std::vector<VkPresentModeKHR>& availablePresentModes)
{
for (auto& presentMode : availablePresentModes)
{
if (presentMode == VK_PRESENT_MODE_FIFO_RELAXED_KHR)
{
return presentMode;
}
}
// guaranteed to be supported
return VK_PRESENT_MODE_FIFO_KHR;
}

Expand Down
8 changes: 7 additions & 1 deletion engine/renderer/graphicsContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@

namespace GfxRenderEngine
{
namespace Chrono
{
using TimePoint = std::chrono::time_point<std::chrono::high_resolution_clock>;
using Duration = std::chrono::duration<float, std::chrono::seconds::period>;
} // namespace Chrono

class GraphicsContext
{

Expand All @@ -47,7 +53,7 @@ namespace GfxRenderEngine

virtual bool Init() = 0;
virtual void SetVSync(int interval) = 0;
virtual void SwapBuffers() = 0;
virtual void LimitFrameRate(Chrono::TimePoint) = 0;
virtual bool IsInitialized() const = 0;

virtual Renderer* GetRenderer() const = 0;
Expand Down

0 comments on commit 0040106

Please sign in to comment.