[cairo-commit] 3 commits - src/cairoint.h src/cairo-meta-surface.c src/cairo-surface.c util/cairo-trace

Chris Wilson ickle at kemper.freedesktop.org
Sat Jul 4 05:53:05 PDT 2009


 src/cairo-meta-surface.c |   19 ++++++++-
 src/cairo-surface.c      |   92 +++++++++++++++++++++++++++++++++++------------
 src/cairoint.h           |    3 +
 util/cairo-trace/trace.c |   42 +++++++++++++++------
 4 files changed, 120 insertions(+), 36 deletions(-)

New commits:
commit 7903c80ee81777bab6eec408c10b2b59330b10f7
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 4 13:50:15 2009 +0100

    [meta] Cache replays when used as a pattern source
    
    Use the cow-snapshotting mechanism to store the meta surface replay (either
    to an image inside acquire_source_image() or to a similar surface during
    clone_similar()).
    
    Fixes Bug 17971 -- Extreme slowdown for manual convolutions in most
    vector backends.
    https://bugs.freedesktop.org/show_bug.cgi?id=17971

diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c
index 71e6b59..4fb2722 100644
--- a/src/cairo-meta-surface.c
+++ b/src/cairo-meta-surface.c
@@ -244,6 +244,15 @@ _cairo_meta_surface_acquire_source_image (void			 *abstract_surface,
     cairo_meta_surface_t *surface = abstract_surface;
     cairo_surface_t *image;
 
+    image = _cairo_surface_has_snapshot (&surface->base,
+					 &_cairo_image_surface_backend,
+					 surface->content);
+    if (image != NULL) {
+	*image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
+	*image_extra = NULL;
+	return CAIRO_STATUS_SUCCESS;
+    }
+
     image = _cairo_image_surface_create_with_content (surface->content,
 						      ceil (surface->width_pixels),
 						      ceil (surface->height_pixels));
@@ -254,10 +263,15 @@ _cairo_meta_surface_acquire_source_image (void			 *abstract_surface,
 	return status;
     }
 
+    status = _cairo_surface_attach_snapshot (&surface->base, image, NULL);
+    if (unlikely (status)) {
+	cairo_surface_destroy (image);
+	return status;
+    }
+
     *image_out = (cairo_image_surface_t *) image;
     *image_extra = NULL;
-
-    return status;
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static void
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 55aee0e..63e1810 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -267,15 +267,19 @@ _cairo_surface_attach_snapshot (cairo_surface_t *surface,
 
 cairo_surface_t *
 _cairo_surface_has_snapshot (cairo_surface_t *surface,
-			     const cairo_surface_backend_t *backend)
+			     const cairo_surface_backend_t *backend,
+			     cairo_content_t content)
 {
     cairo_surface_t **snapshots;
     unsigned int i;
 
     snapshots = _cairo_array_index (&surface->snapshots, 0);
     for (i = 0; i < surface->snapshots.num_elements; i++) {
-	if (snapshots[i]->backend == backend)
+	if (snapshots[i]->backend == backend &&
+	    snapshots[i]->content == content)
+	{
 	    return snapshots[i];
+	}
     }
 
     return NULL;
@@ -1506,27 +1510,67 @@ _cairo_surface_clone_similar (cairo_surface_t  *surface,
 
 	    /* First check to see if we can replay to a similar surface */
 	    if (_cairo_surface_is_meta (src)) {
+		cairo_meta_surface_t *meta = (cairo_meta_surface_t *) src;
 		cairo_surface_t *similar;
 
-		similar = cairo_surface_create_similar (surface,
-							src->content & content,
-							width, height);
-		status = similar->status;
-		if (unlikely (status))
-		    return status;
-
-		cairo_surface_set_device_offset (similar, -src_x, -src_y);
-
-		status = cairo_meta_surface_replay (src, similar);
-		if (unlikely (status)) {
-		    cairo_surface_destroy (similar);
-		    return status;
+		similar = _cairo_surface_has_snapshot (src,
+						       surface->backend,
+						       src->content & content);
+		if (similar != NULL) {
+		    *clone_out = cairo_surface_reference (similar);
+		    *clone_offset_x = 0;
+		    *clone_offset_y = 0;
+		    return CAIRO_STATUS_SUCCESS;
 		}
 
-		*clone_out = similar;
-		*clone_offset_x = src_x;
-		*clone_offset_y = src_y;
-		return CAIRO_STATUS_SUCCESS;
+		if (width*height*8 < meta->extents.width*meta->extents.height) {
+		    similar = cairo_surface_create_similar (surface,
+							    src->content & content,
+							    width, height);
+		    status = similar->status;
+		    if (unlikely (status))
+			return status;
+
+		    cairo_surface_set_device_offset (similar, -src_x, -src_y);
+
+		    status = cairo_meta_surface_replay (src, similar);
+		    if (unlikely (status)) {
+			cairo_surface_destroy (similar);
+			return status;
+		    }
+
+		    *clone_out = similar;
+		    *clone_offset_x = src_x;
+		    *clone_offset_y = src_y;
+		    return CAIRO_STATUS_SUCCESS;
+		} else {
+		    similar = cairo_surface_create_similar (surface,
+							    src->content & content,
+							    meta->extents.width,
+							    meta->extents.height);
+		    status = similar->status;
+		    if (unlikely (status))
+			return status;
+
+		    status = cairo_meta_surface_replay (src, similar);
+		    if (unlikely (status)) {
+			cairo_surface_destroy (similar);
+			return status;
+		    }
+
+		    status = _cairo_surface_attach_snapshot (src,
+							     similar,
+							     NULL);
+		    if (unlikely (status)) {
+			cairo_surface_destroy (similar);
+			return status;
+		    }
+
+		    *clone_out = similar;
+		    *clone_offset_x = 0;
+		    *clone_offset_y = 0;
+		    return CAIRO_STATUS_SUCCESS;
+		}
 	    }
 
 	    /* If we failed, try again with an image surface */
@@ -1604,7 +1648,9 @@ _cairo_surface_snapshot (cairo_surface_t *surface)
     if (surface->snapshot_of != NULL)
 	return cairo_surface_reference (surface);
 
-    snapshot = _cairo_surface_has_snapshot (surface, surface->backend);
+    snapshot = _cairo_surface_has_snapshot (surface,
+					    surface->backend,
+					    surface->content);
     if (snapshot != NULL)
 	return cairo_surface_reference (snapshot);
 
@@ -1618,7 +1664,8 @@ _cairo_surface_snapshot (cairo_surface_t *surface)
 	    cairo_surface_t *previous;
 
 	    previous = _cairo_surface_has_snapshot (surface,
-		                                    snapshot->backend);
+		                                    snapshot->backend,
+						    snapshot->content);
 	    if (previous != NULL) {
 		cairo_surface_destroy (snapshot);
 		return cairo_surface_reference (previous);
@@ -1628,7 +1675,8 @@ _cairo_surface_snapshot (cairo_surface_t *surface)
 
     if (snapshot == NULL) {
 	snapshot = _cairo_surface_has_snapshot (surface,
-						&_cairo_image_surface_backend);
+						&_cairo_image_surface_backend,
+						surface->content);
 	if (snapshot != NULL)
 	    return cairo_surface_reference (snapshot);
 
diff --git a/src/cairoint.h b/src/cairoint.h
index 52f813f..fed81a5 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1997,7 +1997,8 @@ _cairo_surface_attach_snapshot (cairo_surface_t *surface,
 
 cairo_private cairo_surface_t *
 _cairo_surface_has_snapshot (cairo_surface_t *surface,
-			     const cairo_surface_backend_t *backend);
+			     const cairo_surface_backend_t *backend,
+			     cairo_content_t content);
 
 cairo_private void
 _cairo_surface_detach_snapshot (cairo_surface_t *snapshot);
commit f353ba46a3b8c260f96588fd6bb8d07c2a09d01a
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 4 13:49:35 2009 +0100

    [meta] Copy extents on snapshotting.
    
    Need to copy across the extents as well when snapshotting.

diff --git a/src/cairo-meta-surface.c b/src/cairo-meta-surface.c
index 3c2b74e..71e6b59 100644
--- a/src/cairo-meta-surface.c
+++ b/src/cairo-meta-surface.c
@@ -582,6 +582,7 @@ _cairo_meta_surface_snapshot (void *abstract_other)
 
     meta->width_pixels = other->width_pixels;
     meta->height_pixels = other->height_pixels;
+    meta->extents = other->extents;
     meta->replay_start_idx = other->replay_start_idx;
     meta->content = other->content;
 
commit f4019be7bdff5c67d679f4de1070c25aa99a993d
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 4 13:16:42 2009 +0100

    [trace] Remove a few transient pattern def/undef
    
    It is easier on the eye to use
       '1 index set-source exch pop'
    rather than
       'dup /p0 exch def p0 set-source /p0 undef'
    (as patterns are expected to be temporary so we strive to avoid naming
    them).

diff --git a/util/cairo-trace/trace.c b/util/cairo-trace/trace.c
index 92b4981..e910d9e 100644
--- a/util/cairo-trace/trace.c
+++ b/util/cairo-trace/trace.c
@@ -1985,20 +1985,29 @@ cairo_set_source (cairo_t *cr, cairo_pattern_t *source)
 {
     _emit_line_info ();
     if (cr != NULL && source != NULL && _write_lock ()) {
+	Object *obj = _get_object (PATTERN, source);
+	bool need_context_and_pattern = true;
+
 	if (_is_current (PATTERN, source, 0) &&
 	    _is_current (CONTEXT, cr, 1))
 	{
-	    _consume_operand ();
+	    if (obj->defined) {
+		_consume_operand ();
+		need_context_and_pattern = false;
+	    }
 	}
 	else if (_is_current (PATTERN, source, 1) &&
 		 _is_current (CONTEXT, cr, 0))
 	{
-	    _trace_printf ("exch ");
-	    _exch_operands ();
-	    _consume_operand ();
+	    if (obj->defined) {
+		_trace_printf ("exch ");
+		_exch_operands ();
+		_consume_operand ();
+		need_context_and_pattern = false;
+	    }
 	}
-	else
-	{
+
+	if (need_context_and_pattern) {
 	    _emit_context (cr);
 	    _emit_pattern_id (source);
 	}
@@ -2353,18 +2362,29 @@ cairo_mask (cairo_t *cr, cairo_pattern_t *pattern)
 {
     _emit_line_info ();
     if (cr != NULL && pattern != NULL && _write_lock ()) {
+	Object *obj = _get_object (PATTERN, pattern);
+	bool need_context_and_pattern = true;
+
 	if (_is_current (PATTERN, pattern, 0) &&
 	    _is_current (CONTEXT, cr, 1))
 	{
-	    _consume_operand ();
+	    if (obj->defined) {
+		_consume_operand ();
+		need_context_and_pattern = false;
+	    }
 	}
 	else if (_is_current (PATTERN, pattern, 1) &&
 		 _is_current (CONTEXT, cr, 0))
 	{
-	    _trace_printf ("exch ");
-	    _exch_operands ();
-	    _consume_operand ();
-	} else {
+	    if (obj->defined) {
+		_trace_printf ("exch ");
+		_exch_operands ();
+		_consume_operand ();
+		need_context_and_pattern = false;
+	    }
+	}
+
+	if (need_context_and_pattern) {
 	    _emit_context (cr);
 	    _emit_pattern_id (pattern);
 	}


More information about the cairo-commit mailing list