[cairo-commit] 3 commits - src/cairo-default-context.c src/cairo-xcb-connection-core.c test/Makefile.sources test/reference test/xcb-huge-subimage.c

Uli Schlachter psychon at kemper.freedesktop.org
Mon Dec 17 09:37:16 PST 2012


 src/cairo-default-context.c              |   23 +++++---
 src/cairo-xcb-connection-core.c          |   72 ++++++++++++++++++++++-----
 test/Makefile.sources                    |    1 
 test/reference/xcb-huge-subimage.ref.png |binary
 test/xcb-huge-subimage.c                 |   81 +++++++++++++++++++++++++++++++
 5 files changed, 154 insertions(+), 23 deletions(-)

New commits:
commit 51435eeb0c4d9e53d76dae8b5af279ad518a05f8
Author: Uli Schlachter <psychon at znc.in>
Date:   Mon Dec 17 18:33:22 2012 +0100

    xcb: Fix xcb-huge-subimage
    
    This teaches the xcb backend how to split up a PutImage request for a subimage
    into multiple requests. The backend already does the same for "normal" PutImage
    where it doesn't have to assemble the image from various rows.
    
    Signed-off-by: Uli Schlachter <psychon at znc.in>

diff --git a/src/cairo-xcb-connection-core.c b/src/cairo-xcb-connection-core.c
index 0eb2b84..ae7c023 100644
--- a/src/cairo-xcb-connection-core.c
+++ b/src/cairo-xcb-connection-core.c
@@ -159,20 +159,20 @@ _cairo_xcb_connection_put_image (cairo_xcb_connection_t *connection,
     }
 }
 
-void
-_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
-				    xcb_drawable_t dst,
-				    xcb_gcontext_t gc,
-				    int16_t src_x,
-				    int16_t src_y,
-				    uint16_t width,
-				    uint16_t height,
-				    uint16_t cpp,
-				    int stride,
-				    int16_t dst_x,
-				    int16_t dst_y,
-				    uint8_t depth,
-				    void *_data)
+static void
+_cairo_xcb_connection_do_put_subimage (cairo_xcb_connection_t *connection,
+				       xcb_drawable_t dst,
+				       xcb_gcontext_t gc,
+				       int16_t src_x,
+				       int16_t src_y,
+				       uint16_t width,
+				       uint16_t height,
+				       uint16_t cpp,
+				       int stride,
+				       int16_t dst_x,
+				       int16_t dst_y,
+				       uint8_t depth,
+				       void *_data)
 {
     xcb_protocol_request_t xcb_req = {
 	0 /* count */,
@@ -239,6 +239,50 @@ _cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
 	free (vec);
 }
 
+void
+_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
+				    xcb_drawable_t dst,
+				    xcb_gcontext_t gc,
+				    int16_t src_x,
+				    int16_t src_y,
+				    uint16_t width,
+				    uint16_t height,
+				    uint16_t cpp,
+				    int stride,
+				    int16_t dst_x,
+				    int16_t dst_y,
+				    uint8_t depth,
+				    void *_data)
+{
+    const uint32_t req_size = sizeof(xcb_put_image_request_t);
+    uint32_t length = height * cpp * width;
+    uint32_t len = (req_size + length) >> 2;
+
+    if (len < connection->maximum_request_length) {
+	_cairo_xcb_connection_do_put_subimage (connection, dst, gc, src_x, src_y,
+			width, height, cpp, stride, dst_x, dst_y, depth, _data);
+    } else {
+	int rows = (connection->maximum_request_length - req_size - 4) / (cpp * width);
+	if (rows > 0) {
+	    do {
+		if (rows > height)
+		    rows = height;
+
+		length = rows * cpp * width;
+
+		_cairo_xcb_connection_do_put_subimage (connection, dst, gc, src_x, src_y,
+			width, rows, cpp, stride, dst_x, dst_y, depth, _data);
+
+		height -= rows;
+		dst_y += rows;
+		_data = (char *) _data + stride * rows;
+	    } while (height);
+	} else {
+	    ASSERT_NOT_REACHED;
+	}
+    }
+}
+
 cairo_status_t
 _cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection,
 				 xcb_drawable_t src,
commit 5fb364287f96e4457d8df107ba3d0dc3f99f6f04
Author: Uli Schlachter <psychon at znc.in>
Date:   Mon Dec 17 18:29:21 2012 +0100

    test: Add xcb-huge-subimage
    
    This creates an image surface with a non-natural stride and paints it to a
    similar surface.
    
    In the xcb backend, this causes a call to _cairo_xcb_connection_put_subimage()
    which tries to send a huge PutImage request. As a result, xcb kills the X11
    connection.
    
    Signed-off-by: Uli Schlachter <psychon at znc.in>

diff --git a/test/Makefile.sources b/test/Makefile.sources
index 7dc8b88..1bf93e5 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -367,6 +367,7 @@ test_sources = \
 	world-map.c					\
 	white-in-noop.c					\
 	xcb-huge-image-shm.c				\
