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

4a39a8
From 3c64ba81e7844a6d3bfe1d171eda5d3cb052002f Mon Sep 17 00:00:00 2001
4a39a8
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@gmail.com>
4a39a8
Date: Fri, 11 Sep 2020 16:32:12 +0200
4a39a8
Subject: [PATCH] compositor: Make sure _NET_WM_FRAME_DRAWN timestamp has the
4a39a8
 right scope
4a39a8
4a39a8
The timestamp sent with _NET_WM_FRAME_DRAWN should be in "high
4a39a8
resolution X server timestamps", meaning they should have the same scope
4a39a8
as the built in X11 32 bit unsigned integer timestamps, i.e. overflow at
4a39a8
the same time.
4a39a8
4a39a8
This was not done correctly when mutter had determined the X server used
4a39a8
the monotonic clock, where it'd just forward the monotonic clock,
4a39a8
confusing any client using _NET_WM_FRAME_DRAWN and friends.
4a39a8
4a39a8
Fix this by 1) splitting the timestamp conversiot into an X11 case and a
4a39a8
display server case, where the display server case simply clamps the
4a39a8
monotonic clock, as it is assumed Xwayland is always usign the monotonic
4a39a8
clock, and 2) if we're a X11 compositing manager, if the X server is
4a39a8
using the monotonic clock, apply the same semantics as the display
4a39a8
server case and always just clamp, or if not, calculate the offset every
4a39a8
10 seconds, and offset the monotonic clock timestamp with the calculated
4a39a8
X server timestamp offset.
4a39a8
4a39a8
This fixes an issue that would occur if mutter (or rather GNOME Shell)
4a39a8
would have been started before a X11 timestamp overflow, after the
4a39a8
overflow happened. In this case, GTK3 clients would get unclamped
4a39a8
timestamps, and get very confused, resulting in frames queued several
4a39a8
weeks into the future.
4a39a8
---
4a39a8
 src/compositor/compositor-private.h | 43 +++++++++++--
4a39a8
 src/compositor/compositor.c         | 95 +++++++++++++++++++++--------
4a39a8
 src/compositor/meta-window-actor.c  | 22 +++++--
4a39a8
 3 files changed, 123 insertions(+), 37 deletions(-)
4a39a8
4a39a8
diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h
4a39a8
index 25cab92805..d4cb9bbdc2 100644
4a39a8
--- a/src/compositor/compositor-private.h
4a39a8
+++ b/src/compositor/compositor-private.h
4a39a8
@@ -18,8 +18,9 @@ struct _MetaCompositor
4a39a8
   guint           pre_paint_func_id;
4a39a8
   guint           post_paint_func_id;
4a39a8
 
4a39a8
-  gint64          server_time_query_time;
4a39a8
-  gint64          server_time_offset;
4a39a8
+  gboolean xserver_uses_monotonic_clock;
4a39a8
+  int64_t xserver_time_query_time_us;
4a39a8
+  int64_t xserver_time_offset_us;
4a39a8
 
4a39a8
   int             glx_opcode;
4a39a8
   guint           stereo_tree_ext : 1;
4a39a8
@@ -62,8 +63,8 @@ void     meta_end_modal_for_plugin   (MetaCompositor   *compositor,
4a39a8
                                       MetaPlugin       *plugin,
4a39a8
                                       guint32           timestamp);
4a39a8
 
4a39a8
-gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
4a39a8
-                                                      gint64       monotonic_time);
4a39a8
+int64_t meta_compositor_monotonic_to_high_res_xserver_time (MetaCompositor *compositor,
4a39a8
+                                                            int64_t         monotonic_time);
4a39a8
 
4a39a8
 gboolean meta_compositor_window_is_stereo     (MetaScreen *screen,
4a39a8
                                                Window      xwindow);
