Avoid triple buffering with Xdbe in cairo

* src/xterm.h (struct x_output): Remove member cr_surface.
Add members cr_surface_desired_width and cr_surface_desired_height.
(x_cr_destroy_frame_context) [USE_CAIRO]: Add extern.

* src/xterm.c (x_free_cr_resources): Remove function.
(FRAME_CR_SURFACE) [USE_CAIRO]: Remove macro.
(FRAME_CR_SURFACE_DESIRED_WIDTH, FRAME_CR_SURFACE_DESIRED_HEIGHT) [USE_CAIRO]:
New macros.
(x_cr_destroy_frame_context) [USE_CAIRO]: Rename from x_cr_destroy_surface.
All Uses changed.  Don't use FRAME_CR_SURFACE.  Make non-static.
(x_cr_update_surface_desired_size) [USE_CAIRO]: New function.
(x_begin_cr_clip) [USE_CAIRO]: Create Xlib surface if Xdbe is in use.
Use FRAME_CR_SURFACE_DESIRED_WIDTH and FRAME_CR_SURFACE_DESIRED_HEIGHT.
(x_end_cr_clip) [USE_CAIRO]: Call x_mark_frame_dirty if Xdbe is in use.
(x_cr_draw_frame, x_cr_export_frames) [USE_CAIRO]: Save and restore cairo
context instead of freeing and clearing it.
(x_update_begin) [USE_CAIRO]: Don't create cairo surface here.
(show_back_buffer) [USE_CAIRO]: Call cairo_surface_flush before swapping.
(x_update_end) [USE_CAIRO]: Don't copy image surface if Xdbe is in use.
Get image surface by cairo_get_target instead of FRAME_CR_SURFACE.
(x_scroll_run) [USE_CAIRO]: Use XCopyArea if Xdbe is in use.
(handle_one_xevent) [USE_CAIRO] <ConfigureNotify>: Call
x_cr_update_surface_desired_size instead of x_cr_destroy_surface.
(x_free_frame_resources) [USE_CAIRO]: Call x_cr_destroy_frame_context instead
of x_free_cr_resources.

* src/xfns.c (set_up_x_back_buffer, tear_down_x_back_buffer) [USE_CAIRO]:
Call x_cr_destroy_frame_context.
This commit is contained in:
YAMAMOTO Mitsuharu 2019-05-19 08:35:40 +09:00
parent 5f9671e57e
commit b87e5eea1d
3 changed files with 102 additions and 119 deletions

View file

