From 12a78711c94ccf5c46dd4e9653596c87b6fe0a18 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Fri, 30 Sep 2022 14:54:15 +0800 Subject: [PATCH] Fix calculation of frame times when X server time overflows * etc/TODO: Add TODO about frame synchronization and animations. * src/xterm.c (x_display_set_last_user_time): Handle cases when the monotonic time is not the server time due to the latter overflowing. --- etc/TODO | 20 ++++++++++++++++++++ src/xterm.c | 31 ++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/etc/TODO b/etc/TODO index fefc586123e..d884539037d 100644 --- a/etc/TODO +++ b/etc/TODO @@ -1763,6 +1763,26 @@ enough environment under which the fix can be tested. The MPX code has not been tested under X toolkit or GTK+ 2.x builds and is not expected to work there. +** Framework for doing animations +Emacs does animations all over the place, usually "pluse" animations. +These currently animate by waiting for a small but fixed amount of +time between each redisplay, which causes screen tearing by not +synchronizing with the vertical refresh. Frame synchronization works +by causing redisplay to delay until the next time the monitor can +refresh; this works, but can cause substandard frame rate when +redisplay happens less often than the monitor refreshing, as redisplay +will have to continually wait for missed monitor refresh. + +The right remedy for this problem is to define a function that returns +the amount of time remaining before the next vertical blanking period, +and to schedule animation redisplay within that period, using the +information provided by the _NET_WM_FRAME_DRAWN and +_NET_WM_FRAME_TIMINGS compositor messages on X and the +BScreen::GetMonitorInfo function on Haiku. Ideally, all features +performing animations should be modified to use that method of +scheduling redisplay. Examples include xref-pulse-momentarily and +pixel-scroll-precision-start-momentum. + This file is part of GNU Emacs. diff --git a/src/xterm.c b/src/xterm.c index cb5d540dd3f..947cf7edb54 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -7607,6 +7607,11 @@ static void x_display_set_last_user_time (struct x_display_info *dpyinfo, Time time, bool send_event) { +#if defined HAVE_XSYNC && !defined USE_GTK && defined HAVE_CLOCK_GETTIME + uint_fast64_t monotonic_time; + uint_fast64_t monotonic_ms; + int_fast64_t diff_ms; +#endif #ifndef USE_GTK struct frame *focus_frame; Time old_time; @@ -7627,9 +7632,8 @@ x_display_set_last_user_time (struct x_display_info *dpyinfo, Time time, { /* See if the current CLOCK_MONOTONIC time is reasonably close to the X server time. */ - uint_fast64_t monotonic_time = x_sync_current_monotonic_time (); - uint_fast64_t monotonic_ms = monotonic_time / 1000; - int_fast64_t diff_ms; + monotonic_time = x_sync_current_monotonic_time (); + monotonic_ms = monotonic_time / 1000; dpyinfo->server_time_monotonic_p = (monotonic_time != 0 @@ -7647,6 +7651,27 @@ x_display_set_last_user_time (struct x_display_info *dpyinfo, Time time, monotonic_time, &dpyinfo->server_time_offset)) dpyinfo->server_time_offset = 0; + + /* If the server time is reasonably close to the monotonic + time after the latter is truncated to CARD32, simply make + the offset that between the server time in ms and the + actual time in ms. */ + + monotonic_ms = monotonic_ms & 0xffffffff; + if (!INT_SUBTRACT_WRAPV (time, monotonic_ms, &diff_ms) + && -500 < diff_ms && diff_ms < 500) + { + /* The server timestamp overflowed. Make the time + offset exactly how much it overflowed by. */ + + if (INT_SUBTRACT_WRAPV (monotonic_time / 1000, monotonic_ms, + &dpyinfo->server_time_offset) + || INT_MULTIPLY_WRAPV (dpyinfo->server_time_offset, + 1000, &dpyinfo->server_time_offset) + || INT_SUBTRACT_WRAPV (0, dpyinfo->server_time_offset, + &dpyinfo->server_time_offset)) + dpyinfo->server_time_offset = 0; + } } } #endif -- 2.39.2