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 <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2011-08-02 13:51:30 +01:00
parent 36a1423045
commit fd613cb9f9
6 changed files with 310 additions and 168 deletions

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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;
}