From ec871dd3f596a8183e37982821645ac5a5791fe0 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sun, 4 Jul 2021 16:50:19 +0200 Subject: [PATCH] Wrap tick API This avoids to use the SDL timer API directly, and will allow to handle generic ticks (possibly negative). --- app/meson.build | 1 + app/src/fps_counter.c | 19 +++++++++---------- app/src/fps_counter.h | 2 +- app/src/server.c | 4 ++-- app/src/util/thread.c | 7 ++++++- app/src/util/thread.h | 5 +++-- app/src/util/tick.c | 16 ++++++++++++++++ app/src/util/tick.h | 20 ++++++++++++++++++++ 8 files changed, 58 insertions(+), 16 deletions(-) create mode 100644 app/src/util/tick.c create mode 100644 app/src/util/tick.h diff --git a/app/meson.build b/app/meson.build index 0663c641..6c94f33e 100644 --- a/app/meson.build +++ b/app/meson.build @@ -25,6 +25,7 @@ src = [ 'src/util/process.c', 'src/util/str_util.c', 'src/util/thread.c', + 'src/util/tick.c', ] if host_machine.system() == 'windows' diff --git a/app/src/fps_counter.c b/app/src/fps_counter.c index bbf71887..4fad6550 100644 --- a/app/src/fps_counter.c +++ b/app/src/fps_counter.c @@ -1,11 +1,10 @@ #include "fps_counter.h" #include -#include #include "util/log.h" -#define FPS_COUNTER_INTERVAL_MS 1000 +#define FPS_COUNTER_INTERVAL SC_TICK_FROM_SEC(1) bool fps_counter_init(struct fps_counter *counter) { @@ -47,7 +46,7 @@ set_started(struct fps_counter *counter, bool started) { static void display_fps(struct fps_counter *counter) { unsigned rendered_per_second = - counter->nr_rendered * 1000 / FPS_COUNTER_INTERVAL_MS; + counter->nr_rendered * SC_TICK_FREQ / FPS_COUNTER_INTERVAL; if (counter->nr_skipped) { LOGI("%u fps (+%u frames skipped)", rendered_per_second, counter->nr_skipped); @@ -68,8 +67,8 @@ check_interval_expired(struct fps_counter *counter, uint32_t now) { counter->nr_skipped = 0; // add a multiple of the interval uint32_t elapsed_slices = - (now - counter->next_timestamp) / FPS_COUNTER_INTERVAL_MS + 1; - counter->next_timestamp += FPS_COUNTER_INTERVAL_MS * elapsed_slices; + (now - counter->next_timestamp) / FPS_COUNTER_INTERVAL + 1; + counter->next_timestamp += FPS_COUNTER_INTERVAL * elapsed_slices; } static int @@ -82,11 +81,11 @@ run_fps_counter(void *data) { sc_cond_wait(&counter->state_cond, &counter->mutex); } while (!counter->interrupted && is_started(counter)) { - uint32_t now = SDL_GetTicks(); + sc_tick now = sc_tick_now(); check_interval_expired(counter, now); assert(counter->next_timestamp > now); - uint32_t remaining = counter->next_timestamp - now; + sc_tick remaining = counter->next_timestamp - now; // ignore the reason (timeout or signaled), we just loop anyway sc_cond_timedwait(&counter->state_cond, &counter->mutex, remaining); @@ -99,7 +98,7 @@ run_fps_counter(void *data) { bool fps_counter_start(struct fps_counter *counter) { sc_mutex_lock(&counter->mutex); - counter->next_timestamp = SDL_GetTicks() + FPS_COUNTER_INTERVAL_MS; + counter->next_timestamp = sc_tick_now() + FPS_COUNTER_INTERVAL; counter->nr_rendered = 0; counter->nr_skipped = 0; sc_mutex_unlock(&counter->mutex); @@ -165,7 +164,7 @@ fps_counter_add_rendered_frame(struct fps_counter *counter) { } sc_mutex_lock(&counter->mutex); - uint32_t now = SDL_GetTicks(); + sc_tick now = sc_tick_now(); check_interval_expired(counter, now); ++counter->nr_rendered; sc_mutex_unlock(&counter->mutex); @@ -178,7 +177,7 @@ fps_counter_add_skipped_frame(struct fps_counter *counter) { } sc_mutex_lock(&counter->mutex); - uint32_t now = SDL_GetTicks(); + sc_tick now = sc_tick_now(); check_interval_expired(counter, now); ++counter->nr_skipped; sc_mutex_unlock(&counter->mutex); diff --git a/app/src/fps_counter.h b/app/src/fps_counter.h index de252586..9609c814 100644 --- a/app/src/fps_counter.h +++ b/app/src/fps_counter.h @@ -24,7 +24,7 @@ struct fps_counter { bool interrupted; unsigned nr_rendered; unsigned nr_skipped; - uint32_t next_timestamp; + sc_tick next_timestamp; }; bool diff --git a/app/src/server.c b/app/src/server.c index a4cdb0c9..ca609e25 100644 --- a/app/src/server.c +++ b/app/src/server.c @@ -554,10 +554,10 @@ server_stop(struct server *server) { sc_mutex_lock(&server->mutex); bool signaled = false; if (!server->process_terminated) { -#define WATCHDOG_DELAY_MS 1000 +#define WATCHDOG_DELAY SC_TICK_FROM_SEC(1) signaled = sc_cond_timedwait(&server->process_terminated_cond, &server->mutex, - WATCHDOG_DELAY_MS); + WATCHDOG_DELAY); } sc_mutex_unlock(&server->mutex); diff --git a/app/src/util/thread.c b/app/src/util/thread.c index de05365d..07b1f6a6 100644 --- a/app/src/util/thread.c +++ b/app/src/util/thread.c @@ -123,7 +123,12 @@ sc_cond_wait(sc_cond *cond, sc_mutex *mutex) { } bool -sc_cond_timedwait(sc_cond *cond, sc_mutex *mutex, uint32_t ms) { +sc_cond_timedwait(sc_cond *cond, sc_mutex *mutex, sc_tick delay) { + if (delay < 0) { + return false; // timeout + } + + uint32_t ms = SC_TICK_TO_MS(delay); int r = SDL_CondWaitTimeout(cond->cond, mutex->mutex, ms); #ifndef NDEBUG if (r < 0) { diff --git a/app/src/util/thread.h b/app/src/util/thread.h index dd3a630e..a59c09a1 100644 --- a/app/src/util/thread.h +++ b/app/src/util/thread.h @@ -5,7 +5,8 @@ #include #include -#include + +#include "tick.h" /* Forward declarations */ typedef struct SDL_Thread SDL_Thread; @@ -72,7 +73,7 @@ sc_cond_wait(sc_cond *cond, sc_mutex *mutex); // return true on signaled, false on timeout bool -sc_cond_timedwait(sc_cond *cond, sc_mutex *mutex, uint32_t ms); +sc_cond_timedwait(sc_cond *cond, sc_mutex *mutex, sc_tick ms); void sc_cond_signal(sc_cond *cond); diff --git a/app/src/util/tick.c b/app/src/util/tick.c new file mode 100644 index 00000000..b85ce971 --- /dev/null +++ b/app/src/util/tick.c @@ -0,0 +1,16 @@ +#include "tick.h" + +#include + +sc_tick +sc_tick_now(void) { + // SDL_GetTicks() resolution is in milliseconds, but sc_tick are expressed + // in microseconds to store PTS without precision loss. + // + // As an alternative, SDL_GetPerformanceCounter() and + // SDL_GetPerformanceFrequency() could be used, but: + // - the conversions (avoiding overflow) are expansive, since the + // frequency is not known at compile time; + // - in practice, we don't need more precision for now. + return (sc_tick) SDL_GetTicks() * 1000; +} diff --git a/app/src/util/tick.h b/app/src/util/tick.h new file mode 100644 index 00000000..a7494458 --- /dev/null +++ b/app/src/util/tick.h @@ -0,0 +1,20 @@ +#ifndef SC_TICK_H +#define SC_TICK_H + +#include + +typedef int64_t sc_tick; +#define SC_TICK_FREQ 1000000 // microsecond + +// To be adapted if SC_TICK_FREQ changes +#define SC_TICK_TO_US(tick) (tick) +#define SC_TICK_TO_MS(tick) ((tick) / 1000) +#define SC_TICK_TO_SEC(tick) ((tick) / 1000000) +#define SC_TICK_FROM_US(us) (us) +#define SC_TICK_FROM_MS(ms) ((ms) * 1000) +#define SC_TICK_FROM_SEC(sec) ((sec) * 1000000) + +sc_tick +sc_tick_now(void); + +#endif