[mutter/cherry-pick-bf6dde87] compositor: Make sure _NET_WM_FRAME_DRAWN timestamp has the right scope




commit dd4a3b97f7270fb1b15c8ecae08bce33caa0ea8f
Author: Jonas Ådahl <jadahl gmail com>
Date:   Wed Jul 8 14:53:14 2020 +0000

    compositor: Make sure _NET_WM_FRAME_DRAWN timestamp has the right scope
    
    The timestamp sent with _NET_WM_FRAME_DRAWN should be in "high
    resolution X server timestamps", meaning they should have the same scope
    as the built in X11 32 bit unsigned integer timestamps, i.e. overflow at
    the same time.
    
    This was not done correctly when mutter had determined the X server used
    the monotonic clock, where it'd just forward the monotonic clock,
    confusing any client using _NET_WM_FRAME_DRAWN and friends.
    
    Fix this by 1) splitting the timestamp conversiot into an X11 case and a
    display server case, where the display server case simply clamps the
    monotonic clock, as it is assumed Xwayland is always usign the monotonic
    clock, and 2) if we're a X11 compositing manager, if the X server is
    using the monotonic clock, apply the same semantics as the display
    server case and always just clamp, or if not, calculate the offset every
    10 seconds, and offset the monotonic clock timestamp with the calculated
    X server timestamp offset.
    
    This fixes an issue that would occur if mutter (or rather GNOME Shell)
    would have been started before a X11 timestamp overflow, after the
    overflow happened. In this case, GTK3 clients would get unclamped
    timestamps, and get very confused, resulting in frames queued several
    weeks into the future.
    
    https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1494
    
    
    (cherry picked from commit bf6dde87f862bebce595d7cb35c74981a909cfe8)

 clutter/clutter/clutter-private.h       |  6 +++
 src/compositor/compositor-private.h     | 23 +++++++++++-
 src/compositor/compositor.c             | 39 +++-----------------
 src/compositor/meta-compositor-server.c |  9 +++++
 src/compositor/meta-compositor-x11.c    | 65 +++++++++++++++++++++++++++++++++
 src/compositor/meta-window-actor-x11.c  | 21 +++++++----
 6 files changed, 121 insertions(+), 42 deletions(-)
---
diff --git a/clutter/clutter/clutter-private.h b/clutter/clutter/clutter-private.h
index e4119b99fa..3211cb9d7c 100644
--- a/clutter/clutter/clutter-private.h
+++ b/clutter/clutter/clutter-private.h
@@ -337,6 +337,12 @@ ns2us (uint64_t ns)
   return us (ns / 1000);
 }
 
+static inline int64_t
+s2us (int64_t s)
+{
+  return ms2us (s * 1000);
+}
+
 G_END_DECLS
 
 #endif /* __CLUTTER_PRIVATE_H__ */
diff --git a/src/compositor/compositor-private.h b/src/compositor/compositor-private.h
index feb60b7e6b..b81e77d4cf 100644
--- a/src/compositor/compositor-private.h
+++ b/src/compositor/compositor-private.h
@@ -5,6 +5,7 @@
 
 #include <X11/extensions/Xfixes.h>
 
+#include "clutter/clutter-mutter.h"
 #include "clutter/clutter.h"
 #include "compositor/meta-plugin-manager.h"
 #include "compositor/meta-window-actor-private.h"
@@ -29,6 +30,8 @@ struct _MetaCompositorClass
                         ClutterStageView *stage_view);
   void (* remove_window) (MetaCompositor *compositor,
                           MetaWindow     *window);
