[cairo-commit] src/cairo-xcb-surface-render.c

Chris Wilson ickle at kemper.freedesktop.org
Sun Jan 23 04:31:21 PST 2011


 src/cairo-xcb-surface-render.c |  120 +++++++++++++++++++++++------------------
 1 file changed, 68 insertions(+), 52 deletions(-)

New commits:
commit bef8b28300ab1f9b46db9d54b072f6f9318dca30
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jan 23 12:28:06 2011 +0000

    xcb: Apply a clip region for compositing many-pixel-aligned-boxes
    
    Based on a patch by  Uli Schlachter.
    
    Uli found that the "fast-path" for compositing pixel-aligned boxes did
    not live up to its name; using multiple Composite is many times slower,
    because of the extra protocol and driver overheads, than specifying a
    clip region and a single Composite.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index 425473a..0b76e8e 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -293,7 +293,8 @@ _cairo_xcb_surface_clear_clip_region (cairo_xcb_surface_t *surface)
     uint32_t values[] = { XCB_NONE };
     _cairo_xcb_connection_render_change_picture (surface->connection,
 						 surface->picture,
-						 XCB_RENDER_CP_CLIP_MASK, values);
+						 XCB_RENDER_CP_CLIP_MASK,
+						 values);
 }
 
 static void
@@ -1433,6 +1434,7 @@ _render_fill_boxes (void			*abstract_dst,
     return CAIRO_STATUS_SUCCESS;
 }
 
+/* pixel aligned, non-overlapping boxes */
 static cairo_int_status_t
 _render_composite_boxes (cairo_xcb_surface_t	*dst,
 			 cairo_operator_t	 op,
@@ -1443,6 +1445,9 @@ _render_composite_boxes (cairo_xcb_surface_t	*dst,
 {
     cairo_xcb_picture_t *src, *mask;
     const struct _cairo_boxes_chunk *chunk;
+    xcb_rectangle_t stack_boxes[128];
+    xcb_rectangle_t *clip_boxes;
+    int num_boxes;
     int render_op;
 
     render_op = _render_operator (op);
@@ -1456,67 +1461,78 @@ _render_composite_boxes (cairo_xcb_surface_t	*dst,
     if (unlikely (src->base.status))
 	return src->base.status;
 
-    if (mask_pattern != NULL) {
-	mask = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
-	if (unlikely (mask->base.status)) {
-	    cairo_surface_destroy (&src->base);
-	    return mask->base.status;
-	}
+    /* amalgamate into a single Composite call by setting a clip region */
+    clip_boxes = stack_boxes;
+    if (boxes->num_boxes > ARRAY_LENGTH(stack_boxes)) {
+	clip_boxes = _cairo_malloc_ab(boxes->num_boxes, sizeof(xcb_rectangle_t));
+	if (unlikely (clip_boxes == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
 
-	for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
-	    const cairo_box_t *box = chunk->base;
-	    int i;
+    num_boxes = 0;
+    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	const cairo_box_t *box = chunk->base;
+	int i;
 
-	    for (i = 0; i < chunk->count; i++) {
-		int x = _cairo_fixed_integer_round_down (box[i].p1.x);
-		int y = _cairo_fixed_integer_round_down (box[i].p1.y);
-		int width  = _cairo_fixed_integer_round_down (box[i].p2.x) - x;
-		int height = _cairo_fixed_integer_round_down (box[i].p2.y) - y;
-
-		if (width && height) {
-		    _cairo_xcb_connection_render_composite (dst->connection,
-							    render_op,
-							    src->picture,
-							    mask->picture,
-							    dst->picture,
-							    x + src->x,
-							    y + src->y,
-							    x + mask->x,
-							    y + mask->y,
-							    x, y,
-							    width, height);
-		}
+	for (i = 0; i < chunk->count; i++) {
+	    int x = _cairo_fixed_integer_round_down (box[i].p1.x);
+	    int y = _cairo_fixed_integer_round_down (box[i].p1.y);
+	    int width  = _cairo_fixed_integer_round_down (box[i].p2.x) - x;
+	    int height = _cairo_fixed_integer_round_down (box[i].p2.y) - y;
+
+	    if (width && height) {
+		clip_boxes[num_boxes].x = x;
+		clip_boxes[num_boxes].y = y;
+		clip_boxes[num_boxes].width = width;
+		clip_boxes[num_boxes].height = height;
+		num_boxes++;
 	    }
 	}
+    }
 
-	cairo_surface_destroy (&mask->base);
-    } else {
-	for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
-	    const cairo_box_t *box = chunk->base;
-	    int i;
+    if (num_boxes) {
+	_cairo_xcb_connection_render_set_picture_clip_rectangles(dst->connection,
+								 dst->picture,
+								 0, 0,
+								 num_boxes,
+								 clip_boxes);
 
-	    for (i = 0; i < chunk->count; i++) {
-		int x = _cairo_fixed_integer_round_down (box[i].p1.x);
-		int y = _cairo_fixed_integer_round_down (box[i].p1.y);
-		int width  = _cairo_fixed_integer_round_down (box[i].p2.x) - x;
-		int height = _cairo_fixed_integer_round_down (box[i].p2.y) - y;
-
-		if (width && height) {
-		    _cairo_xcb_connection_render_composite (dst->connection,
-							    render_op,
-							    src->picture,
-							    XCB_NONE,
-							    dst->picture,
-							    x + src->x,
-							    y + src->y,
-							    0, 0,
-							    x, y,
-							    width, height);
-		}
+	if (mask_pattern != NULL) {
+	    mask = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
+	    if (unlikely (mask->base.status)) {
+		cairo_surface_destroy (&src->base);
+		return mask->base.status;
 	    }
+
+	    _cairo_xcb_connection_render_composite (dst->connection,
+						    render_op,
+						    src->picture,
+						    mask->picture,
+						    dst->picture,
+						    src->x, src->y,
+						    mask->x, mask->y,
+						    extents->x, extents->y,
+						    extents->width, extents->height);
+
+	    cairo_surface_destroy (&mask->base);
+	} else {
+	    _cairo_xcb_connection_render_composite (dst->connection,
+						    render_op,
+						    src->picture,
+						    XCB_NONE,
+						    dst->picture,
+						    src->x, src->y,
+						    0, 0,
+						    extents->x, extents->y,
+						    extents->width, extents->height);
 	}
+
+	_cairo_xcb_surface_clear_clip_region (dst);
     }
 
+    if (clip_boxes != stack_boxes)
+	free (clip_boxes);
+
     cairo_surface_destroy (&src->base);
 
     return CAIRO_STATUS_SUCCESS;


More information about the cairo-commit mailing list