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

From 8121bbd083b5a568709305270b554f2add3ba4a1 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 2 Dec 2022 01:17:17 -0800
Subject: [PATCH] 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
---
 WhatsNew.txt                                |   8 +-
 docs/README-migration.md                    |  28 +++++
 include/SDL3/SDL_events.h                   | 109 +++++++++++------
 include/SDL3/SDL_mutex.h                    |  97 ++++++++++++---
 include/SDL3/SDL_timer.h                    |  90 ++++++--------
 src/audio/alsa/SDL_alsa_audio.c             |   4 +-
 src/core/unix/SDL_poll.c                    |  17 ++-
 src/core/unix/SDL_poll.h                    |   2 +-
 src/dynapi/SDL_dynapi_overrides.h           |   6 +-
 src/dynapi/SDL_dynapi_procs.h               |  14 ++-
 src/events/SDL_events.c                     |  64 ++++++----
 src/events/SDL_mouse.c                      |   4 +-
 src/events/SDL_mouse_c.h                    |   2 +-
 src/haptic/android/SDL_syshaptic.c          |  11 +-
 src/haptic/windows/SDL_windowshaptic_c.h    |   2 +-
 src/haptic/windows/SDL_xinputhaptic.c       |   5 +-
 src/hidapi/SDL_hidapi.c                     |   6 +-
 src/joystick/SDL_gamecontroller.c           |   6 +-
 src/joystick/SDL_joystick.c                 |  22 +---
 src/joystick/SDL_sysjoystick.h              |   8 +-
 src/joystick/android/SDL_sysjoystick.c      |   7 +-
 src/joystick/hidapi/SDL_hidapi_ps4.c        |   8 +-
 src/joystick/hidapi/SDL_hidapi_ps5.c        |   8 +-
 src/joystick/hidapi/SDL_hidapi_shield.c     |   8 +-
 src/joystick/hidapi/SDL_hidapi_switch.c     |  82 ++++++-------
 src/joystick/hidapi/SDL_hidapi_wii.c        |  36 +++---
 src/joystick/hidapi/SDL_hidapi_xboxone.c    |  14 +--
 src/joystick/linux/SDL_sysjoystick.c        |   6 +-
 src/joystick/windows/SDL_rawinputjoystick.c |   6 +-
 src/power/uikit/SDL_syspower.m              |   4 +-
 src/render/SDL_render.c                     |  18 +--
 src/render/SDL_sysrender.h                  |   4 +-
 src/thread/SDL_thread.c                     |  39 ++++++
 src/thread/generic/SDL_syscond.c            |  19 +--
 src/thread/generic/SDL_syscond_c.h          |   4 +-
 src/thread/generic/SDL_syssem.c             |  55 +++------
 src/thread/n3ds/SDL_syscond.c               |  15 +--
 src/thread/n3ds/SDL_syssem.c                |  21 +---
 src/thread/ngage/SDL_syssem.cpp             |  33 ++---
 src/thread/ps2/SDL_syssem.c                 |  18 +--
 src/thread/psp/SDL_syscond.c                |  16 +--
 src/thread/psp/SDL_syssem.c                 |  25 ++--
 src/thread/pthread/SDL_syscond.c            |  32 ++---
 src/thread/pthread/SDL_syssem.c             |  74 +++++-------
 src/thread/stdcpp/SDL_syscond.cpp           |  17 +--
 src/thread/vita/SDL_syscond.c               |  16 +--
 src/thread/vita/SDL_syssem.c                |  25 ++--
 src/thread/windows/SDL_syscond_cv.c         |  32 ++---
 src/thread/windows/SDL_syssem.c             | 117 ++++++------------
 src/timer/SDL_timer.c                       | 127 ++++++++++++++++----
 src/timer/dummy/SDL_systimer.c              |  31 +----
 src/timer/haiku/SDL_systimer.c              |  34 +-----
 src/timer/n3ds/SDL_systimer.c               |  35 +-----
 src/timer/ngage/SDL_systimer.cpp            |  48 ++------
 src/timer/ps2/SDL_systimer.c                |  42 +------
 src/timer/psp/SDL_systimer.c                |  51 +++-----
 src/timer/unix/SDL_systimer.c               | 102 +++++-----------
 src/timer/vita/SDL_systimer.c               |  42 +------
 src/timer/windows/SDL_systimer.c            | 120 +++---------------
 src/video/SDL_sysvideo.h                    |   2 +-
 src/video/cocoa/SDL_cocoaevents.h           |   2 +-
 src/video/cocoa/SDL_cocoaevents.m           |   8 +-
 src/video/cocoa/SDL_cocoaopengl.m           |   2 +-
 src/video/cocoa/SDL_cocoawindow.m           |   6 +-
 src/video/wayland/SDL_waylanddatamanager.c  |   6 +-
 src/video/wayland/SDL_waylandevents.c       |  16 +--
 src/video/wayland/SDL_waylandevents_c.h     |   4 +-
 src/video/wayland/SDL_waylandopengles.c     |   8 +-
 src/video/windows/SDL_windowsevents.c       |  17 +--
 src/video/windows/SDL_windowsevents.h       |   2 +-
 src/video/windows/SDL_windowswindow.h       |   2 +-
 src/video/x11/SDL_x11clipboard.c            |   4 +-
 src/video/x11/SDL_x11events.c               |  21 ++--
 src/video/x11/SDL_x11events.h               |   2 +-
 src/video/x11/SDL_x11video.h                |   4 +-
 src/video/x11/SDL_x11window.c               |  19 ++-
 src/video/x11/SDL_x11window.h               |   6 +-
 test/controllermap.c                        |   6 +-
 test/testatomic.c                           |  16 +--
 test/testautomation_timer.c                 |  20 +--
 test/testdraw2.c                            |  11 +-
 test/testgeometry.c                         |   3 +-
 test/testgl2.c                              |   3 +-
 test/testgles2.c                            |   2 +-
 test/testgles2_sdf.c                        |   2 +-
 test/testintersections.c                    |   3 +-
 test/testoffscreen.c                        |   3 +-
 test/testrendercopyex.c                     |   2 +-
 test/testrendertarget.c                     |   2 +-
 test/testscale.c                            |   2 +-
 test/testsem.c                              |  24 ++--
 test/testsprite2.c                          |  11 +-
 test/testtimer.c                            |  31 ++---
 test/testviewport.c                         |   3 +-
 test/testvulkan.c                           |   3 +-
 test/testyuv.c                              |   5 +-
 96 files changed, 937 insertions(+), 1242 deletions(-)