@ -2784,6 +2784,9 @@ set_up_x_back_buffer (struct frame *f)
block_input ();
if (FRAME_X_WINDOW (f) && !FRAME_X_DOUBLE_BUFFERED_P (f))
{
#ifdef USE_CAIRO
x_cr_destroy_frame_context (f);
#endif
FRAME_X_RAW_DRAWABLE (f) = FRAME_X_WINDOW (f);
if (FRAME_DISPLAY_INFO (f)->supports_xdbe)
{
@ -2813,6 +2816,9 @@ tear_down_x_back_buffer (struct frame *f)
{
if (FRAME_X_DOUBLE_BUFFERED_P (f))
{
#ifdef USE_CAIRO
x_cr_destroy_frame_context (f);
#endif
XdbeDeallocateBackBufferName (FRAME_X_DISPLAY (f),
FRAME_X_DRAWABLE (f));
FRAME_X_RAW_DRAWABLE (f) = FRAME_X_WINDOW (f);

View file

@ -201,7 +201,6 @@ enum xembed_message
XEMBED_ACTIVATE_ACCELERATOR = 14
};
static void x_free_cr_resources (struct frame *);
static bool x_alloc_nearest_color_1 (Display *, Colormap, XColor *);
static void x_raise_frame (struct frame *);
static void x_lower_frame (struct frame *);
@ -298,7 +297,10 @@ record_event (char *locus, int type)
#ifdef USE_CAIRO
#define FRAME_CR_CONTEXT(f) ((f)->output_data.x->cr_context)
#define FRAME_CR_SURFACE(f) ((f)->output_data.x->cr_surface)
#define FRAME_CR_SURFACE_DESIRED_WIDTH(f) \
((f)->output_data.x->cr_surface_desired_width)
#define FRAME_CR_SURFACE_DESIRED_HEIGHT(f) \
((f)->output_data.x->cr_surface_desired_height)
static struct x_gc_ext_data *
x_gc_get_ext_data (struct frame *f, GC gc, int create_if_not_found_p)
@ -333,19 +335,28 @@ x_extension_initialize (struct x_display_info *dpyinfo)
dpyinfo->ext_codes = ext_codes;
}
static void
x_cr_destroy_surface (struct frame *f)
void
x_cr_destroy_frame_context (struct frame *f)
{
if (FRAME_CR_SURFACE (f))
if (FRAME_CR_CONTEXT (f))
{
cairo_t *cr = FRAME_CR_CONTEXT (f);
cairo_surface_destroy (FRAME_CR_SURFACE (f));
FRAME_CR_SURFACE (f) = 0;
if (cr) cairo_destroy (cr);
cairo_destroy (FRAME_CR_CONTEXT (f));
FRAME_CR_CONTEXT (f) = NULL;
}
}
static void
x_cr_update_surface_desired_size (struct frame *f, int width, int height)
{
if (FRAME_CR_SURFACE_DESIRED_WIDTH (f) != width
|| FRAME_CR_SURFACE_DESIRED_HEIGHT (f) != height)
{
x_cr_destroy_frame_context (f);
FRAME_CR_SURFACE_DESIRED_WIDTH (f) = width;
FRAME_CR_SURFACE_DESIRED_HEIGHT (f) = height;
}
}
cairo_t *
x_begin_cr_clip (struct frame *f, GC gc)
{
@ -353,21 +364,19 @@ x_begin_cr_clip (struct frame *f, GC gc)
if (!cr)
{
if (! FRAME_CR_SURFACE (f))
{
int scale = 1;
#ifdef USE_GTK
scale = xg_get_scale (f);
#endif
FRAME_CR_SURFACE (f) =
cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
scale * FRAME_PIXEL_WIDTH (f),
scale * FRAME_PIXEL_HEIGHT (f));
}
cr = cairo_create (FRAME_CR_SURFACE (f));
FRAME_CR_CONTEXT (f) = cr;
int width = FRAME_CR_SURFACE_DESIRED_WIDTH (f);
int height = FRAME_CR_SURFACE_DESIRED_HEIGHT (f);
cairo_surface_t *surface;
if (FRAME_X_DOUBLE_BUFFERED_P (f))
surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
FRAME_X_RAW_DRAWABLE (f),
FRAME_X_VISUAL (f),
width, height);
else
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
width, height);
cr = FRAME_CR_CONTEXT (f) = cairo_create (surface);
cairo_surface_destroy (surface);
}
cairo_save (cr);
@ -395,6 +404,8 @@ void
x_end_cr_clip (struct frame *f)
{
cairo_restore (FRAME_CR_CONTEXT (f));
if (FRAME_X_DOUBLE_BUFFERED_P (f))
x_mark_frame_dirty (f);
}
void
@ -532,11 +543,11 @@ x_cr_draw_frame (cairo_t *cr, struct frame *f)
width = FRAME_PIXEL_WIDTH (f);
height = FRAME_PIXEL_HEIGHT (f);
x_free_cr_resources (f);
cairo_t *saved_cr = FRAME_CR_CONTEXT (f);
FRAME_CR_CONTEXT (f) = cr;
x_clear_area (f, 0, 0, width, height);
expose_frame (f, 0, 0, width, height);
FRAME_CR_CONTEXT (f) = NULL;
FRAME_CR_CONTEXT (f) = saved_cr;
}
static cairo_status_t
@ -615,11 +626,11 @@ x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type)
while (1)
{
x_free_cr_resources (f);
cairo_t *saved_cr = FRAME_CR_CONTEXT (f);
FRAME_CR_CONTEXT (f) = cr;
x_clear_area (f, 0, 0, width, height);
expose_frame (f, 0, 0, width, height);
FRAME_CR_CONTEXT (f) = NULL;
FRAME_CR_CONTEXT (f) = saved_cr;
if (NILP (frames))
break;
@ -653,35 +664,6 @@ x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type)
#endif /* USE_CAIRO */
static void
x_free_cr_resources (struct frame *f)
{
#ifdef USE_CAIRO
if (f == NULL)
{
Lisp_Object rest, frame;
FOR_EACH_FRAME (rest, frame)
if (FRAME_X_P (XFRAME (frame)))
x_free_cr_resources (XFRAME (frame));
}
else
{
cairo_t *cr = FRAME_CR_CONTEXT (f);
if (cr)
{
cairo_surface_t *surface = cairo_get_target (cr);
if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB)
{
cairo_destroy (cr);
FRAME_CR_CONTEXT (f) = NULL;
}
}
}
#endif
}
static void
x_set_clip_rectangles (struct frame *f, GC gc, XRectangle *rectangles, int n)
{
@ -996,41 +978,7 @@ x_set_frame_alpha (struct frame *f)
static void
x_update_begin (struct frame *f)
{
#ifdef USE_CAIRO
if (FRAME_TOOLTIP_P (f) && !FRAME_VISIBLE_P (f))
return;
if (! FRAME_CR_SURFACE (f))
{
int width, height;
#ifdef USE_GTK
if (FRAME_GTK_WIDGET (f))
{
GdkWindow *w = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
int scale = xg_get_scale (f);
width = scale * gdk_window_get_width (w);
height = scale * gdk_window_get_height (w);
}
else
#endif
{
width = FRAME_PIXEL_WIDTH (f);
height = FRAME_PIXEL_HEIGHT (f);
if (! FRAME_EXTERNAL_TOOL_BAR (f))
height += FRAME_TOOL_BAR_HEIGHT (f);
if (! FRAME_EXTERNAL_MENU_BAR (f))
height += FRAME_MENU_BAR_HEIGHT (f);
}
if (width > 0 && height > 0)
{
block_input();
FRAME_CR_SURFACE (f) = cairo_image_surface_create
(CAIRO_FORMAT_ARGB32, width, height);
unblock_input();
}
}
#endif /* USE_CAIRO */
/* Nothing to do. */
}
/* Draw a vertical window border from (x,y0) to (x,y1) */
@ -1122,6 +1070,11 @@ show_back_buffer (struct frame *f)
if (FRAME_X_DOUBLE_BUFFERED_P (f))
{
#ifdef HAVE_XDBE
#ifdef USE_CAIRO
cairo_t *cr = FRAME_CR_CONTEXT (f);
if (cr)
cairo_surface_flush (cairo_get_target (cr));
#endif
XdbeSwapInfo swap_info;
memset (&swap_info, 0, sizeof (swap_info));
swap_info.swap_window = FRAME_X_WINDOW (f);
@ -1158,30 +1111,33 @@ x_update_end (struct frame *f)
MOUSE_HL_INFO (f)->mouse_face_defer = false;
#ifdef USE_CAIRO
if (FRAME_CR_SURFACE (f))
if (!FRAME_X_DOUBLE_BUFFERED_P (f))
{
cairo_t *cr;
cairo_surface_t *surface;
int width, height;
block_input ();
width = FRAME_PIXEL_WIDTH (f);
height = FRAME_PIXEL_HEIGHT (f);
if (! FRAME_EXTERNAL_TOOL_BAR (f))
height += FRAME_TOOL_BAR_HEIGHT (f);
if (! FRAME_EXTERNAL_MENU_BAR (f))
height += FRAME_MENU_BAR_HEIGHT (f);
surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
FRAME_X_DRAWABLE (f),
FRAME_DISPLAY_INFO (f)->visual,
width,
height);
cr = cairo_create (surface);
cairo_surface_destroy (surface);
cairo_surface_t *source_surface = cairo_get_target (FRAME_CR_CONTEXT (f));
if (source_surface)
{
cairo_t *cr;
cairo_surface_t *surface;
int width, height;
cairo_set_source_surface (cr, FRAME_CR_SURFACE (f), 0, 0);
cairo_paint (cr);
cairo_destroy (cr);
width = FRAME_PIXEL_WIDTH (f);
height = FRAME_PIXEL_HEIGHT (f);
if (! FRAME_EXTERNAL_TOOL_BAR (f))
height += FRAME_TOOL_BAR_HEIGHT (f);
if (! FRAME_EXTERNAL_MENU_BAR (f))
height += FRAME_MENU_BAR_HEIGHT (f);
surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
FRAME_X_DRAWABLE (f),
FRAME_X_VISUAL (f),
width, height);
cr = cairo_create (surface);
cairo_surface_destroy (surface);
cairo_set_source_surface (cr, source_surface, 0, 0);
cairo_paint (cr);
cairo_destroy (cr);
}
unblock_input ();
}
#endif
@ -4253,7 +4209,21 @@ x_scroll_run (struct window *w, struct run *run)
gui_clear_cursor (w);
#ifdef USE_CAIRO
if (FRAME_CR_CONTEXT (f))
if (FRAME_X_DOUBLE_BUFFERED_P (f))
{
cairo_t *cr = FRAME_CR_CONTEXT (f);
if (cr)
cairo_surface_flush (cairo_get_target (cr));
XCopyArea (FRAME_X_DISPLAY (f),
FRAME_X_DRAWABLE (f), FRAME_X_DRAWABLE (f),
f->output_data.x->normal_gc,
x, from_y,
width, height,
x, to_y);
if (cr)
cairo_surface_mark_dirty (cairo_get_target (cr));
}
else if (FRAME_CR_CONTEXT (f))
{
cairo_surface_t *s = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
width, height);
@ -8711,7 +8681,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
font_drop_xrender_surfaces (f);
unblock_input ();
#ifdef USE_CAIRO
if (f) x_cr_destroy_surface (f);
if (f)
x_cr_update_surface_desired_size (f, configureEvent.xconfigure.width,
configureEvent.xconfigure.height);
#endif
#ifdef USE_GTK
if (!f
@ -8725,7 +8697,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
xg_frame_resized (f, configureEvent.xconfigure.width,
configureEvent.xconfigure.height);
#ifdef USE_CAIRO
x_cr_destroy_surface (f);
x_cr_update_surface_desired_size (f, configureEvent.xconfigure.width,
configureEvent.xconfigure.height);
#endif
f = 0;
}
@ -11835,7 +11808,9 @@ x_free_frame_resources (struct frame *f)
free_frame_xic (f);
#endif
x_free_cr_resources (f);
#ifdef USE_CAIRO
x_cr_destroy_frame_context (f);
#endif
#ifdef USE_X_TOOLKIT
if (f->output_data.x->widget)
{

View file

@ -725,8 +725,9 @@ struct x_output
#ifdef USE_CAIRO
/* Cairo drawing context. */
cairo_t *cr_context;
/* Cairo surface for double buffering */
cairo_surface_t *cr_surface;
/* Width and height reported by the last ConfigureNotify event.
They are used when creating the cairo surface next time. */
int cr_surface_desired_width, cr_surface_desired_height;
#endif
};
@ -1107,6 +1108,7 @@ extern int x_dispatch_event (XEvent *, Display *);
#endif
extern int x_x_to_emacs_modifiers (struct x_display_info *, int);
#ifdef USE_CAIRO
extern void x_cr_destroy_frame_context (struct frame *);
extern cairo_t *x_begin_cr_clip (struct frame *, GC);
extern void x_end_cr_clip (struct frame *);
extern void x_set_cr_source_with_gc_foreground (struct frame *, GC);