Blame SOURCES/0001-compositor-Make-sure-_NET_WM_FRAME_DRAWN-timestamp-h.patch

6ddca0
From b0f3604cdb653ef133f9684adffeb6b93f6906f8 Mon Sep 17 00:00:00 2001
6ddca0
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
6ddca0
Date: Wed, 26 Jan 2022 10:51:07 +0100
6ddca0
Subject: [PATCH] compositor: Make sure _NET_WM_FRAME_DRAWN timestamp has the
6ddca0
 right scope
6ddca0
6ddca0
The timestamp sent with _NET_WM_FRAME_DRAWN should be in "high
6ddca0
resolution X server timestamps", meaning they should have the same scope
6ddca0
as the built in X11 32 bit unsigned integer timestamps, i.e. overflow at
6ddca0
the same time.
6ddca0
6ddca0
This was not done correctly when mutter had determined the X server used
6ddca0
the monotonic clock, where it'd just forward the monotonic clock,
6ddca0
confusing any client using _NET_WM_FRAME_DRAWN and friends.
6ddca0
6ddca0
Fix this by 1) splitting the timestamp conversiot into an X11 case and a
6ddca0
display server case, where the display server case simply clamps the
6ddca0
monotonic clock, as it is assumed Xwayland is always usign the monotonic
6ddca0
clock, and 2) if we're a X11 compositing manager, if the X server is
6ddca0
using the monotonic clock, apply the same semantics as the display
6ddca0
server case and always just clamp, or if not, calculate the offset every
6ddca0
10 seconds, and offset the monotonic clock timestamp with the calculated
6ddca0
X server timestamp offset.
6ddca0
6ddca0
This fixes an issue that would occur if mutter (or rather GNOME Shell)
6ddca0
would have been started before a X11 timestamp overflow, after the
6ddca0
overflow happened. In this case, GTK3 clients would get unclamped
6ddca0
timestamps, and get very confused, resulting in frames queued several
6ddca0
weeks into the future.
6ddca0
---
6ddca0
 src/compositor/compositor-private.h    |   9 +-
6ddca0
 src/compositor/compositor.c            | 117 +++++++++++++++++++------
6ddca0
 src/compositor/meta-window-actor-x11.c |  12 +--
6ddca0
 3 files changed, 104 insertions(+), 34 deletions(-)
6ddca0
6ddca0
diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h
6ddca0
index f7008751215d..4588a8af7f2f 100644
6ddca0
--- a/src/compositor/compositor-private.h
6ddca0
+++ b/src/compositor/compositor-private.h
6ddca0
@@ -49,6 +49,10 @@ struct _MetaCompositor
6ddca0
 
6ddca0
   gboolean frame_has_updated_xsurfaces;
6ddca0
   gboolean have_x11_sync_object;
6ddca0
+
6ddca0
+  gboolean xserver_uses_monotonic_clock;
6ddca0
+  int64_t xserver_time_query_time_us;
6ddca0
+  int64_t xserver_time_offset_us;
6ddca0
 };
6ddca0
 
6ddca0
 /* Wait 2ms after vblank before starting to draw next frame */
6ddca0
@@ -64,8 +68,9 @@ void     meta_end_modal_for_plugin   (MetaCompositor   *compositor,
6ddca0
                                       MetaPlugin       *plugin,
6ddca0
                                       guint32           timestamp);
6ddca0
 
6ddca0
-gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
6ddca0
-                                                      gint64       monotonic_time);
6ddca0
+int64_t
6ddca0
+meta_compositor_monotonic_to_high_res_xserver_time (MetaDisplay *display,
6ddca0
+                                                    int64_t      monotonic_time_us);
6ddca0
 
6ddca0
 gboolean meta_compositor_window_is_stereo     (MetaDisplay *display,
6ddca0
                                                Window       xwindow);
6ddca0
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
6ddca0
index ce2c1b8a3bc1..a3fbe5d888f9 100644
6ddca0
--- a/src/compositor/compositor.c
6ddca0
+++ b/src/compositor/compositor.c
6ddca0
@@ -88,6 +88,40 @@
6ddca0
 #include "wayland/meta-wayland-private.h"
6ddca0
 #endif
6ddca0
 
6ddca0
+static inline int64_t
6ddca0
+us (int64_t us)
6ddca0
+{
6ddca0
+  return us;
6ddca0
+}
6ddca0
+
6ddca0
+static inline int64_t
6ddca0
+ms2us (int64_t ms)
6ddca0
+{
6ddca0
+  return us (ms * 1000);
6ddca0
+}
6ddca0
+
6ddca0
+static inline int64_t
6ddca0
+s2us (int64_t s)
6ddca0
+{
6ddca0
+  return ms2us(s * 1000);
6ddca0
+}
6ddca0
+
6ddca0
+/*
6ddca0
+ * This function takes a 64 bit time stamp from the monotonic clock, and clamps
6ddca0
+ * it to the scope of the X server clock, without losing the granularity.
6ddca0
+ */
6ddca0
+static inline int64_t
6ddca0
+meta_translate_to_high_res_xserver_time (int64_t time_us)
6ddca0
+{
6ddca0
+  int64_t us;
6ddca0
+  int64_t ms;
6ddca0
+
6ddca0
+  us = time_us % 1000;
6ddca0
+  ms = time_us / 1000;
6ddca0
+
6ddca0
+  return ms2us (ms & 0xffffffff) + us;
6ddca0
+}
6ddca0
+
6ddca0
 static void
