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

@@ -32,8 +32,8 @@ typedef struct _SDL_Timer
int timerID;
SDL_TimerCallback callback;
void *param;
Uint32 interval;
Uint32 scheduled;
Uint64 interval;
Uint64 scheduled;
SDL_atomic_t canceled;
struct _SDL_Timer *next;
} SDL_Timer;
@@ -82,7 +82,7 @@ static void SDL_AddTimerInternal(SDL_TimerData *data, SDL_Timer *timer)
prev = NULL;
for (curr = data->timers; curr; prev = curr, curr = curr->next) {
if ((Sint32)(timer->scheduled - curr->scheduled) < 0) {
if (curr->scheduled > timer->scheduled) {
break;
}
}
@@ -103,7 +103,7 @@ static int SDLCALL SDL_TimerThread(void *_data)
SDL_Timer *current;
SDL_Timer *freelist_head = NULL;
SDL_Timer *freelist_tail = NULL;
Uint32 tick, now, interval, delay;
Uint64 tick, now, interval, delay;
/* Threaded timer loop:
* 1. Queue timers added by other threads
@@ -143,13 +143,13 @@ static int SDLCALL SDL_TimerThread(void *_data)
/* Initial delay if there are no timers */
delay = SDL_MUTEX_MAXWAIT;
tick = SDL_GetTicks();
tick = SDL_GetTicksNS();
/* Process all the pending timers for this tick */
while (data->timers) {
current = data->timers;
if ((Sint32)(tick - current->scheduled) < 0) {
if (tick < current->scheduled) {
/* Scheduled for the future, wait a bit */
delay = (current->scheduled - tick);
break;
@@ -161,7 +161,8 @@ static int SDLCALL SDL_TimerThread(void *_data)
if (SDL_AtomicGet(&current->canceled)) {
interval = 0;
} else {
interval = current->callback(current->interval, current->param);
/* FIXME: We could potentially support sub-millisecond timers now */
interval = SDL_MS_TO_NS(current->callback((Uint32)SDL_NS_TO_MS(current->interval), current->param));
}
if (interval > 0) {
@@ -183,7 +184,7 @@ static int SDLCALL SDL_TimerThread(void *_data)
}
/* Adjust the delay based on processing time */
now = SDL_GetTicks();
now = SDL_GetTicksNS();
interval = (now - tick);
if (interval > delay) {
delay = 0;
@@ -196,7 +197,7 @@ static int SDLCALL SDL_TimerThread(void *_data)
That's okay, it just means we run through the loop a few
extra times.
*/
SDL_SemWaitTimeout(data->sem, delay);
SDL_SemWaitTimeoutNS(data->sem, delay);
}
return 0;
}
@@ -271,8 +272,7 @@ void SDL_TimerQuit(void)
}
}
SDL_TimerID
SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *param)
SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *param)
{
SDL_TimerData *data = &SDL_timer_data;
SDL_Timer *timer;
@@ -304,8 +304,8 @@ SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *param)
timer->timerID = SDL_AtomicIncRef(&data->nextID);
timer->callback = callback;
timer->param = param;
timer->interval = interval;
timer->scheduled = SDL_GetTicks() + interval;
timer->interval = SDL_MS_TO_NS(interval);
timer->scheduled = SDL_GetTicksNS() + timer->interval;
SDL_AtomicSet(&timer->canceled, 0);
entry = (SDL_TimerMap *)SDL_malloc(sizeof(*entry));
@@ -334,8 +334,7 @@ SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *param)
return entry->timerID;
}
SDL_bool
SDL_RemoveTimer(SDL_TimerID id)
SDL_bool SDL_RemoveTimer(SDL_TimerID id)
{
SDL_TimerData *data = &SDL_timer_data;
SDL_TimerMap *prev, *entry;
@@ -417,8 +416,7 @@ void SDL_TimerQuit(void)
}
}
SDL_TimerID
SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *param)
SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *param)
{
SDL_TimerData *data = &SDL_timer_data;
SDL_TimerMap *entry;
@@ -443,8 +441,7 @@ SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *param)
return entry->timerID;
}
SDL_bool
SDL_RemoveTimer(SDL_TimerID id)
SDL_bool SDL_RemoveTimer(SDL_TimerID id)
{
SDL_TimerData *data = &SDL_timer_data;
SDL_TimerMap *prev, *entry;
@@ -471,16 +468,94 @@ SDL_RemoveTimer(SDL_TimerID id)
return SDL_FALSE;
}
#endif /* !defined(__EMSCRIPTEN__) || !SDL_THREADS_DISABLED */
static Uint64 tick_start;
static Uint64 tick_freq;
#if defined(SDL_TIMER_WINDOWS) && \
!defined(__WINRT__) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
#include <timeapi.h>
#define HAVE_TIME_BEGIN_PERIOD
#endif
/* This is a legacy support function; SDL_GetTicks() returns a Uint32,
which wraps back to zero every ~49 days. The newer SDL_GetTicks64()
doesn't have this problem, so we just wrap that function and clamp to
the low 32-bits for binary compatibility. */
Uint32
SDL_GetTicks(void)
static void SDL_SetSystemTimerResolutionMS(int period)
{
return (Uint32)(SDL_GetTicks64() & 0xFFFFFFFF);
#ifdef HAVE_TIME_BEGIN_PERIOD
static int timer_period = 0;
if (period != timer_period) {
if (timer_period) {
timeEndPeriod((UINT)timer_period);
}
timer_period = period;
if (timer_period) {
timeBeginPeriod((UINT)timer_period);
}
}
#endif /* HAVE_TIME_BEGIN_PERIOD */
}
static void SDLCALL SDL_TimerResolutionChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
int period;
/* Unless the hint says otherwise, let's have good sleep precision */
if (hint && *hint) {
period = SDL_atoi(hint);
} else {
period = 1;
}
if (period || oldValue != hint) {
SDL_SetSystemTimerResolutionMS(period);
}
}
void SDL_TicksInit(void)
{
if (tick_start) {
return;
}
/* If we didn't set a precision, set it high. This affects lots of things
on Windows besides the SDL timers, like audio callbacks, etc. */
SDL_AddHintCallback(SDL_HINT_TIMER_RESOLUTION,
SDL_TimerResolutionChanged, NULL);
tick_freq = SDL_GetPerformanceFrequency();
tick_start = SDL_GetPerformanceCounter();
}
void SDL_TicksQuit(void)
{
SDL_DelHintCallback(SDL_HINT_TIMER_RESOLUTION,
SDL_TimerResolutionChanged, NULL);
SDL_SetSystemTimerResolutionMS(0); /* always release our timer resolution request. */
tick_start = 0;
}
Uint64
SDL_GetTicksNS(void)
{
if (!tick_start) {
SDL_TicksInit();
}
return ((SDL_GetPerformanceCounter() - tick_start) * SDL_NS_PER_SECOND) / tick_freq;
}
Uint64 SDL_GetTicks(void)
{
return SDL_NS_TO_MS(SDL_GetTicksNS());
}
void SDL_Delay(Uint32 ms)
{
SDL_DelayNS(SDL_MS_TO_NS(ms));
}
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -22,45 +22,20 @@
#if defined(SDL_TIMER_DUMMY) || defined(SDL_TIMERS_DISABLED)
static SDL_bool ticks_started = SDL_FALSE;
void SDL_TicksInit(void)
{
if (ticks_started) {
return;
}
ticks_started = SDL_TRUE;
}
void SDL_TicksQuit(void)
{
ticks_started = SDL_FALSE;
}
Uint64
SDL_GetTicks64(void)
SDL_GetPerformanceCounter(void)
{
if (!ticks_started) {
SDL_TicksInit();
}
SDL_Unsupported();
return 0;
}
Uint64
SDL_GetPerformanceCounter(void)
{
return SDL_GetTicks();
}
Uint64
SDL_GetPerformanceFrequency(void)
{
return 1000;
return 1;
}
void SDL_Delay(Uint32 ms)
void SDL_DelayNS(Uint64 ns)
{
SDL_Unsupported();
}

