[cairo-commit] 5 commits - src/cairo-surface-subsurface.c src/cairo-xcb-private.h src/cairo-xcb-surface.c src/cairo-xcb-surface-render.c src/cairo-xlib-xcb-surface.c test/cairo-test-runner.c

Chris Wilson ickle at kemper.freedesktop.org
Sat May 8 12:19:27 PDT 2010


 src/cairo-surface-subsurface.c |   10 +-
 src/cairo-xcb-private.h        |    5 +
 src/cairo-xcb-surface-render.c |  171 ++++++++++++++++++++++++++++++++++++++++-
 src/cairo-xcb-surface.c        |   31 ++++---
 src/cairo-xlib-xcb-surface.c   |   23 +++++
 test/cairo-test-runner.c       |   10 ++
 6 files changed, 226 insertions(+), 24 deletions(-)

New commits:
commit 9d863cd3942c3086c24d67305f7a5892604d0eeb
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat May 8 18:20:11 2010 +0100

    xcb: Find the correct xcb_screen_t for faking Screen
    
    When choosing the xcb_screen_t to use for the xlib-xcb backing surface,
    it helps if it matches the screen used to generate similar surfaces and
    snapshots - otherwise we end up pulling the image back from the XServer
    every time we want to use the Picture.

diff --git a/src/cairo-xlib-xcb-surface.c b/src/cairo-xlib-xcb-surface.c
index 4db129e..7e674bf 100644
--- a/src/cairo-xlib-xcb-surface.c
+++ b/src/cairo-xlib-xcb-surface.c
@@ -342,6 +342,21 @@ cairo_xlib_surface_create_for_bitmap (Display  *dpy,
 }
 
 #if CAIRO_HAS_XLIB_XRENDER_SURFACE