diff --git a/WhatsNew.txt b/WhatsNew.txt
index a0d065cc5326..c9b3bfb87456 100644
--- a/WhatsNew.txt
+++ b/WhatsNew.txt
@@ -32,4 +32,10 @@ General:
 * Added SDL_CreateSurface() and SDL_CreateSurfaceFrom() which replace the SDL_CreateRGBSurface*()
 * Removed unused 'flags' parameter from SDL_ConvertSurface and SDL_ConvertSurfaceFormat
 * Removed 'SDL_GL_CONTEXT_EGL' from OpenGL configuration attributes
-
+* SDL_GetTicks() now returns a 64-bit value and the tick values should be directly compared instead of using the SDL_TICKS_PASSED macro
+* Added SDL_GetTicksNS() to return the number of nanoseconds since the SDL library initialized
+* Added SDL_DelayNS() to specify a delay in nanoseconds, to the highest precision the system will support
+* Added SDL_WaitEventTimeoutNS() to wait for events with the highest possible precision
+* Added SDL_SemWaitTimeoutNS() to wait for a semaphore with the highest possible precision
+* Added SDL_CondWaitTimeoutNS() to wait for a condition variable the highest possible precision
+* The timestamp member of the SDL_Event structure is now in nanoseconds, filled in with SDL_GetTicksNS()
diff --git a/docs/README-migration.md b/docs/README-migration.md
index 735d7c682ffa..079d22fe160a 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -31,6 +31,10 @@ LDFLAGS += $(shell pkg-config sdl3 --libs)
 The SDL3main and SDL3test libraries have been renamed SDL3_main and SDL3_test, respectively.
 
 
