Make frame synchronization more robust

* src/xterm.c (x_sync_wait_for_frame_drawn_event)
(x_sync_handle_frame_drawn): Only cancel frame synchronization
if hanging twice or more in a row.
* src/xterm.h (struct x_output, FRAME_X_DRAW_JUST_HUNG): New
flag.
This commit is contained in:
Po Lu 2022-11-27 19:17:38 +08:00
parent ea2f2f1e71
commit 80bfd6dc5b
2 changed files with 45 additions and 7 deletions

View file

@ -6919,13 +6919,27 @@ x_sync_wait_for_frame_drawn_event (struct frame *f)
x_sync_is_frame_drawn_event, (XPointer) f,
make_timespec (1, 0)))
{
/* TODO: display this warning in the echo area. */
fprintf (stderr, "Warning: compositing manager spent more than 1 second "
"drawing a frame. Frame synchronization has been disabled\n");
FRAME_X_OUTPUT (f)->use_vsync_p = false;
/* The first time a draw hangs, treat it as a random fluctuation
on the part of the compositor. If the next draw continues to
hang, disable frame synchronization. */
if (FRAME_X_DRAW_JUST_HUNG (f))
{
fprintf (stderr, "Warning: compositing manager spent more than 1 "
"second drawing a frame. Frame synchronization has "
"been disabled\n");
FRAME_X_OUTPUT (f)->use_vsync_p = false;
/* Also change the frame parameter to reflect the new state. */
store_frame_param (f, Quse_frame_synchronization, Qnil);
/* Also change the frame parameter to reflect the new
state. */
store_frame_param (f, Quse_frame_synchronization, Qnil);
}
else
{
fprintf (stderr, "Warning: compositing manager spent more than 1 "
"second drawing a frame. Frame synchronization will be "
"disabled if this happens again\n");
FRAME_X_DRAW_JUST_HUNG (f) = true;
}
}
else
x_sync_note_frame_times (FRAME_DISPLAY_INFO (f), f, &event);
@ -7128,8 +7142,26 @@ static void
x_sync_handle_frame_drawn (struct x_display_info *dpyinfo,
XEvent *message, struct frame *f)
{
XSyncValue value, counter;
if (FRAME_OUTER_WINDOW (f) == message->xclient.window)
FRAME_X_WAITING_FOR_DRAW (f) = false;
{
counter = FRAME_X_COUNTER_VALUE (f);
/* Check that the counter in the message is the same as the
counter in the frame. */
XSyncIntsToValue (&value,
message->xclient.data.l[0] & 0xffffffff,
message->xclient.data.l[1] & 0xffffffff);
if (XSyncValueEqual (value, counter))
FRAME_X_WAITING_FOR_DRAW (f) = false;
/* As long as a _NET_WM_FRAME_DRAWN message arrives, we know
that the compositor is still sending events, so avoid timing
out. */
FRAME_X_DRAW_JUST_HUNG (f) = false;
}
x_sync_note_frame_times (dpyinfo, f, message);
}

View file

@ -1179,6 +1179,10 @@ struct x_output
frame. */
bool_bf waiting_for_frame_p : 1;
/* Whether or not Emacs just skipped waiting for a frame due to a
timeout. */
bool_bf draw_just_hung_p : 1;
#if !defined USE_GTK && defined HAVE_CLOCK_GETTIME
/* Whether or not Emacs should wait for the compositing manager to
draw frames before starting a new frame. */
@ -1392,6 +1396,8 @@ extern void x_mark_frame_dirty (struct frame *f);
FRAME_X_OUTPUT (f)->extended_frame_counter
#define FRAME_X_WAITING_FOR_DRAW(f) \
FRAME_X_OUTPUT (f)->waiting_for_frame_p
#define FRAME_X_DRAW_JUST_HUNG(f) \
FRAME_X_OUTPUT (f)->draw_just_hung_p
#define FRAME_X_COUNTER_VALUE(f) \
FRAME_X_OUTPUT (f)->current_extended_counter_value
#endif