scrcpy/app/src/util/tick.c
Romain Vimont 682a691173 Use timers with microsecond precision
SDL only provides millisecond precision. Use system timers to get a
better precision.
2021-12-08 23:45:45 +01:00

55 lines
1.5 KiB
C

#include "tick.h"
#include <assert.h>
#include <time.h>
#ifdef _WIN32
# include <windows.h>
#endif
sc_tick
sc_tick_now(void) {
#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.
// <https://docs.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter>
// <https://docs.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancefrequency>
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
}