+## SDL_events.h
+
+The `timestamp` member of the SDL_Event structure now represents nanoseconds, and is populated with `SDL_GetTicksNS()`
+
 ## SDL_platform.h
 
 The preprocessor symbol __MACOSX__ has been renamed __MACOS__, and __IPHONEOS__ has been renamed __IOS__
@@ -223,6 +227,30 @@ The structures in this file are versioned separately from the rest of SDL, allow
 This function now returns a standard int result instead of SDL_bool, returning 0 if the function succeeds or a negative error code if there was an error. You should also pass `SDL_SYSWM_CURRENT_VERSION` as the new third version parameter. The version member of the info structure will be filled in with the version of data that is returned, the minimum of the version you requested and the version supported by the runtime SDL library.
 
 
+## SDL_timer.h
+
+SDL_GetTicks() now returns a 64-bit value. Instead of using the `SDL_TICKS_PASSED` macro, you can directly compare tick values, e.g.
+```c
+Uint32 deadline = SDL_GetTicks() + 1000;
+...
+if (SDL_TICKS_PASSED(SDL_GetTicks(), deadline)) {
+    ...
+}
+```
+becomes:
+```c
+Uint64 deadline = SDL_GetTicks() + 1000
+...
+if (SDL_GetTicks() >= deadline) {
+    ...
+}
+```
+
+If you were using this macro for other things besides SDL ticks values, you can define it in your own code as:
+```c
+#define SDL_TICKS_PASSED(A, B)  ((Sint32)((B) - (A)) <= 0)
+```
+
 ## SDL_version.h
 
 SDL_GetRevisionNumber() has been removed from the API, it always returned 0 in SDL 2.0
diff --git a/include/SDL3/SDL_events.h b/include/SDL3/SDL_events.h
index 0e110fdfe71e..00c111006ea2 100644
--- a/include/SDL3/SDL_events.h
+++ b/include/SDL3/SDL_events.h
@@ -182,7 +182,7 @@ typedef enum
 typedef struct SDL_CommonEvent
 {
     Uint32 type;
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
 } SDL_CommonEvent;
 
 /**
@@ -191,7 +191,7 @@ typedef struct SDL_CommonEvent
 typedef struct SDL_DisplayEvent
 {
     Uint32 type;        /**< ::SDL_DISPLAYEVENT */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     Uint32 display;     /**< The associated display index */
     Uint8 event;        /**< ::SDL_DisplayEventID */
     Uint8 padding1;
