diff options
author | Owen W. Taylor <otaylor@fishsoup.net> | 2015-07-15 12:38:38 -0400 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2015-07-15 12:46:06 -0400 |
commit | 6504b2e53468004c7936e7f79fba03291dc58128 (patch) | |
tree | d239d5d8962d9bfc127789c05379c9ce5288de40 | |
parent | 24e1323eb33f22c1126d1701639b2605c4443868 (diff) | |
download | gtk+-6504b2e53468004c7936e7f79fba03291dc58128.tar.gz |
GdkDisplayX11: Properly translate server timestamps from _NET_WM_FRAME_* messages
When using frame times from _NET_WM_FRAME_DRAWN and _NET_WM_FRAME_TIMINGS, we
were treating them as local monotonic times, but they are actually extended-precision
versions of the server time, and need to be translated to monotonic times in the
case where the X server and client aren't running on the same system.
This fixes rendering stalls when using X over a remote ssh connection.
https://bugzilla.gnome.org/show_bug.cgi?id=741800
-rw-r--r-- | gdk/x11/gdkdisplay-x11.c | 43 | ||||
-rw-r--r-- | gdk/x11/gdkdisplay-x11.h | 6 |
2 files changed, 48 insertions, 1 deletions
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c index da4382fad7..f2824b65bd 100644 --- a/gdk/x11/gdkdisplay-x11.c +++ b/gdk/x11/gdkdisplay-x11.c @@ -1108,6 +1108,47 @@ find_frame_timings (GdkFrameClock *clock, return NULL; } +/* _NET_WM_FRAME_DRAWN and _NET_WM_FRAME_TIMINGS messages represent time + * as a "high resolution server time" - this is the server time interpolated + * to microsecond resolution. The advantage of this time representation + * is that if X server is running on the same computer as a client, and + * the Xserver uses 'clock_gettime(CLOCK_MONOTONIC, ...)' for the server + * time, the client can detect this, and all such clients will share a + * a time representation with high accuracy. If there is not a common + * time source, then the time synchronization will be less accurate. + */ +gint64 +server_time_to_monotonic_time (GdkX11Display *display_x11, + gint64 server_time) +{ + if (display_x11->server_time_query_time == 0 || + (!display_x11->server_time_is_monotonic_time && + server_time > display_x11->server_time_query_time + 10*1000*1000)) /* 10 seconds */ + { + gint64 current_server_time = gdk_x11_get_server_time (display_x11->leader_gdk_window); + gint64 current_server_time_usec = (gint64)current_server_time * 1000; + gint64 current_monotonic_time = g_get_monotonic_time (); + display_x11->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 (current_server_time_usec > current_monotonic_time - 1000*1000 && + current_server_time_usec < current_monotonic_time + 1000*1000) + display_x11->server_time_is_monotonic_time = TRUE; + + display_x11->server_time_offset = current_server_time_usec - current_monotonic_time; + } + + if (display_x11->server_time_is_monotonic_time) + return server_time; + else + return server_time - display_x11->server_time_offset; +} + GdkFilterReturn _gdk_wm_protocols_filter (GdkXEvent *xev, GdkEvent *event, @@ -1140,7 +1181,7 @@ _gdk_wm_protocols_filter (GdkXEvent *xev, guint32 d3 = xevent->xclient.data.l[3]; guint64 serial = ((guint64)d1 << 32) | d0; - gint64 frame_drawn_time = ((guint64)d3 << 32) | d2; + gint64 frame_drawn_time = server_time_to_monotonic_time (GDK_X11_DISPLAY (display), ((guint64)d3 << 32) | d2); gint64 refresh_interval, presentation_time; GdkFrameClock *clock = gdk_window_get_frame_clock (win); diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h index b0c49a0858..aadf255ba6 100644 --- a/gdk/x11/gdkdisplay-x11.h +++ b/gdk/x11/gdkdisplay-x11.h @@ -131,6 +131,12 @@ struct _GdkX11Display gint glx_error_base; gint glx_event_base; + /* Translation between X server time and system-local monotonic time */ + gint64 server_time_query_time; + gint64 server_time_offset; + + guint server_time_is_monotonic_time : 1; + guint have_glx : 1; /* GLX extensions we check */ |