From fd613cb9f94daff0c8d4fdb27ff89894d41682a3 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 2 Aug 2011 13:51:30 +0100 Subject: [PATCH] xcb: track fallback damage And only upload the parts of the image that are modified during the fallback. I have to keep reminding myself that the goal is always to reduce the amount of fallbacks required... Signed-off-by: Chris Wilson --- src/cairo-composite-rectangles-private.h | 4 + src/cairo-composite-rectangles.c | 18 ++ src/cairo-xcb-connection.c | 6 +- src/cairo-xcb-private.h | 14 +- src/cairo-xcb-surface-render.c | 122 +++------ src/cairo-xcb-surface.c | 314 ++++++++++++++++++----- 6 files changed, 310 insertions(+), 168 deletions(-) diff --git a/src/cairo-composite-rectangles-private.h b/src/cairo-composite-rectangles-private.h index 8603108dd..fd7728995 100644 --- a/src/cairo-composite-rectangles-private.h +++ b/src/cairo-composite-rectangles-private.h @@ -147,6 +147,10 @@ cairo_private cairo_bool_t _cairo_composite_rectangles_can_reduce_clip (cairo_composite_rectangles_t *composite, cairo_clip_t *clip); +cairo_private cairo_int_status_t +_cairo_composite_rectangles_add_to_damage (cairo_composite_rectangles_t *composite, + cairo_boxes_t *damage); + cairo_private void _cairo_composite_rectangles_fini (cairo_composite_rectangles_t *extents); diff --git a/src/cairo-composite-rectangles.c b/src/cairo-composite-rectangles.c index c66d3d628..7fc0f5fe5 100644 --- a/src/cairo-composite-rectangles.c +++ b/src/cairo-composite-rectangles.c @@ -436,3 +436,21 @@ _cairo_composite_rectangles_can_reduce_clip (cairo_composite_rectangles_t *compo _cairo_box_from_rectangle (&box, &extents); return _cairo_clip_contains_box (clip, &box); } + +cairo_int_status_t +_cairo_composite_rectangles_add_to_damage (cairo_composite_rectangles_t *composite, + cairo_boxes_t *damage) +{ + cairo_int_status_t status; + int n; + + for (n = 0; n < composite->clip->num_boxes; n++) { + status = _cairo_boxes_add (damage, + CAIRO_ANTIALIAS_NONE, + &composite->clip->boxes[n]); + if (unlikely (status)) + return status; + } + + return CAIRO_INT_STATUS_SUCCESS; +} diff --git a/src/cairo-xcb-connection.c b/src/cairo-xcb-connection.c index 2808395e1..2c63a93ba 100644 --- a/src/cairo-xcb-connection.c +++ b/src/cairo-xcb-connection.c @@ -806,10 +806,9 @@ cairo_xcb_device_debug_cap_xshm_version (cairo_device_t *device, int minor_version) { cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device; - cairo_status_t status; if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) { - status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH); return; } @@ -843,10 +842,9 @@ cairo_xcb_device_debug_cap_xrender_version (cairo_device_t *device, int minor_version) { cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device; - cairo_status_t status; if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) { - status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH); return; } diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h index c27843ace..42a112cd2 100644 --- a/src/cairo-xcb-private.h +++ b/src/cairo-xcb-private.h @@ -87,7 +87,8 @@ struct _cairo_xcb_shm_info { struct _cairo_xcb_surface { cairo_surface_t base; - cairo_surface_t *fallback; + cairo_image_surface_t *fallback; + cairo_boxes_t fallback_damage; cairo_xcb_connection_t *connection; cairo_xcb_screen_t *screen; @@ -430,14 +431,14 @@ cairo_private cairo_int_status_t _cairo_xcb_surface_render_paint (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - const cairo_clip_t *clip); + cairo_composite_rectangles_t *composite); cairo_private cairo_int_status_t _cairo_xcb_surface_render_mask (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - const cairo_clip_t *clip); + cairo_composite_rectangles_t *composite); cairo_private cairo_int_status_t _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface, @@ -449,7 +450,7 @@ _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - const cairo_clip_t *clip); + cairo_composite_rectangles_t *composite); cairo_private cairo_int_status_t _cairo_xcb_surface_render_fill (cairo_xcb_surface_t *surface, @@ -459,7 +460,7 @@ _cairo_xcb_surface_render_fill (cairo_xcb_surface_t *surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - const cairo_clip_t *clip); + cairo_composite_rectangles_t *composite); cairo_private cairo_int_status_t _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface, @@ -468,7 +469,8 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface, cairo_scaled_font_t *scaled_font, cairo_glyph_t *glyphs, int num_glyphs, - const cairo_clip_t *clip); + cairo_composite_rectangles_t *composite, + cairo_bool_t overlap); cairo_private void _cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font); diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c index 42178b2e8..0cb7e158a 100644 --- a/src/cairo-xcb-surface-render.c +++ b/src/cairo-xcb-surface-render.c @@ -3415,9 +3415,8 @@ cairo_int_status_t _cairo_xcb_surface_render_paint (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, - const cairo_clip_t *clip) + cairo_composite_rectangles_t *composite) { - cairo_composite_rectangles_t extents; cairo_boxes_t boxes; cairo_status_t status; @@ -3430,36 +3429,20 @@ _cairo_xcb_surface_render_paint (cairo_xcb_surface_t *surface, return CAIRO_INT_STATUS_UNSUPPORTED; } - if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) { - surface->deferred_clear = TRUE; - surface->deferred_clear_color = *CAIRO_COLOR_TRANSPARENT; - return CAIRO_STATUS_SUCCESS; - } - - if (clip == NULL && - source->type == CAIRO_PATTERN_TYPE_SOLID && + if (source->type == CAIRO_PATTERN_TYPE_SOLID && (op == CAIRO_OPERATOR_SOURCE || + op == CAIRO_OPERATOR_CLEAR || (surface->base.is_clear && (op == CAIRO_OPERATOR_ADD || op == CAIRO_OPERATOR_OVER)))) { - cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source; surface->deferred_clear = TRUE; - surface->deferred_clear_color = solid->color; + surface->deferred_clear_color = composite->source_pattern.solid.color; return CAIRO_STATUS_SUCCESS; } - status = _cairo_composite_rectangles_init_for_paint (&extents, - &surface->base, - op, source, - clip); - if (unlikely (status)) - return status; - - _cairo_clip_steal_boxes(extents.clip, &boxes); - status = _clip_and_composite_boxes (surface, op, source, &boxes, &extents); - _cairo_clip_unsteal_boxes (extents.clip, &boxes); - - _cairo_composite_rectangles_fini (&extents); + _cairo_clip_steal_boxes(composite->clip, &boxes); + status = _clip_and_composite_boxes (surface, op, source, &boxes, composite); + _cairo_clip_unsteal_boxes (composite->clip, &boxes); return status; } @@ -3469,9 +3452,8 @@ _cairo_xcb_surface_render_mask (cairo_xcb_surface_t *surface, cairo_operator_t op, const cairo_pattern_t *source, const cairo_pattern_t *mask, - const cairo_clip_t *clip) + cairo_composite_rectangles_t *composite) { - cairo_composite_rectangles_t extents; cairo_status_t status; if (unlikely (! _operator_is_supported (surface->connection->flags, op))) @@ -3480,31 +3462,24 @@ _cairo_xcb_surface_render_mask (cairo_xcb_surface_t *surface, if ((surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0) return CAIRO_INT_STATUS_UNSUPPORTED; - status = _cairo_composite_rectangles_init_for_mask (&extents, &surface->base, - op, source, mask, clip); - if (unlikely (status)) - return status; - if (mask->type == CAIRO_PATTERN_TYPE_SOLID && - extents.clip->path == NULL && - ! _cairo_clip_is_region (extents.clip)) { + composite->clip->path == NULL && + ! _cairo_clip_is_region (composite->clip)) { status = _clip_and_composite (surface, op, source, _composite_opacity_boxes, _composite_opacity_boxes, (void *) mask, - &extents, need_unbounded_clip (&extents)); + composite, need_unbounded_clip (composite)); } else { xcb_draw_func_t mask_func = NULL; if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) - mask_func = extents.clip->path ? _composite_mask_clip : _composite_mask_clip_boxes; + mask_func = composite->clip->path ? _composite_mask_clip : _composite_mask_clip_boxes; status = _clip_and_composite (surface, op, source, _composite_mask, mask_func, (void *) mask, - &extents, need_bounded_clip (&extents)); + composite, need_bounded_clip (composite)); } - _cairo_composite_rectangles_fini (&extents); - return status; } @@ -3613,9 +3588,8 @@ _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias, - const cairo_clip_t *clip) + cairo_composite_rectangles_t *composite) { - cairo_composite_rectangles_t extents; cairo_int_status_t status; if (unlikely (! _operator_is_supported (surface->connection->flags, op))) @@ -3627,19 +3601,11 @@ _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface, return CAIRO_INT_STATUS_UNSUPPORTED; } - status = _cairo_composite_rectangles_init_for_stroke (&extents, - &surface->base, - op, source, - path, style, ctm, - clip); - if (unlikely (status)) - return status; - status = CAIRO_INT_STATUS_UNSUPPORTED; if (_cairo_path_fixed_stroke_is_rectilinear (path)) { cairo_boxes_t boxes; - _cairo_boxes_init_with_clip (&boxes, extents.clip); + _cairo_boxes_init_with_clip (&boxes, composite->clip); status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path, style, ctm, @@ -3647,7 +3613,7 @@ _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface, &boxes); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { status = _clip_and_composite_boxes (surface, op, source, - &boxes, &extents); + &boxes, composite); } _cairo_boxes_fini (&boxes); } @@ -3658,20 +3624,18 @@ _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface, path, style, ctm, ctm_inverse, tolerance, antialias, - &extents); + composite); } else if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) { status = _cairo_xcb_surface_render_stroke_via_mask (surface, op, source, path, style, ctm, ctm_inverse, tolerance, antialias, - &extents); + composite); } else { ASSERT_NOT_REACHED; } } - _cairo_composite_rectangles_fini (&extents); - return status; } @@ -3763,9 +3727,8 @@ _cairo_xcb_surface_render_fill (cairo_xcb_surface_t *surface, cairo_fill_rule_t fill_rule, double tolerance, cairo_antialias_t antialias, - const cairo_clip_t *clip) + cairo_composite_rectangles_t *composite) { - cairo_composite_rectangles_t extents; cairo_int_status_t status; if (unlikely (! _operator_is_supported (surface->connection->flags, op))) @@ -3777,24 +3740,18 @@ _cairo_xcb_surface_render_fill (cairo_xcb_surface_t *surface, return CAIRO_INT_STATUS_UNSUPPORTED; } - status = _cairo_composite_rectangles_init_for_fill (&extents, &surface->base, - op, source, path, - clip); - if (unlikely (status)) - return status; - status = CAIRO_INT_STATUS_UNSUPPORTED; if (_cairo_path_fixed_fill_is_rectilinear (path)) { cairo_boxes_t boxes; - _cairo_boxes_init_with_clip (&boxes, extents.clip); + _cairo_boxes_init_with_clip (&boxes, composite->clip); status = _cairo_path_fixed_fill_rectilinear_to_boxes (path, fill_rule, antialias, &boxes); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { status = _clip_and_composite_boxes (surface, op, source, - &boxes, &extents); + &boxes, composite); } _cairo_boxes_fini (&boxes); } @@ -3803,18 +3760,16 @@ _cairo_xcb_surface_render_fill (cairo_xcb_surface_t *surface, if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) { status = _cairo_xcb_surface_render_fill_as_polygon (surface, op, source, path, fill_rule, tolerance, antialias, - &extents); + composite); } else if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) { status = _cairo_xcb_surface_render_fill_via_mask (surface, op, source, path, fill_rule, tolerance, antialias, - &extents); + composite); } else { ASSERT_NOT_REACHED; } } - _cairo_composite_rectangles_fini (&extents); - return status; } @@ -4759,11 +4714,10 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface, cairo_scaled_font_t *scaled_font, cairo_glyph_t *glyphs, int num_glyphs, - const cairo_clip_t *clip) + cairo_composite_rectangles_t *composite, + cairo_bool_t overlap) { - cairo_composite_rectangles_t extents; cairo_int_status_t status; - cairo_bool_t overlap; if (unlikely (! _operator_is_supported (surface->connection->flags, op))) return CAIRO_INT_STATUS_UNSUPPORTED; @@ -4771,19 +4725,11 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface, if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS | CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0) return CAIRO_INT_STATUS_UNSUPPORTED; - status = _cairo_composite_rectangles_init_for_glyphs (&extents, &surface->base, - op, source, - scaled_font, - glyphs, num_glyphs, - clip, &overlap); - if (unlikely (status)) - return status; - status = CAIRO_INT_STATUS_UNSUPPORTED; if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS && 0) { _cairo_scaled_font_freeze_cache (scaled_font); - status = _can_composite_glyphs (surface, &extents.bounded, + status = _can_composite_glyphs (surface, &composite->bounded, scaled_font, glyphs, &num_glyphs); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { composite_glyphs_info_t info; @@ -4794,11 +4740,11 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface, info.num_glyphs = num_glyphs; info.use_mask = overlap || - ! extents.is_bounded || - ! _cairo_clip_is_region(extents.clip); + ! composite->is_bounded || + ! _cairo_clip_is_region(composite->clip); - if (extents.mask.width > extents.unbounded.width || - extents.mask.height > extents.unbounded.height) + if (composite->mask.width > composite->unbounded.width || + composite->mask.height > composite->unbounded.height) { /* Glyphs are tricky since we do not directly control the * geometry and their inked extents depend on the @@ -4809,8 +4755,8 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface, } status = _clip_and_composite (surface, op, source, _composite_glyphs, NULL, - &info, &extents, - need_bounded_clip (&extents) | + &info, composite, + need_bounded_clip (composite) | flags); } @@ -4822,10 +4768,8 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t *surface, status = _cairo_xcb_surface_render_glyphs_via_mask (surface, op, source, scaled_font, glyphs, num_glyphs, - &extents); + composite); } - _cairo_composite_rectangles_fini (&extents); - return status; } diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c index 67568bd39..b3ca31996 100644 --- a/src/cairo-xcb-surface.c +++ b/src/cairo-xcb-surface.c @@ -43,6 +43,7 @@ #include "cairo-xcb.h" #include "cairo-xcb-private.h" +#include "cairo-composite-rectangles-private.h" #include "cairo-default-context-private.h" #include "cairo-image-surface-private.h" #include "cairo-surface-backend-private.h" @@ -188,9 +189,10 @@ _cairo_xcb_surface_finish (void *abstract_surface) cairo_status_t status; if (surface->fallback != NULL) { - cairo_surface_finish (surface->fallback); - cairo_surface_destroy (surface->fallback); + cairo_surface_finish (&surface->fallback->base); + cairo_surface_destroy (&surface->fallback->base); } + _cairo_boxes_fini (&surface->fallback_damage); cairo_list_del (&surface->link); @@ -455,7 +457,7 @@ _cairo_xcb_surface_acquire_source_image (void *abstract_surface, cairo_surface_t *image; if (surface->fallback != NULL) { - image = cairo_surface_reference (surface->fallback); + image = cairo_surface_reference (&surface->fallback->base); goto DONE; } @@ -582,6 +584,108 @@ _put_image (cairo_xcb_surface_t *surface, return status; } +static cairo_int_status_t +_put_shm_image_boxes (cairo_xcb_surface_t *surface, + cairo_image_surface_t *image, + xcb_gcontext_t gc, + cairo_boxes_t *boxes) +{ +#if CAIRO_HAS_XCB_SHM_FUNCTIONS + cairo_xcb_shm_info_t *shm_info; + + shm_info = _cairo_user_data_array_get_data (&image->base.user_data, + (const cairo_user_data_key_t *) surface->connection); + if (shm_info != NULL) { + struct _cairo_boxes_chunk *chunk; + + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + int i; + + for (i = 0; i < chunk->count; i++) { + cairo_box_t *b = &chunk->base[i]; + int x = _cairo_fixed_integer_part (b->p1.x); + int y = _cairo_fixed_integer_part (b->p1.y); + int width = _cairo_fixed_integer_part (b->p2.x - b->p1.x); + int height = _cairo_fixed_integer_part (b->p2.y - b->p1.y); + + _cairo_xcb_connection_shm_put_image (surface->connection, + surface->drawable, + gc, + surface->width, surface->height, + x, y, + width, height, + x, y, + image->depth, + shm_info->shm, + shm_info->offset); + } + } + } + + return CAIRO_INT_STATUS_SUCCESS; +#endif + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_status_t +_put_image_boxes (cairo_xcb_surface_t *surface, + cairo_image_surface_t *image, + cairo_boxes_t *boxes) +{ + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; + xcb_gcontext_t gc; + + if (boxes->num_boxes == 0) + return CAIRO_STATUS_SUCCESS; + + /* XXX track damaged region? */ + + status = _cairo_xcb_connection_acquire (surface->connection); + if (unlikely (status)) + return status; + + assert (image->pixman_format == surface->pixman_format); + assert (image->depth == surface->depth); + assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format))); + + gc = _cairo_xcb_screen_get_gc (surface->screen, + surface->drawable, + surface->depth); + + status = _put_shm_image_boxes (surface, image, gc, boxes); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + struct _cairo_boxes_chunk *chunk; + + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + int i; + + for (i = 0; i < chunk->count; i++) { + cairo_box_t *b = &chunk->base[i]; + int x = _cairo_fixed_integer_part (b->p1.x); + int y = _cairo_fixed_integer_part (b->p1.y); + int width = _cairo_fixed_integer_part (b->p2.x - b->p1.x); + int height = _cairo_fixed_integer_part (b->p2.y - b->p1.y); + _cairo_xcb_connection_put_image (surface->connection, + surface->drawable, gc, + width, height, + x, y, + image->depth, + image->stride, + image->data + + x * PIXMAN_FORMAT_BPP (image->pixman_format) / 8 + + y * image->stride); + + } + } + status = CAIRO_STATUS_SUCCESS; + } + + _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc); + _cairo_xcb_connection_release (surface->connection); + return status; +} + static cairo_status_t _cairo_xcb_surface_flush (void *abstract_surface) { @@ -598,20 +702,27 @@ _cairo_xcb_surface_flush (void *abstract_surface) status = surface->base.status; if (status == CAIRO_STATUS_SUCCESS && ! surface->base.finished) { - status = cairo_surface_status (surface->fallback); + status = cairo_surface_status (&surface->fallback->base); - if (status == CAIRO_STATUS_SUCCESS) { - status = _put_image (surface, (cairo_image_surface_t *)surface->fallback); - } + if (status == CAIRO_STATUS_SUCCESS) + status = _cairo_bentley_ottmann_tessellate_boxes (&surface->fallback_damage, + CAIRO_FILL_RULE_WINDING, + &surface->fallback_damage); + + if (status == CAIRO_STATUS_SUCCESS) + status = _put_image_boxes (surface, + surface->fallback, + &surface->fallback_damage); if (status == CAIRO_STATUS_SUCCESS) { _cairo_surface_attach_snapshot (&surface->base, - surface->fallback, + &surface->fallback->base, cairo_surface_finish); } } - cairo_surface_destroy (surface->fallback); + _cairo_boxes_clear (&surface->fallback_damage); + cairo_surface_destroy (&surface->fallback->base); surface->fallback = NULL; return status; @@ -625,7 +736,7 @@ _cairo_xcb_surface_map_to_image (void *abstract_surface, cairo_surface_t *image; if (surface->fallback) - return surface->fallback->backend->map_to_image (surface->fallback, extents); + return surface->fallback->base.backend->map_to_image (&surface->fallback->base, extents); image = _get_image (surface, TRUE, extents->x, extents->y, @@ -638,10 +749,8 @@ _cairo_xcb_surface_map_to_image (void *abstract_surface, * uploading the image will handle the problem for us. */ if (surface->deferred_clear && - ! (extents->x == 0 && - extents->y == 0 && - extents->width == surface->width && - extents->height == surface->height)) { + ! (extents->width == surface->width && + extents->height == surface->height)) { cairo_status_t status = _cairo_xcb_surface_clear (surface); if (unlikely (status)) { cairo_surface_destroy(image); @@ -661,22 +770,32 @@ _cairo_xcb_surface_unmap (void *abstract_surface, cairo_xcb_surface_t *surface = abstract_surface; if (surface->fallback) - return surface->fallback->backend->unmap_image (surface->fallback, image); + return surface->fallback->base.backend->unmap_image (&surface->fallback->base, image); return _put_image (abstract_surface, image); } static cairo_surface_t * -_cairo_xcb_surface_fallback (cairo_xcb_surface_t *surface) +_cairo_xcb_surface_fallback (cairo_xcb_surface_t *surface, + cairo_composite_rectangles_t *composite) { - cairo_surface_t *image; + cairo_image_surface_t *image; + cairo_status_t status; - image = _get_image (surface, TRUE, 0, 0, surface->width, surface->height); + image = (cairo_image_surface_t *) + _get_image (surface, TRUE, 0, 0, surface->width, surface->height); /* If there was a deferred clear, _get_image applied it */ - if (image->status == CAIRO_STATUS_SUCCESS) + if (image->base.status == CAIRO_STATUS_SUCCESS) { surface->deferred_clear = FALSE; - return image; + surface->fallback = image; + } + + status = _cairo_composite_rectangles_add_to_damage (composite, + &surface->fallback_damage); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + return &surface->fallback->base; } static cairo_int_status_t @@ -686,21 +805,34 @@ _cairo_xcb_surface_paint (void *abstract_surface, const cairo_clip_t *clip) { cairo_xcb_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t composite; cairo_int_status_t status; + status = _cairo_composite_rectangles_init_for_paint (&composite, + &surface->base, + op, source, + clip); + if (unlikely (status)) + return status; + if (surface->fallback == NULL) { status = _cairo_xcb_surface_cairo_paint (surface, op, source, clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; + goto done; - status = _cairo_xcb_surface_render_paint (surface, op, source, clip); + status = _cairo_xcb_surface_render_paint (surface, op, source, + &composite); if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; - - surface->fallback = _cairo_xcb_surface_fallback (surface); + goto done; } - return _cairo_surface_paint (surface->fallback, op, source, clip); + status = _cairo_surface_paint (_cairo_xcb_surface_fallback (surface, + &composite), + op, source, clip); + +done: + _cairo_composite_rectangles_fini (&composite); + return status; } static cairo_int_status_t @@ -711,25 +843,34 @@ _cairo_xcb_surface_mask (void *abstract_surface, const cairo_clip_t *clip) { cairo_xcb_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t composite; cairo_int_status_t status; + status = _cairo_composite_rectangles_init_for_mask (&composite, + &surface->base, + op, source, mask, clip); + if (unlikely (status)) + return status; + if (surface->fallback == NULL) { status = _cairo_xcb_surface_cairo_mask (surface, op, source, mask, clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; + goto done; status = _cairo_xcb_surface_render_mask (surface, - op, source, mask, clip); + op, source, mask, &composite); if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; - - surface->fallback = _cairo_xcb_surface_fallback (surface); + goto done; } - return _cairo_surface_mask (surface->fallback, - op, source, mask, - clip); + status = _cairo_surface_mask (_cairo_xcb_surface_fallback (surface, + &composite), + op, source, mask, + clip); +done: + _cairo_composite_rectangles_fini (&composite); + return status; } static cairo_int_status_t @@ -745,8 +886,17 @@ _cairo_xcb_surface_stroke (void *abstract_surface, const cairo_clip_t *clip) { cairo_xcb_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t composite; cairo_int_status_t status; + status = _cairo_composite_rectangles_init_for_stroke (&composite, + &surface->base, + op, source, + path, style, ctm, + clip); + if (unlikely (status)) + return status; + if (surface->fallback == NULL) { status = _cairo_xcb_surface_cairo_stroke (surface, op, source, path, style, @@ -755,26 +905,28 @@ _cairo_xcb_surface_stroke (void *abstract_surface, clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; + goto done; status = _cairo_xcb_surface_render_stroke (surface, op, source, path, style, ctm, ctm_inverse, tolerance, antialias, - clip); + &composite); if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; - - surface->fallback = _cairo_xcb_surface_fallback (surface); + goto done; } - return _cairo_surface_stroke (surface->fallback, - op, source, - path, style, - ctm, ctm_inverse, - tolerance, antialias, - clip); + status = _cairo_surface_stroke (_cairo_xcb_surface_fallback (surface, + &composite), + op, source, + path, style, + ctm, ctm_inverse, + tolerance, antialias, + clip); +done: + _cairo_composite_rectangles_fini (&composite); + return status; } static cairo_int_status_t @@ -788,31 +940,41 @@ _cairo_xcb_surface_fill (void *abstract_surface, const cairo_clip_t *clip) { cairo_xcb_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t composite; cairo_int_status_t status; + status = _cairo_composite_rectangles_init_for_fill (&composite, + &surface->base, + op, source, path, + clip); + if (unlikely (status)) + return status; + if (surface->fallback == NULL) { status = _cairo_xcb_surface_cairo_fill (surface, op, source, path, fill_rule, tolerance, antialias, clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; + goto done; status = _cairo_xcb_surface_render_fill (surface, op, source, path, fill_rule, tolerance, antialias, - clip); + &composite); if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; - - surface->fallback = _cairo_xcb_surface_fallback (surface); + goto done; } - return _cairo_surface_fill (surface->fallback, - op, source, - path, fill_rule, - tolerance, antialias, - clip); + status = _cairo_surface_fill (_cairo_xcb_surface_fallback (surface, + &composite), + op, source, + path, fill_rule, + tolerance, antialias, + clip); +done: + _cairo_composite_rectangles_fini (&composite); + return status; } static cairo_int_status_t @@ -825,7 +987,18 @@ _cairo_xcb_surface_glyphs (void *abstract_surface, const cairo_clip_t *clip) { cairo_xcb_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t composite; cairo_int_status_t status; + cairo_bool_t overlap; + + status = _cairo_composite_rectangles_init_for_glyphs (&composite, + &surface->base, + op, source, + scaled_font, + glyphs, num_glyphs, + clip, &overlap); + if (unlikely (status)) + return status; if (surface->fallback == NULL) { status = _cairo_xcb_surface_cairo_glyphs (surface, @@ -833,25 +1006,27 @@ _cairo_xcb_surface_glyphs (void *abstract_surface, scaled_font, glyphs, num_glyphs, clip); if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; + goto done; status = _cairo_xcb_surface_render_glyphs (surface, op, source, scaled_font, glyphs, num_glyphs, - clip); + &composite, overlap); if (status != CAIRO_INT_STATUS_UNSUPPORTED) - return status; - - surface->fallback = _cairo_xcb_surface_fallback (surface); + goto done; } - return _cairo_surface_show_text_glyphs (surface->fallback, - op, source, - NULL, 0, - glyphs, num_glyphs, - NULL, 0, 0, - scaled_font, - clip); + status = _cairo_surface_show_text_glyphs (_cairo_xcb_surface_fallback (surface, + &composite), + op, source, + NULL, 0, + glyphs, num_glyphs, + NULL, 0, 0, + scaled_font, + clip); +done: + _cairo_composite_rectangles_fini (&composite); + return status; } const cairo_surface_backend_t _cairo_xcb_surface_backend = { @@ -910,8 +1085,6 @@ _cairo_xcb_surface_create_internal (cairo_xcb_screen_t *screen, surface->screen = screen; cairo_list_add (&surface->link, &screen->surfaces); - surface->fallback = NULL; - surface->drawable = drawable; surface->owns_pixmap = owns_pixmap; @@ -931,6 +1104,9 @@ _cairo_xcb_surface_create_internal (cairo_xcb_screen_t *screen, surface->pixman_format = pixman_format; surface->xrender_format = xrender_format; + surface->fallback = NULL; + _cairo_boxes_init (&surface->fallback_damage); + return &surface->base; }