+	xcb-huge-subimage.c				\
 	xcb-stress-cache.c				\
 	xcb-snapshot-assert.c				\
 	xcomposite-projection.c				\
diff --git a/test/reference/xcb-huge-subimage.ref.png b/test/reference/xcb-huge-subimage.ref.png
new file mode 100644
index 0000000..a0b24c8
Binary files /dev/null and b/test/reference/xcb-huge-subimage.ref.png differ
diff --git a/test/xcb-huge-subimage.c b/test/xcb-huge-subimage.c
new file mode 100644
index 0000000..fc8e278
--- /dev/null
+++ b/test/xcb-huge-subimage.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright © 2012 Uli Schlachter
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Author: Uli Schlachter <psychon at znc.in>
+ */
+
+#include "cairo-test.h"
+
+#define WIDTH 6000
+#define HEIGHT 6000
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_surface_t *surface;
+    cairo_surface_t *image;
+    cairo_surface_t *subimage;
+    cairo_rectangle_int_t extents;
+    cairo_t *cr2;
+
+    extents.x = extents.y = 10;
+    extents.width = WIDTH - 20;
+    extents.height = HEIGHT - 20;
+
+    /* We use a similar surface to have way smaller ref images */
+    surface = cairo_surface_create_similar (cairo_get_target (cr),
+					    CAIRO_CONTENT_COLOR_ALPHA,
+					    WIDTH, HEIGHT);
+
+    /* First we have to defeat xcb's deferred clear */
+    cr2 = cairo_create (surface);
+    cairo_test_paint_checkered (cr2);
+    cairo_destroy (cr2);
+
+    /* Get us an image surface with a non-natural stride */
+    image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+					WIDTH, HEIGHT);
+    subimage = cairo_surface_map_to_image (image, &extents);
+
+    /* Paint the subimage to the similar surface and trigger the big upload */
+    cr2 = cairo_create (surface);
+    cairo_set_source_surface (cr2, subimage, 0, 0);
+    cairo_paint (cr2);
+    cairo_destroy (cr2);
+
+    /* Finally we make sure that errors aren't lost. */
+    cairo_surface_unmap_image (image, subimage);
+    cairo_set_source_surface (cr, surface, 0, 0);
+    cairo_paint (cr);
+    cairo_surface_destroy (image);
+    cairo_surface_destroy (surface);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (xcb_huge_subimage,
+	    "Test if the maximum request size is honored",
+	    "xcb", /* keywords */
+	    NULL, /* requirements */
+	    2, 2,
+	    NULL, draw)
commit 749ef6be4d11b95d666b0e5fe06df926b828d655
Author: Uli Schlachter <psychon at znc.in>
Date:   Mon Dec 17 17:45:25 2012 +0100

    context: Use recording surfaces for unbounded groups
    
    The old code uses an uninitialized variable for the extents of the group that is
    created. This patch makes it use an unbounded recording surface instead.
    
    This has the implicit assumption that everything that is unbounded smells like a
    recording surface. Let's see when this assumption breaks. :-)
    
    http://lists.cairographics.org/archives/cairo/2012-October/023585.html
    
    Signed-off-by: Uli Schlachter <psychon at znc.in>

diff --git a/src/cairo-default-context.c b/src/cairo-default-context.c
index 3d828ef..fee08f0 100644
--- a/src/cairo-default-context.c
+++ b/src/cairo-default-context.c
@@ -149,23 +149,28 @@ _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content)
     } else {
 	cairo_surface_t *parent_surface;
 	cairo_rectangle_int_t extents;
-	cairo_bool_t is_empty;
+	cairo_bool_t bounded, is_empty;
 
 	parent_surface = _cairo_gstate_get_target (cr->gstate);
 
 	/* Get the extents that we'll use in creating our new group surface */
-	is_empty = _cairo_surface_get_extents (parent_surface, &extents);
+	bounded = _cairo_surface_get_extents (parent_surface, &extents);
 	if (clip)
+	    /* XXX: This assignment just fixes a compiler warning? */
 	    is_empty = _cairo_rectangle_intersect (&extents,
 						   _cairo_clip_get_extents (clip));
 
-	/* XXX unbounded surface creation */
-
-	group_surface = _cairo_surface_create_similar_solid (parent_surface,
-							     content,
-							     extents.width,
-							     extents.height,
-							     CAIRO_COLOR_TRANSPARENT);
+	if (!bounded) {
+	    /* XXX: Generic solution? */
+	    group_surface = cairo_recording_surface_create (content, NULL);
+	    extents.x = extents.y = 0;
+	} else {
+	    group_surface = _cairo_surface_create_similar_solid (parent_surface,
+								 content,
+								 extents.width,
+								 extents.height,
+								 CAIRO_COLOR_TRANSPARENT);
+	}
 	status = group_surface->status;
 	if (unlikely (status))
 	    goto bail;


More information about the cairo-commit mailing list