mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-02-16 16:44:06 +00:00
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:
@@ -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(¤t->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: */
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user