+  int64_t (* monotonic_to_high_res_xserver_time) (MetaCompositor *compositor,
+                                                  int64_t         time_us);
 };
 
 gboolean meta_compositor_do_manage (MetaCompositor  *compositor,
@@ -49,8 +52,8 @@ void     meta_end_modal_for_plugin   (MetaCompositor   *compositor,
 
 MetaPluginManager * meta_compositor_get_plugin_manager (MetaCompositor *compositor);
 
-gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
-                                                      gint64       monotonic_time);
+int64_t meta_compositor_monotonic_to_high_res_xserver_time (MetaCompositor *compositor,
+                                                            int64_t         monotonic_time_us);
 
 void meta_compositor_flash_window (MetaCompositor *compositor,
                                    MetaWindow     *window);
@@ -77,4 +80,20 @@ gboolean meta_compositor_is_switching_workspace (MetaCompositor *compositor);
 
 MetaLaters * meta_compositor_get_laters (MetaCompositor *compositor);
 
+/*
+ * This function takes a 64 bit time stamp from the monotonic clock, and clamps
+ * it to the scope of the X server clock, without losing the granularity.
+ */
+static inline int64_t
+meta_translate_to_high_res_xserver_time (int64_t time_us)
+{
+  int64_t us;
+  int64_t ms;
+
+  us = time_us % 1000;
+  ms = time_us / 1000;
+
+  return ms2us (ms & 0xffffffff) + us;
+}
+
 #endif /* META_COMPOSITOR_PRIVATE_H */
diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c
index e5fc844a42..4206ced8dd 100644
--- a/src/compositor/compositor.c
+++ b/src/compositor/compositor.c
@@ -1458,7 +1458,7 @@ meta_compositor_flash_window (MetaCompositor *compositor,
 }
 
 /**
- * meta_compositor_monotonic_time_to_server_time:
+ * meta_compositor_monotonic_to_high_res_xserver_time:
  * @display: a #MetaDisplay
  * @monotonic_time: time in the units of g_get_monotonic_time()
  *
@@ -1471,40 +1471,13 @@ meta_compositor_flash_window (MetaCompositor *compositor,
  * a time representation with high accuracy. If there is not a common
  * time source, then the time synchronization will be less accurate.
  */
-gint64
-meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
-                                               gint64       monotonic_time)
+int64_t
+meta_compositor_monotonic_to_high_res_xserver_time (MetaCompositor *compositor,
+                                                   int64_t         monotonic_time_us)
 {
-  MetaCompositor *compositor = display->compositor;
-  MetaCompositorPrivate *priv =
-    meta_compositor_get_instance_private (compositor);
-
-  if (priv->server_time_query_time == 0 ||
-      (!priv->server_time_is_monotonic_time &&
-       monotonic_time > priv->server_time_query_time + 10*1000*1000)) /* 10 seconds */
-    {
-      guint32 server_time = meta_display_get_current_time_roundtrip (display);
-      gint64 server_time_usec = (gint64)server_time * 1000;
-      gint64 current_monotonic_time = g_get_monotonic_time ();
-      priv->server_time_query_time = current_monotonic_time;
-
-      /* If the server time is within a second of the monotonic time,
-       * we assume that they are identical. This seems like a big margin,
-       * but we want to be as robust as possible even if the system
-       * is under load and our processing of the server response is
-       * delayed.
-       */
-      if (server_time_usec > current_monotonic_time - 1000*1000 &&
-          server_time_usec < current_monotonic_time + 1000*1000)
-        priv->server_time_is_monotonic_time = TRUE;
-
-      priv->server_time_offset = server_time_usec - current_monotonic_time;
-    }
+  MetaCompositorClass *klass = META_COMPOSITOR_GET_CLASS (compositor);
 
-  if (priv->server_time_is_monotonic_time)
-    return monotonic_time;
-  else
-    return monotonic_time + priv->server_time_offset;
+  return klass->monotonic_to_high_res_xserver_time (compositor, monotonic_time_us);
 }
 
 void
diff --git a/src/compositor/meta-compositor-server.c b/src/compositor/meta-compositor-server.c
index f53c10a196..2dbaf34eb5 100644
--- a/src/compositor/meta-compositor-server.c
+++ b/src/compositor/meta-compositor-server.c
@@ -36,6 +36,13 @@ meta_compositor_server_unmanage (MetaCompositor *compositor)
 {
 }
 
