mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-05-27 10:57:22 +08:00
Fixed timer overflow on some platforms
We have an implementation that uses 128-bit math and one that handles large values without it (thanks @jessechounard and @rabbit-ecl!) Fixes https://github.com/libsdl-org/SDL/issues/15042
This commit is contained in:
+28
-6
@@ -535,11 +535,20 @@ bool SDL_RemoveTimer(SDL_TimerID id)
|
|||||||
|
|
||||||
#endif // !SDL_PLATFORM_EMSCRIPTEN
|
#endif // !SDL_PLATFORM_EMSCRIPTEN
|
||||||
|
|
||||||
|
#ifdef USE_128BIT_MATH
|
||||||
|
typedef unsigned __int128 Uint128;
|
||||||
|
#endif
|
||||||
|
|
||||||
static Uint64 tick_start;
|
static Uint64 tick_start;
|
||||||
|
#ifdef USE_128BIT_MATH
|
||||||
|
static Uint128 tick_numerator_ns;
|
||||||
|
static Uint128 tick_numerator_ms;
|
||||||
|
#else
|
||||||
static Uint32 tick_numerator_ns;
|
static Uint32 tick_numerator_ns;
|
||||||
static Uint32 tick_denominator_ns;
|
static Uint32 tick_denominator_ns;
|
||||||
static Uint32 tick_numerator_ms;
|
static Uint32 tick_numerator_ms;
|
||||||
static Uint32 tick_denominator_ms;
|
static Uint32 tick_denominator_ms;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(SDL_TIMER_WINDOWS) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
#if defined(SDL_TIMER_WINDOWS) && !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
|
||||||
#include <mmsystem.h>
|
#include <mmsystem.h>
|
||||||
@@ -583,7 +592,9 @@ static void SDLCALL SDL_TimerResolutionChanged(void *userdata, const char *name,
|
|||||||
void SDL_InitTicks(void)
|
void SDL_InitTicks(void)
|
||||||
{
|
{
|
||||||
Uint64 tick_freq;
|
Uint64 tick_freq;
|
||||||
|
#ifndef USE_128BIT_MATH
|
||||||
Uint32 gcd;
|
Uint32 gcd;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (tick_start) {
|
if (tick_start) {
|
||||||
return;
|
return;
|
||||||
@@ -597,6 +608,10 @@ void SDL_InitTicks(void)
|
|||||||
tick_freq = SDL_GetPerformanceFrequency();
|
tick_freq = SDL_GetPerformanceFrequency();
|
||||||
SDL_assert(tick_freq > 0 && tick_freq <= (Uint64)SDL_MAX_UINT32);
|
SDL_assert(tick_freq > 0 && tick_freq <= (Uint64)SDL_MAX_UINT32);
|
||||||
|
|
||||||
|
#ifdef USE_128BIT_MATH
|
||||||
|
tick_numerator_ns = ((Uint128)SDL_NS_PER_SECOND << 32) / tick_freq;
|
||||||
|
tick_numerator_ms = ((Uint128)SDL_MS_PER_SECOND << 32) / tick_freq;
|
||||||
|
#else
|
||||||
gcd = SDL_CalculateGCD(SDL_NS_PER_SECOND, (Uint32)tick_freq);
|
gcd = SDL_CalculateGCD(SDL_NS_PER_SECOND, (Uint32)tick_freq);
|
||||||
tick_numerator_ns = (SDL_NS_PER_SECOND / gcd);
|
tick_numerator_ns = (SDL_NS_PER_SECOND / gcd);
|
||||||
tick_denominator_ns = (Uint32)(tick_freq / gcd);
|
tick_denominator_ns = (Uint32)(tick_freq / gcd);
|
||||||
@@ -604,6 +619,7 @@ void SDL_InitTicks(void)
|
|||||||
gcd = SDL_CalculateGCD(SDL_MS_PER_SECOND, (Uint32)tick_freq);
|
gcd = SDL_CalculateGCD(SDL_MS_PER_SECOND, (Uint32)tick_freq);
|
||||||
tick_numerator_ms = (SDL_MS_PER_SECOND / gcd);
|
tick_numerator_ms = (SDL_MS_PER_SECOND / gcd);
|
||||||
tick_denominator_ms = (Uint32)(tick_freq / gcd);
|
tick_denominator_ms = (Uint32)(tick_freq / gcd);
|
||||||
|
#endif
|
||||||
|
|
||||||
tick_start = SDL_GetPerformanceCounter();
|
tick_start = SDL_GetPerformanceCounter();
|
||||||
if (!tick_start) {
|
if (!tick_start) {
|
||||||
@@ -630,9 +646,12 @@ Uint64 SDL_GetTicksNS(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
starting_value = (SDL_GetPerformanceCounter() - tick_start);
|
starting_value = (SDL_GetPerformanceCounter() - tick_start);
|
||||||
value = (starting_value * tick_numerator_ns);
|
#ifdef USE_128BIT_MATH
|
||||||
SDL_assert(value >= starting_value);
|
value = (Uint64)(((Uint128)starting_value * tick_numerator_ns) >> 32);
|
||||||
value /= tick_denominator_ns;
|
#else
|
||||||
|
value = (starting_value / tick_denominator_ns) * tick_numerator_ns +
|
||||||
|
(starting_value % tick_denominator_ns) * tick_numerator_ns / tick_denominator_ns;
|
||||||
|
#endif
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -645,9 +664,12 @@ Uint64 SDL_GetTicks(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
starting_value = (SDL_GetPerformanceCounter() - tick_start);
|
starting_value = (SDL_GetPerformanceCounter() - tick_start);
|
||||||
value = (starting_value * tick_numerator_ms);
|
#ifdef USE_128BIT_MATH
|
||||||
SDL_assert(value >= starting_value);
|
value = (Uint64)(((Uint128)starting_value * tick_numerator_ms) >> 32);
|
||||||
value /= tick_denominator_ms;
|
#else
|
||||||
|
value = (starting_value / tick_denominator_ms) * tick_numerator_ms +
|
||||||
|
(starting_value % tick_denominator_ms) * tick_numerator_ms / tick_denominator_ms;
|
||||||
|
#endif
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user