From 33bf668697ecb3ac7223936d3b2d481e020713f8 Mon Sep 17 00:00:00 2001
From: Geoffrey McRae <geoff@hostfission.com>
Date: Mon, 19 Jul 2021 10:58:40 +1000
Subject: [PATCH] [client] app: correct FPS to use an actual per second value

---
 client/src/app.c  |  9 +++-----
 client/src/main.c | 54 ++++++++++++++++++++++++++++++++---------------
 client/src/main.h |  6 ++++--
 3 files changed, 44 insertions(+), 25 deletions(-)

diff --git a/client/src/app.c b/client/src/app.c
index e5d158cf..0860a6bd 100644
--- a/client/src/app.c
+++ b/client/src/app.c
@@ -691,12 +691,9 @@ bool app_renderImGui(void)
       ImGuiWindowFlags_NoNav           | ImGuiWindowFlags_NoTitleBar
     );
 
-    const float fps = 1000.0f / (g_state.renderTimeTotal /
-      ringbuffer_getCount(g_state.renderTimings));
-    const float ups = 1000.0f / (g_state.frameTimeTotal  /
-      ringbuffer_getCount(g_state.frameTimings));
-
-    igText("FPS:%4.2f UPS:%4.2f", fps, ups);
+    igText("FPS:%4.2f UPS:%4.2f",
+        atomic_load_explicit(&g_state.fps, memory_order_relaxed),
+        atomic_load_explicit(&g_state.ups, memory_order_relaxed));
 
     igEnd();
   }
diff --git a/client/src/main.c b/client/src/main.c
index a94e1d4d..8c6b2f9f 100644
--- a/client/src/main.c
+++ b/client/src/main.c
@@ -95,6 +95,26 @@ static void lgInit(void)
     g_state.ds->showPointer(true);
 }
 
+static bool fpsTimerFn(void * unused)
+{
+  const float renderTime =
+    (float)atomic_exchange_explicit(&g_state.renderTime, 0,
+        memory_order_acquire);
+
+  const float fps = 1e9f / (renderTime /
+    (float)atomic_exchange_explicit(&g_state.renderCount, 0,
+      memory_order_acquire));
+
+  const float ups = 1e9f / (renderTime /
+    (float)atomic_exchange_explicit(&g_state.frameCount, 0,
+      memory_order_acquire));
+
+  atomic_store_explicit(&g_state.fps, fps, memory_order_relaxed);
+  atomic_store_explicit(&g_state.ups, ups, memory_order_relaxed);
+
+  return true;
+}
+
 static int renderThread(void * unused)
 {
   if (!g_state.lgr->render_startup(g_state.lgrData))
@@ -106,6 +126,14 @@ static int renderThread(void * unused)
     return 1;
   }
 
+  /* start up the fps timer */
+  LGTimer * fpsTimer;
+  if (!lgCreateTimer(1000, fpsTimerFn, NULL, &fpsTimer))
+  {
+    DEBUG_ERROR("Failed to create the fps timer");
+    return 1;
+  }
+
   LG_LOCK_INIT(g_state.lgrLock);
 
   /* signal to other threads that the renderer is ready */
@@ -147,15 +175,17 @@ static int renderThread(void * unused)
     }
     LG_UNLOCK(g_state.lgrLock);
 
-    const uint64_t t      = nanotime();
-    const uint64_t delta  = t - g_state.lastRenderTime;
+    const uint64_t t     = nanotime();
+    const uint64_t delta = t - g_state.lastRenderTime;
+
     g_state.lastRenderTime = t;
+    atomic_fetch_add_explicit(&g_state.renderTime , delta, memory_order_relaxed);
+    atomic_fetch_add_explicit(&g_state.renderCount, 1    , memory_order_relaxed);
 
     if (g_state.lastRenderTimeValid)
     {
-      const float fdelta = (float)delta / 1000000.0f;
+      const float fdelta = (float)delta / 1e6f;
       ringbuffer_push(g_state.renderTimings, &fdelta);
-      g_state.renderTimeTotal += fdelta;
     }
     g_state.lastRenderTimeValid = true;
 
@@ -177,6 +207,8 @@ static int renderThread(void * unused)
 
   g_state.state = APP_STATE_SHUTDOWN;
 
+  lgTimerDestroy(fpsTimer);
+
   if (t_cursor)
     lgJoinThread(t_cursor, NULL);
 
@@ -591,10 +623,10 @@ int main_frameThread(void * unused)
     {
       const float fdelta = (float)delta / 1000000.0f;
       ringbuffer_push(g_state.frameTimings, &fdelta);
-      g_state.frameTimeTotal += fdelta;
     }
     g_state.lastFrameTimeValid = true;
 
+    atomic_fetch_add_explicit(&g_state.frameCount, 1, memory_order_relaxed);
     lgSignalEvent(e_frame);
     lgmpClientMessageDone(queue);
   }
@@ -679,13 +711,6 @@ static bool tryRenderer(const int index, const LG_RendererParams lgrParams,
   return true;
 }
 
-static void rbSubtractFloat(void * value_, void * udata_)
-{
-  float * value = (float *)value_;
-  float * udata = (float *)udata_;
-  *udata -= *value;
-}
-
 static int lg_run(void)
 {
   memset(&g_state, 0, sizeof(g_state));
@@ -710,11 +735,6 @@ static int lg_run(void)
   g_state.renderTimings = ringbuffer_new(256, sizeof(float));
   g_state.frameTimings  = ringbuffer_new(256, sizeof(float));
 
-  ringbuffer_setPreOverwriteFn(g_state.renderTimings, rbSubtractFloat,
-      &g_state.renderTimeTotal);
-  ringbuffer_setPreOverwriteFn(g_state.frameTimings , rbSubtractFloat,
-      &g_state.frameTimeTotal);
-
   app_registerGraph("RENDER", g_state.renderTimings);
   app_registerGraph("UPLOAD", g_state.frameTimings);
 
diff --git a/client/src/main.h b/client/src/main.h
index fe5a4f4c..7513cf1e 100644
--- a/client/src/main.h
+++ b/client/src/main.h
@@ -103,8 +103,10 @@ struct AppState
   bool                  lastRenderTimeValid;
   RingBuffer            renderTimings;
   RingBuffer            frameTimings;
-  float                 renderTimeTotal;
-  float                 frameTimeTotal;
+
+  atomic_uint_least64_t renderTime;
+  atomic_uint_least64_t renderCount, frameCount;
+  _Atomic(float)        fps, ups;
 
   uint64_t resizeTimeout;
   bool     resizeDone;