6ddca0
 on_presented (ClutterStage     *stage,
6ddca0
               CoglFrameEvent    event,
6ddca0
@@ -612,6 +646,37 @@ meta_compositor_select_stereo_notify (MetaDisplay *display,
6ddca0
     }
6ddca0
 }
6ddca0
 
6ddca0
+static void
6ddca0
+determine_server_clock_source (MetaCompositor *compositor)
6ddca0
+{
6ddca0
+  MetaDisplay *display = compositor->display;
6ddca0
+  MetaX11Display *x11_display = display->x11_display;
6ddca0
+  uint32_t server_time_ms;
6ddca0
+  int64_t server_time_us;
6ddca0
+  int64_t translated_monotonic_now_us;
6ddca0
+
6ddca0
+  if (meta_is_wayland_compositor ())
6ddca0
+    {
6ddca0
+      compositor->xserver_uses_monotonic_clock = TRUE;
6ddca0
+      return;
6ddca0
+    }
6ddca0
+
6ddca0
+  server_time_ms = meta_x11_display_get_current_time_roundtrip (x11_display);
6ddca0
+  server_time_us = ms2us (server_time_ms);
6ddca0
+  translated_monotonic_now_us =
6ddca0
+    meta_translate_to_high_res_xserver_time (g_get_monotonic_time ());
6ddca0
+
6ddca0
+  /* If the server time offset is within a second of the monotonic time, we
6ddca0
+   * assume that they are identical. This seems like a big margin, but we want
6ddca0
+   * to be as robust as possible even if the system is under load and our
6ddca0
+   * processing of the server response is delayed.
6ddca0
+   */
6ddca0
+  if (ABS (server_time_us - translated_monotonic_now_us) < s2us (1))
6ddca0
+    compositor->xserver_uses_monotonic_clock = TRUE;
6ddca0
+  else
6ddca0
+    compositor->xserver_uses_monotonic_clock = FALSE;
6ddca0
+}
6ddca0
+
6ddca0
 void
6ddca0
 meta_compositor_manage (MetaCompositor *compositor)