+static int64_t
+meta_compositor_server_monotonic_to_high_res_xserver_time (MetaCompositor *compositor,
+                                                           int64_t         monotonic_time_us)
+{
+  return meta_translate_to_high_res_xserver_time (monotonic_time_us);
+}
+
 MetaCompositorServer *
 meta_compositor_server_new (MetaDisplay *display,
                             MetaBackend *backend)
@@ -58,4 +65,6 @@ meta_compositor_server_class_init (MetaCompositorServerClass *klass)
 
   compositor_class->manage = meta_compositor_server_manage;
   compositor_class->unmanage = meta_compositor_server_unmanage;
+  compositor_class->monotonic_to_high_res_xserver_time =
+   meta_compositor_server_monotonic_to_high_res_xserver_time;
 }
diff --git a/src/compositor/meta-compositor-x11.c b/src/compositor/meta-compositor-x11.c
index fcd292a1f3..e7da103e3a 100644
--- a/src/compositor/meta-compositor-x11.c
+++ b/src/compositor/meta-compositor-x11.c
@@ -45,6 +45,10 @@ struct _MetaCompositorX11
   gboolean have_x11_sync_object;
 
   MetaWindow *unredirected_window;
+
+  gboolean xserver_uses_monotonic_clock;
+  int64_t xserver_time_query_time_us;
+  int64_t xserver_time_offset_us;
 };
 
 G_DEFINE_TYPE (MetaCompositorX11, meta_compositor_x11, META_TYPE_COMPOSITOR)
@@ -102,6 +106,32 @@ meta_compositor_x11_process_xevent (MetaCompositorX11 *compositor_x11,
     meta_x11_handle_event (xevent);
 }
 
+static void
+determine_server_clock_source (MetaCompositorX11 *compositor_x11)
+{
+  MetaCompositor *compositor = META_COMPOSITOR (compositor_x11);
+  MetaDisplay *display = meta_compositor_get_display (compositor);
+  MetaX11Display *x11_display = display->x11_display;
+  uint32_t server_time_ms;
+  int64_t server_time_us;
+  int64_t translated_monotonic_now_us;
+
+  server_time_ms = meta_x11_display_get_current_time_roundtrip (x11_display);
+  server_time_us = ms2us (server_time_ms);
+  translated_monotonic_now_us =
+    meta_translate_to_high_res_xserver_time (g_get_monotonic_time ());
+
+  /* If the server time offset is within a second of the monotonic time, we
+   * assume that they are identical. This seems like a big margin, but we want
+   * to be as robust as possible even if the system is under load and our
+   * processing of the server response is delayed.
+   */
+  if (ABS (server_time_us - translated_monotonic_now_us) < s2us (1))
+    compositor_x11->xserver_uses_monotonic_clock = TRUE;
+  else
+    compositor_x11->xserver_uses_monotonic_clock = FALSE;
+}
+
 static gboolean
 meta_compositor_x11_manage (MetaCompositor  *compositor,
                             GError         **error)
@@ -135,6 +165,8 @@ meta_compositor_x11_manage (MetaCompositor  *compositor,
       return FALSE;
     }
 
+  determine_server_clock_source (compositor_x11);
+
   meta_x11_display_set_cm_selection (display->x11_display);
 
   compositor_x11->output = display->x11_display->composite_overlay_window;
@@ -376,6 +408,37 @@ meta_compositor_x11_remove_window (MetaCompositor *compositor,
   parent_class->remove_window (compositor, window);
 }
 