+static xcb_screen_t *
+_cairo_xcb_screen_from_root (xcb_connection_t *connection,
+			     xcb_window_t id)
+{
+    xcb_depth_iterator_t d;
+    xcb_screen_iterator_t s;
+
+    s = xcb_setup_roots_iterator (xcb_get_setup (connection));
+    for (; s.rem; xcb_screen_next (&s)) {
+	if (s.data->root == id)
+	    return s.data;
+    }
+
+    return NULL;
+}
 cairo_surface_t *
 cairo_xlib_surface_create_with_xrender_format (Display		    *dpy,
 					       Drawable		    drawable,
@@ -351,6 +366,8 @@ cairo_xlib_surface_create_with_xrender_format (Display		    *dpy,
 					       int		    height)
 {
     xcb_render_pictforminfo_t xcb_format;
+    xcb_connection_t *connection;
+    xcb_screen_t *screen;
 
     xcb_format.id = format->id;
     xcb_format.type = format->type;
@@ -365,9 +382,11 @@ cairo_xlib_surface_create_with_xrender_format (Display		    *dpy,
     xcb_format.direct.alpha_mask = format->direct.alphaMask;
     xcb_format.colormap = format->colormap;
 
+    connection = XGetXCBConnection (dpy);
+    screen = _cairo_xcb_screen_from_root (connection, (xcb_window_t) scr->root);
+
     return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, format,
-					   cairo_xcb_surface_create_with_xrender_format (XGetXCBConnection (dpy),
-											 (xcb_screen_t *) scr,
+					   cairo_xcb_surface_create_with_xrender_format (connection, screen,
 											 drawable,
 											 &xcb_format,
 											 width, height));
commit 448d3571088463fc61641badcdfdc8c0002ae12a
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat May 8 09:59:54 2010 +0100

    xcb: Upload images in place.
    
    A common operation is to store an image in a similar surface, so
    construct a fast path to avoid the allocation and double-blit through a
    temporary pixmap.

diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
index c03d8c2..1c8fc41 100644
--- a/src/cairo-xcb-private.h
+++ b/src/cairo-xcb-private.h
@@ -85,6 +85,8 @@ struct _cairo_xcb_surface {
     cairo_bool_t owns_pixmap;
     int use_pixmap;
 
+    cairo_bool_t deferred_clear;
+
     int width;
     int height;
     int depth;
@@ -435,6 +437,9 @@ cairo_private void
 _cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
 				      cairo_scaled_font_t  *scaled_font);
 
+cairo_private void
+_cairo_xcb_surface_clear (cairo_xcb_surface_t *dst);
+
 cairo_private cairo_status_t
 _cairo_xcb_surface_core_copy_boxes (cairo_xcb_surface_t		*dst,
 				   const cairo_pattern_t	*src_pattern,
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index dba8750..c108bae 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -1131,7 +1131,7 @@ _cairo_xcb_surface_picture (cairo_xcb_surface_t *target,
 			    const cairo_surface_pattern_t *pattern,
 			    const cairo_rectangle_int_t *extents)
 {
-    cairo_surface_t *const source = pattern->surface;
+    cairo_surface_t *source = pattern->surface;
     cairo_xcb_picture_t *picture;
     cairo_filter_t filter;
     cairo_extend_t extend;
@@ -1144,6 +1144,17 @@ _cairo_xcb_surface_picture (cairo_xcb_surface_t *target,
             return _cairo_xcb_black_picture (target);
     }
 
+    {
+	cairo_xcb_surface_t *snapshot;
+
+	snapshot = (cairo_xcb_surface_t *)
+	    _cairo_surface_has_snapshot (source, &_cairo_xcb_surface_backend);
+	if (snapshot != NULL) {
+	    if (snapshot->screen == target->screen)
+		source = &snapshot->base;
+	}
+    }
+
     picture = (cairo_xcb_picture_t *)
 	_cairo_surface_has_snapshot (source, &_cairo_xcb_picture_backend);
     if (picture != NULL) {
@@ -1440,7 +1451,7 @@ COMPILE_TIME_ASSERT (sizeof (xcb_rectangle_t) <= sizeof (cairo_box_t));
 static cairo_status_t
 _render_fill_boxes (void			*abstract_dst,
 		    cairo_operator_t		 op,
-		    const cairo_color_t	*color,
+		    const cairo_color_t		*color,
 		    cairo_boxes_t		*boxes)
 {
     cairo_xcb_surface_t *dst = abstract_dst;
@@ -2324,6 +2335,27 @@ _cairo_xcb_surface_fixup_unbounded_boxes (cairo_xcb_surface_t *dst,
     return status;
 }
 
+void
+_cairo_xcb_surface_clear (cairo_xcb_surface_t *dst)
+{
+    xcb_gcontext_t gc;
+    xcb_rectangle_t rect;
+
+    gc = _cairo_xcb_screen_get_gc (dst->screen, dst->drawable, dst->depth);
+
+    rect.x = rect.y = 0;
+    rect.width  = dst->width;
+    rect.height = dst->height;
+
+    _cairo_xcb_connection_poly_fill_rectangle (dst->connection,
+					       dst->drawable, gc,
+					       1, &rect);
+
+    _cairo_xcb_screen_put_gc (dst->screen, dst->depth, gc);
+
+    dst->deferred_clear = FALSE;
+}
+
 static cairo_status_t
 _clip_and_composite (cairo_xcb_surface_t	*dst,
 		     cairo_operator_t		 op,
@@ -2373,6 +2405,9 @@ _clip_and_composite (cairo_xcb_surface_t	*dst,
 	return status;
     }
 
+    if (dst->deferred_clear)
+	_cairo_xcb_surface_clear (dst);
+
     _cairo_xcb_surface_ensure_picture (dst);
 
     if (clip_region != NULL)
@@ -2526,7 +2561,7 @@ _composite_boxes (cairo_xcb_surface_t *dst,
 	else
 	    color = &((cairo_solid_pattern_t *) src)->color;
 
-	if (! (op == CAIRO_OPERATOR_IN && color->alpha >= 0xff00))
+	if (! (op == CAIRO_OPERATOR_IN && color->alpha_short >= 0xff00))
 	    status = _render_fill_boxes (dst, op, color, boxes);
     }
     else
@@ -2573,6 +2608,112 @@ _composite_boxes (cairo_xcb_surface_t *dst,
 }
 
 static cairo_status_t
+_upload_image_inplace (cairo_xcb_surface_t *surface,
+		       const cairo_pattern_t *source,
+		       const cairo_rectangle_int_t *extents)
+{
+    const cairo_surface_pattern_t *pattern;
+    cairo_image_surface_t *image;
+    xcb_gcontext_t gc;
+    cairo_status_t status;
+    int len, tx, ty;
+
+    if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    pattern = (const cairo_surface_pattern_t *) source;
+    if (pattern->surface->type != CAIRO_SURFACE_TYPE_IMAGE)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    {
+	cairo_xcb_surface_t *snapshot;
+
+	snapshot = (cairo_xcb_surface_t *)
+	    _cairo_surface_has_snapshot (pattern->surface, &_cairo_xcb_surface_backend);
+	if (snapshot != NULL) {
+	    if (snapshot->screen == surface->screen)
+		return CAIRO_INT_STATUS_UNSUPPORTED;
+	}
+    }
+
+    {
+	cairo_xcb_picture_t *snapshot;
+
+	snapshot = (cairo_xcb_picture_t *)
+	    _cairo_surface_has_snapshot (pattern->surface, &_cairo_xcb_picture_backend);
+	if (snapshot != NULL) {
+	    if (snapshot->screen == surface->screen)
+		return CAIRO_INT_STATUS_UNSUPPORTED;
+	}
+    }
+
+    image = (cairo_image_surface_t *) pattern->surface;
+    if (image->format == CAIRO_FORMAT_INVALID)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (image->depth != surface->depth)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    image = (cairo_image_surface_t *) pattern->surface;
+    if (source->extend != CAIRO_EXTEND_NONE &&
+	(extents->x + tx < 0 ||
+	 extents->y + ty < 0 ||
+	 extents->x + tx + extents->width > image->width ||
+	 extents->y + ty + extents->height > image->height))
+    {
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    status = _cairo_xcb_connection_acquire (surface->connection);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_xcb_connection_take_socket (surface->connection);
+    if (unlikely (status)) {
+	_cairo_xcb_connection_release (surface->connection);
+	return status;
+    }
+    gc = _cairo_xcb_screen_get_gc (surface->screen, surface->drawable, image->depth);
+
+    /* Do we need to trim the image? */
+    len = CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format));
+    if (len == image->stride) {
+	_cairo_xcb_connection_put_image (surface->connection,
+					 surface->drawable, gc,
+					 image->width, image->height,
+					 extents->x, extents->y,
+					 image->depth,
+					 image->stride,
+					 image->data);
+    } else {
+	_cairo_xcb_connection_put_subimage (surface->connection,
+					    surface->drawable, gc,
+					    extents->x + tx, extents->y + ty,
+					    image->width, image->height,
+					    PIXMAN_FORMAT_BPP (image->pixman_format) / 8,
+					    image->stride,
+					    extents->x, extents->y,
+					    image->depth,
+					    image->data);
+
+    }
+
+    _cairo_xcb_screen_put_gc (surface->screen, image->depth, gc);
+    _cairo_xcb_connection_release (surface->connection);
+
+    if (surface->width == image->width && surface->height == image->height &&
+	extents->width == image->width && extents->height == image->height)
+    {
+	_cairo_surface_attach_snapshot (&image->base, &surface->base, NULL);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
 _clip_and_composite_boxes (cairo_xcb_surface_t *dst,
 			   cairo_operator_t op,
 			   const cairo_pattern_t *src,
@@ -2587,9 +2728,26 @@ _clip_and_composite_boxes (cairo_xcb_surface_t *dst,
     if (boxes->num_boxes == 0 && extents->is_bounded)
 	return CAIRO_STATUS_SUCCESS;
 
+    if (clip == NULL &&
+	(op == CAIRO_OPERATOR_SOURCE || (op == CAIRO_OPERATOR_OVER && dst->base.is_clear)) &&
+	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, &extents->bounded);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
+    }
+
     if ((dst->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
 	return _core_boxes (dst, op, src, boxes, antialias, clip, extents);
 
+    if (dst->deferred_clear)
+	_cairo_xcb_surface_clear (dst);
+
     /* Use a fast path if the boxes are pixel aligned */
     status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
@@ -2906,6 +3064,11 @@ _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;
+	return CAIRO_STATUS_SUCCESS;
+    }
+
     status = _cairo_composite_rectangles_init_for_paint (&extents,
 							 surface->width,
 							 surface->height,
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index f21d580..7b72832 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -398,6 +398,17 @@ _get_image (cairo_xcb_surface_t		 *surface,
     xcb_get_image_reply_t *reply;
     cairo_status_t status;
 
+    if (surface->base.is_clear || surface->deferred_clear) {
+	image = (cairo_image_surface_t *)
+	    _cairo_image_surface_create_with_pixman_format (NULL,
+							    surface->pixman_format,
+							    surface->width,
+							    surface->height,
+							    0);
+	*image_out = image;
+	return image->base.status;
+    }
+
     connection = surface->connection;
 
     status = _cairo_xcb_connection_acquire (connection);
@@ -414,18 +425,6 @@ _get_image (cairo_xcb_surface_t		 *surface,
 	    goto FAIL;
     }
 
-    if (surface->base.is_clear) {
-	image = (cairo_image_surface_t *)
-	    _cairo_image_surface_create_with_pixman_format (NULL,
-							    surface->pixman_format,
-							    surface->width,
-							    surface->height,
-							    0);
-	status = image->base.status;
-	*image_out = image;
-	goto FAIL;
-    }
-
     if (surface->use_pixmap == 0) {
 	status = _cairo_xcb_connection_get_image (connection,
 						  surface->drawable,
@@ -687,8 +686,12 @@ _cairo_xcb_surface_flush (void *abstract_surface)
     if (surface->drm != NULL && ! surface->marked_dirty)
 	return surface->drm->backend->flush (surface->drm);
 
-    if (likely (surface->fallback == NULL))
+    if (likely (surface->fallback == NULL)) {
+	if (! surface->base.finished && surface->deferred_clear)
+	    _cairo_xcb_surface_clear (surface);
+
 	return CAIRO_STATUS_SUCCESS;
+    }
 
     status = surface->base.status;
     if (status == CAIRO_STATUS_SUCCESS && ! surface->base.finished) {
@@ -1077,6 +1080,8 @@ _cairo_xcb_surface_create_internal (cairo_xcb_screen_t		*screen,
     surface->owns_pixmap = owns_pixmap;
     surface->use_pixmap = 0;
 
+    surface->deferred_clear = FALSE;
+
     surface->width  = width;
     surface->height = height;
     surface->depth  = PIXMAN_FORMAT_DEPTH (pixman_format);
commit e48cbd3b47a6e4f7c1f66b3085df41546460e477
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat May 8 09:56:46 2010 +0100

    xcb: Reset picture after failed snapshot.
    
    Clear the local picture variable if we cannot use the snapshot so that
    we are forced to create a new and valid picture.

diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index 5ea02e8..dba8750 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -1131,13 +1131,12 @@ _cairo_xcb_surface_picture (cairo_xcb_surface_t *target,
 			    const cairo_surface_pattern_t *pattern,
 			    const cairo_rectangle_int_t *extents)
 {
-    cairo_surface_t *source;
+    cairo_surface_t *const source = pattern->surface;
     cairo_xcb_picture_t *picture;
     cairo_filter_t filter;
     cairo_extend_t extend;
     cairo_status_t status;
 
-    source = pattern->surface;
     if (source->is_clear) {
         if (source->content & CAIRO_CONTENT_ALPHA)
 	    return _cairo_xcb_transparent_picture (target);
@@ -1152,6 +1151,7 @@ _cairo_xcb_surface_picture (cairo_xcb_surface_t *target,
 	    picture = (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
 	    goto setup_picture;
 	}
+	picture = NULL;
     }
 
     if (source->type == CAIRO_SURFACE_TYPE_XCB)
commit 4e3c19833ef8631c1f1cd54870c0a86d88252886
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri May 7 21:30:13 2010 +0100

    test: Force cairo-test-suite to return SUCCESS
    
    Set the CAIRO_TEST_FORCE_PASS environment variable to run through the
    test suite and ignore errors. Useful for forcing distcheck to continue
    past a broken test suite.

diff --git a/test/cairo-test-runner.c b/test/cairo-test-runner.c
index 1e789ec..d130321 100644
--- a/test/cairo-test-runner.c
+++ b/test/cairo-test-runner.c
@@ -94,6 +94,7 @@ typedef struct _cairo_test_runner {
     cairo_bool_t list_only;
     cairo_bool_t full_test;
     cairo_bool_t exact_test_names;
+    cairo_bool_t force_pass;
 } cairo_test_runner_t;
 
 typedef enum {
@@ -532,6 +533,9 @@ _runner_fini (cairo_test_runner_t *runner)
 
     cairo_test_fini (&runner->base);
 
+    if (runner->force_pass)
+	return CAIRO_TEST_SUCCESS;
+
     return runner->num_failed + runner->num_crashed ?
 	CAIRO_TEST_FAILURE :
 	runner->num_passed + runner->num_xfailed ?
@@ -672,6 +676,12 @@ main (int argc, char **argv)
 	}
     }
 
+    if (getenv ("CAIRO_TEST_FORCE_PASS")) {
+	const char *env = getenv ("CAIRO_TEST_FORCE_PASS");
+
+	runner.force_pass = atoi (env);
+    }
+
     _parse_cmdline (&runner, &argc, &argv);
     append_argv (&argc, &argv, getenv ("CAIRO_TESTS"));
 
commit ad8abc01105f02a05497969b6b5ec2c8742daeb2
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri May 7 21:28:58 2010 +0100

    subsurface: Don't double apply device offset for deep subsurfaces.
    
    If we have a subsurface of a subsurface then the device offset has
    already been applied to the extents that we use to offset the new
    subsurface.

diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 90fb16d..59b56a4 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -522,13 +522,13 @@ cairo_surface_create_for_rectangle (cairo_surface_t *target,
 	surface->extents.x += sub->extents.x;
 	surface->extents.y += sub->extents.y;
 	target = sub->target;
+    } else {
+	ret = _cairo_matrix_is_integer_translation (&target->device_transform, &tx, &ty);
+	assert (ret);
+	surface->extents.x += tx;
+	surface->extents.y += ty;
     }
 
-    ret = _cairo_matrix_is_integer_translation (&target->device_transform, &tx, &ty);
-    assert (ret);
-    surface->extents.x += tx;
-    surface->extents.y += ty;
-
     surface->target = cairo_surface_reference (target);
     surface->owns_target = FALSE;
 


More information about the cairo-commit mailing list