[cairo-commit] 5 commits - src/cairo-xcb-private.h src/cairo-xcb-shm.c src/cairo-xcb-surface.c src/cairo-xcb-surface-core.c test/Makefile.refs test/Makefile.sources test/xcb-huge-image-shm.c test/xcb-huge-image-shm.ref.png

Uli Schlachter psychon at kemper.freedesktop.org
Thu Aug 18 07:35:51 PDT 2011


 src/cairo-xcb-private.h         |    2 +
 src/cairo-xcb-shm.c             |   11 +++---
 src/cairo-xcb-surface-core.c    |    3 +
 src/cairo-xcb-surface.c         |   55 +++++++-------------------------
 test/Makefile.refs              |    1 
 test/Makefile.sources           |    1 
 test/xcb-huge-image-shm.c       |   67 ++++++++++++++++++++++++++++++++++++++++
 test/xcb-huge-image-shm.ref.png |binary
 8 files changed, 92 insertions(+), 48 deletions(-)

New commits:
commit 5d92ce3a181c439e0b5a160a5820bf20ccaf5414
Author: Uli Schlachter <psychon at znc.in>
Date:   Thu Aug 18 15:37:13 2011 +0200

    xcb-shm: Fix a logic error while allocating mem
    
    The "continue;" in the old code never worked, because it first checked the loop
    condition. Since "FALSE" (hopefully) never evaluates to true, the loop was still
    left.
    
    Signed-off-by: Uli Schlachter <psychon at znc.in>

diff --git a/src/cairo-xcb-shm.c b/src/cairo-xcb-shm.c
index 1d630a7..ffcaec8 100644
--- a/src/cairo-xcb-shm.c
+++ b/src/cairo-xcb-shm.c
@@ -548,11 +548,12 @@ _cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *connection,
 	if (pool->shmid != -1)
 	    break;
 
