Преглед на файлове

wayland: Cleanup timestamp handling

Better handle some very rare, but possible edge cases if the system has been running for many days.
Frank Praznik преди 10 месеца
родител
ревизия
a1332d77f6
променени са 1 файла, в които са добавени 44 реда и са изтрити 48 реда
  1. 44 48
      src/video/wayland/SDL_waylandevents.c

+ 44 - 48
src/video/wayland/SDL_waylandevents.c

@@ -179,7 +179,7 @@ static void Wayland_GetScaledMouseRect(SDL_Window *window, SDL_Rect *scaled_rect
     scaled_rect->h = (int)SDL_ceil(window->mouse_rect.h / window_data->pointer_scale.y);
 }
 
-static Uint64 Wayland_GetEventTimestamp(Uint64 nsTimestamp)
+static Uint64 Wayland_AdjustEventTimestampBase(Uint64 nsTimestamp)
 {
     static Uint64 timestamp_offset = 0;
     const Uint64 now = SDL_GetTicksNS();
@@ -197,16 +197,9 @@ static Uint64 Wayland_GetEventTimestamp(Uint64 nsTimestamp)
     return nsTimestamp;
 }
 
-static void input_timestamp_listener(void *data, struct zwp_input_timestamps_v1 *zwp_input_timestamps_v1,
-                                             uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec)
-{
-    *((Uint64 *)data) = ((((Uint64)tv_sec_hi << 32) | (Uint64)tv_sec_lo) * SDL_NS_PER_SECOND) + tv_nsec;
-}
-
-static const struct zwp_input_timestamps_v1_listener timestamp_listener = {
-    input_timestamp_listener
-};
-
+/* This should only be called with 32-bit millisecond timestamps received in Wayland events!
+ * No synthetic or high-res timestamps, as they can corrupt the rollover offset!
+ */
 static Uint64 Wayland_EventTimestampMSToNS(Uint32 wl_timestamp_ms)
 {
     static Uint64 timestamp_offset = 0;
@@ -222,38 +215,38 @@ static Uint64 Wayland_EventTimestampMSToNS(Uint32 wl_timestamp_ms)
     return SDL_MS_TO_NS(wl_timestamp_ms) + timestamp_offset;
 }
 
-static Uint64 Wayland_GetKeyboardTimestamp(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms)
-{
-    if (wl_timestamp_ms) {
-        return Wayland_GetEventTimestamp(seat->keyboard.highres_timestamp_ns ? seat->keyboard.highres_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms));
-    }
-
-    return 0;
-}
+/* Even if high-res timestamps are available, the millisecond timestamps are still processed
+ * to accumulate the rollover offset if needed later.
+ */
 
 static Uint64 Wayland_GetKeyboardTimestampRaw(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms)
 {
-    return seat->keyboard.highres_timestamp_ns ? seat->keyboard.highres_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms);
+    const Uint64 adjustedTimestampMS = Wayland_EventTimestampMSToNS(wl_timestamp_ms);
+    return seat->keyboard.timestamps ? seat->keyboard.highres_timestamp_ns : adjustedTimestampMS;
 }
 
 static Uint64 Wayland_GetPointerTimestamp(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms)
 {
-    if (wl_timestamp_ms) {
-        return Wayland_GetEventTimestamp(seat->pointer.highres_timestamp_ns ? seat->pointer.highres_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms));
-    }
-
-    return 0;
+    const Uint64 adjustedTimestampMS = Wayland_EventTimestampMSToNS(wl_timestamp_ms);
+    return Wayland_AdjustEventTimestampBase(seat->pointer.timestamps ? seat->pointer.highres_timestamp_ns : adjustedTimestampMS);
 }
 
 Uint64 Wayland_GetTouchTimestamp(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms)
 {
-    if (wl_timestamp_ms) {
-        return Wayland_GetEventTimestamp(seat->touch.highres_timestamp_ns ? seat->touch.highres_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms));
-    }
+    const Uint64 adjustedTimestampMS = Wayland_EventTimestampMSToNS(wl_timestamp_ms);
+    return Wayland_AdjustEventTimestampBase(seat->touch.timestamps ? seat->touch.highres_timestamp_ns : adjustedTimestampMS);
+}
 
-    return 0;
+static void input_timestamp_listener(void *data, struct zwp_input_timestamps_v1 *zwp_input_timestamps_v1,
+                                             uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec)
+{
+    *((Uint64 *)data) = ((((Uint64)tv_sec_hi << 32) | (Uint64)tv_sec_lo) * SDL_NS_PER_SECOND) + tv_nsec;
 }
 
