summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2024-04-09 03:29:14 +0200
committerMel <einebeere@gmail.com>2024-04-09 03:29:14 +0200
commit2ab9e650f814d47e78fc95500605b4561922893d (patch)
tree1850dcdd1e198d8ca77b2677b5f1721757e16441 /src
parent15237a469afe1fd6a6958466bae761ec68b647dc (diff)
downloadmeowcraft-2ab9e650f814d47e78fc95500605b4561922893d.tar.zst
meowcraft-2ab9e650f814d47e78fc95500605b4561922893d.zip
Add FPS limiting for render thread
Diffstat (limited to 'src')
-rw-r--r--src/Render.cpp23
-rw-r--r--src/Render.hpp2
-rw-r--r--src/Time.cpp5
-rw-r--r--src/Time.hpp7
4 files changed, 36 insertions, 1 deletions
diff --git a/src/Render.cpp b/src/Render.cpp
index 2b16ed0..caebc29 100644
--- a/src/Render.cpp
+++ b/src/Render.cpp
@@ -7,6 +7,9 @@
 #include "GFX/Image/PPMParser.hpp"
 #include "GFX/Shading/Program.hpp"
 #include "Math/MVP.hpp"
+#include <thread>
+
+#define FPS_LIMIT 30
 
 namespace MC {
 
@@ -36,12 +39,22 @@ void Render::run() {
     glFrontFace(GL_CCW);
     glCullFace(GL_BACK);
 
+    Time render_time{};
+
     while (!m_window.should_close()) {
         Scene scene = m_control->wait_for_render_data();
 
+        render_time.start_frame();
         m_window.start_render();
         render_scene(scene, texture);
+        render_time.end_frame();
 
+        wait_until_next_frame_start(render_time.delta_raw());
+
+        // This signal has to be the last thing in the loop,
+        // otherwise the logic thread could be blocked during
+        // it's `wait_for_render_finish` call.
+        // Still weird though, maybe there's a better way?
         m_control->finish_render();
     }
 }
@@ -102,4 +115,14 @@ void Render::setup_gl() {
     }
 }
 
+void Render::wait_until_next_frame_start(Real spent_time_budget) const {
+    constexpr Real total_frame_time_budget = 1.0 / FPS_LIMIT;
+    Real remaining_time_budget = total_frame_time_budget - spent_time_budget;
+
+    if (remaining_time_budget > 0) {
+        auto frame_end = Time::now() + TO(U64, remaining_time_budget * 1000);
+        while (Time::now() < frame_end) std::this_thread::yield();
+    }
+}
+
 }
diff --git a/src/Render.hpp b/src/Render.hpp
index 09c6fee..6670858 100644
--- a/src/Render.hpp
+++ b/src/Render.hpp
@@ -80,6 +80,8 @@ private:
     void render_scene(Scene const& actions, GFX::Texture const& texture) const;
     static void setup_gl();
 
+    void wait_until_next_frame_start(Real spent_time_budget) const;
+
     GFX::Resources m_resources;
     GFX::Window& m_window;
     std::shared_ptr<Control> m_control;
diff --git a/src/Time.cpp b/src/Time.cpp
index 1953fed..a9608cc 100644
--- a/src/Time.cpp
+++ b/src/Time.cpp
@@ -12,7 +12,6 @@ void Time::start_frame() {
 void Time::end_frame() {
     auto frame_end = now();
     m_delta = TO(Real, frame_end - m_current_frame_start) / 1000.0;
-    m_delta = std::clamp(m_delta, delta_min, delta_max);
 
     m_total_frames++;
 }
@@ -26,6 +25,10 @@ Time::Tick Time::tick() const {
 }
 
 Real Time::delta() const {
+    return std::clamp(m_delta, delta_min, delta_max);
+}
+
+Real Time::delta_raw() const {
     return m_delta;
 }
 
diff --git a/src/Time.hpp b/src/Time.hpp
index 64ab4a2..62e2809 100644
--- a/src/Time.hpp
+++ b/src/Time.hpp
@@ -7,8 +7,10 @@ namespace MC {
 
 class Time {
 public:
+    // TODO: Document exact units of types.
     using Timestamp = U64;
     using Tick = U64;
+    // TODO: Create `Time::Duration` type.
 
     Time() = default;
 
@@ -23,7 +25,12 @@ public:
     // This is the same as total_frames(), but is more descriptive, sometimes.
     // :)
     PURE Tick tick() const;
+    // The time in seconds that has passed since the last frame.
+    // This is always a value between `0.001` and `0.1`.
     PURE Real delta() const;
+    // The time in seconds that has passed since the last frame.
+    // Unlike `delta()`, this value is not clamped, and can be any positive value.
+    PURE Real delta_raw() const;
 
     PURE Timestamp frame_start() const;