From 682a6911735cb8f6dccd9653ce30b72f267235c6 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Mon, 6 Dec 2021 23:33:59 +0100 Subject: [PATCH] Use timers with microsecond precision SDL only provides millisecond precision. Use system timers to get a better precision. --- app/src/util/tick.c | 59 +++++++++++++++++++++++++++++++++++++-------- app/src/util/tick.h | 2 ++ 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/app/src/util/tick.c b/app/src/util/tick.c index b85ce971..cc0bab5e 100644 --- a/app/src/util/tick.c +++ b/app/src/util/tick.c @@ -1,16 +1,55 @@ #include "tick.h" -#include +#include +#include +#ifdef _WIN32 +# include +#endif 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; +#ifndef _WIN32 + // Maximum sc_tick precision (microsecond) + struct timespec ts; + int ret = clock_gettime(CLOCK_MONOTONIC, &ts); + if (ret) { + abort(); + } + + return SC_TICK_FROM_SEC(ts.tv_sec) + SC_TICK_FROM_NS(ts.tv_nsec); +#else + LARGE_INTEGER c; + + // On systems that run Windows XP or later, the function will always + // succeed and will thus never return zero. + // + // + + BOOL ok = QueryPerformanceCounter(&c); + assert(ok); + (void) ok; + + LONGLONG counter = c.QuadPart; + + static LONGLONG frequency; + if (!frequency) { + // Initialize on first call + LARGE_INTEGER f; + ok = QueryPerformanceFrequency(&f); + assert(ok); + frequency = f.QuadPart; + assert(frequency); + } + + if (frequency % SC_TICK_FREQ == 0) { + // Expected case (typically frequency = 10000000, i.e. 100ns precision) + sc_tick div = frequency / SC_TICK_FREQ; + return SC_TICK_FROM_US(counter / div); + } + + // Split the division to avoid overflow + sc_tick secs = SC_TICK_FROM_SEC(counter / frequency); + sc_tick subsec = SC_TICK_FREQ * (counter % frequency) / frequency; + return secs + subsec; +#endif } diff --git a/app/src/util/tick.h b/app/src/util/tick.h index 47d02529..2d941f23 100644 --- a/app/src/util/tick.h +++ b/app/src/util/tick.h @@ -10,9 +10,11 @@ typedef int64_t sc_tick; #define SC_TICK_FREQ 1000000 // microsecond // To be adapted if SC_TICK_FREQ changes +#define SC_TICK_TO_NS(tick) ((tick) * 1000) #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_NS(ns) ((ns) / 1000) #define SC_TICK_FROM_US(us) (us) #define SC_TICK_FROM_MS(ms) ((ms) * 1000) #define SC_TICK_FROM_SEC(sec) ((sec) * 1000000)