View File

@@ -24,34 +24,6 @@
#include <kernel/OS.h>
static bigtime_t start;
static SDL_bool ticks_started = SDL_FALSE;
void SDL_TicksInit(void)
{
if (ticks_started) {
return;
}
ticks_started = SDL_TRUE;
/* Set first ticks value */
start = system_time();
}
void SDL_TicksQuit(void)
{
ticks_started = SDL_FALSE;
}
Uint64
SDL_GetTicks64(void)
{
if (!ticks_started) {
SDL_TicksInit();
}
return (Uint64)((system_time() - start) / 1000);
}
Uint64
SDL_GetPerformanceCounter(void)
@@ -62,12 +34,12 @@ SDL_GetPerformanceCounter(void)
Uint64
SDL_GetPerformanceFrequency(void)
{
return 1000000;
return SDL_US_PER_SECOND;
}
void SDL_Delay(Uint32 ms)
void SDL_DelayNS(Uint64 ns)
{
snooze(ms * 1000);
snooze((bigtime_t)SDL_NS_TO_US(ns));
}
#endif /* SDL_TIMER_HAIKU */

View File

@@ -24,37 +24,6 @@
#include <3ds.h>
static SDL_bool ticks_started = SDL_FALSE;
static u64 start_tick;
#define NSEC_PER_MSEC 1000000ULL
void SDL_TicksInit(void)
{
if (ticks_started) {
return;
}
ticks_started = SDL_TRUE;
start_tick = svcGetSystemTick();
}
void SDL_TicksQuit(void)
{
ticks_started = SDL_FALSE;
}
Uint64
SDL_GetTicks64(void)
{
u64 elapsed;
if (!ticks_started) {
SDL_TicksInit();
}
elapsed = svcGetSystemTick() - start_tick;
return elapsed / CPU_TICKS_PER_MSEC;
}
Uint64
SDL_GetPerformanceCounter(void)
@@ -68,9 +37,9 @@ SDL_GetPerformanceFrequency(void)
return SYSCLOCK_ARM11;
}
void SDL_Delay(Uint32 ms)
void SDL_DelayNS(Uint64 ns)
{
svcSleepThread(ms * NSEC_PER_MSEC);
svcSleepThread(ns);
}
#endif /* SDL_TIMER_N3DS */