+static const struct zwp_input_timestamps_v1_listener timestamp_listener = {
+    input_timestamp_listener
+};
+
 static void Wayland_SeatRegisterInputTimestampListeners(SDL_WaylandSeat *seat)
 {
     if (seat->display->input_timestamps_manager) {
@@ -308,7 +301,7 @@ static bool keyboard_repeat_handle(SDL_WaylandKeyboardRepeat *repeat_info, Uint6
     while (elapsed >= repeat_info->next_repeat_ns) {
         if (repeat_info->scancode != SDL_SCANCODE_UNKNOWN) {
             const Uint64 timestamp = repeat_info->wl_press_time_ns + repeat_info->next_repeat_ns;
-            SDL_SendKeyboardKeyIgnoreModifiers(Wayland_GetEventTimestamp(timestamp), repeat_info->keyboard_id, repeat_info->key, repeat_info->scancode, true);
+            SDL_SendKeyboardKeyIgnoreModifiers(Wayland_AdjustEventTimestampBase(timestamp), repeat_info->keyboard_id, repeat_info->key, repeat_info->scancode, true);
         }
         if (repeat_info->text[0]) {
             SDL_SendKeyboardText(repeat_info->text);
@@ -574,17 +567,15 @@ void Wayland_PumpEvents(SDL_VideoDevice *_this)
     }
 }
 
-static void pointer_handle_motion(void *data, struct wl_pointer *pointer,
-                                  uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
+static void pointer_handle_motion_common(SDL_WaylandSeat *seat, Uint64 nsTimestamp, wl_fixed_t sx_w, wl_fixed_t sy_w)
 {
-    SDL_WaylandSeat *seat = data;
     SDL_WindowData *window_data = seat->pointer.focus;
     SDL_Window *window = window_data ? window_data->sdlwindow : NULL;
 
     if (window_data) {
         const float sx = (float)(wl_fixed_to_double(sx_w) * window_data->pointer_scale.x);
         const float sy = (float)(wl_fixed_to_double(sy_w) * window_data->pointer_scale.y);
-        SDL_SendMouseMotion(Wayland_GetPointerTimestamp(seat, time), window_data->sdlwindow, seat->pointer.sdl_id, false, sx, sy);
+        SDL_SendMouseMotion(nsTimestamp, window_data->sdlwindow, seat->pointer.sdl_id, false, sx, sy);
 
         seat->pointer.last_motion.x = (int)SDL_floorf(sx);
         seat->pointer.last_motion.y = (int)SDL_floorf(sy);
@@ -678,6 +669,13 @@ static void pointer_handle_motion(void *data, struct wl_pointer *pointer,
     }
 }
 
+static void pointer_handle_motion(void *data, struct wl_pointer *pointer,
+                                  uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
+{
+    SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
+    pointer_handle_motion_common(seat, Wayland_GetPointerTimestamp(seat, time), sx_w, sy_w);
+}
+
 static void pointer_handle_enter(void *data, struct wl_pointer *pointer,
                                  uint32_t serial, struct wl_surface *surface,
                                  wl_fixed_t sx_w, wl_fixed_t sy_w)
@@ -706,7 +704,7 @@ static void pointer_handle_enter(void *data, struct wl_pointer *pointer,
      * FIXME: This causes a movement event with an anomalous timestamp when
      *        the cursor enters the window.
      */
-    pointer_handle_motion(data, pointer, 0, sx_w, sy_w);
+    pointer_handle_motion_common(seat, 0, sx_w, sy_w);
 
     // Update the pointer grab state.
     Wayland_SeatUpdatePointerGrab(seat);
@@ -845,11 +843,10 @@ static bool Wayland_ProcessHitTest(SDL_WaylandSeat *seat, Uint32 serial)
 }
 
 static void pointer_handle_button_common(SDL_WaylandSeat *seat, uint32_t serial,
-                                         uint32_t time, uint32_t button, uint32_t state_w)
+                                         Uint64 nsTimestamp, uint32_t button, uint32_t state_w)
 {
     SDL_WindowData *window = seat->pointer.focus;
     enum wl_pointer_button_state state = state_w;
-    Uint64 timestamp = Wayland_GetPointerTimestamp(seat, time);
     Uint8 sdl_button;
     const bool down = (state != 0);
 
@@ -913,7 +910,7 @@ static void pointer_handle_button_common(SDL_WaylandSeat *seat, uint32_t serial,
         }
 
         if (!ignore_click) {
-            SDL_SendMouseButton(timestamp, window->sdlwindow, seat->pointer.sdl_id, sdl_button, down);
+            SDL_SendMouseButton(nsTimestamp, window->sdlwindow, seat->pointer.sdl_id, sdl_button, down);
         }
     }
 }
@@ -922,15 +919,13 @@ static void pointer_handle_button(void *data, struct wl_pointer *pointer, uint32
                                   uint32_t time, uint32_t button, uint32_t state_w)
 {
     SDL_WaylandSeat *seat = data;
-
-    pointer_handle_button_common(seat, serial, time, button, state_w);
+    pointer_handle_button_common(seat, serial, Wayland_GetPointerTimestamp(seat, time), button, state_w);
 }
 
 static void pointer_handle_axis_common_v1(SDL_WaylandSeat *seat,
-                                          uint32_t time, uint32_t axis, wl_fixed_t value)
+                                          Uint64 nsTimestamp, uint32_t axis, wl_fixed_t value)
 {
     SDL_WindowData *window = seat->pointer.focus;
-    const Uint64 timestamp = Wayland_GetPointerTimestamp(seat, time);
     const enum wl_pointer_axis a = axis;
 
     if (seat->pointer.focus) {
@@ -952,7 +947,7 @@ static void pointer_handle_axis_common_v1(SDL_WaylandSeat *seat,
         x /= WAYLAND_WHEEL_AXIS_UNIT;
         y /= WAYLAND_WHEEL_AXIS_UNIT;
 
-        SDL_SendMouseWheel(timestamp, window->sdlwindow, seat->pointer.sdl_id, x, y, SDL_MOUSEWHEEL_NORMAL);
+        SDL_SendMouseWheel(nsTimestamp, window->sdlwindow, seat->pointer.sdl_id, x, y, SDL_MOUSEWHEEL_NORMAL);
     }
 }
 
@@ -1033,12 +1028,13 @@ static void pointer_handle_axis(void *data, struct wl_pointer *pointer,
                                 uint32_t time, uint32_t axis, wl_fixed_t value)
 {
     SDL_WaylandSeat *seat = data;
+    const Uint64 nsTimestamp = Wayland_GetPointerTimestamp(seat, time);
 
     if (wl_seat_get_version(seat->wl_seat) >= WL_POINTER_FRAME_SINCE_VERSION) {
-        seat->pointer.current_axis_info.timestamp_ns = Wayland_GetPointerTimestamp(seat, time);
+        seat->pointer.current_axis_info.timestamp_ns = nsTimestamp;
         pointer_handle_axis_common(seat, AXIS_EVENT_CONTINUOUS, axis, value);
     } else {
-        pointer_handle_axis_common_v1(seat, time, axis, value);
+        pointer_handle_axis_common_v1(seat, nsTimestamp, axis, value);
     }
 }
 
@@ -1166,7 +1162,7 @@ static void relative_pointer_handle_relative_motion(void *data,
             SDL_Mouse *mouse = SDL_GetMouse();
 
             // Relative pointer event times are in microsecond granularity.
-            const Uint64 timestamp = Wayland_GetEventTimestamp(SDL_US_TO_NS(((Uint64)time_hi << 32) | (Uint64)time_lo));
+            const Uint64 timestamp = Wayland_AdjustEventTimestampBase(SDL_US_TO_NS(((Uint64)time_hi << 32) | (Uint64)time_lo));
 
             double dx;
             double dy;
@@ -2022,7 +2018,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
 
     const SDL_Scancode scancode = Wayland_GetScancodeForKey(seat, key);
     Wayland_HandleModifierKeys(seat, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
-    Uint64 timestamp = Wayland_GetKeyboardTimestamp(seat, time);
+    Uint64 timestamp = Wayland_AdjustEventTimestampBase(timestamp_raw_ns);
 
     SDL_SendKeyboardKeyIgnoreModifiers(timestamp, seat->keyboard.sdl_id, key, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
 
@@ -3243,7 +3239,7 @@ static void tablet_tool_handle_frame(void *data, struct zwp_tablet_tool_v2 *tool
         return;  // Not a pen we report on.
     }
 
-    const Uint64 timestamp = Wayland_GetEventTimestamp(Wayland_EventTimestampMSToNS(time));
+    const Uint64 timestamp = Wayland_AdjustEventTimestampBase(Wayland_EventTimestampMSToNS(time));
     const SDL_PenID instance_id = sdltool->instance_id;
     SDL_Window *window = sdltool->tool_focus;