Convert ticks to 64-bit, added nanosecond precision to the API

Fixes https://github.com/libsdl-org/SDL/issues/5512
Fixes https://github.com/libsdl-org/SDL/issues/6731
This commit is contained in:
Sam Lantinga
2022-12-02 01:17:17 -08:00
parent 764b899a13
commit 8121bbd083
96 changed files with 938 additions and 1243 deletions

View File

@@ -61,76 +61,34 @@
#endif
/* The first ticks value of the application */
#if HAVE_CLOCK_GETTIME
static struct timespec start_ts;
#elif defined(__APPLE__)
static uint64_t start_mach;
#if !defined(HAVE_CLOCK_GETTIME) && defined(__APPLE__)
mach_timebase_info_data_t mach_base_info;
#endif
static SDL_bool checked_monotonic_time = SDL_FALSE;
static SDL_bool has_monotonic_time = SDL_FALSE;
static struct timeval start_tv;
static SDL_bool ticks_started = SDL_FALSE;
void SDL_TicksInit(void)
static void CheckMonotonicTime(void)
{
if (ticks_started) {
return;
}
ticks_started = SDL_TRUE;
/* Set first ticks value */
#if HAVE_CLOCK_GETTIME
if (clock_gettime(SDL_MONOTONIC_CLOCK, &start_ts) == 0) {
struct timespec value;
if (clock_gettime(SDL_MONOTONIC_CLOCK, &value) == 0) {
has_monotonic_time = SDL_TRUE;
} else
#elif defined(__APPLE__)
if (mach_timebase_info(&mach_base_info) == 0) {
has_monotonic_time = SDL_TRUE;
start_mach = mach_absolute_time();
} else
}
#endif
{
gettimeofday(&start_tv, NULL);
}
}
void SDL_TicksQuit(void)
{
ticks_started = SDL_FALSE;
}
Uint64
SDL_GetTicks64(void)
{
if (!ticks_started) {
SDL_TicksInit();
}
if (has_monotonic_time) {
#if HAVE_CLOCK_GETTIME
struct timespec now;
clock_gettime(SDL_MONOTONIC_CLOCK, &now);
return (Uint64)(((Sint64)(now.tv_sec - start_ts.tv_sec) * 1000) + ((now.tv_nsec - start_ts.tv_nsec) / 1000000));
#elif defined(__APPLE__)
const uint64_t now = mach_absolute_time();
return (((now - start_mach) * mach_base_info.numer) / mach_base_info.denom) / 1000000;
#else
SDL_assert(SDL_FALSE);
return 0;
#endif
} else {
struct timeval now;
gettimeofday(&now, NULL);
return (Uint64)(((Sint64)(now.tv_sec - start_tv.tv_sec) * 1000) + ((now.tv_usec - start_tv.tv_usec) / 1000));
}
checked_monotonic_time = SDL_TRUE;
}
Uint64
SDL_GetPerformanceCounter(void)
{
Uint64 ticks;
if (!ticks_started) {
SDL_TicksInit();
if (!checked_monotonic_time) {
CheckMonotonicTime();
}
if (has_monotonic_time) {
@@ -139,7 +97,7 @@ SDL_GetPerformanceCounter(void)
clock_gettime(SDL_MONOTONIC_CLOCK, &now);
ticks = now.tv_sec;
ticks *= 1000000000;
ticks *= SDL_NS_PER_SECOND;
ticks += now.tv_nsec;
#elif defined(__APPLE__)
ticks = mach_absolute_time();
@@ -152,7 +110,7 @@ SDL_GetPerformanceCounter(void)
gettimeofday(&now, NULL);
ticks = now.tv_sec;
ticks *= 1000000;
ticks *= SDL_US_PER_SECOND;
ticks += now.tv_usec;
}
return ticks;
@@ -161,30 +119,30 @@ SDL_GetPerformanceCounter(void)
Uint64
SDL_GetPerformanceFrequency(void)
{
if (!ticks_started) {
SDL_TicksInit();
if (!checked_monotonic_time) {
CheckMonotonicTime();
}
if (has_monotonic_time) {
#if HAVE_CLOCK_GETTIME
return 1000000000;
return SDL_NS_PER_SECOND;
#elif defined(__APPLE__)
Uint64 freq = mach_base_info.denom;
freq *= 1000000000;
freq *= SDL_NS_PER_SECOND;
freq /= mach_base_info.numer;
return freq;
#endif
}
return 1000000;
return SDL_US_PER_SECOND;
}
void SDL_Delay(Uint32 ms)
void SDL_DelayNS(Uint64 ns)
{
int was_error;
#if HAVE_NANOSLEEP
struct timespec elapsed, tv;
struct timespec tv, remaining;
#else
struct timeval tv;
Uint64 then, now, elapsed;
@@ -193,36 +151,36 @@ void SDL_Delay(Uint32 ms)
#ifdef __EMSCRIPTEN__
if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, SDL_TRUE)) {
/* pseudo-synchronous pause, used directly or through e.g. SDL_WaitEvent */
emscripten_sleep(ms);
emscripten_sleep(ns / SDL_NS_PER_MS);
return;
}
#endif
/* Set the timeout interval */
#if HAVE_NANOSLEEP
elapsed.tv_sec = ms / 1000;
elapsed.tv_nsec = (ms % 1000) * 1000000;
remaining.tv_sec = (ns / SDL_NS_PER_SECOND);
remaining.tv_nsec = (ns % SDL_NS_PER_SECOND);
#else
then = SDL_GetTicks64();
then = SDL_GetTicksNS();
#endif
do {
errno = 0;
#if HAVE_NANOSLEEP
tv.tv_sec = elapsed.tv_sec;
tv.tv_nsec = elapsed.tv_nsec;
was_error = nanosleep(&tv, &elapsed);
tv.tv_sec = remaining.tv_sec;
tv.tv_nsec = remaining.tv_nsec;
was_error = nanosleep(&tv, &remaining);
#else
/* Calculate the time interval left (in case of interrupt) */
now = SDL_GetTicks64();
now = SDL_GetTicksNS();
elapsed = (now - then);
then = now;
if (elapsed >= ((Uint64)ms)) {
if (elapsed >= ns) {
break;
}
ms -= (Uint32)elapsed;
tv.tv_sec = ms / 1000;
tv.tv_usec = (ms % 1000) * 1000;
ns -= elapsed;
tv.tv_sec = (ns / SDL_NS_PER_SECOND)
tv.tv_usec = SDL_NS_TO_US(ns % SDL_NS_PER_SECOND);
was_error = select(0, NULL, NULL, NULL, &tv);
#endif /* HAVE_NANOSLEEP */