+static int64_t
+meta_compositor_x11_monotonic_to_high_res_xserver_time (MetaCompositor *compositor,
+                                                        int64_t         monotonic_time_us)
+{
+  MetaCompositorX11 *compositor_x11 = META_COMPOSITOR_X11 (compositor);
+  int64_t now_us;
+
+  if (compositor_x11->xserver_uses_monotonic_clock)
+    return meta_translate_to_high_res_xserver_time (monotonic_time_us);
+
+  now_us = g_get_monotonic_time ();
+
+  if (compositor_x11->xserver_time_query_time_us == 0 ||
+      now_us > (compositor_x11->xserver_time_query_time_us + s2us (10)))
+    {
+      MetaDisplay *display = meta_compositor_get_display (compositor);
+      MetaX11Display *x11_display = display->x11_display;
+      uint32_t xserver_time_ms;
+      int64_t xserver_time_us;
+
+      compositor_x11->xserver_time_query_time_us = now_us;
+
+      xserver_time_ms =
+        meta_x11_display_get_current_time_roundtrip (x11_display);
+      xserver_time_us = ms2us (xserver_time_ms);
+      compositor_x11->xserver_time_offset_us = xserver_time_us - now_us;
+    }
+
+  return monotonic_time_us + compositor_x11->xserver_time_offset_us;
+}
+
 Window
 meta_compositor_x11_get_output_xwindow (MetaCompositorX11 *compositor_x11)
 {
@@ -443,4 +506,6 @@ meta_compositor_x11_class_init (MetaCompositorX11Class *klass)
   compositor_class->before_paint = meta_compositor_x11_before_paint;
   compositor_class->after_paint = meta_compositor_x11_after_paint;
   compositor_class->remove_window = meta_compositor_x11_remove_window;
+  compositor_class->monotonic_to_high_res_xserver_time =
+   meta_compositor_x11_monotonic_to_high_res_xserver_time;
 }
diff --git a/src/compositor/meta-window-actor-x11.c b/src/compositor/meta-window-actor-x11.c
index f9577e752e..566aac4ec9 100644
--- a/src/compositor/meta-window-actor-x11.c
+++ b/src/compositor/meta-window-actor-x11.c
@@ -163,12 +163,14 @@ do_send_frame_drawn (MetaWindowActorX11 *actor_x11,
     meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11));
   MetaDisplay *display = meta_window_get_display (window);
   Display *xdisplay = meta_x11_display_get_xdisplay (display->x11_display);
+  int64_t now_us;
 
   XClientMessageEvent ev = { 0, };
 
+  now_us = g_get_monotonic_time ();
   frame->frame_drawn_time =
-    meta_compositor_monotonic_time_to_server_time (display,
-                                                   g_get_monotonic_time ());
+    meta_compositor_monotonic_to_high_res_xserver_time (display->compositor,
+                                                        now_us);
   actor_x11->frame_drawn_time = frame->frame_drawn_time;
 
   ev.type = ClientMessage;
@@ -208,9 +210,12 @@ do_send_frame_timings (MetaWindowActorX11 *actor_x11,
 
   if (presentation_time != 0)
     {
-      int64_t presentation_time_server =
-        meta_compositor_monotonic_time_to_server_time (display,
-                                                       presentation_time);
+      MetaCompositor *compositor = display->compositor;
+      int64_t presentation_time_server;
+
+      presentation_time_server =
+        meta_compositor_monotonic_to_high_res_xserver_time (compositor,
+                                                            presentation_time);
       int64_t presentation_time_offset = presentation_time_server - frame->frame_drawn_time;
       if (presentation_time_offset == 0)
         presentation_time_offset = 1;
@@ -283,6 +288,7 @@ queue_send_frame_messages_timeout (MetaWindowActorX11 *actor_x11)
     meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11));
   MetaDisplay *display = meta_window_get_display (window);
   MetaLogicalMonitor *logical_monitor;
+  int64_t now_us;
   int64_t current_time;
   float refresh_rate;
   int interval, offset;
@@ -307,9 +313,10 @@ queue_send_frame_messages_timeout (MetaWindowActorX11 *actor_x11)
       refresh_rate = 60.0f;
     }
 
+  now_us = g_get_monotonic_time ();
   current_time =
-    meta_compositor_monotonic_time_to_server_time (display,
-                                                   g_get_monotonic_time ());
+    meta_compositor_monotonic_to_high_res_xserver_time (display->compositor,
+                                                        now_us);
   interval = (int) (1000000 / refresh_rate) * 6;
   offset = MAX (0, actor_x11->frame_drawn_time + interval - current_time) / 1000;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]