4a39a8
@@ -79,4 +80,38 @@ MetaCloseDialog * meta_compositor_create_close_dialog (MetaCompositor *composito
4a39a8
 MetaInhibitShortcutsDialog * meta_compositor_create_inhibit_shortcuts_dialog (MetaCompositor *compositor,
4a39a8
                                                                               MetaWindow     *window);
4a39a8
 
4a39a8
+static inline int64_t
4a39a8
+us (int64_t us)
4a39a8
+{
4a39a8
+  return us;
4a39a8
+}
4a39a8
+
4a39a8
+static inline int64_t
4a39a8
+ms2us (int64_t ms)
4a39a8
+{
4a39a8
+  return us (ms * 1000);
4a39a8
+}
4a39a8
+
4a39a8
+static inline int64_t
4a39a8
+s2us (int64_t s)
4a39a8
+{
4a39a8
+  return ms2us(s * 1000);
4a39a8
+}
4a39a8
+
4a39a8
+/*
4a39a8
+ * This function takes a 64 bit time stamp from the monotonic clock, and clamps
4a39a8
+ * it to the scope of the X server clock, without losing the granularity.
4a39a8
+ */
4a39a8
+static inline int64_t
4a39a8
+meta_translate_to_high_res_xserver_time (int64_t time_us)
4a39a8
+{
4a39a8
+  int64_t us;
4a39a8
+  int64_t ms;
4a39a8
+
4a39a8
+  us = time_us % 1000;
4a39a8
+  ms = time_us / 1000;
4a39a8
+
4a39a8
+  return ms2us (ms & 0xffffffff) + us;
4a39a8
+}
4a39a8
+
4a39a8
 #endif /* META_COMPOSITOR_PRIVATE_H */
4a39a8
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
4a39a8
index 799bcddf5a..d8df1df015 100644
4a39a8
--- a/src/compositor/compositor.c
4a39a8
+++ b/src/compositor/compositor.c
4a39a8
@@ -580,6 +580,30 @@ meta_compositor_select_stereo_notify (MetaScreen *screen,
4a39a8
     }
4a39a8
 }
4a39a8
 
4a39a8
+static void
4a39a8
+determine_server_clock_source (MetaCompositor *compositor)
4a39a8
+{
4a39a8
+  MetaDisplay *display = compositor->display;
4a39a8
+  uint32_t server_time_ms;
4a39a8
+  int64_t server_time_us;
4a39a8
+  int64_t translated_monotonic_now_us;
4a39a8
+
4a39a8
+  server_time_ms = meta_display_get_current_time_roundtrip (display);
4a39a8
+  server_time_us = ms2us (server_time_ms);
4a39a8
+  translated_monotonic_now_us =
4a39a8
+    meta_translate_to_high_res_xserver_time (g_get_monotonic_time ());
4a39a8
+
4a39a8
+  /* If the server time offset is within a second of the monotonic time, we
4a39a8
+   * assume that they are identical. This seems like a big margin, but we want
4a39a8
+   * to be as robust as possible even if the system is under load and our
4a39a8
+   * processing of the server response is delayed.
4a39a8
+   */
4a39a8
+  if (ABS (server_time_us - translated_monotonic_now_us) < s2us (1))
4a39a8
+    compositor->xserver_uses_monotonic_clock = TRUE;
4a39a8
+  else
4a39a8
+    compositor->xserver_uses_monotonic_clock = FALSE;
4a39a8
+}
4a39a8
+
4a39a8
 void
4a39a8
 meta_compositor_manage (MetaCompositor *compositor)
