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

Chris Wilson ickle at kemper.freedesktop.org
Wed Jul 20 11:57:49 PDT 2011


 src/cairo-xcb-surface-render.c |  270 ++++++++++++++++++++++++++++++++++++-----
 src/cairo-xcb-surface.c        |    5 
 2 files changed, 242 insertions(+), 33 deletions(-)

New commits:
commit 6b3e5cd39c81941a73ed709eadf8beae5407dc05
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jul 20 14:32:10 2011 +0100

    xcb: Reduce one pass for masking, now just 2 passes required!
    
    Another 10% off fishbowl for both snb and pnv.
    
    [Note this exposes the bugs in the polygon clipper; naive *and* broken.]
    
    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 80d7fee..6ebe134 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -1377,7 +1377,7 @@ _render_composite_boxes (cairo_xcb_surface_t	*dst,
 	} else {
 	    stack_extents.x = clip_boxes[0].x;
 	    stack_extents.y = clip_boxes[0].y;
-	    stack_extents.width = clip_boxes[0].width;
+	    stack_extents.width  = clip_boxes[0].width;
 	    stack_extents.height = clip_boxes[0].height;
 	    extents = &stack_extents;
 	}
@@ -1475,7 +1475,7 @@ typedef struct {
 
 COMPILE_TIME_ASSERT (sizeof (xcb_render_trapezoid_t) <= sizeof (cairo_trapezoid_t));
 
-static cairo_status_t
+static cairo_int_status_t
 _composite_traps (void *closure,
 		  cairo_xcb_surface_t	*dst,
 		  cairo_operator_t	 op,
@@ -1568,6 +1568,8 @@ _composite_traps (void *closure,
 	render_reference_x = xtraps[0].left.p2.x >> 16;
 	render_reference_y = xtraps[0].left.p2.y >> 16;
     }
+    render_reference_x += src->x + dst_x;
+    render_reference_y += src->y + dst_y;
 
     _cairo_xcb_surface_set_precision (dst, info->antialias);
     _cairo_xcb_connection_render_trapezoids (dst->connection,
@@ -1575,8 +1577,8 @@ _composite_traps (void *closure,
 					     src->picture,
 					     dst->picture,
 					     xrender_format,
-					     src->x + render_reference_x,
-					     src->y + render_reference_y,
+					     render_reference_x,
+					     render_reference_y,
 					     traps->num_traps, xtraps);
 
     cairo_surface_destroy (&src->base);
@@ -1586,7 +1588,7 @@ _composite_traps (void *closure,
 
 /* low-level composite driver */
 
-typedef cairo_status_t
+typedef cairo_int_status_t
 (*xcb_draw_func_t) (void				*closure,
 		    cairo_xcb_surface_t			*dst,
 		    cairo_operator_t			 op,
@@ -1603,7 +1605,7 @@ static void do_unaligned_row(void (*blt)(void *closure,
 			     void *closure,
 			     const cairo_box_t *b,
 			     int tx, int y, int h,
-			     int coverage)
+			     uint16_t coverage)
 {
     int x1 = _cairo_fixed_integer_part (b->p1.x) - tx;
     int x2 = _cairo_fixed_integer_part (b->p2.x) - tx;
@@ -1614,7 +1616,8 @@ static void do_unaligned_row(void (*blt)(void *closure,
 	    x1++;
 	}
 
-	blt(closure, x1, y, x2-x1, h, 256*coverage);
+	if (x2 > x1)
+	    blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8));
 
 	if (! _cairo_fixed_is_integer (b->p2.x))
 	    blt(closure, x2, y, 1, h,
@@ -1640,7 +1643,8 @@ static void do_unaligned_box(void (*blt)(void *closure,
 	    y1++;
 	}
 
-	do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256);
+	if (y2 > 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,
@@ -1665,7 +1669,7 @@ static void blt_in(void *closure,
 
     rect.x = x;
     rect.y = y;
-    rect.width = w;
+    rect.width  = w;
     rect.height = h;
 
     _cairo_xcb_connection_render_fill_rectangles (mask->connection,
@@ -1677,13 +1681,14 @@ static void blt_in(void *closure,
 static cairo_xcb_surface_t *
 _create_composite_mask (cairo_clip_t		*clip,
 			xcb_draw_func_t		 draw_func,
+			xcb_draw_func_t		 mask_func,
 			void			*draw_closure,
 			cairo_xcb_surface_t	*dst,
 			const cairo_rectangle_int_t*extents)
 {
     cairo_xcb_surface_t *surface;
     cairo_bool_t need_clip_combine;
-    cairo_status_t status;
+    cairo_int_status_t status;
 
     surface = (cairo_xcb_surface_t *)
 	_cairo_xcb_surface_create_similar (dst, CAIRO_CONTENT_ALPHA,
@@ -1697,6 +1702,15 @@ _create_composite_mask (cairo_clip_t		*clip,
     surface->deferred_clear = TRUE;
     surface->base.is_clear = TRUE;
 
+    if (mask_func) {
+	status = mask_func (draw_closure, surface,
+			    CAIRO_OPERATOR_ADD, NULL,
+			    extents->x, extents->y,
+			    extents, clip);
+	if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED))
+	    return surface;
+    }
+
     /* Is it worth setting the clip region here? */
     status = draw_func (draw_closure, surface,
 			CAIRO_OPERATOR_ADD, NULL,
@@ -1746,6 +1760,7 @@ _clip_and_composite_with_mask (cairo_clip_t		*clip,
 			       cairo_operator_t		 op,
 			       const cairo_pattern_t	*pattern,
 			       xcb_draw_func_t		 draw_func,
+			       xcb_draw_func_t		 mask_func,
 			       void			*draw_closure,
 			       cairo_xcb_surface_t	*dst,
 			       const cairo_rectangle_int_t*extents)
@@ -1753,7 +1768,9 @@ _clip_and_composite_with_mask (cairo_clip_t		*clip,
     cairo_xcb_surface_t *mask;
     cairo_xcb_picture_t *src;
 
-    mask = _create_composite_mask (clip, draw_func, draw_closure, dst, extents);
+    mask = _create_composite_mask (clip,
+				   draw_func, mask_func, draw_closure,
+				   dst, extents);
     if (unlikely (mask->base.status))
 	return mask->base.status;
 
@@ -1915,6 +1932,7 @@ static cairo_status_t
 _clip_and_composite_source (cairo_clip_t		*clip,
 			    const cairo_pattern_t	*pattern,
 			    xcb_draw_func_t		 draw_func,
+			    xcb_draw_func_t		 mask_func,
 			    void			*draw_closure,
 			    cairo_xcb_surface_t		*dst,
 			    const cairo_rectangle_int_t	*extents)
@@ -1923,7 +1941,9 @@ _clip_and_composite_source (cairo_clip_t		*clip,
     cairo_xcb_picture_t *src;
 
     /* Create a surface that is mask IN clip */
-    mask = _create_composite_mask (clip, draw_func, draw_closure, dst, extents);
+    mask = _create_composite_mask (clip,
+				   draw_func, mask_func, draw_closure,
+				   dst, extents);
     if (unlikely (mask->base.status))
 	return mask->base.status;
 
@@ -2327,6 +2347,7 @@ _clip_and_composite (cairo_xcb_surface_t	*dst,
 		     cairo_operator_t		 op,
 		     const cairo_pattern_t	*src,
 		     xcb_draw_func_t		 draw_func,
+		     xcb_draw_func_t		 mask_func,
 		     void			*draw_closure,
 		     cairo_composite_rectangles_t*extents,
 		     unsigned int need_clip)
@@ -2368,7 +2389,7 @@ _clip_and_composite (cairo_xcb_surface_t	*dst,
 
     if (op == CAIRO_OPERATOR_SOURCE) {
 	status = _clip_and_composite_source (extents->clip, src,
-					     draw_func, draw_closure,
+					     draw_func, mask_func, draw_closure,
 					     dst, &extents->bounded);
     } else {
 	if (op == CAIRO_OPERATOR_CLEAR) {
@@ -2379,7 +2400,9 @@ _clip_and_composite (cairo_xcb_surface_t	*dst,
 	if (need_clip & NEED_CLIP_SURFACE) {
 	    if (extents->is_bounded) {
 		status = _clip_and_composite_with_mask (extents->clip, op, src,
-							draw_func, draw_closure,
+							draw_func,
+							mask_func,
+							draw_closure,
 							dst, &extents->bounded);
 	    } else {
 		status = _clip_and_composite_combine (extents->clip, op, src,
@@ -2823,6 +2846,31 @@ _composite_polygon (cairo_xcb_surface_t *dst,
 	return status;
     }
 
+    if (extents->clip->path != NULL && extents->is_bounded) {
+	cairo_polygon_t clipper;
+	cairo_fill_rule_t clipper_fill_rule;
+	cairo_antialias_t clipper_antialias;
+
+	status = _cairo_clip_get_polygon (extents->clip,
+					  &clipper,
+					  &clipper_fill_rule,
+					  &clipper_antialias);
+	if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	    if (clipper_antialias == antialias) {
+		status = _cairo_polygon_intersect (polygon, fill_rule,
+						   &clipper, clipper_fill_rule);
+		if (likely (status == CAIRO_STATUS_SUCCESS)) {
+		    cairo_clip_t * clip = _cairo_clip_copy_region (extents->clip);
+		    _cairo_clip_destroy (extents->clip);
+		    extents->clip = clip;
+
+		    fill_rule = CAIRO_FILL_RULE_WINDING;
+		}
+		_cairo_polygon_fini (&clipper);
+	    }
+	}
+    }
+
     _cairo_traps_init (&traps.traps);
 
     status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule);
@@ -2852,8 +2900,7 @@ _composite_polygon (cairo_xcb_surface_t *dst,
 	cairo_boxes_t boxes;
 
 	_boxes_for_traps (&boxes, &traps.traps, antialias);
-	status = _clip_and_composite_boxes (dst, op, source,
-					    &boxes, extents);
+	status = _clip_and_composite_boxes (dst, op, source, &boxes, extents);
     }
     else
     {
@@ -2864,7 +2911,7 @@ _composite_polygon (cairo_xcb_surface_t *dst,
 	status = trim_extents_to_traps (extents, &traps.traps);
 	if (likely (status == CAIRO_STATUS_SUCCESS)) {
 	    status = _clip_and_composite (dst, op, source,
-					  _composite_traps, &traps,
+					  _composite_traps, NULL, &traps,
 					  extents, need_unbounded_clip (extents));
 	}
     }
@@ -2875,7 +2922,6 @@ CLEANUP_TRAPS:
     return status;
 }
 
-
 static cairo_status_t
 _clip_and_composite_boxes (cairo_xcb_surface_t *dst,
 			   cairo_operator_t op,
@@ -2911,7 +2957,7 @@ _clip_and_composite_boxes (cairo_xcb_surface_t *dst,
 	cairo_polygon_t polygon;
 	cairo_fill_rule_t fill_rule;
 	cairo_antialias_t antialias;
-	cairo_clip_t *clip ;
+	cairo_clip_t *clip;
 
 	clip = _cairo_clip_copy (extents->clip);
 	clip = _cairo_clip_intersect_boxes (clip, boxes);
@@ -2973,15 +3019,15 @@ _clip_and_composite_boxes (cairo_xcb_surface_t *dst,
     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));
+				      _composite_traps, NULL, &info,
+				      extents, need_unbounded_clip (extents));
     }
 
     _cairo_traps_fini (&info.traps);
     return status;
 }
 
-static cairo_status_t
+static cairo_int_status_t
 _composite_mask (void				*closure,
 		 cairo_xcb_surface_t		*dst,
 		 cairo_operator_t		 op,
@@ -3051,6 +3097,151 @@ _composite_mask (void				*closure,
     return CAIRO_STATUS_SUCCESS;
 }
 
+struct composite_box_info {
+    cairo_xcb_surface_t *dst;
+    cairo_xcb_picture_t *src;
+    uint8_t op;
+};
+
+static void composite_box(void *closure,
+			  int16_t x, int16_t y,
+			  int16_t w, int16_t h,
+			  uint16_t coverage)
+{
+    struct composite_box_info *info = closure;
+
+    if (coverage < 0xff00) {
+	cairo_solid_pattern_t mask_pattern;
+	cairo_xcb_picture_t *mask;
+	cairo_color_t color;
+
+	color.red = color.green = color.blue = 0;
+	color.alpha = 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)) {
+	    _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);
+	}
+	cairo_surface_destroy (&mask->base);
+    } else {
+	_cairo_xcb_connection_render_composite (info->dst->connection,
+						info->op,
+						info->src->picture,
+						XCB_NONE,
+						info->dst->picture,
+						x + info->src->x,  y + info->src->y,
+						0,                 0,
+						x,                 y,
+						w,                 h);
+    }
+}
+
+static cairo_int_status_t
+_composite_mask_clip_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)
+{
+    struct composite_box_info info;
+    cairo_status_t status;
+    int i;
+
+    assert (src_pattern == NULL);
+    assert (op == CAIRO_OPERATOR_ADD);
+    assert (dst->base.is_clear);
+
+    if (clip->num_boxes > 1) {
+	status = _cairo_xcb_surface_clear (dst);
+	if (unlikely (status))
+	    return status;
+    }
+
+    info.op = XCB_RENDER_PICT_OP_SRC;
+    info.dst = dst;
+    info.src = _cairo_xcb_picture_for_pattern (dst, closure, extents);
+    if (unlikely (info.src->base.status))
+	return info.src->base.status;
+
+    info.src->x += dst_x;
+    info.src->y += dst_y;
+
+    for (i = 0; i < clip->num_boxes; i++)
+	do_unaligned_box(composite_box, &info, &clip->boxes[i], dst_x, dst_y);
+    cairo_surface_destroy (&info.src->base);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_composite_mask_clip (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_pattern_t *mask_pattern = closure;
+    cairo_polygon_t polygon;
+    cairo_fill_rule_t fill_rule;
+    composite_traps_info_t info;
+    cairo_status_t status;
+
+    assert (src_pattern == NULL);
+    assert (op == CAIRO_OPERATOR_ADD);
+    assert (dst->base.is_clear);
+
+    status = _cairo_clip_get_polygon (clip, &polygon,
+				      &fill_rule, &info.antialias);
+    if (unlikely (status))
+	return status;
+
+    _cairo_traps_init (&info.traps);
+    status = _cairo_bentley_ottmann_tessellate_polygon (&info.traps,
+							&polygon,
+							fill_rule);
+    _cairo_polygon_fini (&polygon);
+    if (unlikely (status))
+	return status;
+
+    if (info.traps.has_intersections) {
+	if (info.traps.is_rectangular)
+	    status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&info.traps, CAIRO_FILL_RULE_WINDING);
+	else if (info.traps.is_rectilinear)
+	    status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (&info.traps, CAIRO_FILL_RULE_WINDING);
+	else
+	    status = _cairo_bentley_ottmann_tessellate_traps (&info.traps, CAIRO_FILL_RULE_WINDING);
+	if (unlikely (status)) {
+	    _cairo_traps_fini (&info.traps);
+	    return status;
+	}
+    }
+
+    dst->deferred_clear = FALSE; /* assert(trap extents == extents); */
+
+    status = _composite_traps (&info,
+			       dst, CAIRO_OPERATOR_SOURCE, mask_pattern,
+			       dst_x, dst_y,
+			       extents, NULL);
+    _cairo_traps_fini (&info.traps);
+
+    return status;
+}
+
 struct composite_opacity_info {
     uint8_t op;
     cairo_xcb_surface_t *dst;
@@ -3100,7 +3291,7 @@ static void composite_opacity(void *closure,
     cairo_surface_destroy (&mask->base);
 }
 
-static cairo_status_t
+static cairo_int_status_t
 _composite_opacity_boxes (void				*closure,
 			  cairo_xcb_surface_t		*dst,
 			  cairo_operator_t		 op,
@@ -3234,11 +3425,16 @@ _cairo_xcb_surface_render_mask (cairo_xcb_surface_t	*surface,
 	extents.clip->path == NULL &&
 	! _cairo_clip_is_region (extents.clip)) {
 	status = _clip_and_composite (surface, op, source,
-				      _composite_opacity_boxes, (void *) mask,
+				      _composite_opacity_boxes, NULL,
+				      (void *) mask,
 				      &extents, need_unbounded_clip (&extents));
     } else {
+	xcb_draw_func_t mask_func = NULL;
+	if (surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS)
+	    mask_func = extents.clip->path ? _composite_mask_clip : _composite_mask_clip_boxes;
 	status = _clip_and_composite (surface, op, source,
-				      _composite_mask, (void *) mask,
+				      _composite_mask, mask_func,
+				      (void *) mask,
 				      &extents, need_bounded_clip (&extents));
     }
 
@@ -3331,7 +3527,7 @@ _cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t		*dst,
 
 	cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
 	status = _clip_and_composite (dst, op, source,
-				      _composite_mask, (void *) &mask.base,
+				      _composite_mask, NULL, &mask.base,
 				      extents, need_bounded_clip (extents));
 	_cairo_pattern_fini (&mask.base);
     }
@@ -3483,7 +3679,7 @@ _cairo_xcb_surface_render_fill_via_mask (cairo_xcb_surface_t	*dst,
 
 	cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
 	status = _clip_and_composite (dst, op, source,
-				      _composite_mask, (void *) &mask.base,
+				      _composite_mask, NULL, &mask.base,
 				      extents, need_bounded_clip (extents));
 
 	_cairo_pattern_fini (&mask.base);
@@ -3606,7 +3802,7 @@ _cairo_xcb_surface_render_glyphs_via_mask (cairo_xcb_surface_t		*dst,
 
 	cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
 	status = _clip_and_composite (dst, op, source,
-				      _composite_mask, (void *) &mask.base,
+				      _composite_mask, NULL, &mask.base,
 				      extents, need_bounded_clip (extents));
 
 	_cairo_pattern_fini (&mask.base);
@@ -4297,7 +4493,7 @@ _emit_glyphs_chunk (cairo_xcb_surface_t *dst,
     return CAIRO_STATUS_SUCCESS;
 }
 
-static cairo_status_t
+static cairo_int_status_t
 _composite_glyphs (void				*closure,
 		  cairo_xcb_surface_t		*dst,
 		  cairo_operator_t		 op,
@@ -4530,8 +4726,9 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t	*surface,
 		    ! _cairo_clip_is_region(extents.clip);
 
 		status = _clip_and_composite (surface, op, source,
-					      _composite_glyphs, &info,
-					      &extents, need_bounded_clip (&extents));
+					      _composite_glyphs,
+					      NULL, &info, &extents,
+					      need_bounded_clip (&extents));
 	    }
 	}
 
commit a585a092ee188381c0f0e93e9eee03cf1fed3692
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jul 20 15:28:34 2011 +0100

    xcb: squash initial ChangePicture request for precision
    
    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 ac07023..80d7fee 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -302,12 +302,21 @@ _cairo_xcb_surface_ensure_picture (cairo_xcb_surface_t *surface)
 {
     assert (surface->fallback == NULL);
     if (surface->picture == XCB_NONE) {
+	uint32_t values[1];
+	uint32_t flags = 0;
+	int n = 0;
+
+	if (surface->precision != XCB_RENDER_POLY_MODE_PRECISE) {
+	    flags |= XCB_RENDER_CP_POLY_MODE;
+	    values[n++] = surface->precision;
+	}
+
 	surface->picture = _cairo_xcb_connection_get_xid (surface->connection);
 	_cairo_xcb_connection_render_create_picture (surface->connection,
 						     surface->picture,
 						     surface->drawable,
 						     surface->xrender_format,
-						     0, NULL);
+						     flags, values);
     }
 }
 
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 200c4c0..2014ae7 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -934,7 +934,10 @@ _cairo_xcb_surface_create_internal (cairo_xcb_screen_t		*screen,
     surface->depth  = PIXMAN_FORMAT_DEPTH (pixman_format);
 
     surface->picture = XCB_NONE;
-    surface->precision = XCB_RENDER_POLY_MODE_PRECISE;
+    if (screen->connection->force_precision != -1)
+	surface->precision = screen->connection->force_precision;
+    else
+	surface->precision = XCB_RENDER_POLY_MODE_IMPRECISE;
 
     surface->pixman_format = pixman_format;
     surface->xrender_format = xrender_format;


More information about the cairo-commit mailing list