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

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