4a39a8
 {
4a39a8
@@ -588,6 +612,8 @@ meta_compositor_manage (MetaCompositor *compositor)
4a39a8
   MetaScreen *screen = display->screen;
4a39a8
   MetaBackend *backend = meta_get_backend ();
4a39a8
 
4a39a8
+  determine_server_clock_source (compositor);
4a39a8
+
4a39a8
   compositor->stereo_tree_ext = screen_has_stereo_tree_ext (screen);
4a39a8
 
4a39a8
   meta_screen_set_cm_selection (display->screen);
4a39a8
@@ -1524,6 +1550,40 @@ meta_compositor_flash_window (MetaCompositor *compositor,
4a39a8
   clutter_actor_restore_easing_state (flash);
4a39a8
 }
4a39a8
 
4a39a8
+static int64_t
4a39a8
+meta_compositor_monotonic_to_high_res_xserver_time_x11 (MetaCompositor *compositor,
4a39a8
+                                                        int64_t         monotonic_time_us)
4a39a8
+{
4a39a8
+  int64_t now_us;
4a39a8
+
4a39a8
+  if (compositor->xserver_uses_monotonic_clock)
4a39a8
+    return meta_translate_to_high_res_xserver_time (monotonic_time_us);
4a39a8
+
4a39a8
+  now_us = g_get_monotonic_time ();
4a39a8
+
4a39a8
+  if (compositor->xserver_time_query_time_us == 0 ||
4a39a8
+      now_us > (compositor->xserver_time_query_time_us + s2us (10)))
4a39a8
+    {
4a39a8
+      MetaDisplay *display = compositor->display;
4a39a8
+      uint32_t xserver_time_ms;
4a39a8
+      int64_t xserver_time_us;
4a39a8
+
4a39a8
+      compositor->xserver_time_query_time_us = now_us;
4a39a8
+
4a39a8
+      xserver_time_ms = meta_display_get_current_time_roundtrip (display);
4a39a8
+      xserver_time_us = ms2us (xserver_time_ms);
4a39a8
+      compositor->xserver_time_offset_us = xserver_time_us - now_us;
4a39a8
+    }
4a39a8
+
4a39a8
+  return monotonic_time_us + compositor->xserver_time_offset_us;
4a39a8
+}
4a39a8
+
4a39a8
+static int64_t
4a39a8
+meta_compositor_monotonic_to_high_res_xserver_time_server (int64_t monotonic_time_us)
4a39a8
+{
4a39a8
+  return meta_translate_to_high_res_xserver_time (monotonic_time_us);
4a39a8
+}
4a39a8
+
4a39a8
 /**
4a39a8
  * meta_compositor_monotonic_time_to_server_time:
4a39a8
  * @display: a #MetaDisplay
4a39a8
@@ -1539,37 +1599,18 @@ meta_compositor_flash_window (MetaCompositor *compositor,
4a39a8
  * time source, then the time synchronization will be less accurate.
4a39a8
  */
4a39a8
 gint64
4a39a8
-meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
4a39a8
-                                               gint64       monotonic_time)
4a39a8
+meta_compositor_monotonic_to_high_res_xserver_time (MetaCompositor *compositor,
4a39a8
+                                                    int64_t         monotonic_time)
4a39a8
 {
4a39a8
-  MetaCompositor *compositor = display->compositor;
4a39a8
-
4a39a8
-  if (compositor->server_time_query_time == 0 ||
4a39a8
-      (!compositor->server_time_is_monotonic_time &&
4a39a8
-       monotonic_time > compositor->server_time_query_time + 10*1000*1000)) /* 10 seconds */
4a39a8
+  if (meta_is_wayland_compositor ())
4a39a8
     {
4a39a8
-      guint32 server_time = meta_display_get_current_time_roundtrip (display);
4a39a8
-      gint64 server_time_usec = (gint64)server_time * 1000;
4a39a8
-      gint64 current_monotonic_time = g_get_monotonic_time ();
4a39a8
-      compositor->server_time_query_time = current_monotonic_time;
4a39a8
-
4a39a8
-      /* If the server time is within a second of the monotonic time,
4a39a8
-       * we assume that they are identical. This seems like a big margin,
4a39a8
-       * but we want to be as robust as possible even if the system
4a39a8
-       * is under load and our processing of the server response is
4a39a8
-       * delayed.
4a39a8
-       */
4a39a8
-      if (server_time_usec > current_monotonic_time - 1000*1000 &&
4a39a8
-          server_time_usec < current_monotonic_time + 1000*1000)
4a39a8
-        compositor->server_time_is_monotonic_time = TRUE;
4a39a8
-
4a39a8
-      compositor->server_time_offset = server_time_usec - current_monotonic_time;
4a39a8
+      return meta_compositor_monotonic_to_high_res_xserver_time_server (monotonic_time);
4a39a8
     }
4a39a8
-
4a39a8
-  if (compositor->server_time_is_monotonic_time)
4a39a8
-    return monotonic_time;
4a39a8
   else
4a39a8
-    return monotonic_time + compositor->server_time_offset;
4a39a8
+    {
4a39a8
+      return meta_compositor_monotonic_to_high_res_xserver_time_x11 (compositor,
4a39a8
+                                                                     monotonic_time);
4a39a8
+    }
4a39a8
 }
