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.
This commit is contained in:
Po Lu 2022-09-30 14:54:15 +08:00
parent b7a3770ecc
commit 12a78711c9
2 changed files with 48 additions and 3 deletions

View file

@ -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.

View file

@ -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