diff --git a/clutter/clutter/clutter-private.h b/clutter/clutter/clutter-private.h index 7e3b63cfa..a504b74ba 100644 --- a/clutter/clutter/clutter-private.h +++ b/clutter/clutter/clutter-private.h @@ -298,6 +298,12 @@ ns2us (int64_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 feb60b7e6..b81e77d4c 100644 --- a/src/compositor/compositor-private.h +++ b/src/compositor/compositor-private.h @@ -5,6 +5,7 @@ #include +#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 6583b2ade..3be8d2e9e 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); + MetaCompositorClass *klass = META_COMPOSITOR_GET_CLASS (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; - } - - 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 f53c10a19..2dbaf34eb 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 fcd292a1f..e7da103e3 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 f9577e752..566aac4ec 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;