4a39a8
 
4a39a8
 void
4a39a8
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
4a39a8
index f1f86e14b6..82dde9a2a3 100644
4a39a8
--- a/src/compositor/meta-window-actor.c
4a39a8
+++ b/src/compositor/meta-window-actor.c
4a39a8
@@ -973,6 +973,7 @@ queue_send_frame_messages_timeout (MetaWindowActor *self)
4a39a8
   MetaWindow *window = priv->window;
4a39a8
   MetaDisplay *display = meta_window_get_display (priv->window);
4a39a8
   MetaLogicalMonitor *logical_monitor;
4a39a8
+  int64_t now_us;
4a39a8
   int64_t current_time;
4a39a8
   float refresh_rate;
4a39a8
   int interval, offset;
4a39a8
@@ -997,9 +998,10 @@ queue_send_frame_messages_timeout (MetaWindowActor *self)
4a39a8
       refresh_rate = 60.0f;
4a39a8
     }
4a39a8
 
4a39a8
+  now_us = g_get_monotonic_time ();
4a39a8
   current_time =
4a39a8
-    meta_compositor_monotonic_time_to_server_time (display,
4a39a8
-                                                   g_get_monotonic_time ());
4a39a8
+    meta_compositor_monotonic_to_high_res_xserver_time (display->compositor,
4a39a8
+                                                        now_us);
4a39a8
   interval = (int)(1000000 / refresh_rate) * 6;
4a39a8
   offset = MAX (0, priv->frame_drawn_time + interval - current_time) / 1000;
4a39a8
 
4a39a8
@@ -2009,11 +2011,14 @@ do_send_frame_drawn (MetaWindowActor *self, FrameData *frame)
4a39a8
   MetaWindowActorPrivate *priv = self->priv;
4a39a8
   MetaDisplay *display = meta_window_get_display (priv->window);
4a39a8
   Display *xdisplay = meta_display_get_xdisplay (display);
4a39a8
+  int64_t now_us;
4a39a8
 
4a39a8
   XClientMessageEvent ev = { 0, };
4a39a8
 
4a39a8
-  frame->frame_drawn_time = meta_compositor_monotonic_time_to_server_time (display,
4a39a8
-                                                                           g_get_monotonic_time ());
4a39a8
+  now_us = g_get_monotonic_time ();
4a39a8
+  frame->frame_drawn_time =
4a39a8
+    meta_compositor_monotonic_to_high_res_xserver_time (display->compositor, now_us);
4a39a8
+
4a39a8
   priv->frame_drawn_time = frame->frame_drawn_time;
4a39a8
 
4a39a8
   ev.type = ClientMessage;
4a39a8
@@ -2089,8 +2094,13 @@ do_send_frame_timings (MetaWindowActor  *self,
4a39a8
 
4a39a8
   if (presentation_time != 0)
4a39a8
     {
4a39a8
-      gint64 presentation_time_server = meta_compositor_monotonic_time_to_server_time (display,
4a39a8
-                                                                                       presentation_time);
4a39a8
+      MetaCompositor *compositor = display->compositor;
4a39a8
+      int64_t presentation_time_server;
4a39a8
+
4a39a8
+      presentation_time_server =
4a39a8
+        meta_compositor_monotonic_to_high_res_xserver_time (compositor,
4a39a8
+                                                            presentation_time);
4a39a8
+
4a39a8
       gint64 presentation_time_offset = presentation_time_server - frame->frame_drawn_time;
4a39a8
       if (presentation_time_offset == 0)
4a39a8
         presentation_time_offset = 1;
4a39a8
-- 
4a39a8
2.35.3
4a39a8