-	if (errno == EINVAL && bytes > size) {
-	    bytes >>= 1;
-	    continue;
-	}
-    } while (FALSE);
+	/* If the allocation failed because we asked for too much memory, we try
+	 * again with a smaller request, as long as our allocation still fits. */
+	bytes >>= 1;
+	if (errno != EINVAL || bytes < size)
+	    break;
+    } while (TRUE);
     if (pool->shmid == -1) {
 	int err = errno;
 	if (! (err == EINVAL || err == ENOMEM))
commit 73e7391e6e53b894f763f4715590d3be7e7ec243
Author: Uli Schlachter <psychon at znc.in>
Date:   Thu Aug 18 15:20:35 2011 +0200

    xcb: Handle SHM exhaustion via falling back
    
    When we couldn't get an image from the X11 server via SHM because we ran out
    shared memory, we should try again via a normal GetImage request.
    
    Fixes: xcb-huge-image-shm
    
    Signed-off-by: Uli Schlachter <psychon at znc.in>

diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index c3df5ed..ebea5ff 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -348,8 +348,13 @@ _get_image (cairo_xcb_surface_t		 *surface,
     if (use_shm) {
 	image = _get_shm_image (surface, x, y, width, height);
 	if (image) {
-	    _cairo_xcb_connection_release (connection);
-	    return image;
+	    /* XXX This only wants to catch SHM exhaustion,
+	     * not other allocation failures. */
+	    if (image->status != CAIRO_STATUS_NO_MEMORY) {
+		_cairo_xcb_connection_release (connection);
+		return image;
+	    }
+	    cairo_surface_destroy (image);
 	}
     }
 
commit aeba5acbad463db3a9eeb44e26a15979d1831472
Author: Uli Schlachter <psychon at znc.in>
Date:   Thu Aug 18 15:10:47 2011 +0200

    test: Add a test that maps a huge surface
    
    This test currently fails in the xcb backend if xcb-shm is enabled.
    
    Signed-off-by: Uli Schlachter <psychon at znc.in>

diff --git a/test/Makefile.refs b/test/Makefile.refs
index 2d291f0..500fd82 100644
--- a/test/Makefile.refs
+++ b/test/Makefile.refs
@@ -1402,6 +1402,7 @@ REFERENCE_IMAGES = \
 	world-map-stroke.ref.png \
 	world-map.image16.ref.png \
 	world-map.ref.png \
+	xcb-huge-image-shm.ref.png \
 	xcb-snapshot-assert.ref.png \
 	xcb-stress-cache.ref.png \
 	xcb-surface-source.argb32.ref.png \
diff --git a/test/Makefile.sources b/test/Makefile.sources
index a39a201..7001193 100644
--- a/test/Makefile.sources
+++ b/test/Makefile.sources
@@ -320,6 +320,7 @@ test_sources = \
 	user-font-rescale.c				\
 	world-map.c					\
 	white-in-noop.c					\
+	xcb-huge-image-shm.c				\
 	xcb-stress-cache.c				\
 	xcb-snapshot-assert.c				\
 	xcomposite-projection.c				\
diff --git a/test/xcb-huge-image-shm.c b/test/xcb-huge-image-shm.c
new file mode 100644
index 0000000..269d7f0
--- /dev/null
+++ b/test/xcb-huge-image-shm.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2011 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 3000
+#define HEIGHT 3000
+
+static cairo_test_status_t
+draw (cairo_t *cr, int width, int height)
+{
+    cairo_surface_t *surface;
+    cairo_surface_t *image;
+    cairo_t *cr2;
+
+    /* 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);
+
+    /* Now we try to map this to an image. This will try to use shared memory
+     * but fail the allocation, because of the huge surface. */
+    image = cairo_surface_map_to_image (surface, NULL);
+    cairo_surface_unmap_image (surface, image);
+
+    /* Finally we make sure that errors aren't lost. */
+    cairo_set_source_surface (cr, surface, 0, 0);
+    cairo_paint (cr);
+    cairo_surface_destroy (surface);
+
+    return CAIRO_TEST_SUCCESS;
+}
+
+CAIRO_TEST (xcb_huge_image_shm,
+	    "Force a failed shm allocation when receiving an image",
+	    "xcb", /* keywords */
+	    NULL, /* requirements */
+	    2, 2,
+	    NULL, draw)
diff --git a/test/xcb-huge-image-shm.ref.png b/test/xcb-huge-image-shm.ref.png
new file mode 100644
index 0000000..a0b24c8
Binary files /dev/null and b/test/xcb-huge-image-shm.ref.png differ
commit 8951c51d9e63dc175bc1eff6592833de627bce74
Author: Uli Schlachter <psychon at znc.in>
Date:   Thu Aug 18 12:51:28 2011 +0200

    xcb: Merge two functions for creating shm images
    
    This merges most of _cairo_xcb_surface_create_similar_image() into
    _cairo_xcb_shm_image_create().
    
    These two functions where already doing almost the same thing with only some
    differences in error handling.
    
    Signed-off-by: Uli Schlachter <psychon at znc.in>

diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
index d9557b4..648bd57 100644
--- a/src/cairo-xcb-private.h
+++ b/src/cairo-xcb-private.h
@@ -56,6 +56,8 @@
 #include <xcb/xcbext.h>
 #include <pixman.h>
 
+#define XLIB_COORD_MAX 32767
+
 /* maximum number of cached GC's */
 #define GC_CACHE_SIZE 4
 
diff --git a/src/cairo-xcb-surface-core.c b/src/cairo-xcb-surface-core.c
index 0770dcd..20cb5d3 100644
--- a/src/cairo-xcb-surface-core.c
+++ b/src/cairo-xcb-surface-core.c
@@ -156,6 +156,9 @@ _cairo_xcb_shm_image_create_shm (cairo_xcb_connection_t *connection,
     if (! (connection->flags & CAIRO_XCB_HAS_SHM))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
+    if (unlikely (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
     stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (pixman_format));
     size = stride * height;
     if (size <= CAIRO_XCB_SHM_SMALL_IMAGE)
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 48aa176..c3df5ed 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -46,8 +46,6 @@
 #include "cairo-default-context-private.h"
 #include "cairo-image-surface-private.h"
 
-#define XLIB_COORD_MAX 32767
-
 #if CAIRO_HAS_XLIB_XCB_FUNCTIONS
 slim_hidden_proto (cairo_xcb_surface_create);
 slim_hidden_proto (cairo_xcb_surface_create_for_bitmap);
@@ -164,56 +162,22 @@ _cairo_xcb_surface_create_similar_image (void			*abstract_other,
 					 int			 width,
 					 int			 height)
 {
-#if CAIRO_HAS_XCB_SHM_FUNCTIONS
     cairo_xcb_surface_t *other = abstract_other;
     cairo_xcb_connection_t *connection = other->connection;
 
-    cairo_surface_t *image;
     cairo_xcb_shm_info_t *shm_info;
+    cairo_image_surface_t *image;
     cairo_status_t status;
-    size_t stride;
     pixman_format_code_t pixman_format;
 
-    if (unlikely(width > XLIB_COORD_MAX || height > XLIB_COORD_MAX))
-	return cairo_image_surface_create (format, width, height);
-
-    if ((connection->flags & CAIRO_XCB_HAS_SHM) == 0)
-	return cairo_image_surface_create (format, width, height);
-
     pixman_format = _cairo_format_to_pixman_format_code (format);
 
-    stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width,
-					 PIXMAN_FORMAT_BPP (pixman_format));
-    status = _cairo_xcb_connection_allocate_shm_info (connection,
-						      stride * height,
-						      &shm_info);
+    status = _cairo_xcb_shm_image_create (connection, pixman_format,
+					  width, height, &image,
+					  &shm_info);
     if (unlikely (status))
-	return cairo_image_surface_create (format, width, height);
-
-    image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
-							    pixman_format,
-							    width,
-							    height,
-							    stride);
-    if (unlikely (image->status)) {
-	_cairo_xcb_shm_info_destroy (shm_info);
-	return image;
-    }
-
-    status = _cairo_user_data_array_set_data (&image->user_data,
-					      (const cairo_user_data_key_t *) connection,
-					      shm_info,
-					      (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
-    if (unlikely (status)) {
-	cairo_surface_destroy (image);
-	_cairo_xcb_shm_info_destroy (shm_info);
 	return _cairo_surface_create_in_error (status);
-    }
-
-    return image;
-#else
-    return cairo_image_surface_create (format, width, height);
-#endif
+    return &image->base;
 }
 
 static cairo_status_t
commit 0da3d3efd21e4a8bf1356c0829ac5b0a30f2df88
Author: Uli Schlachter <psychon at znc.in>
Date:   Mon Aug 8 22:35:20 2011 +0200

    xcb: Fallback to image if allocating SHM fails
    
    This turns an !!!ERROR!!! for scale-offset-similar with xcb-fallback into a
    failed test and might fix other problems. However, since the problem here partly
    is a race, those other problems might only be hit sometimes.
    
    Signed-off-by: Uli Schlachter <psychon at znc.in>

diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index abf8fe3..48aa176 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -188,7 +188,7 @@ _cairo_xcb_surface_create_similar_image (void			*abstract_other,
 						      stride * height,
 						      &shm_info);
     if (unlikely (status))
-	return _cairo_surface_create_in_error (status);
+	return cairo_image_surface_create (format, width, height);
 
     image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
 							    pixman_format,


More information about the cairo-commit mailing list