From 952cc28e58eafbdd409bf36f9ca656dae533542b Mon Sep 17 00:00:00 2001 From: Po Lu Date: Tue, 3 May 2022 09:22:06 +0800 Subject: [PATCH] Clean up X11 double buffering code This fixes several latent bugs where code went down the path with double buffering enabled when it wasn't, and vice versa. * src/xfns.c (x_set_inhibit_double_buffering): Improve commentary and only define when HAVE_XDBE. (x_mark_frame_dirty): Only set buffer flip flag when HAVE_XDBE. (initial_set_up_x_back_buffer): Clean up coding style and remove unnecessary block_input pair. (Fx_double_buffered_p): Always return nil if !HAVE_XDBE. (x_frame_parm_handlers): Don't set double buffering handler if !HAVE_XDBE. * src/xftfont.c (xftfont_drop_xrender_surfaces, xftfont_driver): Only define when XDBE is available. * src/xterm.c (x_drop_xrender_surfaces): Likewise. (x_clear_window): Don't test double buffering flags when !HAVE_XDBE. (show_back_buffer): Only define when HAVE_XDBE. (x_flip_and_flush): Don't try to flip when !HAVE_XDBE. (XTframe_up_to_date): Likewise. (XTbuffer_flipping_unblocked_hook): Only define when Xdbe is available. (x_clear_area): Don't test double buffering flags when Xdbe is not available. (flush_dirty_back_buffer_on): Don't define if there's no DBE. (handle_one_xevent, x_create_terminal): Likewise. * src/xterm.h (FRAME_X_DRAWABLE): Fix coding style. --- src/xfns.c | 39 +++++++++++++++++++++---------- src/xftfont.c | 63 ++++++++++++++++++++++++++++----------------------- src/xterm.c | 54 +++++++++++++++++++++++++++++++++++-------- src/xterm.h | 4 +++- 4 files changed, 109 insertions(+), 51 deletions(-) diff --git a/src/xfns.c b/src/xfns.c index 7176d626094..14721c6ce83 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -823,22 +823,24 @@ x_set_tool_bar_position (struct frame *f, wrong_choice (choice, new_value); } +#ifdef HAVE_XDBE static void x_set_inhibit_double_buffering (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) { - block_input (); + bool want_double_buffering, was_double_buffered; + if (FRAME_X_WINDOW (f) && !EQ (new_value, old_value)) { - bool want_double_buffering = NILP (new_value); - bool was_double_buffered = FRAME_X_DOUBLE_BUFFERED_P (f); - /* font_drop_xrender_surfaces in xftfont does something only if - we're double-buffered, so call font_drop_xrender_surfaces before - and after any potential change. One of the calls will end up - being a no-op. */ + want_double_buffering = NILP (new_value); + was_double_buffered = FRAME_X_DOUBLE_BUFFERED_P (f); + + block_input (); if (want_double_buffering != was_double_buffered) { + /* Force XftDraw etc to be recreated with the new double + buffered drawable. */ font_drop_xrender_surfaces (f); /* Scroll bars decide whether or not to use a back buffer @@ -860,9 +862,10 @@ x_set_inhibit_double_buffering (struct frame *f, SET_FRAME_GARBAGED (f); font_drop_xrender_surfaces (f); } + unblock_input (); } - unblock_input (); } +#endif /** * x_set_undecorated: @@ -3548,8 +3551,11 @@ xic_set_xfontset (struct frame *f, const char *base_fontname) void x_mark_frame_dirty (struct frame *f) { - if (FRAME_X_DOUBLE_BUFFERED_P (f) && !FRAME_X_NEED_BUFFER_FLIP (f)) +#ifdef HAVE_XDBE + if (FRAME_X_DOUBLE_BUFFERED_P (f) + && !FRAME_X_NEED_BUFFER_FLIP (f)) FRAME_X_NEED_BUFFER_FLIP (f) = true; +#endif } static void @@ -3630,12 +3636,12 @@ tear_down_x_back_buffer (struct frame *f) void initial_set_up_x_back_buffer (struct frame *f) { - block_input (); eassert (FRAME_X_WINDOW (f)); FRAME_X_RAW_DRAWABLE (f) = FRAME_X_WINDOW (f); - if (NILP (CDR (Fassq (Qinhibit_double_buffering, f->param_alist)))) + + if (NILP (CDR (Fassq (Qinhibit_double_buffering, + f->param_alist)))) set_up_x_back_buffer (f); - unblock_input (); } #if defined HAVE_XINPUT2 @@ -8614,7 +8620,12 @@ DEFUN ("x-double-buffered-p", Fx_double_buffered_p, Sx_double_buffered_p, (Lisp_Object frame) { struct frame *f = decode_live_frame (frame); + +#ifdef HAVE_XDBE return FRAME_X_DOUBLE_BUFFERED_P (f) ? Qt : Qnil; +#else + return Qnil; +#endif } @@ -9360,7 +9371,11 @@ frame_parm_handler x_frame_parm_handlers[] = gui_set_alpha, x_set_sticky, x_set_tool_bar_position, +#ifdef HAVE_XDBE x_set_inhibit_double_buffering, +#else + NULL, +#endif x_set_undecorated, x_set_parent_frame, x_set_skip_taskbar, diff --git a/src/xftfont.c b/src/xftfont.c index e27c6cf3146..31fb877c35b 100644 --- a/src/xftfont.c +++ b/src/xftfont.c @@ -643,18 +643,23 @@ xftfont_end_for_frame (struct frame *f) return 0; } -/* When using X double buffering, the XftDraw structure we build - seems to be useless once a frame is resized, so recreate it on +/* When using X double buffering, the XRender surfaces we create seem + to become useless once the window acting as the front buffer is + resized for an unknown reason (X server bug?), so recreate it on ConfigureNotify and in some other cases. */ +#ifdef HAVE_XDBE static void xftfont_drop_xrender_surfaces (struct frame *f) { - block_input (); if (FRAME_X_DOUBLE_BUFFERED_P (f)) - xftfont_end_for_frame (f); - unblock_input (); + { + block_input (); + xftfont_end_for_frame (f); + unblock_input (); + } } +#endif static bool xftfont_cached_font_ok (struct frame *f, Lisp_Object font_object, @@ -741,35 +746,37 @@ static void syms_of_xftfont_for_pdumper (void); struct font_driver const xftfont_driver = { /* We can't draw a text without device dependent functions. */ - .type = LISPSYM_INITIALLY (Qxft), - .get_cache = xfont_get_cache, - .list = xftfont_list, - .match = xftfont_match, - .list_family = ftfont_list_family, - .open_font = xftfont_open, - .close_font = xftfont_close, - .prepare_face = xftfont_prepare_face, - .done_face = xftfont_done_face, - .has_char = xftfont_has_char, - .encode_char = xftfont_encode_char, - .text_extents = xftfont_text_extents, - .draw = xftfont_draw, - .get_bitmap = ftfont_get_bitmap, - .anchor_point = ftfont_anchor_point, + .type = LISPSYM_INITIALLY (Qxft), + .get_cache = xfont_get_cache, + .list = xftfont_list, + .match = xftfont_match, + .list_family = ftfont_list_family, + .open_font = xftfont_open, + .close_font = xftfont_close, + .prepare_face = xftfont_prepare_face, + .done_face = xftfont_done_face, + .has_char = xftfont_has_char, + .encode_char = xftfont_encode_char, + .text_extents = xftfont_text_extents, + .draw = xftfont_draw, + .get_bitmap = ftfont_get_bitmap, + .anchor_point = ftfont_anchor_point, #ifdef HAVE_LIBOTF - .otf_capability = ftfont_otf_capability, + .otf_capability = ftfont_otf_capability, #endif - .end_for_frame = xftfont_end_for_frame, + .end_for_frame = xftfont_end_for_frame, #if defined HAVE_M17N_FLT && defined HAVE_LIBOTF - .shape = xftfont_shape, + .shape = xftfont_shape, #endif #if defined HAVE_OTF_GET_VARIATION_GLYPHS || defined HAVE_FT_FACE_GETCHARVARIANTINDEX - .get_variation_glyphs = ftfont_variation_glyphs, + .get_variation_glyphs = ftfont_variation_glyphs, +#endif + .filter_properties = ftfont_filter_properties, + .cached_font_ok = xftfont_cached_font_ok, + .combining_capability = ftfont_combining_capability, +#ifdef HAVE_XDBE + .drop_xrender_surfaces = xftfont_drop_xrender_surfaces, #endif - .filter_properties = ftfont_filter_properties, - .cached_font_ok = xftfont_cached_font_ok, - .combining_capability = ftfont_combining_capability, - .drop_xrender_surfaces = xftfont_drop_xrender_surfaces, }; #ifdef HAVE_HARFBUZZ struct font_driver xfthbfont_driver; diff --git a/src/xterm.c b/src/xterm.c index 517869dde34..adfe90522d4 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -3780,6 +3780,7 @@ x_flush (struct frame *f) unblock_input (); } +#ifdef HAVE_XDBE static void x_drop_xrender_surfaces (struct frame *f) { @@ -3795,6 +3796,7 @@ x_drop_xrender_surfaces (struct frame *f) } #endif } +#endif #ifdef HAVE_XRENDER void @@ -5127,9 +5129,14 @@ x_clear_window (struct frame *f) x_end_cr_clip (f); #else #ifndef USE_GTK - if (FRAME_X_DOUBLE_BUFFERED_P (f) || (f->alpha_background != 1.0)) + if (f->alpha_background != 1.0 +#ifdef HAVE_XDBE + || FRAME_X_DOUBLE_BUFFERED_P (f) #endif - x_clear_area (f, 0, 0, FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f)); + ) +#endif + x_clear_area (f, 0, 0, FRAME_PIXEL_WIDTH (f), + FRAME_PIXEL_HEIGHT (f)); #ifndef USE_GTK else XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); @@ -5456,13 +5463,15 @@ x_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1) /* Show the frame back buffer. If frame is double-buffered, atomically publish to the user's screen graphics updates made since the last call to show_back_buffer. */ + +#ifdef HAVE_XDBE static void show_back_buffer (struct frame *f) { block_input (); + if (FRAME_X_DOUBLE_BUFFERED_P (f)) { -#ifdef HAVE_XDBE #ifdef USE_CAIRO cairo_t *cr = FRAME_CR_CONTEXT (f); if (cr) @@ -5473,13 +5482,12 @@ show_back_buffer (struct frame *f) swap_info.swap_window = FRAME_X_WINDOW (f); swap_info.swap_action = XdbeCopied; XdbeSwapBuffers (FRAME_X_DISPLAY (f), &swap_info, 1); -#else - eassert (!"should have back-buffer only with XDBE"); -#endif } FRAME_X_NEED_BUFFER_FLIP (f) = false; + unblock_input (); } +#endif /* Updates back buffer and flushes changes to display. Called from minibuf read code. Note that we display the back buffer even if @@ -5488,8 +5496,10 @@ static void x_flip_and_flush (struct frame *f) { block_input (); +#ifdef HAVE_XDBE if (FRAME_X_NEED_BUFFER_FLIP (f)) show_back_buffer (f); +#endif x_flush (f); unblock_input (); } @@ -5538,8 +5548,12 @@ XTframe_up_to_date (struct frame *f) eassert (FRAME_X_P (f)); block_input (); FRAME_MOUSE_UPDATE (f); - if (!buffer_flipping_blocked_p () && FRAME_X_NEED_BUFFER_FLIP (f)) + +#ifdef HAVE_XDBE + if (!buffer_flipping_blocked_p () + && FRAME_X_NEED_BUFFER_FLIP (f)) show_back_buffer (f); +#endif #ifdef HAVE_XSYNC #ifndef HAVE_GTK3 @@ -5592,12 +5606,14 @@ XTframe_up_to_date (struct frame *f) unblock_input (); } +#ifdef HAVE_XDBE static void XTbuffer_flipping_unblocked_hook (struct frame *f) { if (FRAME_X_NEED_BUFFER_FLIP (f)) show_back_buffer (f); } +#endif /** * x_clear_under_internal_border: @@ -8716,8 +8732,11 @@ x_clear_area (struct frame *f, int x, int y, int width, int height) x_end_cr_clip (f); #else #ifndef USE_GTK - if (FRAME_X_DOUBLE_BUFFERED_P (f) - || f->alpha_background != 1.0) + if (f->alpha_background != 1.0 +#ifdef HAVE_XDBE + || FRAME_X_DOUBLE_BUFFERED_P (f) +#endif + ) #endif { #if defined HAVE_XRENDER && \ @@ -13738,7 +13757,9 @@ x_net_wm_state (struct frame *f, Window window) store_frame_param (f, Qshaded, shaded ? Qt : Qnil); } -/* Flip back buffers on FRAME if it has undrawn content. */ +/* Flip back buffers on F if it has undrawn content. */ + +#ifdef HAVE_XDBE static void flush_dirty_back_buffer_on (struct frame *f) { @@ -13749,6 +13770,7 @@ flush_dirty_back_buffer_on (struct frame *f) show_back_buffer (f); unblock_input (); } +#endif #ifdef HAVE_GTK3 void @@ -14707,8 +14729,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, SET_FRAME_ICONIFIED (f, false); } +#ifdef HAVE_XDBE if (FRAME_X_DOUBLE_BUFFERED_P (f)) x_drop_xrender_surfaces (f); +#endif f->output_data.x->has_been_visible = true; SET_FRAME_GARBAGED (f); unblock_input (); @@ -14753,8 +14777,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, #endif } +#ifdef HAVE_XDBE if (!FRAME_GARBAGED_P (f)) show_back_buffer (f); +#endif } else { @@ -14802,7 +14828,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifdef USE_GTK x_clear_under_internal_border (f); #endif +#ifdef HAVE_XDBE show_back_buffer (f); +#endif } #ifdef USE_X_TOOLKIT else @@ -16016,8 +16044,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, for size changes: that's not sufficient. We miss some surface invalidations and flicker. */ block_input (); +#ifdef HAVE_XDBE if (f && FRAME_X_DOUBLE_BUFFERED_P (f)) x_drop_xrender_surfaces (f); +#endif unblock_input (); #if defined USE_CAIRO && !defined USE_GTK if (f) @@ -19447,11 +19477,13 @@ handle_one_xevent (struct x_display_info *dpyinfo, redisplay. To ensure that these changes become visible, draw them here. */ +#ifdef HAVE_XDBE if (f) flush_dirty_back_buffer_on (f); if (any && any != f) flush_dirty_back_buffer_on (any); +#endif return count; } @@ -24309,7 +24341,9 @@ x_create_terminal (struct x_display_info *dpyinfo) terminal->update_end_hook = x_update_end; terminal->read_socket_hook = XTread_socket; terminal->frame_up_to_date_hook = XTframe_up_to_date; +#ifdef HAVE_XDBE terminal->buffer_flipping_unblocked_hook = XTbuffer_flipping_unblocked_hook; +#endif terminal->defined_color_hook = x_defined_color; terminal->query_frame_background_color = x_query_frame_background_color; terminal->query_colors = x_query_colors; diff --git a/src/xterm.h b/src/xterm.h index 65349834c9b..80b57137981 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -1025,13 +1025,15 @@ extern void x_mark_frame_dirty (struct frame *f); code after any drawing command, but we can run code whenever someone asks for the handle necessary to draw. */ #define FRAME_X_DRAWABLE(f) \ - (x_mark_frame_dirty((f)), FRAME_X_RAW_DRAWABLE ((f))) + (x_mark_frame_dirty ((f)), FRAME_X_RAW_DRAWABLE ((f))) +#ifdef HAVE_XDBE #define FRAME_X_DOUBLE_BUFFERED_P(f) \ (FRAME_X_WINDOW (f) != FRAME_X_RAW_DRAWABLE (f)) /* Return the need-buffer-flip flag for frame F. */ #define FRAME_X_NEED_BUFFER_FLIP(f) ((f)->output_data.x->need_buffer_flip) +#endif /* Return the outermost X window associated with the frame F. */ #ifdef USE_X_TOOLKIT -- 2.39.5