summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-07-19 11:29:49 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2011-07-20 13:19:38 +0100
commitd5d4a0f24031580db93d3b7909482687458718e2 (patch)
tree2b3b4082648f83d03baa073d91d832a3c4eb322a /src
parentb419fdcacd636dc2274695f922f758a8b521ca01 (diff)
xcb: Take advantage of clip-boxes
A demonstration of step 2, improves performance for selected benchmarks on selected GPUs by up to 30%. firefox-fishbowl on snb {i5-2520m): 42s -> 29s. firefox-talos-gfx on snb: 7.6 -> 5.2s. firefox-fishbowl on pnv (n450): 380 -> 360s. Whist this looks like it is getting close to as good as we can achieve, we are constrained by both our API and Xrender and fishbowl is about 50% slower than peak performance (on snb). And it fixes the older performance regression in firefox-planet-gnome. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src')
-rw-r--r--src/cairo-boxes-intersect.c5
-rw-r--r--src/cairo-clip-private.h3
-rw-r--r--src/cairo-clip.c32
-rw-r--r--src/cairo-composite-rectangles-private.h4
-rw-r--r--src/cairo-composite-rectangles.c33
-rw-r--r--src/cairo-debug.c10
-rw-r--r--src/cairo-xcb-private.h1
-rw-r--r--src/cairo-xcb-surface-render.c777
-rw-r--r--src/cairo-xcb-surface.c1
9 files changed, 622 insertions, 244 deletions
diff --git a/src/cairo-boxes-intersect.c b/src/cairo-boxes-intersect.c
index 831abc10..230c6f01 100644
--- a/src/cairo-boxes-intersect.c
+++ b/src/cairo-boxes-intersect.c
@@ -572,14 +572,13 @@ _cairo_boxes_intersect (const cairo_boxes_t *a,
return CAIRO_STATUS_SUCCESS;
}
- if (unlikely (a->num_boxes == 1)) {
+ if (a->num_boxes == 1) {
cairo_box_t box = a->chunks.base[0];
return _cairo_boxes_intersect_with_box (b, &box, out);
}
- if (unlikely (b->num_boxes == 1)) {
+ if (b->num_boxes == 1) {
cairo_box_t box = b->chunks.base[0];
return _cairo_boxes_intersect_with_box (a, &box, out);
- /* XXX */
}
rectangles = stack_rectangles;
diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h
index 861be63c..2ad53efd 100644
--- a/src/cairo-clip-private.h
+++ b/src/cairo-clip-private.h
@@ -95,6 +95,9 @@ cairo_private cairo_clip_t *
_cairo_clip_copy (const cairo_clip_t *clip);
cairo_private cairo_clip_t *
+_cairo_clip_copy_region (const cairo_clip_t *clip);
+
+cairo_private cairo_clip_t *
_cairo_clip_copy_with_translation (const cairo_clip_t *clip, int tx, int ty);
cairo_private cairo_bool_t
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 99d7cd46..e5979d52 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -176,6 +176,38 @@ _cairo_clip_copy (const cairo_clip_t *clip)
}
cairo_clip_t *
+_cairo_clip_copy_region (const cairo_clip_t *clip)
+{
+ cairo_clip_t *copy;
+ int i;
+
+ if (clip == NULL || _cairo_clip_is_all_clipped (clip))
+ return (cairo_clip_t *) clip;
+
+ assert (clip->num_boxes);
+
+ copy = _cairo_clip_create ();
+ copy->extents = clip->extents;
+
+ copy->boxes = _cairo_malloc_ab (clip->num_boxes, sizeof (cairo_box_t));
+ if (unlikely (copy->boxes == NULL))
+ return _cairo_clip_set_all_clipped (copy);
+
+ for (i = 0; i < clip->num_boxes; i++) {
+ copy->boxes[i].p1.x = _cairo_fixed_floor (clip->boxes[i].p1.x);
+ copy->boxes[i].p1.y = _cairo_fixed_floor (clip->boxes[i].p1.y);
+ copy->boxes[i].p2.x = _cairo_fixed_ceil (clip->boxes[i].p2.x);
+ copy->boxes[i].p2.y = _cairo_fixed_ceil (clip->boxes[i].p2.y);
+ }
+ copy->num_boxes = clip->num_boxes;
+
+ copy->region = cairo_region_reference (clip->region);
+ copy->is_region = TRUE;
+
+ return copy;
+}
+
+cairo_clip_t *
_cairo_clip_intersect_path (cairo_clip_t *clip,
const cairo_path_fixed_t *path,
cairo_fill_rule_t fill_rule,
diff --git a/src/cairo-composite-rectangles-private.h b/src/cairo-composite-rectangles-private.h
index 2b4bdba9..62244b2b 100644
--- a/src/cairo-composite-rectangles-private.h
+++ b/src/cairo-composite-rectangles-private.h
@@ -104,6 +104,10 @@ _cairo_composite_rectangles_init_for_glyphs (cairo_composite_rectangles_t *exten
const cairo_clip_t *clip,
cairo_bool_t *overlap);
+cairo_private cairo_int_status_t
+_cairo_composite_rectangles_intersect_mask_extents (cairo_composite_rectangles_t *extents,
+ const cairo_box_t *box);
+
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 cab7c0cf..7f288cb9 100644
--- a/src/cairo-composite-rectangles.c
+++ b/src/cairo-composite-rectangles.c
@@ -112,6 +112,9 @@ _cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents,
if (! ret && extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK)
return CAIRO_INT_STATUS_NOTHING_TO_DO;
+ if (extents->is_bounded == (CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE))
+ extents->unbounded = extents->bounded;
+
extents->clip = _cairo_clip_reduce_for_composite (clip, extents);
if (_cairo_clip_is_all_clipped (extents->clip))
return CAIRO_INT_STATUS_NOTHING_TO_DO;
@@ -120,6 +123,36 @@ _cairo_composite_rectangles_intersect (cairo_composite_rectangles_t *extents,
}
cairo_int_status_t
+_cairo_composite_rectangles_intersect_mask_extents (cairo_composite_rectangles_t *extents,
+ const cairo_box_t *box)
+{
+ cairo_rectangle_int_t mask;
+ cairo_int_status_t status;
+ cairo_clip_t *clip;
+
+ _cairo_box_round_to_rectangle (box, &mask);
+ if (mask.x == extents->mask.x &&
+ mask.y == extents->mask.y &&
+ mask.width == extents->mask.width &&
+ mask.height == extents->mask.height)
+ {
+ return CAIRO_INT_STATUS_SUCCESS;
+ }
+
+ _cairo_rectangle_intersect (&extents->mask, &mask);
+
+ extents->mask = mask;
+ clip = extents->clip;
+
+ status = _cairo_composite_rectangles_intersect (extents, clip);
+
+ if (clip != extents->clip)
+ _cairo_clip_destroy (clip);
+
+ return status;
+}
+
+cairo_int_status_t
_cairo_composite_rectangles_init_for_mask (cairo_composite_rectangles_t *extents,
int surface_width, int surface_height,
cairo_operator_t op,
diff --git a/src/cairo-debug.c b/src/cairo-debug.c
index 99289e3f..9e687482 100644
--- a/src/cairo-debug.c
+++ b/src/cairo-debug.c
@@ -269,6 +269,16 @@ _cairo_debug_print_polygon (FILE *stream, cairo_polygon_t *polygon)
_cairo_fixed_to_double (polygon->extents.p1.y),
_cairo_fixed_to_double (polygon->extents.p2.x),
_cairo_fixed_to_double (polygon->extents.p2.y));
+ if (polygon->num_limits) {
+ fprintf (stream,
+ " : limit=(%f, %f), (%f, %f) x %d\n",
+ _cairo_fixed_to_double (polygon->limit.p1.x),
+ _cairo_fixed_to_double (polygon->limit.p1.y),
+ _cairo_fixed_to_double (polygon->limit.p2.x),
+ _cairo_fixed_to_double (polygon->limit.p2.y),
+ polygon->num_limits);
+ }
+
for (n = 0; n < polygon->num_edges; n++) {
cairo_edge_t *edge = &polygon->edges[n];
diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
index d52306ec..1a81cef3 100644
--- a/src/cairo-xcb-private.h
+++ b/src/cairo-xcb-private.h
@@ -90,6 +90,7 @@ struct _cairo_xcb_surface {
int use_pixmap;
cairo_bool_t deferred_clear;
+ cairo_color_t deferred_clear_color;
int width;
int height;
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index 66e933e2..ac070234 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -55,6 +55,13 @@
* extension if it is available.
*/
+static cairo_status_t
+_clip_and_composite_boxes (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_boxes_t *boxes,
+ cairo_composite_rectangles_t *extents);
+
static inline cairo_xcb_connection_t *
_picture_to_connection (cairo_xcb_picture_t *picture)
{
@@ -1466,7 +1473,7 @@ _composite_traps (void *closure,
const cairo_pattern_t *pattern,
int dst_x, int dst_y,
const cairo_rectangle_int_t *extents,
- cairo_region_t *clip_region)
+ cairo_clip_t *clip)
{
composite_traps_info_t *info = closure;
const cairo_traps_t *traps = &info->traps;
@@ -1475,8 +1482,15 @@ _composite_traps (void *closure,
xcb_render_pictformat_t xrender_format;
xcb_render_trapezoid_t *xtraps;
int render_reference_x, render_reference_y;
+ cairo_status_t status;
int i;
+ if (dst->deferred_clear) {
+ status = _cairo_xcb_surface_clear (dst);
+ if (unlikely (status))
+ return status;
+ }
+
src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
if (unlikely (src->base.status))
return src->base.status;
@@ -1571,7 +1585,85 @@ typedef cairo_status_t
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
- cairo_region_t *clip_region);
+ cairo_clip_t *clip);
+
+static void do_unaligned_row(void (*blt)(void *closure,
+ int16_t x, int16_t y,
+ int16_t w, int16_t h,
+ uint16_t coverage),
+ void *closure,
+ const cairo_box_t *b,
+ int tx, int y, int h,
+ int coverage)
+{
+ int x1 = _cairo_fixed_integer_part (b->p1.x) - tx;
+ int x2 = _cairo_fixed_integer_part (b->p2.x) - tx;
+ if (x2 > x1) {
+ if (! _cairo_fixed_is_integer (b->p1.x)) {
+ blt(closure, x1, y, 1, h,
+ coverage * (256 - _cairo_fixed_fractional_part (b->p1.x)));
+ x1++;
+ }
+
+ blt(closure, x1, y, x2-x1, h, 256*coverage);
+
+ if (! _cairo_fixed_is_integer (b->p2.x))
+ blt(closure, x2, y, 1, h,
+ coverage * _cairo_fixed_fractional_part (b->p2.x));
+ } else
+ blt(closure, x1, y, 1, h,
+ coverage * (b->p2.x - b->p1.x));
+}
+
+static void do_unaligned_box(void (*blt)(void *closure,
+ int16_t x, int16_t y,
+ int16_t w, int16_t h,
+ uint16_t coverage),
+ void *closure,
+ const cairo_box_t *b, int tx, int ty)
+{
+ int y1 = _cairo_fixed_integer_part (b->p1.y) - ty;
+ int y2 = _cairo_fixed_integer_part (b->p2.y) - ty;
+ if (y2 > y1) {
+ if (! _cairo_fixed_is_integer (b->p1.y)) {
+ do_unaligned_row(blt, closure, b, tx, y1, 1,
+ 256 - _cairo_fixed_fractional_part (b->p1.y));
+ y1++;
+ }
+
+ do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
+
+ if (! _cairo_fixed_is_integer (b->p2.y))
+ do_unaligned_row(blt, closure, b, tx, y2, 1,
+ _cairo_fixed_fractional_part (b->p2.y));
+ } else
+ do_unaligned_row(blt, closure, b, tx, y1, 1,
+ b->p2.y - b->p1.y);
+}
+
+
+static void blt_in(void *closure,
+ int16_t x, int16_t y,
+ int16_t w, int16_t h,
+ uint16_t coverage)
+{
+ cairo_xcb_surface_t *mask = closure;
+ xcb_render_color_t color;
+ xcb_rectangle_t rect;
+
+ color.red = color.green = color.blue = 0;
+ color.alpha = coverage;
+
+ rect.x = x;
+ rect.y = y;
+ rect.width = w;
+ rect.height = h;
+
+ _cairo_xcb_connection_render_fill_rectangles (mask->connection,
+ XCB_RENDER_PICT_OP_IN,
+ mask->picture,
+ color, 1, &rect);
+}
static cairo_xcb_surface_t *
_create_composite_mask (cairo_clip_t *clip,
@@ -1581,11 +1673,9 @@ _create_composite_mask (cairo_clip_t *clip,
const cairo_rectangle_int_t*extents)
{
cairo_xcb_surface_t *surface;
- cairo_bool_t clip_surface = FALSE;
+ cairo_bool_t need_clip_combine;
cairo_status_t status;
- clip_surface = ! _cairo_clip_is_region (clip);
-
surface = (cairo_xcb_surface_t *)
_cairo_xcb_surface_create_similar (dst, CAIRO_CONTENT_ALPHA,
extents->width, extents->height);
@@ -1594,27 +1684,9 @@ _create_composite_mask (cairo_clip_t *clip,
_cairo_xcb_surface_ensure_picture (surface);
- if (surface->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
- xcb_render_color_t clear;
- xcb_rectangle_t xrect;
-
- clear.red = clear.green = clear.blue = clear.alpha = 0;
-
- xrect.x = xrect.y = 0;
- xrect.width = extents->width;
- xrect.height = extents->height;
-
- _cairo_xcb_connection_render_fill_rectangles (surface->connection,
- XCB_RENDER_PICT_OP_CLEAR,
- surface->picture,
- clear, 1, &xrect);
- } else {
- status = _cairo_xcb_surface_clear (surface);
- if (unlikely (status)) {
- cairo_surface_destroy (&surface->base);
- return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status);
- }
- }
+ surface->deferred_clear_color = *CAIRO_COLOR_TRANSPARENT;
+ surface->deferred_clear = TRUE;
+ surface->base.is_clear = TRUE;
/* Is it worth setting the clip region here? */
status = draw_func (draw_closure, surface,
@@ -1626,7 +1698,26 @@ _create_composite_mask (cairo_clip_t *clip,
return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status);
}
- if (clip_surface) {
+ if (surface->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
+ int i;
+
+ for (i = 0; i < clip->num_boxes; i++) {
+ cairo_box_t *b = &clip->boxes[i];
+
+ if (! _cairo_fixed_is_integer (b->p1.x) ||
+ ! _cairo_fixed_is_integer (b->p1.y) ||
+ ! _cairo_fixed_is_integer (b->p2.x) ||
+ ! _cairo_fixed_is_integer (b->p2.y))
+ {
+ do_unaligned_box(blt_in, surface, b, extents->x, extents->y);
+ }
+ }
+
+ need_clip_combine = clip->path != NULL;
+ } else
+ need_clip_combine = ! _cairo_clip_is_region (clip);
+
+ if (need_clip_combine) {
status = _cairo_clip_combine_with_surface (clip, &surface->base,
extents->x, extents->y);
if (unlikely (status)) {
@@ -2160,17 +2251,27 @@ _cairo_xcb_surface_clear (cairo_xcb_surface_t *dst)
rect.height = dst->height;
if (dst->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) {
- xcb_render_color_t transparent = { 0 };
+ xcb_render_color_t color;
+ uint8_t op;
+
+ color.red = dst->deferred_clear_color.red_short;
+ color.green = dst->deferred_clear_color.green_short;
+ color.blue = dst->deferred_clear_color.blue_short;
+ color.alpha = dst->deferred_clear_color.alpha_short;
+
+ if (color.alpha == 0)
+ op = XCB_RENDER_PICT_OP_CLEAR;
+ else
+ op = XCB_RENDER_PICT_OP_SRC;
_cairo_xcb_surface_ensure_picture (dst);
_cairo_xcb_connection_render_fill_rectangles (dst->connection,
- XCB_RENDER_PICT_OP_CLEAR,
- dst->picture,
- transparent,
+ op, dst->picture, color,
1, &rect);
} else {
gc = _cairo_xcb_screen_get_gc (dst->screen, dst->drawable, dst->depth);
+ /* XXX color */
_cairo_xcb_connection_poly_fill_rectangle (dst->connection,
dst->drawable, gc,
1, &rect);
@@ -2184,22 +2285,34 @@ _cairo_xcb_surface_clear (cairo_xcb_surface_t *dst)
return CAIRO_STATUS_SUCCESS;
}
+enum {
+ NEED_CLIP_REGION = 0x1,
+ NEED_CLIP_SURFACE = 0x2,
+};
+
static cairo_bool_t
need_bounded_clip (cairo_composite_rectangles_t *extents)
{
- return ! _cairo_clip_is_region (extents->clip);
+ unsigned int flags = NEED_CLIP_REGION;
+ if (! _cairo_clip_is_region (extents->clip))
+ flags |= NEED_CLIP_SURFACE;
+ return flags;
}
static cairo_bool_t
need_unbounded_clip (cairo_composite_rectangles_t *extents)
{
- if (! extents->is_bounded)
- return need_bounded_clip (extents);
-
- return extents->clip->path != NULL;
+ unsigned int flags = 0;
+ if (! extents->is_bounded) {
+ flags |= NEED_CLIP_REGION;
+ if (! _cairo_clip_is_region (extents->clip))
+ flags |= NEED_CLIP_SURFACE;
+ }
+ if (extents->clip->path != NULL)
+ flags |= NEED_CLIP_SURFACE;
+ return flags;
}
-
static cairo_status_t
_clip_and_composite (cairo_xcb_surface_t *dst,
cairo_operator_t op,
@@ -2207,10 +2320,10 @@ _clip_and_composite (cairo_xcb_surface_t *dst,
xcb_draw_func_t draw_func,
void *draw_closure,
cairo_composite_rectangles_t*extents,
- cairo_bool_t need_clip_surface)
+ unsigned int need_clip)
{
+ cairo_region_t *clip_region = NULL;
cairo_status_t status;
- cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
status = _cairo_xcb_connection_acquire (dst->connection);
if (unlikely (status))
@@ -2226,11 +2339,16 @@ _clip_and_composite (cairo_xcb_surface_t *dst,
_cairo_xcb_surface_ensure_picture (dst);
- if (clip_region != NULL) {
- status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
- if (unlikely (status)) {
- _cairo_xcb_connection_release (dst->connection);
- return status;
+ if (need_clip & NEED_CLIP_REGION) {
+ clip_region = _cairo_clip_get_region (extents->clip);
+ if (cairo_region_contains_rectangle (clip_region, &extents->unbounded) == CAIRO_REGION_OVERLAP_IN)
+ clip_region = NULL;
+ if (clip_region != NULL) {
+ status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status)) {
+ _cairo_xcb_connection_release (dst->connection);
+ return status;
+ }
}
}
@@ -2249,7 +2367,7 @@ _clip_and_composite (cairo_xcb_surface_t *dst,
src = NULL;
}
- if (need_clip_surface) {
+ if (need_clip & NEED_CLIP_SURFACE) {
if (extents->is_bounded) {
status = _clip_and_composite_with_mask (extents->clip, op, src,
draw_func, draw_closure,
@@ -2264,18 +2382,18 @@ _clip_and_composite (cairo_xcb_surface_t *dst,
dst, op, src,
0, 0,
&extents->bounded,
- clip_region);
+ extents->clip);
}
}
if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
- if (need_clip_surface)
+ if (need_clip & NEED_CLIP_SURFACE)
status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst, extents, extents->clip);
else
status = _cairo_xcb_surface_fixup_unbounded (dst, extents);
}
- if (clip_region != NULL)
+ if (clip_region)
_cairo_xcb_surface_clear_clip_region (dst);
_cairo_xcb_connection_release (dst->connection);
@@ -2336,7 +2454,7 @@ _composite_boxes (cairo_xcb_surface_t *dst,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+ if (cairo_region_contains_rectangle (clip_region, &extents->bounded) == CAIRO_REGION_OVERLAP_IN)
clip_region = NULL;
status = _cairo_xcb_connection_acquire (dst->connection);
@@ -2550,7 +2668,7 @@ _upload_image_inplace (cairo_xcb_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
-static void
+static cairo_int_status_t
trim_extents_to_traps (cairo_composite_rectangles_t *extents,
cairo_traps_t *traps)
{
@@ -2560,87 +2678,7 @@ trim_extents_to_traps (cairo_composite_rectangles_t *extents,
* we need to compensate when fixing up the unbounded area.
*/
_cairo_traps_extents (traps, &box);
- _cairo_box_round_to_rectangle (&box, &extents->mask);
- _cairo_rectangle_intersect (&extents->bounded, &extents->mask);
-}
-
-static cairo_status_t
-_clip_and_composite_boxes (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *src,
- cairo_boxes_t *boxes,
- cairo_composite_rectangles_t *extents)
-{
- composite_traps_info_t info;
- cairo_int_status_t status;
-
- if (boxes->num_boxes == 0 && extents->is_bounded)
- return CAIRO_STATUS_SUCCESS;
-
- if (boxes->is_pixel_aligned && _cairo_clip_is_region (extents->clip) &&
- (op == CAIRO_OPERATOR_SOURCE || (op == CAIRO_OPERATOR_OVER && dst->base.is_clear)))
- {
- if (boxes->num_boxes == 1 &&
- extents->bounded.width == dst->width &&
- extents->bounded.height == dst->height)
- {
- op = CAIRO_OPERATOR_SOURCE;
- dst->deferred_clear = FALSE;
- }
-
- status = _upload_image_inplace (dst, src, boxes);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
- }
-
- if (dst->deferred_clear) {
- status = _cairo_xcb_surface_clear (dst);
- if (unlikely (status)) {
- return status;
- }
-
- if (op == CAIRO_OPERATOR_OVER)
- op = CAIRO_OPERATOR_SOURCE;
- }
-
- if (boxes->is_pixel_aligned &&
- _cairo_clip_is_region (extents->clip) &&
- op == CAIRO_OPERATOR_SOURCE) {
- status = _upload_image_inplace (dst, src, boxes);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
- }
-
- if ((dst->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
- return _core_boxes (dst, op, src, boxes, extents);
-
- if (dst->deferred_clear) {
- status = _cairo_xcb_surface_clear (dst);
- if (unlikely (status))
- return status;
- }
-
- /* Use a fast path if the boxes are pixel aligned */
- status = _composite_boxes (dst, op, src, boxes, extents);
- if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
-
- if ((dst->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) == 0)
- return CAIRO_INT_STATUS_UNSUPPORTED;
-
- /* Otherwise render via a mask and composite in the usual fashion. */
- status = _cairo_traps_init_boxes (&info.traps, boxes);
- if (unlikely (status))
- return status;
-
- trim_extents_to_traps (extents, &info.traps);
- info.antialias = CAIRO_ANTIALIAS_DEFAULT;
- status = _clip_and_composite (dst, op, src,
- _composite_traps, &info,
- extents, need_unbounded_clip (extents));
-
- _cairo_traps_fini (&info.traps);
- return status;
+ return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
}
static cairo_bool_t
@@ -2735,6 +2773,206 @@ _boxes_for_traps (cairo_boxes_t *boxes,
}
static cairo_status_t
+_composite_polygon (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_polygon_t *polygon,
+ cairo_antialias_t antialias,
+ cairo_fill_rule_t fill_rule,
+ cairo_composite_rectangles_t *extents)
+{
+ composite_traps_info_t traps;
+ cairo_bool_t clip_surface = ! _cairo_clip_is_region (extents->clip);
+ cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
+ cairo_status_t status;
+
+ if (polygon->num_edges == 0) {
+ status = CAIRO_STATUS_SUCCESS;
+
+ if (! extents->is_bounded) {
+ if (cairo_region_contains_rectangle (clip_region, &extents->unbounded) == CAIRO_REGION_OVERLAP_IN)
+ clip_region = NULL;
+
+ if (clip_surface == FALSE) {
+ if (clip_region != NULL) {
+ status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
+ if (unlikely (status))
+ return status;
+ }
+
+ status = _cairo_xcb_surface_fixup_unbounded (dst, extents);
+
+ if (clip_region != NULL)
+ _cairo_xcb_surface_clear_clip_region (dst);
+ } else {
+ status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst,
+ extents,
+ extents->clip);
+ }
+ }
+
+ return status;
+ }
+
+ _cairo_traps_init (&traps.traps);
+
+ status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule);
+ if (unlikely (status))
+ goto CLEANUP_TRAPS;
+
+ if (traps.traps.has_intersections) {
+ if (traps.traps.is_rectangular)
+ status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
+ else if (traps.traps.is_rectilinear)
+ status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
+ else
+ status = _cairo_bentley_ottmann_tessellate_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
+ if (unlikely (status))
+ goto CLEANUP_TRAPS;
+ }
+
+ /* Use a fast path if the trapezoids consist of a simple region,
+ * but we can only do this if we do not have a clip surface, or can
+ * substitute the mask with the clip.
+ */
+ if (traps.traps.maybe_region &&
+ _traps_are_pixel_aligned (&traps.traps, antialias) &&
+ (! clip_surface ||
+ (extents->is_bounded && op != CAIRO_OPERATOR_SOURCE)))
+ {
+ cairo_boxes_t boxes;
+
+ _boxes_for_traps (&boxes, &traps.traps, antialias);
+ status = _clip_and_composite_boxes (dst, op, source,
+ &boxes, extents);
+ }
+ else
+ {
+ /* Otherwise render the trapezoids to a mask and composite in the usual
+ * fashion.
+ */
+ traps.antialias = antialias;
+ status = trim_extents_to_traps (extents, &traps.traps);
+ if (likely (status == CAIRO_STATUS_SUCCESS)) {
+ status = _clip_and_composite (dst, op, source,
+ _composite_traps, &traps,
+ extents, need_unbounded_clip (extents));
+ }
+ }
+
+CLEANUP_TRAPS:
+ _cairo_traps_fini (&traps.traps);
+
+ return status;
+}
+
+
+static cairo_status_t
+_clip_and_composite_boxes (cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src,
+ cairo_boxes_t *boxes,
+ cairo_composite_rectangles_t *extents)
+{
+ composite_traps_info_t info;
+ cairo_int_status_t status;
+
+ if (boxes->num_boxes == 0 && extents->is_bounded)
+ return CAIRO_STATUS_SUCCESS;
+
+ if (boxes->is_pixel_aligned && _cairo_clip_is_region (extents->clip) &&
+ (op == CAIRO_OPERATOR_SOURCE ||
+ (dst->base.is_clear && (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD))))
+ {
+ if (boxes->num_boxes == 1 &&
+ extents->bounded.width == dst->width &&
+ extents->bounded.height == dst->height)
+ {
+ op = CAIRO_OPERATOR_SOURCE;
+ dst->deferred_clear = FALSE;
+ }
+
+ status = _upload_image_inplace (dst, src, boxes);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
+
+ /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
+ if (extents->clip->path != NULL && extents->is_bounded) {
+ cairo_polygon_t polygon;
+ cairo_fill_rule_t fill_rule;
+ cairo_antialias_t antialias;
+ cairo_clip_t *clip ;
+
+ clip = _cairo_clip_copy (extents->clip);
+ clip = _cairo_clip_intersect_boxes (clip, boxes);
+ status = _cairo_clip_get_polygon (clip, &polygon,
+ &fill_rule, &antialias);
+ _cairo_clip_path_destroy (clip->path);
+ clip->path = NULL;
+ if (likely (status == CAIRO_INT_STATUS_SUCCESS)) {
+ cairo_clip_t *saved_clip = extents->clip;
+ extents->clip = clip;
+ status = _composite_polygon (dst, op, src,
+ &polygon,
+ antialias,
+ fill_rule,
+ extents);
+ if (extents->clip != clip)
+ clip = NULL;
+ extents->clip = saved_clip;
+ _cairo_polygon_fini (&polygon);
+ }
+ if (clip)
+ _cairo_clip_destroy (clip);
+
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
+
+ if (dst->deferred_clear) {
+ status = _cairo_xcb_surface_clear (dst);
+ if (unlikely (status))
+ return status;
+ }
+
+ if (boxes->is_pixel_aligned &&
+ _cairo_clip_is_region (extents->clip) &&
+ op == CAIRO_OPERATOR_SOURCE) {
+ status = _upload_image_inplace (dst, src, boxes);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+ }
+
+ if ((dst->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
+ return _core_boxes (dst, op, src, boxes, extents);
+
+ /* Use a fast path if the boxes are pixel aligned */
+ status = _composite_boxes (dst, op, src, boxes, extents);
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+ return status;
+
+ if ((dst->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) == 0)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
+
+ /* Otherwise render via a mask and composite in the usual fashion. */
+ status = _cairo_traps_init_boxes (&info.traps, boxes);
+ if (unlikely (status))
+ return status;
+
+ info.antialias = CAIRO_ANTIALIAS_DEFAULT;
+ status = trim_extents_to_traps (extents, &info.traps);
+ if (status == CAIRO_INT_STATUS_SUCCESS) {
+ status = _clip_and_composite (dst, op, src,
+ _composite_traps, &info,
+ extents, need_unbounded_clip (extents));
+ }
+
+ _cairo_traps_fini (&info.traps);
+ return status;
+}
+
+static cairo_status_t
_composite_mask (void *closure,
cairo_xcb_surface_t *dst,
cairo_operator_t op,
@@ -2742,10 +2980,25 @@ _composite_mask (void *closure,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
- cairo_region_t *clip_region)
+ cairo_clip_t *clip)
{
const cairo_pattern_t *mask_pattern = closure;
cairo_xcb_picture_t *src, *mask = NULL;
+ cairo_status_t status;
+
+ if (dst->base.is_clear) {
+ if (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD)
+ op = CAIRO_OPERATOR_SOURCE;
+ }
+
+ if (op == CAIRO_OPERATOR_SOURCE && clip == NULL)
+ dst->deferred_clear = FALSE;
+
+ if (dst->deferred_clear) {
+ status = _cairo_xcb_surface_clear (dst);
+ if (unlikely (status))
+ return status;
+ }
if (src_pattern != NULL) {
src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents);
@@ -2789,6 +3042,105 @@ _composite_mask (void *closure,
return CAIRO_STATUS_SUCCESS;
}
+struct composite_opacity_info {
+ uint8_t op;
+ cairo_xcb_surface_t *dst;
+ cairo_xcb_picture_t *src;
+ double opacity;
+};
+
+static void composite_opacity(void *closure,
+ int16_t x, int16_t y,
+ int16_t w, int16_t h,
+ uint16_t coverage)
+{
+ struct composite_opacity_info *info = closure;
+ cairo_solid_pattern_t mask_pattern;
+ cairo_xcb_picture_t *mask;
+ cairo_color_t color;
+
+ color.red = color.green = color.blue = 0;
+ color.alpha = info->opacity * coverage;
+ _cairo_pattern_init_solid (&mask_pattern, &color);
+
+ mask = _cairo_xcb_picture_for_pattern (info->dst, &mask_pattern.base, NULL);
+ if (likely (mask->base.status == CAIRO_STATUS_SUCCESS)) {
+ if (info->src) {
+ _cairo_xcb_connection_render_composite (info->dst->connection,
+ info->op,
+ info->src->picture,
+ mask->picture,
+ info->dst->picture,
+ x + info->src->x, y + info->src->y,
+ 0, 0,
+ x, y,
+ w, h);
+ } else {
+ _cairo_xcb_connection_render_composite (info->dst->connection,
+ info->op,
+ mask->picture,
+ XCB_NONE,
+ info->dst->picture,
+ 0, 0,
+ 0, 0,
+ x, y,
+ w, h);
+ }
+ }
+
+ cairo_surface_destroy (&mask->base);
+}
+
+static cairo_status_t
+_composite_opacity_boxes (void *closure,
+ cairo_xcb_surface_t *dst,
+ cairo_operator_t op,
+ const cairo_pattern_t *src_pattern,
+ int dst_x,
+ int dst_y,
+ const cairo_rectangle_int_t *extents,
+ cairo_clip_t *clip)
+{
+ const cairo_solid_pattern_t *mask_pattern = closure;
+ struct composite_opacity_info info;
+ cairo_status_t status;
+ int i;
+
+ if (dst->base.is_clear) {
+ if (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD)
+ op = CAIRO_OPERATOR_SOURCE;
+ }
+
+ if (op == CAIRO_OPERATOR_SOURCE && clip == NULL)
+ dst->deferred_clear = FALSE;
+
+ if (dst->deferred_clear) {
+ status = _cairo_xcb_surface_clear (dst);
+ if (unlikely (status))
+ return status;
+ }
+
+ info.op = _render_operator (op);
+ info.dst = dst;
+
+ if (src_pattern != NULL) {
+ info.src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents);
+ if (unlikely (info.src->base.status))
+ return info.src->base.status;
+ } else
+ info.src = NULL;
+
+ info.opacity = mask_pattern->color.alpha;
+
+ /* XXX for lots of boxes create a clip region for the fully opaque areas */
+ for (i = 0; i < clip->num_boxes; i++)
+ do_unaligned_box(composite_opacity, &info,
+ &clip->boxes[i], dst_x, dst_y);
+ cairo_surface_destroy (&info.src->base);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
/* high level rasteriser -> compositor */
cairo_int_status_t
@@ -2812,6 +3164,19 @@ _cairo_xcb_surface_render_paint (cairo_xcb_surface_t *surface,
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 &&
+ (op == CAIRO_OPERATOR_SOURCE ||
+ (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;
return CAIRO_STATUS_SUCCESS;
}
@@ -2856,103 +3221,19 @@ _cairo_xcb_surface_render_mask (cairo_xcb_surface_t *surface,
if (unlikely (status))
return status;
- status = _clip_and_composite (surface, op, source,
- _composite_mask, (void *) mask,
- &extents, need_bounded_clip (&extents));
-
- _cairo_composite_rectangles_fini (&extents);
-
- return status;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_render_composite_polygon (cairo_xcb_surface_t *dst,
- cairo_operator_t op,
- const cairo_pattern_t *source,
- cairo_polygon_t *polygon,
- cairo_antialias_t antialias,
- cairo_fill_rule_t fill_rule,
- cairo_composite_rectangles_t *extents)
-{
- composite_traps_info_t traps;
- cairo_bool_t clip_surface = ! _cairo_clip_is_region (extents->clip);
- cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip);
- cairo_status_t status;
-
- if (polygon->num_edges == 0) {
- status = CAIRO_STATUS_SUCCESS;
-
- if (! extents->is_bounded) {
- if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
- clip_region = NULL;
-
- if (clip_surface == FALSE) {
- if (clip_region != NULL) {
- status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
- if (unlikely (status))
- return status;
- }
-
- status = _cairo_xcb_surface_fixup_unbounded (dst, extents);
-
- if (clip_region != NULL)
- _cairo_xcb_surface_clear_clip_region (dst);
- } else {
- status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst,
- extents,
- extents->clip);
- }
- }
-
- return status;
- }
-
- _cairo_traps_init (&traps.traps);
-
- status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule);
- if (unlikely (status))
- goto CLEANUP_TRAPS;
-
- if (traps.traps.has_intersections) {
- if (traps.traps.is_rectangular)
- status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
- else if (traps.traps.is_rectilinear)
- status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
- else
- status = _cairo_bentley_ottmann_tessellate_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
- if (unlikely (status))
- goto CLEANUP_TRAPS;
- }
-
- /* Use a fast path if the trapezoids consist of a simple region,
- * but we can only do this if we do not have a clip surface, or can
- * substitute the mask with the clip.
- */
- if (traps.traps.maybe_region &&
- _traps_are_pixel_aligned (&traps.traps, antialias) &&
- (! clip_surface ||
- (extents->is_bounded && op != CAIRO_OPERATOR_SOURCE)))
- {
- cairo_boxes_t boxes;
-
- _boxes_for_traps (&boxes, &traps.traps, antialias);
- status = _clip_and_composite_boxes (dst, op, source,
- &boxes, extents);
- }
- else
- {
- /* Otherwise render the trapezoids to a mask and composite in the usual
- * fashion.
- */
- trim_extents_to_traps (extents, &traps.traps);
- traps.antialias = antialias;
- status = _clip_and_composite (dst, op, source,
- _composite_traps, &traps,
- extents, need_unbounded_clip (extents));
+ if (mask->type == CAIRO_PATTERN_TYPE_SOLID &&
+ extents.clip->path == NULL &&
+ ! _cairo_clip_is_region (extents.clip)) {
+ status = _clip_and_composite (surface, op, source,
+ _composite_opacity_boxes, (void *) mask,
+ &extents, need_unbounded_clip (&extents));
+ } else {
+ status = _clip_and_composite (surface, op, source,
+ _composite_mask, (void *) mask,
+ &extents, need_bounded_clip (&extents));
}
-CLEANUP_TRAPS:
- _cairo_traps_fini (&traps.traps);
+ _cairo_composite_rectangles_fini (&extents);
return status;
}
@@ -2979,10 +3260,10 @@ _cairo_xcb_surface_render_stroke_as_polygon (cairo_xcb_surface_t *dst,
tolerance,
&polygon);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
- status = _cairo_xcb_surface_render_composite_polygon (dst, op, source,
- &polygon, antialias,
- CAIRO_FILL_RULE_WINDING,
- extents);
+ status = _composite_polygon (dst, op, source,
+ &polygon, antialias,
+ CAIRO_FILL_RULE_WINDING,
+ extents);
}
_cairo_polygon_fini (&polygon);
@@ -3011,6 +3292,7 @@ _cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t *dst,
{
cairo_surface_t *image;
cairo_status_t status;
+ cairo_clip_t *clip;
int x, y;
x = extents->bounded.x;
@@ -3023,13 +3305,15 @@ _cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t *dst,
_clear_image (image);
+ clip = _cairo_clip_copy_region (extents->clip);
status = _cairo_surface_offset_stroke (image, x, y,
CAIRO_OPERATOR_ADD,
&_cairo_pattern_white.base,
path, stroke_style,
ctm, ctm_inverse,
tolerance, antialias,
- NULL);
+ clip);
+ _cairo_clip_destroy (clip);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
cairo_surface_pattern_t mask;
@@ -3082,7 +3366,6 @@ _cairo_xcb_surface_render_stroke (cairo_xcb_surface_t *surface,
if (unlikely (status))
return status;
-
status = CAIRO_INT_STATUS_UNSUPPORTED;
if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
cairo_boxes_t boxes;
@@ -3139,11 +3422,11 @@ _cairo_xcb_surface_render_fill_as_polygon (cairo_xcb_surface_t *dst,
_cairo_polygon_init_with_clip (&polygon, extents->clip);
status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
- status = _cairo_xcb_surface_render_composite_polygon (dst, op, source,
- &polygon,
- antialias,
- fill_rule,
- extents);
+ status = _composite_polygon (dst, op, source,
+ &polygon,
+ antialias,
+ fill_rule,
+ extents);
}
_cairo_polygon_fini (&polygon);
@@ -3162,6 +3445,7 @@ _cairo_xcb_surface_render_fill_via_mask (cairo_xcb_surface_t *dst,
{
cairo_surface_t *image;
cairo_status_t status;
+ cairo_clip_t *clip;
int x, y;
x = extents->bounded.x;
@@ -3175,11 +3459,13 @@ _cairo_xcb_surface_render_fill_via_mask (cairo_xcb_surface_t *dst,
_clear_image (image);
+ clip = _cairo_clip_copy_region (extents->clip);
status = _cairo_surface_offset_fill (image, x, y,
CAIRO_OPERATOR_ADD,
&_cairo_pattern_white.base,
path, fill_rule, tolerance, antialias,
- NULL);
+ clip);
+ _cairo_clip_destroy (clip);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
cairo_surface_pattern_t mask;
@@ -3277,6 +3563,7 @@ _cairo_xcb_surface_render_glyphs_via_mask (cairo_xcb_surface_t *dst,
cairo_surface_t *image;
cairo_content_t content;
cairo_status_t status;
+ cairo_clip_t *clip;
int x, y;
content = CAIRO_CONTENT_ALPHA;
@@ -3293,11 +3580,13 @@ _cairo_xcb_surface_render_glyphs_via_mask (cairo_xcb_surface_t *dst,
_clear_image (image);
+ clip = _cairo_clip_copy_region (extents->clip);
status = _cairo_surface_offset_glyphs (image, x, y,
CAIRO_OPERATOR_ADD,
&_cairo_pattern_white.base,
scaled_font, glyphs, num_glyphs,
- NULL);
+ clip);
+ _cairo_clip_destroy (clip);
if (likely (status == CAIRO_STATUS_SUCCESS)) {
cairo_surface_pattern_t mask;
@@ -4007,7 +4296,7 @@ _composite_glyphs (void *closure,
int dst_x,
int dst_y,
const cairo_rectangle_int_t *extents,
- cairo_region_t *clip_region)
+ cairo_clip_t *clip)
{
composite_glyphs_info_t *info = closure;
cairo_scaled_glyph_t *glyph_cache[64];
@@ -4023,6 +4312,12 @@ _composite_glyphs (void *closure,
unsigned int request_size = 0;
int i;
+ if (dst->deferred_clear) {
+ status = _cairo_xcb_surface_clear (dst);
+ if (unlikely (status))
+ return status;
+ }
+
src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
if (unlikely (src->base.status))
return src->base.status;
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 6738cdd9..200c4c01 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -927,6 +927,7 @@ _cairo_xcb_surface_create_internal (cairo_xcb_screen_t *screen,
surface->use_pixmap = 0;
surface->deferred_clear = FALSE;
+ surface->deferred_clear_color = *CAIRO_COLOR_TRANSPARENT;
surface->width = width;
surface->height = height;