[cairo-commit] src/cairo-clip.c src/cairo-directfb-surface.c src/cairo-glitz-surface.c src/cairo-image-surface.c src/cairoint.h src/cairo-nquartz-surface.c src/cairo-pattern.c src/cairo-surface.c src/cairo-xcb-surface.c src/cairo-xlib-surface.c

Carl Worth cworth at kemper.freedesktop.org
Wed Oct 18 17:06:34 PDT 2006


 src/cairo-clip.c             |    7 ++++++-
 src/cairo-directfb-surface.c |   18 +++++++++++++-----
 src/cairo-glitz-surface.c    |   30 ++++++++++++++++++++++--------
 src/cairo-image-surface.c    |    4 ++++
 src/cairo-nquartz-surface.c  |    9 +++++++--
 src/cairo-pattern.c          |   38 ++++++++++++++++++++------------------
 src/cairo-surface.c          |   14 ++++++++++++--
 src/cairo-xcb-surface.c      |    9 +++++++++
 src/cairo-xlib-surface.c     |   18 ++++++++++++++----
 src/cairoint.h               |    8 ++++++++
 10 files changed, 115 insertions(+), 40 deletions(-)

New commits:
diff-tree 8d7a02ed58e06584eb09575e6ca11d0a81094ab6 (from 99e2e99a78e492196a76e76cb47e463223db3012)
Author: Christopher (Monty) Montgomery <xiphmont at gmail.com>
Date:   Wed Oct 18 17:06:23 2006 -0700

    Add extents to clone_similar (fixing subimage_copy performance bug)
    
    This fixes a huge performance bug (entire image was being pushed to X
    server in order to copy a tiny piece of it). I see up to 50x improvement
    from subimage_copy (which was designed to expose this problem) but also
    a 5x improvement in some text performance cases.
    
     xlib-rgba              subimage_copy-512    3.93 2.46% ->   0.07 2.71%: 52.91x faster
    ███████████████████████████████████████████████████▉
     xlib-rgb               subimage_copy-512    4.03 1.97% ->   0.09 2.61%: 44.74x faster
    ███████████████████████████████████████████▊
     xlib-rgba              subimage_copy-256    1.02 2.25% ->   0.07 0.56%: 14.42x faster
    █████████████▍
     xlib-rgba        text_image_rgb_over-256   63.21 1.53% ->  11.87 2.17%:  5.33x faster
    ████▍
     xlib-rgba       text_image_rgba_over-256   62.31 0.72% ->  11.87 2.82%:  5.25x faster
    ████▎
     xlib-rgba     text_image_rgba_source-256   67.97 0.85% ->  16.48 2.23%:  4.13x faster
    ███▏
     xlib-rgba      text_image_rgb_source-256   68.82 0.55% ->  16.93 2.10%:  4.07x faster
    ███▏
     xlib-rgba              subimage_copy-128    0.19 1.72% ->   0.06 0.85%:  3.10x faster
    ██▏

diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 3f7c0c0..516e3b0 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -563,7 +563,12 @@ _cairo_clip_init_deep_copy (cairo_clip_t
         }
 
         if (other->surface) {
-            _cairo_surface_clone_similar (target, clip->surface, &clip->surface);
+            _cairo_surface_clone_similar (target, clip->surface,
+					  clip->surface_rect.x,
+					  clip->surface_rect.y,
+					  clip->surface_rect.width,
+					  clip->surface_rect.height,
+					  &clip->surface);
             clip->surface_rect = other->surface_rect;
         }
 
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index fdff40a..e724ed6 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -548,6 +548,10 @@ _cairo_directfb_surface_release_dest_ima
 static cairo_status_t
 _cairo_directfb_surface_clone_similar (void             *abstract_surface,
                                        cairo_surface_t  *src,
+				       int               src_x,
+				       int               src_y,
+				       int               width,
+				       int               height,
                                        cairo_surface_t **clone_out)
 {
     cairo_directfb_surface_t *surface = abstract_surface;
@@ -583,19 +587,23 @@ _cairo_directfb_surface_clone_similar (v
             cairo_surface_destroy ((cairo_surface_t *)clone);
             return CAIRO_STATUS_NO_MEMORY;
         }
+
+	dst += pitch * src_y;
+	src += image_src->stride * src_y;
         
         if (image_src->format == CAIRO_FORMAT_A1) {
             /* A1 -> A8 */
-            for (i = 0; i < image_src->height; i++) {
-                for (j = 0; j < image_src->width; j++)
+            for (i = 0; i < height; i++) {
+                for (j = src_x; j < src_x + width; j++)
                     dst[j] = (src[j>>3] & (1 << (j&7))) ? 0xff : 0x00;
                 dst += pitch;
                 src += image_src->stride;
             }
         }
-        else {     
-            for (i = 0; i < image_src->height; i++) {
-                direct_memcpy( dst, src, image_src->stride );
+        else {
+	    /* A8 -> A8 */
+            for (i = 0; i < height; i++) {
+                direct_memcpy( dst+src_x, src+src_x, sizeof(*dst)*width );
                 dst += pitch;
                 src += image_src->stride;
             }
diff --git a/src/cairo-glitz-surface.c b/src/cairo-glitz-surface.c
index 3536619..5310e22 100644
--- a/src/cairo-glitz-surface.c
+++ b/src/cairo-glitz-surface.c
@@ -244,8 +244,12 @@ _cairo_glitz_surface_get_image (cairo_gl
 static cairo_status_t
 _cairo_glitz_surface_set_image (void		      *abstract_surface,
 				cairo_image_surface_t *image,
-				int		      x_dst,
-				int		      y_dst)
+				int                    src_x,
+				int                    src_y,
+				int                    width,
+				int                    height,
+				int		       x_dst,
+				int		       y_dst)
 {
     cairo_glitz_surface_t *surface = abstract_surface;
     glitz_buffer_t	  *buffer;
@@ -265,8 +269,8 @@ _cairo_glitz_surface_set_image (void		  
     pf.masks.red_mask = rm;
     pf.masks.green_mask = gm;
     pf.masks.blue_mask = bm;
-    pf.xoffset = 0;
-    pf.skip_lines = 0;
+    pf.xoffset = src_x;
+    pf.skip_lines = src_y;
 
     /* check for negative stride */
     if (image->stride < 0)
@@ -288,7 +292,7 @@ _cairo_glitz_surface_set_image (void		  
 
     glitz_set_pixels (surface->surface,
 		      x_dst, y_dst,
-		      image->width, image->height,
+		      width, height,
 		      &pf,
 		      buffer);
 
@@ -348,7 +352,8 @@ _cairo_glitz_surface_release_dest_image 
 {
     cairo_glitz_surface_t *surface = abstract_surface;
 
-    _cairo_glitz_surface_set_image (surface, image,
+    _cairo_glitz_surface_set_image (surface, image, 0, 0,
+				    image->width, image->height,
 				    image_rect->x, image_rect->y);
 
     cairo_surface_destroy (&image->base);
@@ -357,6 +362,10 @@ _cairo_glitz_surface_release_dest_image 
 static cairo_status_t
 _cairo_glitz_surface_clone_similar (void	    *abstract_surface,
 				    cairo_surface_t *src,
+				    int              src_x,
+				    int              src_y,
+				    int              width,
+				    int              height,
 				    cairo_surface_t **clone_out)
 {
     cairo_glitz_surface_t *surface = abstract_surface;
@@ -385,7 +394,8 @@ _cairo_glitz_surface_clone_similar (void
 	if (clone->base.status)
 	    return CAIRO_STATUS_NO_MEMORY;
 
-	_cairo_glitz_surface_set_image (clone, image_src, 0, 0);
+	_cairo_glitz_surface_set_image (clone, image_src, src_x, src_y,
+					width, height, src_x, src_y);
 
 	*clone_out = &clone->base;
 
@@ -1184,7 +1194,7 @@ _cairo_glitz_surface_composite_trapezoid
 	    return CAIRO_STATUS_NO_MEMORY;
 	}
 
-	_cairo_glitz_surface_set_image (mask, image, 0, 0);
+	_cairo_glitz_surface_set_image (mask, image, src_x, src_y, width, height, 0, 0);
     }
 
     _cairo_glitz_surface_set_attributes (src, &attributes);
@@ -2025,6 +2035,10 @@ _cairo_glitz_surface_old_show_glyphs (ca
 		status =
 		    _cairo_glitz_surface_clone_similar (abstract_surface,
 							image,
+							src_x,
+							src_y,
+							width,
+							height,
 							(cairo_surface_t **)
 							&clone);
 		if (status)
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 8dc9087..0021ae9 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -665,6 +665,10 @@ _cairo_image_surface_release_dest_image 
 static cairo_status_t
 _cairo_image_surface_clone_similar (void		*abstract_surface,
 				    cairo_surface_t	*src,
+				    int                  src_x,
+				    int                  src_y,
+				    int                  width,
+				    int                  height,
 				    cairo_surface_t    **clone_out)
 {
     cairo_image_surface_t *surface = abstract_surface;
diff --git a/src/cairo-nquartz-surface.c b/src/cairo-nquartz-surface.c
index 1c300b1..5e82616 100644
--- a/src/cairo-nquartz-surface.c
+++ b/src/cairo-nquartz-surface.c
@@ -498,7 +498,8 @@ SurfacePatternDrawFunc (void *info, CGCo
 
 	cairo_surface_t *new_surf = NULL;
 
-	_cairo_surface_clone_similar (dummy, pat_surf, &new_surf);
+	_cairo_surface_clone_similar (dummy, pat_surf, rect.x, rect.y,
+				      rect.width, rect.height, &new_surf);
 
 	cairo_surface_destroy(dummy);
 
@@ -1025,6 +1026,10 @@ _cairo_nquartz_surface_create_similar (v
 static cairo_status_t
 _cairo_nquartz_surface_clone_similar (void *abstract_surface,
 				      cairo_surface_t *src,
+				      int              src_x,
+				      int              src_y,
+				      int              width,
+				      int              height,
 				      cairo_surface_t **clone_out)
 {
     cairo_nquartz_surface_t *surface = (cairo_nquartz_surface_t *) abstract_surface;
@@ -1104,7 +1109,7 @@ _cairo_nquartz_surface_clone_similar (vo
     nquartz_image_to_png (quartz_image, NULL);
 
     CGContextDrawImage (new_surface->cgContext,
-			CGRectMake (0, 0, CGImageGetWidth (quartz_image), CGImageGetHeight (quartz_image)),
+			CGRectMake (src_x, src_y, width, height),
 			quartz_image);
     CGImageRelease (quartz_image);
 
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 5f1dd8a..0d0940f 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1005,7 +1005,8 @@ _cairo_pattern_acquire_surface_for_gradi
 
     pixman_image_destroy (pixman_image);
 
-    status = _cairo_surface_clone_similar (dst, &image->base, out);
+    status = _cairo_surface_clone_similar (dst, &image->base,
+					   0, 0, width, height, out);
 
     cairo_surface_destroy (&image->base);
 
@@ -1125,6 +1126,22 @@ _cairo_pattern_acquire_surface_for_surfa
 
     attr->acquired = FALSE;
 
+    attr->extend = pattern->base.extend;
+    attr->filter = pattern->base.filter;
+    if (_cairo_matrix_is_integer_translation (&pattern->base.matrix,
+					      &tx, &ty))
+    {
+	cairo_matrix_init_identity (&attr->matrix);
+	attr->x_offset = tx;
+	attr->y_offset = ty;
+	attr->filter = CAIRO_FILTER_NEAREST;
+    }
+    else
+    {
+	attr->matrix = pattern->base.matrix;
+	attr->x_offset = attr->y_offset = 0;
+    }
+
     if (_cairo_surface_is_image (dst))
     {
 	cairo_image_surface_t *image;
@@ -1140,23 +1157,8 @@ _cairo_pattern_acquire_surface_for_surfa
     }
     else
     {
-	status = _cairo_surface_clone_similar (dst, pattern->surface, out);
-    }
-
-    attr->extend = pattern->base.extend;
-    attr->filter = pattern->base.filter;
-    if (_cairo_matrix_is_integer_translation (&pattern->base.matrix,
-					      &tx, &ty))
-    {
-	cairo_matrix_init_identity (&attr->matrix);
-	attr->x_offset = tx;
-	attr->y_offset = ty;
-	attr->filter = CAIRO_FILTER_NEAREST;
-    }
-    else
-    {
-	attr->matrix = pattern->base.matrix;
-	attr->x_offset = attr->y_offset = 0;
+	status = _cairo_surface_clone_similar (dst, pattern->surface,
+					       x+tx, y+ty, width, height, out);
     }
 
     return status;
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index cbbe89a..dfcf39d 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -987,6 +987,10 @@ _cairo_surface_release_dest_image (cairo
  * _cairo_surface_clone_similar:
  * @surface: a #cairo_surface_t
  * @src: the source image
+ * @src_x: extent for the rectangle in src we actually care about
+ * @src_y: extent for the rectangle in src we actually care about
+ * @width: extent for the rectangle in src we actually care about
+ * @height: extent for the rectangle in src we actually care about
  * @clone_out: location to store a surface compatible with @surface
  *   and with contents identical to @src. The caller must call
  *   cairo_surface_destroy() on the result.
@@ -1002,6 +1006,10 @@ _cairo_surface_release_dest_image (cairo
 cairo_status_t
 _cairo_surface_clone_similar (cairo_surface_t  *surface,
 			      cairo_surface_t  *src,
+			      int               src_x,
+			      int               src_y,
+			      int               width,
+			      int               height,
 			      cairo_surface_t **clone_out)
 {
     cairo_status_t status;
@@ -1014,7 +1022,8 @@ _cairo_surface_clone_similar (cairo_surf
     if (surface->backend->clone_similar == NULL)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    status = surface->backend->clone_similar (surface, src, clone_out);
+    status = surface->backend->clone_similar (surface, src, src_x, src_y,
+					      width, height, clone_out);
     if (status == CAIRO_STATUS_SUCCESS)
         (*clone_out)->device_transform = src->device_transform;
 
@@ -1025,7 +1034,8 @@ _cairo_surface_clone_similar (cairo_surf
     if (status != CAIRO_STATUS_SUCCESS)
 	return status;
 
-    status = surface->backend->clone_similar (surface, &image->base, clone_out);
+    status = surface->backend->clone_similar (surface, &image->base, src_x,
+					      src_y, width, height, clone_out);
     if (status == CAIRO_STATUS_SUCCESS)
         (*clone_out)->device_transform = src->device_transform;
 
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 4039605..d104adf 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -642,6 +642,10 @@ _cairo_xcb_surface_same_screen (cairo_xc
 static cairo_status_t
 _cairo_xcb_surface_clone_similar (void			*abstract_surface,
 				  cairo_surface_t	*src,
+				  int                    src_x,
+				  int                    src_y,
+				  int                    width,
+				  int                    height,
 				  cairo_surface_t     **clone_out)
 {
     cairo_xcb_surface_t *surface = abstract_surface;
@@ -668,6 +672,11 @@ _cairo_xcb_surface_clone_similar (void		
 	if (clone->base.status)
 	    return CAIRO_STATUS_NO_MEMORY;
 
+	/* can't apply extents; no manpages for XCBPutImage and xcb
+	source from freedesktop currently won't build.  XCBPutImage is not
+	referenced in the XCB source from xcb.freedesktop.org/dist
+	anywhere. */
+
 	_draw_image_surface (clone, image_src, 0, 0);
 
 	*clone_out = &clone->base;
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index d0f9158..aaf43e4 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -744,6 +744,10 @@ _cairo_xlib_surface_ensure_gc (cairo_xli
 static cairo_status_t
 _draw_image_surface (cairo_xlib_surface_t   *surface,
 		     cairo_image_surface_t  *image,
+		     int                    src_x,
+		     int                    src_y,
+		     int                    width,
+		     int                    height,
 		     int                    dst_x,
 		     int                    dst_y)
 {
@@ -774,8 +778,8 @@ _draw_image_surface (cairo_xlib_surface_
 
     _cairo_xlib_surface_ensure_gc (surface);
     XPutImage(surface->dpy, surface->drawable, surface->gc,
-	      &ximage, 0, 0, dst_x, dst_y,
-	      image->width, image->height);
+	      &ximage, src_x, src_y, dst_x, dst_y,
+	      width, height);
 
     return CAIRO_STATUS_SUCCESS;
 
@@ -839,7 +843,8 @@ _cairo_xlib_surface_release_dest_image (
     cairo_xlib_surface_t *surface = abstract_surface;
 
     /* ignore errors */
-    _draw_image_surface (surface, image, image_rect->x, image_rect->y);
+    _draw_image_surface (surface, image, 0, 0, image->width, image->height,
+			 image_rect->x, image_rect->y);
 
     cairo_surface_destroy (&image->base);
 }
@@ -859,6 +864,10 @@ _cairo_xlib_surface_same_screen (cairo_x
 static cairo_status_t
 _cairo_xlib_surface_clone_similar (void			*abstract_surface,
 				   cairo_surface_t	*src,
+				   int                   src_x,
+				   int                   src_y,
+				   int                   width,
+				   int                   height,
 				   cairo_surface_t     **clone_out)
 {
     cairo_xlib_surface_t *surface = abstract_surface;
@@ -884,7 +893,8 @@ _cairo_xlib_surface_clone_similar (void	
 	if (clone->base.status)
 	    return CAIRO_STATUS_NO_MEMORY;
 
-	_draw_image_surface (clone, image_src, 0, 0);
+	_draw_image_surface (clone, image_src, src_x, src_y,
+			     width, height, src_x, src_y);
 
 	*clone_out = &clone->base;
 
diff --git a/src/cairoint.h b/src/cairoint.h
index 17482f5..2c5856d 100755
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -723,6 +723,10 @@ struct _cairo_surface_backend {
     cairo_status_t
     (*clone_similar)            (void                   *surface,
 				 cairo_surface_t        *src,
+				 int                     src_x,
+				 int                     src_y,
+				 int                     width,
+				 int                     height,
 				 cairo_surface_t       **clone_out);
 
     /* XXX: dst should be the first argument for consistency */
@@ -1885,6 +1889,10 @@ _cairo_surface_release_dest_image (cairo
 cairo_private cairo_status_t
 _cairo_surface_clone_similar (cairo_surface_t  *surface,
 			      cairo_surface_t  *src,
+			      int               src_x,
+			      int               src_y,
+			      int               width,
+			      int               height,
 			      cairo_surface_t **clone_out);
 
 cairo_private cairo_surface_t *


More information about the cairo-commit mailing list