@@ -206,7 +206,7 @@ typedef struct SDL_DisplayEvent
 typedef struct SDL_WindowEvent
 {
     Uint32 type;        /**< ::SDL_WINDOWEVENT */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     Uint32 windowID;    /**< The associated window */
     Uint8 event;        /**< ::SDL_WindowEventID */
     Uint8 padding1;
@@ -222,7 +222,7 @@ typedef struct SDL_WindowEvent
 typedef struct SDL_KeyboardEvent
 {
     Uint32 type;        /**< ::SDL_KEYDOWN or ::SDL_KEYUP */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     Uint32 windowID;    /**< The window with keyboard focus, if any */
     Uint8 state;        /**< ::SDL_PRESSED or ::SDL_RELEASED */
     Uint8 repeat;       /**< Non-zero if this is a key repeat */
@@ -238,7 +238,7 @@ typedef struct SDL_KeyboardEvent
 typedef struct SDL_TextEditingEvent
 {
     Uint32 type;                                /**< ::SDL_TEXTEDITING */
-    Uint32 timestamp;                           /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;                           /**< In nanoseconds, populated using SDL_GetTicksNS() */
     Uint32 windowID;                            /**< The window with keyboard focus, if any */
     char text[SDL_TEXTEDITINGEVENT_TEXT_SIZE];  /**< The editing text */
     Sint32 start;                               /**< The start cursor of selected editing text */
@@ -252,7 +252,7 @@ typedef struct SDL_TextEditingEvent
 typedef struct SDL_TextEditingExtEvent
 {
     Uint32 type;                                /**< ::SDL_TEXTEDITING_EXT */
-    Uint32 timestamp;                           /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;                           /**< In nanoseconds, populated using SDL_GetTicksNS() */
     Uint32 windowID;                            /**< The window with keyboard focus, if any */
     char* text;                                 /**< The editing text, which should be freed with SDL_free(), and will not be NULL */
     Sint32 start;                               /**< The start cursor of selected editing text */
@@ -266,7 +266,7 @@ typedef struct SDL_TextEditingExtEvent
 typedef struct SDL_TextInputEvent
 {
     Uint32 type;                              /**< ::SDL_TEXTINPUT */
-    Uint32 timestamp;                         /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;                         /**< In nanoseconds, populated using SDL_GetTicksNS() */
     Uint32 windowID;                          /**< The window with keyboard focus, if any */
     char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];  /**< The input text */
 } SDL_TextInputEvent;
@@ -277,7 +277,7 @@ typedef struct SDL_TextInputEvent
 typedef struct SDL_MouseMotionEvent
 {
     Uint32 type;        /**< ::SDL_MOUSEMOTION */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     Uint32 windowID;    /**< The window with mouse focus, if any */
     Uint32 which;       /**< The mouse instance id, or SDL_TOUCH_MOUSEID */
     Uint32 state;       /**< The current button state */
@@ -293,7 +293,7 @@ typedef struct SDL_MouseMotionEvent
 typedef struct SDL_MouseButtonEvent
 {
     Uint32 type;        /**< ::SDL_MOUSEBUTTONDOWN or ::SDL_MOUSEBUTTONUP */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     Uint32 windowID;    /**< The window with mouse focus, if any */
     SDL_MouseID which;       /**< The mouse instance id, or SDL_TOUCH_MOUSEID */
     Uint8 button;       /**< The mouse button index */
@@ -310,7 +310,7 @@ typedef struct SDL_MouseButtonEvent
 typedef struct SDL_MouseWheelEvent
 {
     Uint32 type;        /**< ::SDL_MOUSEWHEEL */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     Uint32 windowID;    /**< The window with mouse focus, if any */
     SDL_MouseID which;       /**< The mouse instance id, or SDL_TOUCH_MOUSEID */
     Sint32 x;           /**< The amount scrolled horizontally, positive to the right and negative to the left */
@@ -328,7 +328,7 @@ typedef struct SDL_MouseWheelEvent
 typedef struct SDL_JoyAxisEvent
 {
     Uint32 type;        /**< ::SDL_JOYAXISMOTION */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     SDL_JoystickID which; /**< The joystick instance id */
     Uint8 axis;         /**< The joystick axis index */
     Uint8 padding1;
@@ -344,7 +344,7 @@ typedef struct SDL_JoyAxisEvent
 typedef struct SDL_JoyBallEvent
 {
     Uint32 type;        /**< ::SDL_JOYBALLMOTION */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     SDL_JoystickID which; /**< The joystick instance id */
     Uint8 ball;         /**< The joystick trackball index */
     Uint8 padding1;
@@ -360,7 +360,7 @@ typedef struct SDL_JoyBallEvent
 typedef struct SDL_JoyHatEvent
 {
     Uint32 type;        /**< ::SDL_JOYHATMOTION */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     SDL_JoystickID which; /**< The joystick instance id */
     Uint8 hat;          /**< The joystick hat index */
     Uint8 value;        /**< The hat position value.
@@ -380,7 +380,7 @@ typedef struct SDL_JoyHatEvent
 typedef struct SDL_JoyButtonEvent
 {
     Uint32 type;        /**< ::SDL_JOYBUTTONDOWN or ::SDL_JOYBUTTONUP */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     SDL_JoystickID which; /**< The joystick instance id */
     Uint8 button;       /**< The joystick button index */
     Uint8 state;        /**< ::SDL_PRESSED or ::SDL_RELEASED */
@@ -394,7 +394,7 @@ typedef struct SDL_JoyButtonEvent
 typedef struct SDL_JoyDeviceEvent
 {
     Uint32 type;        /**< ::SDL_JOYDEVICEADDED or ::SDL_JOYDEVICEREMOVED */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     SDL_JoystickID which;       /**< The joystick device index for the ADDED event, instance id for the REMOVED event */
 } SDL_JoyDeviceEvent;
 
@@ -404,7 +404,7 @@ typedef struct SDL_JoyDeviceEvent
 typedef struct SDL_JoyBatteryEvent
 {
     Uint32 type;        /**< ::SDL_JOYBATTERYUPDATED */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     SDL_JoystickID which; /**< The joystick instance id */
     SDL_JoystickPowerLevel level; /**< The joystick battery level */
 } SDL_JoyBatteryEvent;
@@ -415,7 +415,7 @@ typedef struct SDL_JoyBatteryEvent
 typedef struct SDL_ControllerAxisEvent
 {
     Uint32 type;        /**< ::SDL_CONTROLLERAXISMOTION */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     SDL_JoystickID which; /**< The joystick instance id */
     Uint8 axis;         /**< The controller axis (SDL_GameControllerAxis) */
     Uint8 padding1;
@@ -432,7 +432,7 @@ typedef struct SDL_ControllerAxisEvent
 typedef struct SDL_ControllerButtonEvent
 {
     Uint32 type;        /**< ::SDL_CONTROLLERBUTTONDOWN or ::SDL_CONTROLLERBUTTONUP */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     SDL_JoystickID which; /**< The joystick instance id */
     Uint8 button;       /**< The controller button (SDL_GameControllerButton) */
     Uint8 state;        /**< ::SDL_PRESSED or ::SDL_RELEASED */
@@ -447,7 +447,7 @@ typedef struct SDL_ControllerButtonEvent
 typedef struct SDL_ControllerDeviceEvent
 {
     Uint32 type;        /**< ::SDL_CONTROLLERDEVICEADDED, ::SDL_CONTROLLERDEVICEREMOVED, or ::SDL_CONTROLLERDEVICEREMAPPED */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     SDL_JoystickID which;       /**< The joystick device index for the ADDED event, instance id for the REMOVED or REMAPPED event */
 } SDL_ControllerDeviceEvent;
 
@@ -457,7 +457,7 @@ typedef struct SDL_ControllerDeviceEvent
 typedef struct SDL_ControllerTouchpadEvent
 {
     Uint32 type;        /**< ::SDL_CONTROLLERTOUCHPADDOWN or ::SDL_CONTROLLERTOUCHPADMOTION or ::SDL_CONTROLLERTOUCHPADUP */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     SDL_JoystickID which; /**< The joystick instance id */
     Sint32 touchpad;    /**< The index of the touchpad */
     Sint32 finger;      /**< The index of the finger on the touchpad */
@@ -472,7 +472,7 @@ typedef struct SDL_ControllerTouchpadEvent
 typedef struct SDL_ControllerSensorEvent
 {
     Uint32 type;        /**< ::SDL_CONTROLLERSENSORUPDATE */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     SDL_JoystickID which; /**< The joystick instance id */
     Sint32 sensor;      /**< The type of the sensor, one of the values of ::SDL_SensorType */
     float data[3];      /**< Up to 3 values from the sensor, as defined in SDL_sensor.h */
@@ -485,7 +485,7 @@ typedef struct SDL_ControllerSensorEvent
 typedef struct SDL_AudioDeviceEvent
 {
     Uint32 type;        /**< ::SDL_AUDIODEVICEADDED, or ::SDL_AUDIODEVICEREMOVED */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     Uint32 which;       /**< The audio device index for the ADDED event (valid until next SDL_GetNumAudioDevices() call), SDL_AudioDeviceID for the REMOVED event */
     Uint8 iscapture;    /**< zero if an output device, non-zero if a capture device. */
     Uint8 padding1;
@@ -500,7 +500,7 @@ typedef struct SDL_AudioDeviceEvent
 typedef struct SDL_TouchFingerEvent
 {
     Uint32 type;        /**< ::SDL_FINGERMOTION or ::SDL_FINGERDOWN or ::SDL_FINGERUP */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     SDL_TouchID touchId; /**< The touch device id */
     SDL_FingerID fingerId;
     float x;            /**< Normalized in the range 0...1 */
@@ -518,7 +518,7 @@ typedef struct SDL_TouchFingerEvent
 typedef struct SDL_MultiGestureEvent
 {
     Uint32 type;        /**< ::SDL_MULTIGESTURE */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     SDL_TouchID touchId; /**< The touch device id */
     float dTheta;
     float dDist;
@@ -535,7 +535,7 @@ typedef struct SDL_MultiGestureEvent
 typedef struct SDL_DollarGestureEvent
 {
     Uint32 type;        /**< ::SDL_DOLLARGESTURE or ::SDL_DOLLARRECORD */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     SDL_TouchID touchId; /**< The touch device id */
     SDL_GestureID gestureId;
     Uint32 numFingers;
@@ -553,7 +553,7 @@ typedef struct SDL_DollarGestureEvent
 typedef struct SDL_DropEvent
 {
     Uint32 type;        /**< ::SDL_DROPBEGIN or ::SDL_DROPFILE or ::SDL_DROPTEXT or ::SDL_DROPCOMPLETE */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     char *file;         /**< The file name, which should be freed with SDL_free(), is NULL on begin/complete */
     Uint32 windowID;    /**< The window that was dropped on, if any */
 } SDL_DropEvent;
@@ -565,7 +565,7 @@ typedef struct SDL_DropEvent
 typedef struct SDL_SensorEvent
 {
     Uint32 type;        /**< ::SDL_SENSORUPDATE */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     SDL_SensorID which;       /**< The instance ID of the sensor */
     float data[6];      /**< Up to 6 values from the sensor - additional values can be queried using SDL_SensorGetData() */
     Uint64 timestamp_us; /**< The timestamp of the sensor reading in microseconds, if the hardware provides this information. */
@@ -577,7 +577,7 @@ typedef struct SDL_SensorEvent
 typedef struct SDL_QuitEvent
 {
     Uint32 type;        /**< ::SDL_QUIT */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
 } SDL_QuitEvent;
 
 /**
@@ -586,7 +586,7 @@ typedef struct SDL_QuitEvent
 typedef struct SDL_OSEvent
 {
     Uint32 type;        /**< ::SDL_QUIT */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
 } SDL_OSEvent;
 
 /**
@@ -595,7 +595,7 @@ typedef struct SDL_OSEvent
 typedef struct SDL_UserEvent
 {
     Uint32 type;        /**< ::SDL_USEREVENT through ::SDL_LASTEVENT-1 */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     Uint32 windowID;    /**< The associated window if any */
     Sint32 code;        /**< User defined event code */
     void *data1;        /**< User defined data pointer */
@@ -615,7 +615,7 @@ typedef struct SDL_SysWMmsg SDL_SysWMmsg;
 typedef struct SDL_SysWMEvent
 {
     Uint32 type;        /**< ::SDL_SYSWMEVENT */
-    Uint32 timestamp;   /**< In milliseconds, populated using SDL_GetTicks() */
+    Uint64 timestamp;   /**< In nanoseconds, populated using SDL_GetTicksNS() */
     SDL_SysWMmsg *msg;  /**< driver dependent data, defined in SDL_syswm.h */
 } SDL_SysWMEvent;
 
@@ -669,7 +669,7 @@ typedef union SDL_Event
        the next multiple of 16, 64, and on architectures where pointers are
        even larger the size of SDL_UserEvent will dominate as being 3 pointers.
     */
-    Uint8 padding[sizeof(void *) <= 8 ? 56 : sizeof(void *) == 16 ? 64 : 3 * sizeof(void *)];
+    Uint8 padding[128];
 } SDL_Event;
 
 /* Make sure we haven't broken binary compatibility */
@@ -879,6 +879,7 @@ extern DECLSPEC void SDLCALL SDL_FlushEvents(Uint32 minType, Uint32 maxType);
  * \sa SDL_SetEventFilter
  * \sa SDL_WaitEvent
  * \sa SDL_WaitEventTimeout
+ * \sa SDL_WaitEventTimeoutNS
  */
 extern DECLSPEC int SDLCALL SDL_PollEvent(SDL_Event * event);
 
@@ -901,8 +902,9 @@ extern DECLSPEC int SDLCALL SDL_PollEvent(SDL_Event * event);
  * \sa SDL_PollEvent
  * \sa SDL_PumpEvents
  * \sa SDL_WaitEventTimeout
+ * \sa SDL_WaitEventTimeoutNS
  */
-extern DECLSPEC int SDLCALL SDL_WaitEvent(SDL_Event * event);
+extern DECLSPEC int SDLCALL SDL_WaitEvent(SDL_Event *event);
 
 /**
  * Wait until the specified timeout (in milliseconds) for the next available
@@ -914,10 +916,13 @@ extern DECLSPEC int SDLCALL SDL_WaitEvent(SDL_Event * event);
  * As this function may implicitly call SDL_PumpEvents(), you can only call
  * this function in the thread that initialized the video subsystem.
  *
+ * The timeout is not guaranteed, the actual wait time could be longer
+ * due to system scheduling.
+ *
  * \param event the SDL_Event structure to be filled in with the next event
  *              from the queue, or NULL
- * \param timeout the maximum number of milliseconds to wait for the next
- *                available event
+ * \param timeoutMS the maximum number of milliseconds to wait for the next
+ *                  available event
  * \returns 1 on success or 0 if there was an error while waiting for events;
  *          call SDL_GetError() for more information. This also returns 0 if
  *          the timeout elapsed without an event arriving.
@@ -927,9 +932,39 @@ extern DECLSPEC int SDLCALL SDL_WaitEvent(SDL_Event * event);
  * \sa SDL_PollEvent
  * \sa SDL_PumpEvents
  * \sa SDL_WaitEvent
+ * \sa SDL_WaitEventTimeoutNS
+ */
+extern DECLSPEC int SDLCALL SDL_WaitEventTimeout(SDL_Event *event, Sint32 timeoutMS);
+
+/**
+ * Wait until the specified timeout (in nanoseconds) for the next available
+ * event.
+ *
+ * If `event` is not NULL, the next event is removed from the queue and stored
+ * in the SDL_Event structure pointed to by `event`.
+ *
+ * As this function may implicitly call SDL_PumpEvents(), you can only call
+ * this function in the thread that initialized the video subsystem.
+ *
+ * The timeout is not guaranteed, the actual wait time could be longer
+ * due to system scheduling.
+ *
+ * \param event the SDL_Event structure to be filled in with the next event
+ *              from the queue, or NULL
+ * \param timeoutNS the maximum number of nanoseconds to wait for the next
+ *                  available event
+ * \returns 1 on success or 0 if there was an error while waiting for events;
+ *          call SDL_GetError() for more information. This also returns 0 if
+ *          the timeout elapsed without an event arriving.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_PollEvent
+ * \sa SDL_PumpEvents
+ * \sa SDL_WaitEvent
+ * \sa SDL_WaitEventTimeout
  */
-extern DECLSPEC int SDLCALL SDL_WaitEventTimeout(SDL_Event * event,
-                                                 int timeout);
+extern DECLSPEC int SDLCALL SDL_WaitEventTimeoutNS(SDL_Event *event, Sint64 timeoutNS);
 
 /**
  * Add an event to the event queue.
diff --git a/include/SDL3/SDL_mutex.h b/include/SDL3/SDL_mutex.h
index 6fdbd7db9a0c..7495ab4c13c8 100644
--- a/include/SDL3/SDL_mutex.h
+++ b/include/SDL3/SDL_mutex.h
@@ -46,7 +46,7 @@ extern "C" {
 /**
  *  This is the timeout value which corresponds to never time out.
  */
-#define SDL_MUTEX_MAXWAIT   (~(Uint32)0)
+#define SDL_MUTEX_MAXWAIT   -1
 
 
 /**
@@ -194,6 +194,7 @@ typedef struct SDL_semaphore SDL_sem;
  * \sa SDL_SemValue
  * \sa SDL_SemWait
  * \sa SDL_SemWaitTimeout
+ * \sa SDL_SemWaitTimeoutNS
  */
 extern DECLSPEC SDL_sem *SDLCALL SDL_CreateSemaphore(Uint32 initial_value);
 
@@ -213,8 +214,9 @@ extern DECLSPEC SDL_sem *SDLCALL SDL_CreateSemaphore(Uint32 initial_value);
  * \sa SDL_SemValue
  * \sa SDL_SemWait
  * \sa SDL_SemWaitTimeout
+ * \sa SDL_SemWaitTimeoutNS
  */
-extern DECLSPEC void SDLCALL SDL_DestroySemaphore(SDL_sem * sem);
+extern DECLSPEC void SDLCALL SDL_DestroySemaphore(SDL_sem *sem);
 
 /**
  * Wait until a semaphore has a positive value and then decrements it.
@@ -240,8 +242,9 @@ extern DECLSPEC void SDLCALL SDL_DestroySemaphore(SDL_sem * sem);
  * \sa SDL_SemValue
  * \sa SDL_SemWait
  * \sa SDL_SemWaitTimeout
+ * \sa SDL_SemWaitTimeoutNS
  */
-extern DECLSPEC int SDLCALL SDL_SemWait(SDL_sem * sem);
+extern DECLSPEC int SDLCALL SDL_SemWait(SDL_sem *sem);
 
 /**
  * See if a semaphore has a positive value and decrement it if it does.
@@ -264,8 +267,9 @@ extern DECLSPEC int SDLCALL SDL_SemWait(SDL_sem * sem);
  * \sa SDL_SemValue
  * \sa SDL_SemWait
  * \sa SDL_SemWaitTimeout
+ * \sa SDL_SemWaitTimeoutNS
  */
-extern DECLSPEC int SDLCALL SDL_SemTryWait(SDL_sem * sem);
+extern DECLSPEC int SDLCALL SDL_SemTryWait(SDL_sem *sem);
 
 /**
  * Wait until a semaphore has a positive value and then decrements it.
@@ -276,7 +280,7 @@ extern DECLSPEC int SDLCALL SDL_SemTryWait(SDL_sem * sem);
  * successful it will atomically decrement the semaphore value.
  *
  * \param sem the semaphore to wait on
- * \param timeout the length of the timeout, in milliseconds
+ * \param timeoutMS the length of the timeout, in milliseconds
  * \returns 0 if the wait succeeds, `SDL_MUTEX_TIMEDOUT` if the wait does not
  *          succeed in the allotted time, or a negative error code on failure;
  *          call SDL_GetError() for more information.
@@ -289,8 +293,35 @@ extern DECLSPEC int SDLCALL SDL_SemTryWait(SDL_sem * sem);
  * \sa SDL_SemTryWait
  * \sa SDL_SemValue
  * \sa SDL_SemWait
+ * \sa SDL_SemWaitTimeoutNS
  */
-extern DECLSPEC int SDLCALL SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout);
+extern DECLSPEC int SDLCALL SDL_SemWaitTimeout(SDL_sem *sem, Sint32 timeoutMS);
+
+/**
+ * Wait until a semaphore has a positive value and then decrements it.
+ *
+ * This function suspends the calling thread until either the semaphore
+ * pointed to by `sem` has a positive value, the call is interrupted by a
+ * signal or error, or the specified time has elapsed. If the call is
+ * successful it will atomically decrement the semaphore value.
+ *
+ * \param sem the semaphore to wait on
+ * \param timeoutNS the length of the timeout, in nanoseconds
+ * \returns 0 if the wait succeeds, `SDL_MUTEX_TIMEDOUT` if the wait does not
+ *          succeed in the allotted time, or a negative error code on failure;
+ *          call SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_CreateSemaphore
+ * \sa SDL_DestroySemaphore
+ * \sa SDL_SemPost
+ * \sa SDL_SemTryWait
+ * \sa SDL_SemValue
+ * \sa SDL_SemWait
+ * \sa SDL_SemWaitTimeout
+ */
+extern DECLSPEC int SDLCALL SDL_SemWaitTimeoutNS(SDL_sem *sem, Sint64 timeoutNS);
 
 /**
  * Atomically increment a semaphore's 

(Patch may be truncated, please check the link at the top of this post.)