From 80bfd6dc5bc3738db595a4972893b149b1224800 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sun, 27 Nov 2022 19:17:38 +0800 Subject: [PATCH] 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. --- src/xterm.c | 46 +++++++++++++++++++++++++++++++++++++++------- src/xterm.h | 6 ++++++ 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/src/xterm.c b/src/xterm.c index ec605f5e914..7eaf59d54b1 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -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); } diff --git a/src/xterm.h b/src/xterm.h index c36920081d3..ee429e9c68d 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -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 -- 2.39.5