6ddca0
 {
6ddca0
@@ -622,6 +687,9 @@ meta_compositor_manage (MetaCompositor *compositor)
6ddca0
   if (display->x11_display)
6ddca0
     {
6ddca0
       xdisplay = display->x11_display->xdisplay;
6ddca0
+
6ddca0
+      determine_server_clock_source (compositor);
6ddca0
+
6ddca0
       meta_x11_display_set_cm_selection (display->x11_display);
6ddca0
 
6ddca0
       compositor->stereo_tree_ext = display_has_stereo_tree_ext (display->x11_display);
6ddca0
@@ -1593,7 +1661,7 @@ meta_compositor_flash_window (MetaCompositor *compositor,
6ddca0
 }
6ddca0
 
6ddca0
 /**
6ddca0
- * meta_compositor_monotonic_time_to_server_time:
6ddca0
+ * meta_compositor_monotonic_to_high_res_xserver_time:
6ddca0
  * @display: a #MetaDisplay
6ddca0
  * @monotonic_time: time in the units of g_get_monotonic_time()
6ddca0
  *
6ddca0
@@ -1606,38 +1674,35 @@ meta_compositor_flash_window (MetaCompositor *compositor,
6ddca0
  * a time representation with high accuracy. If there is not a common
6ddca0
  * time source, then the time synchronization will be less accurate.
6ddca0
  */
6ddca0
-gint64
6ddca0
-meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
6ddca0
-                                               gint64       monotonic_time)
6ddca0
+int64_t
6ddca0
+meta_compositor_monotonic_to_high_res_xserver_time (MetaDisplay *display,
6ddca0
+                                                    int64_t      monotonic_time_us)
6ddca0
 {
6ddca0
   MetaCompositor *compositor = display->compositor;
6ddca0
+  int64_t now_us;
6ddca0
+
6ddca0
+  if (compositor->xserver_uses_monotonic_clock)
6ddca0
+    return meta_translate_to_high_res_xserver_time (monotonic_time_us);
6ddca0
 
6ddca0
-  if (compositor->server_time_query_time == 0 ||
6ddca0
-      (!compositor->server_time_is_monotonic_time &&
6ddca0
-       monotonic_time > compositor->server_time_query_time + 10*1000*1000)) /* 10 seconds */
6ddca0
+  now_us = g_get_monotonic_time ();
6ddca0
+
6ddca0
+  if (compositor->xserver_time_query_time_us == 0 ||
6ddca0
+      now_us > (compositor->xserver_time_query_time_us + s2us (10)))
6ddca0
     {
6ddca0
-      guint32 server_time = meta_display_get_current_time_roundtrip (display);
6ddca0
-      gint64 server_time_usec = (gint64)server_time * 1000;
6ddca0
-      gint64 current_monotonic_time = g_get_monotonic_time ();
6ddca0
-      compositor->server_time_query_time = current_monotonic_time;
6ddca0
-
6ddca0
-      /* If the server time is within a second of the monotonic time,
6ddca0
-       * we assume that they are identical. This seems like a big margin,
6ddca0
-       * but we want to be as robust as possible even if the system
6ddca0
-       * is under load and our processing of the server response is
6ddca0
-       * delayed.
6ddca0
-       */
6ddca0
-      if (server_time_usec > current_monotonic_time - 1000*1000 &&
6ddca0
-          server_time_usec < current_monotonic_time + 1000*1000)
6ddca0
-        compositor->server_time_is_monotonic_time = TRUE;
6ddca0
+      MetaDisplay *display = compositor->display;
6ddca0
+      MetaX11Display *x11_display = display->x11_display;
6ddca0
+      uint32_t xserver_time_ms;
6ddca0
+      int64_t xserver_time_us;
6ddca0
 
6ddca0
-      compositor->server_time_offset = server_time_usec - current_monotonic_time;
6ddca0
+      compositor->xserver_time_query_time_us = now_us;
6ddca0
+
6ddca0
+      xserver_time_ms =
6ddca0
+        meta_x11_display_get_current_time_roundtrip (x11_display);
6ddca0
+      xserver_time_us = ms2us (xserver_time_ms);
6ddca0
+      compositor->xserver_time_offset_us = xserver_time_us - now_us;
6ddca0
     }
6ddca0
 
6ddca0
-  if (compositor->server_time_is_monotonic_time)
6ddca0
-    return monotonic_time;
6ddca0
-  else
6ddca0
-    return monotonic_time + compositor->server_time_offset;
6ddca0
+  return monotonic_time_us + compositor->xserver_time_offset_us;
6ddca0
 }
6ddca0
 
6ddca0
 void
6ddca0
diff --git a/src/compositor/meta-window-actor-x11.c b/src/compositor/meta-window-actor-x11.c
6ddca0
index a364323fe057..2b9c25510dc9 100644
6ddca0
--- a/src/compositor/meta-window-actor-x11.c
6ddca0
+++ b/src/compositor/meta-window-actor-x11.c
6ddca0
@@ -105,8 +105,8 @@ do_send_frame_drawn (MetaWindowActorX11 *actor_x11,
6ddca0
   XClientMessageEvent ev = { 0, };
6ddca0
 
6ddca0
   frame->frame_drawn_time =
6ddca0
-    meta_compositor_monotonic_time_to_server_time (display,
6ddca0
-                                                   g_get_monotonic_time ());
6ddca0
+    meta_compositor_monotonic_to_high_res_xserver_time (display,
6ddca0
+                                                        g_get_monotonic_time ());
6ddca0
   actor_x11->frame_drawn_time = frame->frame_drawn_time;
6ddca0
 
6ddca0
   ev.type = ClientMessage;
6ddca0
@@ -147,8 +147,8 @@ do_send_frame_timings (MetaWindowActorX11 *actor_x11,
6ddca0
   if (presentation_time != 0)
6ddca0
     {
6ddca0
       int64_t presentation_time_server =
6ddca0
-        meta_compositor_monotonic_time_to_server_time (display,
6ddca0
-                                                       presentation_time);
6ddca0
+        meta_compositor_monotonic_to_high_res_xserver_time (display,
6ddca0
+                                                            presentation_time);
6ddca0
       int64_t presentation_time_offset = presentation_time_server - frame->frame_drawn_time;
6ddca0
       if (presentation_time_offset == 0)
6ddca0
         presentation_time_offset = 1;
6ddca0
@@ -246,8 +246,8 @@ queue_send_frame_messages_timeout (MetaWindowActorX11 *actor_x11)
6ddca0
     }
6ddca0
 
6ddca0
   current_time =
6ddca0
-    meta_compositor_monotonic_time_to_server_time (display,
6ddca0
-                                                   g_get_monotonic_time ());
6ddca0
+    meta_compositor_monotonic_to_high_res_xserver_time (display,
6ddca0
+                                                        g_get_monotonic_time ());
6ddca0
   interval = (int) (1000000 / refresh_rate) * 6;
6ddca0
   offset = MAX (0, actor_x11->frame_drawn_time + interval - current_time) / 1000;
6ddca0
 
6ddca0
-- 
6ddca0
2.33.1
6ddca0