View File

@@ -25,63 +25,33 @@
#include <e32std.h>
#include <e32hal.h>
static SDL_bool ticks_started = SDL_FALSE;
static TUint start = 0;
static TInt tickPeriodMilliSeconds;
static TUint start_tick = 0;
#ifdef __cplusplus
extern "C" {
#endif
void SDL_TicksInit(void)
{
if (ticks_started) {
return;
}
ticks_started = SDL_TRUE;
start = User::TickCount();
TTimeIntervalMicroSeconds32 period;
TInt tmp = UserHal::TickPeriod(period);
(void)tmp; /* Suppress redundant warning. */
tickPeriodMilliSeconds = period.Int() / 1000;
}
void SDL_TicksQuit(void)
{
ticks_started = SDL_FALSE;
}
Uint64
SDL_GetTicks64(void)
{
if (!ticks_started) {
SDL_TicksInit();
}
TUint deltaTics = User::TickCount() - start;
// Overlaps early, but should do the trick for now.
return (Uint64)(deltaTics * tickPeriodMilliSeconds);
}
Uint64
SDL_GetPerformanceCounter(void)
{
/* FIXME: Need to account for 32-bit wrapping */
return (Uint64)User::TickCount();
}
Uint64
SDL_GetPerformanceFrequency(void)
{
return 1000000;
return SDL_US_PER_SECOND;
}
void SDL_Delay(Uint32 ms)
void SDL_DelayNS(Uint64 ns)
{
User::After(TTimeIntervalMicroSeconds32(ms * 1000));
const Uint64 max_delay = 0x7fffffff * SDL_NS_PER_US;
if (ns > max_delay) {
ns = max_delay;
}
User::After(TTimeIntervalMicroSeconds32((TInt)SDL_NS_TO_US(ns)));
}
#ifdef __cplusplus

View File

@@ -28,54 +28,24 @@
#include <timer.h>
#include <sys/time.h>
static uint64_t start;
static SDL_bool ticks_started = SDL_FALSE;
void SDL_TicksInit(void)
{
if (ticks_started) {
return;
}
ticks_started = SDL_TRUE;
start = GetTimerSystemTime();
}
void SDL_TicksQuit(void)
{
ticks_started = SDL_FALSE;
}
Uint64
SDL_GetTicks64(void)
{
uint64_t now;
if (!ticks_started) {
SDL_TicksInit();
}
now = GetTimerSystemTime();
return (Uint64)((now - start) / (kBUSCLK / CLOCKS_PER_SEC));
}
Uint64
SDL_GetPerformanceCounter(void)
{
return SDL_GetTicks64();
return GetTimerSystemTime();
}
Uint64
SDL_GetPerformanceFrequency(void)
{
return 1000;
return kBUSCLK;
}
void SDL_Delay(Uint32 ms)
void SDL_DelayNS(Uint64 ns)
{
struct timespec tv = { 0 };
tv.tv_sec = ms / 1000;
tv.tv_nsec = (ms % 1000) * 1000000;
struct timespec tv;
tv.tv_sec = (ns / SDL_NS_PER_SECOND);
tv.tv_nsec = (ns % SDL_NS_PER_SECOND);
nanosleep(&tv, NULL);
}

View File

@@ -28,56 +28,33 @@
#include <sys/time.h>
#include <pspthreadman.h>
static struct timeval start;
static SDL_bool ticks_started = SDL_FALSE;
void SDL_TicksInit(void)
{
if (ticks_started) {
return;
}
ticks_started = SDL_TRUE;
gettimeofday(&start, NULL);
}
void SDL_TicksQuit(void)
{
ticks_started = SDL_FALSE;
}
Uint64
SDL_GetTicks64(void)
{
struct timeval now;
if (!ticks_started) {
SDL_TicksInit();
}
gettimeofday(&now, NULL);
return (Uint64)(((Sint64)(now.tv_sec - start.tv_sec) * 1000) + ((now.tv_usec - start.tv_usec) / 1000));
}
Uint64
SDL_GetPerformanceCounter(void)
{
return SDL_GetTicks64();
Uint64 ticks;
struct timeval now;
gettimeofday(&now, NULL);
ticks = now.tv_sec;
ticks *= SDL_US_PER_SECOND;
ticks += now.tv_usec;
return ticks;
}
Uint64
SDL_GetPerformanceFrequency(void)
{
return 1000;
return SDL_US_PER_SECOND;
}
void SDL_Delay(Uint32 ms)
void SDL_DelayNS(Uint64 ns)
{
const Uint32 max_delay = 0xffffffffUL / 1000;
if (ms > max_delay) {
ms = max_delay;
const Uint64 max_delay = 0xffffffff * SDL_NS_PER_US;
if (ns > max_delay) {
ns = max_delay;
}
sceKernelDelayThreadCB(ms * 1000);
sceKernelDelayThreadCB((SceUInt)SDL_NS_TO_US(ns));
}
#endif /* SDL_TIMER_PSP */

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 */

View File

@@ -28,36 +28,6 @@
#include <sys/time.h>
#include <psp2/kernel/processmgr.h>
static uint64_t start;
static SDL_bool ticks_started = SDL_FALSE;
void SDL_TicksInit(void)
{
if (ticks_started) {
return;
}
ticks_started = SDL_TRUE;
start = sceKernelGetProcessTimeWide();
}
void SDL_TicksQuit(void)
{
ticks_started = SDL_FALSE;
}
Uint64
SDL_GetTicks64(void)
{
uint64_t now;
if (!ticks_started) {
SDL_TicksInit();
}
now = sceKernelGetProcessTimeWide();
return (Uint64)((now - start) / 1000);
}
Uint64
SDL_GetPerformanceCounter(void)
@@ -68,16 +38,16 @@ SDL_GetPerformanceCounter(void)
Uint64
SDL_GetPerformanceFrequency(void)
{
return 1000000;
return SDL_US_PER_SECOND;
}
void SDL_Delay(Uint32 ms)
void SDL_DelayNS(Uint64 ns)
{
const Uint32 max_delay = 0xffffffffUL / 1000;
if (ms > max_delay) {
ms = max_delay;
const Uint64 max_delay = 0xffffffff * SDL_NS_PER_US;
if (ns > max_delay) {
ns = max_delay;
}
sceKernelDelayThreadCB(ms * 1000);
sceKernelDelayThreadCB((SceUInt)SDL_NS_TO_US(ns));
}
#endif /* SDL_TIMER_VITA */

View File

@@ -23,99 +23,7 @@
#ifdef SDL_TIMER_WINDOWS
#include "../../core/windows/SDL_windows.h"
#include <mmsystem.h>
/* The first (low-resolution) ticks value of the application */
static DWORD start = 0;
static BOOL ticks_started = FALSE;
/* The first high-resolution ticks value of the application */
static LARGE_INTEGER start_ticks;
/* The number of ticks per second of the high-resolution performance counter */
static LARGE_INTEGER ticks_per_second;
static void SDL_SetSystemTimerResolution(const UINT uPeriod)
{
#if !defined(__WINRT__) && !defined(__XBOXONE__) && !defined(__XBOXSERIES__)
static UINT timer_period = 0;
if (uPeriod != timer_period) {
if (timer_period) {
timeEndPeriod(timer_period);
}
timer_period = uPeriod;
if (timer_period) {
timeBeginPeriod(timer_period);
}
}
#endif
}
static void SDLCALL SDL_TimerResolutionChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
{
UINT uPeriod;
/* Unless the hint says otherwise, let's have good sleep precision */
if (hint && *hint) {
uPeriod = SDL_atoi(hint);
} else {
uPeriod = 1;
}
if (uPeriod || oldValue != hint) {
SDL_SetSystemTimerResolution(uPeriod);
}
}
void SDL_TicksInit(void)
{
BOOL rc;
if (ticks_started) {
return;
}
ticks_started = SDL_TRUE;
/* if we didn't set a precision, set it high. This affects lots of things
on Windows besides the SDL timers, like audio callbacks, etc. */
SDL_AddHintCallback(SDL_HINT_TIMER_RESOLUTION,
SDL_TimerResolutionChanged, NULL);
/* Set first ticks value */
/* QueryPerformanceCounter allegedly is always available and reliable as of WinXP,
so we'll rely on it here.
*/
rc = QueryPerformanceFrequency(&ticks_per_second);
SDL_assert(rc != 0); /* this should _never_ fail if you're on XP or later. */
QueryPerformanceCounter(&start_ticks);
}
void SDL_TicksQuit(void)
{
SDL_DelHintCallback(SDL_HINT_TIMER_RESOLUTION,
SDL_TimerResolutionChanged, NULL);
SDL_SetSystemTimerResolution(0); /* always release our timer resolution request. */
start = 0;
ticks_started = SDL_FALSE;
}
Uint64
SDL_GetTicks64(void)
{
LARGE_INTEGER now;
BOOL rc;
if (!ticks_started) {
SDL_TicksInit();
}
rc = QueryPerformanceCounter(&now);
SDL_assert(rc != 0); /* this should _never_ fail if you're on XP or later. */
return (Uint64)(((now.QuadPart - start_ticks.QuadPart) * 1000) / ticks_per_second.QuadPart);
}
Uint64
SDL_GetPerformanceCounter(void)
@@ -135,7 +43,7 @@ SDL_GetPerformanceFrequency(void)
return (Uint64)frequency.QuadPart;
}
void SDL_Delay(Uint32 ms)
void SDL_DelayNS(Uint64 ns)
{
/* CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag was added in Windows 10 version 1803.
*
@@ -155,7 +63,7 @@ void SDL_Delay(Uint32 ms)
HANDLE timer = CreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
if (timer) {
LARGE_INTEGER due_time;
due_time.QuadPart = -(ms * 10000LL);
due_time.QuadPart = -((LONGLONG)ns / 100);
if (SetWaitableTimerEx(timer, &due_time, 0, NULL, NULL, NULL, 0)) {
WaitForSingleObject(timer, INFINITE);
}
@@ -163,19 +71,23 @@ void SDL_Delay(Uint32 ms)
return;
}
#endif
#if defined(__WINRT__) && defined(_MSC_FULL_VER) && (_MSC_FULL_VER <= 180030723)
static HANDLE mutex = 0;
if (!mutex) {
mutex = CreateEventEx(0, 0, 0, EVENT_ALL_ACCESS);
}
WaitForSingleObjectEx(mutex, ms, FALSE);
#else
if (!ticks_started) {
SDL_TicksInit();
}
Sleep(ms);
{
const Uint64 max_delay = 0xffffffff * SDL_NS_PER_MS;
if (ns > max_delay) {
ns = max_delay;
}
#if defined(__WINRT__) && defined(_MSC_FULL_VER) && (_MSC_FULL_VER <= 180030723)
static HANDLE mutex = 0;
if (!mutex) {
mutex = CreateEventEx(0, 0, 0, EVENT_ALL_ACCESS);
}
WaitForSingleObjectEx(mutex, (DWORD)SDL_NS_TO_MS(ns), FALSE);
#else
Sleep((DWORD)SDL_NS_TO_MS(ns));
#endif
}
}
#endif /* SDL_TIMER_WINDOWS */