[cairo-commit] 2 commits - configure.ac src/cairo-cogl-surface.c src/cairo-damage.c src/cairo-directfb-surface.c src/cairo-gl-surface.c src/cairo-image-compositor.c src/cairo-image-surface.c src/cairo-image-surface-inline.h src/cairo-image-surface-private.h src/cairoint.h src/cairo-mempool.c src/cairo-mempool-private.h src/cairo-quartz-image-surface.c src/cairo-scaled-font.c src/cairo-surface-backend-private.h src/cairo-surface.c src/cairo-surface-inline.h src/cairo-surface-observer.c src/cairo-surface-private.h src/cairo-surface-snapshot.c src/cairo-surface-subsurface.c src/cairo-tor22-scan-converter.c src/cairo-xcb-surface.c src/cairo-xlib-display.c src/cairo-xlib-fallback-compositor.c src/cairo-xlib-private.h src/cairo-xlib-render-compositor.c src/cairo-xlib-source.c src/cairo-xlib-surface.c src/cairo-xlib-surface-shm.c src/cairo-xlib-xcb-surface.c src/drm src/Makefile.sources src/win32

Chris Wilson ickle at kemper.freedesktop.org
Fri Aug 17 05:59:43 PDT 2012


 configure.ac                            |    4 
 src/Makefile.sources                    |    3 
 src/cairo-cogl-surface.c                |    8 
 src/cairo-damage.c                      |    1 
 src/cairo-directfb-surface.c            |    6 
 src/cairo-gl-surface.c                  |    9 
 src/cairo-image-compositor.c            |   26 
 src/cairo-image-surface-inline.h        |    2 
 src/cairo-image-surface-private.h       |    6 
 src/cairo-image-surface.c               |    2 
 src/cairo-mempool-private.h             |   83 ++
 src/cairo-mempool.c                     |  359 ++++++++++
 src/cairo-quartz-image-surface.c        |    6 
 src/cairo-scaled-font.c                 |    2 
 src/cairo-surface-backend-private.h     |    3 
 src/cairo-surface-inline.h              |    4 
 src/cairo-surface-observer.c            |    6 
 src/cairo-surface-private.h             |    3 
 src/cairo-surface-snapshot.c            |    5 
 src/cairo-surface-subsurface.c          |    6 
 src/cairo-surface.c                     |  101 ++
 src/cairo-tor22-scan-converter.c        |    2 
 src/cairo-xcb-surface.c                 |    6 
 src/cairo-xlib-display.c                |    9 
 src/cairo-xlib-fallback-compositor.c    |  190 +++++
 src/cairo-xlib-private.h                |   59 +
 src/cairo-xlib-render-compositor.c      |  155 ++++
 src/cairo-xlib-source.c                 |  231 +++---
 src/cairo-xlib-surface-shm.c            | 1119 ++++++++++++++++++++++++++++++++
 src/cairo-xlib-surface.c                |  286 +++++++-
 src/cairo-xlib-xcb-surface.c            |    5 
 src/cairoint.h                          |    2 
 src/drm/cairo-drm-gallium-surface.c     |    6 
 src/drm/cairo-drm-i915-private.h        |    2 
 src/drm/cairo-drm-i915-surface.c        |    8 
 src/drm/cairo-drm-i965-shader.c         |    4 
 src/drm/cairo-drm-i965-surface.c        |    5 
 src/drm/cairo-drm-intel-private.h       |    3 
 src/drm/cairo-drm-intel-surface.c       |    5 
 src/drm/cairo-drm-radeon-surface.c      |    6 
 src/win32/cairo-win32-display-surface.c |    5 
 src/win32/cairo-win32-gdi-compositor.c  |    4 
 42 files changed, 2519 insertions(+), 238 deletions(-)

New commits:
commit f42c0dcf7b37c8daf80e8075aa5286d137062a88
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Tue Aug 14 21:50:37 2012 +0100

    tor22: Add a simple method to quickly compute coverage (with saturation)
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/cairo-tor22-scan-converter.c b/src/cairo-tor22-scan-converter.c
index 2f93030..b4cdd6c 100644
--- a/src/cairo-tor22-scan-converter.c
+++ b/src/cairo-tor22-scan-converter.c
@@ -248,6 +248,8 @@ typedef int grid_scaled_y_t;
 #  define  GRID_AREA_TO_ALPHA(c)  (c)
 #elif GRID_XY == 64
 #  define  GRID_AREA_TO_ALPHA(c)  (((c) << 2) | -(((c) & 0x40) >> 6))
+#elif GRID_XY == 32
+#  define  GRID_AREA_TO_ALPHA(c)  (((c) << 3) | -(((c) & 0x20) >> 5))
 #elif GRID_XY == 128
 #  define  GRID_AREA_TO_ALPHA(c)  ((((c) << 1) | -((c) >> 7)) & 255)
 #elif GRID_XY == 256
commit 0bfd2acd35547fc2bd0de99cc67d153f0170697d
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon Aug 13 01:34:12 2012 +0100

    xlib: Implement SHM fallbacks and fast upload paths
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/configure.ac b/configure.ac
index 0067bfc..3d668b6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -63,7 +63,7 @@ AM_CONDITIONAL(CAIRO_HAS_DLSYM, test "x$have_dlsym" = "xyes")
 dnl ===========================================================================
 
 CAIRO_ENABLE_SURFACE_BACKEND(xlib, Xlib, auto, [
-  xlib_REQUIRES="x11"
+  xlib_REQUIRES="x11 xext"
   PKG_CHECK_MODULES(xlib, $xlib_REQUIRES, ,
 		    [AC_MSG_RESULT(no)
 		     xlib_REQUIRES=""
@@ -71,7 +71,7 @@ CAIRO_ENABLE_SURFACE_BACKEND(xlib, Xlib, auto, [
 		     if test "x$no_x" = xyes; then
 		       use_xlib="no (requires X development libraries)"
 		     else
-		       xlib_NONPKGCONFIG_LIBS="$X_PRE_LIBS $X_LIBS -lX11 $X_EXTRA_LIBS"
+		       xlib_NONPKGCONFIG_LIBS="$X_PRE_LIBS $X_LIBS -lX11 -lXext $X_EXTRA_LIBS"
 		       xlib_NONPKGCONFIG_CFLAGS=$X_CFLAGS
 		     fi])
 ])
diff --git a/src/Makefile.sources b/src/Makefile.sources
index f487fc1..9a33677 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -87,6 +87,7 @@ cairo_private = \
 	cairo-list-inline.h \
 	cairo-list-private.h \
 	cairo-malloc-private.h \
+	cairo-mempool-private.h \
 	cairo-mutex-impl-private.h \
 	cairo-mutex-list-private.h \
 	cairo-mutex-private.h \
@@ -178,6 +179,7 @@ cairo_sources = \
 	cairo-matrix.c \
 	cairo-mask-compositor.c \
 	cairo-mesh-pattern-rasterizer.c \
+	cairo-mempool.c \
 	cairo-misc.c \
 	cairo-mono-scan-converter.c \
 	cairo-mutex.c \
@@ -311,6 +313,7 @@ cairo_xlib_sources = \
 	cairo-xlib-screen.c \
 	cairo-xlib-source.c \
 	cairo-xlib-surface.c \
+	cairo-xlib-surface-shm.c \
 	cairo-xlib-visual.c \
 	cairo-xlib-xcb-surface.c \
 	$(NULL)
diff --git a/src/cairo-cogl-surface.c b/src/cairo-cogl-surface.c
index ed86acc..d192d75 100644
--- a/src/cairo-cogl-surface.c
+++ b/src/cairo-cogl-surface.c
@@ -929,10 +929,14 @@ _cairo_cogl_journal_flush (cairo_cogl_surface_t *surface)
 }
 
 static cairo_status_t
-_cairo_cogl_surface_flush (void *abstract_surface)
+_cairo_cogl_surface_flush (void *abstract_surface,
+			   unsigned flags)
 {
     cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)abstract_surface;
 
+    if (flags)
+	return CAIRO_STATUS_SUCCESS;
+
     _cairo_cogl_journal_flush (surface);
 
     return CAIRO_STATUS_SUCCESS;
@@ -1331,7 +1335,7 @@ _cairo_cogl_acquire_surface_texture (cairo_cogl_surface_t  *reference_surface,
 
     if (abstract_surface->device == reference_surface->base.device) {
 	cairo_cogl_surface_t *surface = (cairo_cogl_surface_t *)abstract_surface;
-	_cairo_cogl_surface_flush (surface);
+	_cairo_cogl_surface_flush (surface, 0);
 	return surface->texture ? cogl_object_ref (surface->texture) : NULL;
     }
 
diff --git a/src/cairo-damage.c b/src/cairo-damage.c
index 61a58af..1e06b26 100644
--- a/src/cairo-damage.c
+++ b/src/cairo-damage.c
@@ -95,7 +95,6 @@ _cairo_damage_add_boxes(cairo_damage_t *damage,
     if (damage->status)
 	return damage;
 
-
     damage->dirty += count;
 
     n = count;
diff --git a/src/cairo-directfb-surface.c b/src/cairo-directfb-surface.c
index 494ec07..16e367a 100644
--- a/src/cairo-directfb-surface.c
+++ b/src/cairo-directfb-surface.c
@@ -209,10 +209,14 @@ _cairo_dfb_surface_unmap_image (void *abstract_surface,
 }
 
 static cairo_status_t
-_cairo_dfb_surface_flush (void *abstract_surface)
+_cairo_dfb_surface_flush (void *abstract_surface,
+			  unsigned flags)
 {
     cairo_dfb_surface_t *surface = abstract_surface;
 
+    if (flags)
+	return CAIRO_STATUS_SUCCESS;
+
     if (surface->image.pixman_image) {
 	surface->dfb_surface->Unlock (surface->dfb_surface);
 
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 8b63fd2..c0ee79f 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -52,7 +52,7 @@
 static const cairo_surface_backend_t _cairo_gl_surface_backend;
 
 static cairo_status_t
-_cairo_gl_surface_flush (void *abstract_surface);
+_cairo_gl_surface_flush (void *abstract_surface, unsigned flags);
 
 static cairo_bool_t _cairo_surface_is_gl (cairo_surface_t *surface)
 {
@@ -834,7 +834,7 @@ _cairo_gl_surface_draw_image (cairo_gl_surface_t *dst,
 
     cpp = PIXMAN_FORMAT_BPP (src->pixman_format) / 8;
 
-    status = _cairo_gl_surface_flush (&dst->base);
+    status = _cairo_gl_surface_flush (&dst->base, 0);
     if (unlikely (status))
 	goto FAIL;
 
@@ -1200,12 +1200,15 @@ _cairo_gl_surface_get_extents (void		     *abstract_surface,
 }
 
 static cairo_status_t
-_cairo_gl_surface_flush (void *abstract_surface)
+_cairo_gl_surface_flush (void *abstract_surface, unsigned flags)
 {
     cairo_gl_surface_t *surface = abstract_surface;
     cairo_status_t status;
     cairo_gl_context_t *ctx;
 
+    if (flags)
+	return CAIRO_STATUS_SUCCESS;
+
     status = _cairo_gl_context_acquire (surface->base.device, &ctx);
     if (unlikely (status))
         return status;
diff --git a/src/cairo-image-compositor.c b/src/cairo-image-compositor.c
index 1ec9838..768e3a5 100644
--- a/src/cairo-image-compositor.c
+++ b/src/cairo-image-compositor.c
@@ -750,6 +750,16 @@ composite_tristrip (void			*_dst,
     return  CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_int_status_t
+check_composite_glyphs (const cairo_composite_rectangles_t *extents,
+			cairo_scaled_font_t *scaled_font,
+			cairo_glyph_t *glyphs,
+			int *num_glyphs)
+{
+    return CAIRO_STATUS_SUCCESS;
+}
+
+#if HAS_PIXMAN_GLYPHS
 static pixman_glyph_cache_t *global_glyph_cache;
 
 static inline pixman_glyph_cache_t *
@@ -777,16 +787,6 @@ _cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
 }
 
 static cairo_int_status_t
-check_composite_glyphs (const cairo_composite_rectangles_t *extents,
-			cairo_scaled_font_t *scaled_font,
-			cairo_glyph_t *glyphs,
-			int *num_glyphs)
-{
-    return CAIRO_STATUS_SUCCESS;
-}
-
-#if HAS_PIXMAN_GLYPHS
-static cairo_int_status_t
 composite_glyphs (void				*_dst,
 		  cairo_operator_t		 op,
 		  cairo_surface_t		*_src,
@@ -896,6 +896,12 @@ out_unlock:
     return status;
 }
 #else
+void
+_cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
+				cairo_scaled_glyph_t *scaled_glyph)
+{
+}
+
 static cairo_int_status_t
 composite_one_glyph (void				*_dst,
 		     cairo_operator_t			 op,
diff --git a/src/cairo-image-surface-inline.h b/src/cairo-image-surface-inline.h
index f6bed71..4959107 100644
--- a/src/cairo-image-surface-inline.h
+++ b/src/cairo-image-surface-inline.h
@@ -73,7 +73,7 @@ _cairo_image_surface_is_clone (cairo_image_surface_t *image)
 static inline cairo_bool_t
 _cairo_surface_is_image (const cairo_surface_t *surface)
 {
-    return surface->backend == &_cairo_image_surface_backend;
+    return surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE;
 }
 
 /**
diff --git a/src/cairo-image-surface-private.h b/src/cairo-image-surface-private.h
index 9660180..6a159d8 100644
--- a/src/cairo-image-surface-private.h
+++ b/src/cairo-image-surface-private.h
@@ -151,6 +151,12 @@ _cairo_image_surface_init (cairo_image_surface_t *surface,
 			   pixman_image_t	*pixman_image,
 			   pixman_format_code_t	 pixman_format);
 
+cairo_private cairo_surface_t *
+_cairo_image_surface_create_similar (void	       *abstract_other,
+				     cairo_content_t	content,
+				     int		width,
+				     int		height);
+
 cairo_private cairo_image_surface_t *
 _cairo_image_surface_map_to_image (void *abstract_other,
 				   const cairo_rectangle_int_t *extents);
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 23e6ca6..3fe6e43 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -723,7 +723,7 @@ _cairo_format_bits_per_pixel (cairo_format_t format)
     }
 }
 
-static cairo_surface_t *
+cairo_surface_t *
 _cairo_image_surface_create_similar (void	       *abstract_other,
 				     cairo_content_t	content,
 				     int		width,
diff --git a/src/cairo-mempool-private.h b/src/cairo-mempool-private.h
new file mode 100644
index 0000000..4435a5a
--- /dev/null
+++ b/src/cairo-mempool-private.h
@@ -0,0 +1,83 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2007 Chris Wilson
+ * Copyright © 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributors(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_MEMPOOL_PRIVATE_H
+#define CAIRO_MEMPOOL_PRIVATE_H
+
+#include "cairo-compiler-private.h"
+#include "cairo-error-private.h"
+
+CAIRO_BEGIN_DECLS
+
+typedef struct _cairo_mempool cairo_mempool_t;
+
+struct _cairo_mempool {
+    char *base;
+    struct _cairo_memblock {
+	int bits;
+	cairo_list_t link;
+    } *blocks;
+    cairo_list_t free[32];
+    unsigned char *map;
+
+    unsigned int num_blocks;
+    int min_bits;     /* Minimum block size is 1 << min_bits */
+    int num_sizes;
+    int max_free_bits;
+
+    size_t free_bytes;
+    size_t max_bytes;
+};
+
+cairo_private cairo_status_t
+_cairo_mempool_init (cairo_mempool_t *pool,
+		     void *base,
+		     size_t bytes,
+		     int min_bits,
+		     int num_sizes);
+
+cairo_private void *
+_cairo_mempool_alloc (cairo_mempool_t *pi, size_t bytes);
+
+cairo_private void
+_cairo_mempool_free (cairo_mempool_t *pi, void *storage);
+
+cairo_private void
+_cairo_mempool_fini (cairo_mempool_t *pool);
+
+CAIRO_END_DECLS
+
+#endif /* CAIRO_MEMPOOL_PRIVATE_H */
diff --git a/src/cairo-mempool.c b/src/cairo-mempool.c
new file mode 100644
index 0000000..296b739
--- /dev/null
+++ b/src/cairo-mempool.c
@@ -0,0 +1,359 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2007 Chris Wilson
+ * Copyright © 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipoolent may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is Red Hat, Inc.
+ *
+ * Contributors(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-mempool-private.h"
+#include "cairo-list-inline.h"
+
+/* a simple buddy allocator for memory pools
+ * XXX fragmentation? use Doug Lea's malloc?
+ */
+
+#define BITTEST(p, n)  ((p)->map[(n) >> 3] &   (128 >> ((n) & 7)))
+#define BITSET(p, n)   ((p)->map[(n) >> 3] |=  (128 >> ((n) & 7)))
+#define BITCLEAR(p, n) ((p)->map[(n) >> 3] &= ~(128 >> ((n) & 7)))
+
+static void
+clear_bits (cairo_mempool_t *pool, size_t first, size_t last)
+{
+    size_t i, n = last;
+    size_t first_full = (first + 7) & ~7;
+    size_t past_full = last & ~7;
+    size_t bytes;
+
+    if (n > first_full)
+	n = first_full;
+    for (i = first; i < n; i++)
+	  BITCLEAR (pool, i);
+
+    if (past_full > first_full) {
+	bytes = past_full - first_full;
+	bytes = bytes >> 3;
+	memset (pool->map + (first_full >> 3), 0, bytes);
+    }
+
+    if (past_full < n)
+	past_full = n;
+    for (i = past_full; i < last; i++)
+	BITCLEAR (pool, i);
+}
+
+static void
+free_bits (cairo_mempool_t *pool, size_t start, int bits, cairo_bool_t clear)
+{
+    struct _cairo_memblock *block;
+
+    if (clear)
+	clear_bits (pool, start, start + (1 << bits));
+
+    block = pool->blocks + start;
+    block->bits = bits;
+
+    cairo_list_add (&block->link, &pool->free[bits]);
+
+    pool->free_bytes += 1 << (bits + pool->min_bits);
+    if (bits > pool->max_free_bits)
+	pool->max_free_bits = bits;
+}
+
+/* Add a chunk to the free list */
+static void
+free_blocks (cairo_mempool_t *pool,
+	     size_t first,
+	     size_t last,
+	     cairo_bool_t clear)
+{
+    size_t i, len;
+    int bits = 0;
+
+    for (i = first, len = 1; i < last; i += len) {
+        /* To avoid cost quadratic in the number of different
+	 * blocks produced from this chunk of store, we have to
+	 * use the size of the previous block produced from this
+	 * chunk as the starting point to work out the size of the
+	 * next block we can produce. If you look at the binary
+	 * representation of the starting points of the blocks
+	 * produced, you can see that you first of all increase the
+	 * size of the blocks produced up to some maximum as the
+	 * address dealt with gets offsets added on which zap out
+	 * low order bits, then decrease as the low order bits of the
+	 * final block produced get added in. E.g. as you go from
+	 * 001 to 0111 you generate blocks
+	 * of size 001 at 001 taking you to 010
+	 * of size 010 at 010 taking you to 100
+	 * of size 010 at 100 taking you to 110
+	 * of size 001 at 110 taking you to 111
+	 * So the maximum total cost of the loops below this comment
+	 * is one trip from the lowest blocksize to the highest and
+	 * back again.
+	 */
+	while (bits < pool->num_sizes - 1) {
+	    size_t next_bits = bits + 1;
+	    size_t next_len = len << 1;
+
+	    if (i + next_bits > last) {
+		/* off end of chunk to be freed */
+	        break;
+	    }
+
+	    if (i & (next_len - 1)) /* block would not be on boundary */
+	        break;
+
+	    bits = next_bits;
+	    len = next_len;
+	}
+
+	do {
+	    if (i + len <= last && /* off end of chunk to be freed */
+		(i & (len - 1)) == 0) /* block would not be on boundary */
+		break;
+
+	    bits--; len >>=1;
+	} while (len);
+
+	if (len == 0)
+	    break;
+
+	free_bits (pool, i, bits, clear);
+    }
+}
+
+static struct _cairo_memblock *
+get_buddy (cairo_mempool_t *pool, size_t offset, int bits)
+{
+    struct _cairo_memblock *block;
+
+    assert (offset + (1 << bits) <= pool->num_blocks);
+
+    if (BITTEST (pool, offset + (1 << bits) - 1))
+	return NULL; /* buddy is allocated */
+
+    block = pool->blocks + offset;
+    if (block->bits != bits)
+	return NULL; /* buddy is partially allocated */
+
+    return block;
+}
+
+static void
+merge_buddies (cairo_mempool_t *pool,
+	       struct _cairo_memblock *block,
+	       int max_bits)
+{
+    size_t block_offset = block - pool->blocks;
+    int bits = block->bits;
+
+    while (bits < max_bits - 1) {
+	/* while you can, merge two blocks and get a legal block size */
+	size_t buddy_offset = block_offset ^ (1 << bits);
+
+	block = get_buddy (pool, buddy_offset, bits);
+	if (block == NULL)
+	    break;
+
+	cairo_list_del (&block->link);
+
+	/* Merged block starts at buddy */
+	if (buddy_offset < block_offset)
+	    block_offset = buddy_offset;
+
+	bits++;
+    }
+
+    block = pool->blocks + block_offset;
+    block->bits = bits;
+    cairo_list_add (&block->link, &pool->free[bits]);
+
+    if (bits > pool->max_free_bits)
+	pool->max_free_bits = bits;
+}
+
+/* attempt to merge all available buddies up to a particular size */
+static int
+merge_bits (cairo_mempool_t *pool, int max_bits)
+{
+    struct _cairo_memblock *block, *buddy, *next;
+    int bits;
+
+    for (bits = 0; bits < max_bits - 1; bits++) {
+	cairo_list_foreach_entry_safe (block, next,
+				       struct _cairo_memblock,
+				       &pool->free[bits],
+				       link)
+	{
+	    size_t buddy_offset = (block - pool->blocks) ^ (1 << bits);
+
+	    buddy = get_buddy (pool, buddy_offset, bits);
+	    if (buddy == NULL)
+		continue;
+
+	    if (buddy == next) {
+		next = cairo_container_of (buddy->link.next,
+					   struct _cairo_memblock,
+					   link);
+	    }
+
+	    cairo_list_del (&block->link);
+	    merge_buddies (pool, block, max_bits);
+	}
+    }
+
+    return pool->max_free_bits;
+}
+
+/* find store for 1 << bits blocks */
+static void *
+buddy_malloc (cairo_mempool_t *pool, int bits)
+{
+    size_t past, offset;
+    struct _cairo_memblock *block;
+    int b;
+
+    if (bits > pool->max_free_bits && bits > merge_bits (pool, bits))
+	return NULL;
+
+    /* Find a list with blocks big enough on it */
+    block = NULL;
+    for (b = bits; b <= pool->max_free_bits; b++) {
+	if (! cairo_list_is_empty (&pool->free[b])) {
+	    block = cairo_list_first_entry (&pool->free[b],
+					    struct _cairo_memblock,
+					    link);
+	    break;
+	}
+    }
+    assert (block != NULL);
+
+    cairo_list_del (&block->link);
+
+    while (cairo_list_is_empty (&pool->free[pool->max_free_bits])) {
+	if (--pool->max_free_bits == -1)
+	    break;
+    }
+
+    /* Mark end of allocated area */
+    offset = block - pool->blocks;
+    past = offset + (1 << bits);
+    BITSET (pool, past - 1);
+    block->bits = bits;
+
+    /* If we used a larger free block than we needed, free the rest */
+    pool->free_bytes -= 1 << (b + pool->min_bits);
+    free_blocks (pool, past, offset + (1 << b), 0);
+
+    return pool->base + ((block - pool->blocks) << pool->min_bits);
+}
+
+cairo_status_t
+_cairo_mempool_init (cairo_mempool_t *pool,
+		      void *base, size_t bytes,
+		      int min_bits, int num_sizes)
+{
+    int num_blocks;
+    int i;
+
+    assert ((((unsigned long) base) & ((1 << min_bits) - 1)) == 0);
+    assert (num_sizes < ARRAY_LENGTH (pool->free));
+
+    pool->base = base;
+    pool->free_bytes = 0;
+    pool->max_bytes = bytes;
+    pool->max_free_bits = -1;
+
+    num_blocks = bytes >> min_bits;
+    pool->blocks = calloc (num_blocks, sizeof (struct _cairo_memblock));
+    if (pool->blocks == NULL)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    pool->num_blocks = num_blocks;
+    pool->min_bits = min_bits;
+    pool->num_sizes = num_sizes;
+
+    for (i = 0; i < ARRAY_LENGTH (pool->free); i++)
+	cairo_list_init (&pool->free[i]);
+
+    pool->map = malloc ((num_blocks + 7) >> 3);
+    if (pool->map == NULL) {
+	free (pool->blocks);
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    memset (pool->map, -1, (num_blocks + 7) >> 3);
+    clear_bits (pool, 0, num_blocks);
+
+    /* Now add all blocks to the free list */
+    free_blocks (pool, 0, num_blocks, 1);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+void *
+_cairo_mempool_alloc (cairo_mempool_t *pool, size_t bytes)
+{
+    size_t size;
+    int bits;
+
+    size = 1 << pool->min_bits;
+    for (bits = 0; size < bytes; bits++)
+	size <<= 1;
+    if (bits >= pool->num_sizes)
+	return NULL;
+
+    return buddy_malloc (pool, bits);
+}
+
+void
+_cairo_mempool_free (cairo_mempool_t *pool, void *storage)
+{
+    size_t block_offset;
+    struct _cairo_memblock *block;
+
+    block_offset = ((char *)storage - pool->base) >> pool->min_bits;
+    block = pool->blocks + block_offset;
+
+    BITCLEAR (pool, block_offset + ((1 << block->bits) - 1));
+    pool->free_bytes += 1 << (block->bits + pool->min_bits);
+
+    merge_buddies (pool, block, pool->num_sizes);
+}
+
+void
+_cairo_mempool_fini (cairo_mempool_t *pool)
+{
+    free (pool->map);
+    free (pool->blocks);
+}
diff --git a/src/cairo-quartz-image-surface.c b/src/cairo-quartz-image-surface.c
index d3bd940..2715abd 100644
--- a/src/cairo-quartz-image-surface.c
+++ b/src/cairo-quartz-image-surface.c
@@ -141,12 +141,16 @@ _cairo_quartz_image_surface_get_extents (void *asurface,
  */
 
 static cairo_status_t
-_cairo_quartz_image_surface_flush (void *asurface)
+_cairo_quartz_image_surface_flush (void *asurface,
+				   unsigned flags)
 {
     cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface;
     CGImageRef oldImage = surface->image;
     CGImageRef newImage = NULL;
 
+    if (flags)
+	return CAIRO_STATUS_SUCCESS;
+
     /* XXX only flush if the image has been modified. */
 
     /* To be released by the ReleaseCallback */
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index 8c2b645..e7eb4cc 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -213,7 +213,7 @@ _cairo_scaled_glyph_fini (cairo_scaled_font_t *scaled_font,
     }
 
     _cairo_image_scaled_glyph_fini (scaled_font, scaled_glyph);
-    
+
     if (scaled_glyph->surface != NULL)
 	cairo_surface_destroy (&scaled_glyph->surface->base);
 
diff --git a/src/cairo-surface-backend-private.h b/src/cairo-surface-backend-private.h
index c275ce6..955a79f 100644
--- a/src/cairo-surface-backend-private.h
+++ b/src/cairo-surface-backend-private.h
@@ -110,7 +110,8 @@ struct _cairo_surface_backend {
 				 cairo_font_options_t  *options);
 
     cairo_warn cairo_status_t
-    (*flush)                    (void                  *surface);
+    (*flush)                    (void                  *surface,
+				 unsigned               flags);
 
     cairo_warn cairo_status_t
     (*mark_dirty_rectangle)     (void                  *surface,
diff --git a/src/cairo-surface-inline.h b/src/cairo-surface-inline.h
index 27ea8f0..85fbc91 100644
--- a/src/cairo-surface-inline.h
+++ b/src/cairo-surface-inline.h
@@ -41,11 +41,11 @@
 #include "cairo-surface-private.h"
 
 static inline cairo_status_t
-_cairo_surface_flush (cairo_surface_t *surface)
+__cairo_surface_flush (cairo_surface_t *surface, unsigned flags)
 {
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
     if (surface->backend->flush)
-	status = surface->backend->flush (surface);
+	status = surface->backend->flush (surface, flags);
     return status;
 }
 
diff --git a/src/cairo-surface-observer.c b/src/cairo-surface-observer.c
index 83fd1f8..64036b6 100644
--- a/src/cairo-surface-observer.c
+++ b/src/cairo-surface-observer.c
@@ -1202,14 +1202,12 @@ _cairo_surface_observer_glyphs (void			*abstract_surface,
 }
 
 static cairo_status_t
-_cairo_surface_observer_flush (void *abstract_surface)
+_cairo_surface_observer_flush (void *abstract_surface, unsigned flags)
 {
     cairo_surface_observer_t *surface = abstract_surface;
 
     do_callbacks (surface, &surface->flush_callbacks);
-
-    cairo_surface_flush (surface->target);
-    return surface->target->status;
+    return _cairo_surface_flush (surface->target, flags);
 }
 
 static cairo_status_t
diff --git a/src/cairo-surface-private.h b/src/cairo-surface-private.h
index 63202fb..f20ab07 100644
--- a/src/cairo-surface-private.h
+++ b/src/cairo-surface-private.h
@@ -115,4 +115,7 @@ cairo_private cairo_surface_t *
 _cairo_surface_get_source (cairo_surface_t *surface,
 			   cairo_rectangle_int_t *extents);
 
+cairo_private cairo_status_t
+_cairo_surface_flush (cairo_surface_t *surface, unsigned flags);
+
 #endif /* CAIRO_SURFACE_PRIVATE_H */
diff --git a/src/cairo-surface-snapshot.c b/src/cairo-surface-snapshot.c
index 9471e47..68bf905 100644
--- a/src/cairo-surface-snapshot.c
+++ b/src/cairo-surface-snapshot.c
@@ -64,15 +64,14 @@ _cairo_surface_snapshot_finish (void *abstract_surface)
 }
 
 static cairo_status_t
-_cairo_surface_snapshot_flush (void *abstract_surface)
+_cairo_surface_snapshot_flush (void *abstract_surface, unsigned flags)
 {
     cairo_surface_snapshot_t *surface = abstract_surface;
     cairo_surface_t *target;
     cairo_status_t status;
 
     target = _cairo_surface_snapshot_get_target (&surface->base);
-    cairo_surface_flush (target);
-    status = target->status;
+    status = _cairo_surface_flush (target, flags);
     cairo_surface_destroy (target);
 
     return status;
diff --git a/src/cairo-surface-subsurface.c b/src/cairo-surface-subsurface.c
index 7ceef11..051e95f 100644
--- a/src/cairo-surface-subsurface.c
+++ b/src/cairo-surface-subsurface.c
@@ -222,12 +222,10 @@ _cairo_surface_subsurface_glyphs (void			*abstract_surface,
 }
 
 static cairo_status_t
-_cairo_surface_subsurface_flush (void *abstract_surface)
+_cairo_surface_subsurface_flush (void *abstract_surface, unsigned flags)
 {
     cairo_surface_subsurface_t *surface = abstract_surface;
-
-    cairo_surface_flush (surface->target);
-    return surface->target->status;
+    return _cairo_surface_flush (surface->target, flags);
 }
 
 static cairo_status_t
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 6ab2140..dcce41e 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -48,6 +48,7 @@
 #include "cairo-image-surface-inline.h"
 #include "cairo-recording-surface-private.h"
 #include "cairo-region-private.h"
+#include "cairo-surface-inline.h"
 #include "cairo-tee-surface-private.h"
 
 /**
@@ -386,17 +387,13 @@ _cairo_surface_has_snapshot (cairo_surface_t *surface,
     return NULL;
 }
 
-void
+cairo_status_t
 _cairo_surface_begin_modification (cairo_surface_t *surface)
 {
     assert (surface->status == CAIRO_STATUS_SUCCESS);
     assert (! surface->finished);
 
-    _cairo_surface_detach_snapshots (surface);
-    if (surface->snapshot_of != NULL)
-	_cairo_surface_detach_snapshot (surface);
-
-    _cairo_surface_detach_mime_data (surface);
+    return _cairo_surface_flush (surface, 1);
 }
 
 void
@@ -416,6 +413,7 @@ _cairo_surface_init (cairo_surface_t			*surface,
     surface->status = CAIRO_STATUS_SUCCESS;
     surface->unique_id = _cairo_surface_allocate_unique_id ();
     surface->finished = FALSE;
+    surface->_finishing = FALSE;
     surface->is_clear = FALSE;
     surface->serial = 0;
     surface->damage = NULL;
@@ -989,14 +987,12 @@ cairo_surface_get_reference_count (cairo_surface_t *surface)
 static void
 _cairo_surface_finish_snapshots (cairo_surface_t *surface)
 {
-    cairo_surface_flush (surface);
+    cairo_status_t status;
 
     /* update the snapshots *before* we declare the surface as finished */
     surface->_finishing = TRUE;
-
-    _cairo_surface_detach_snapshots (surface);
-    if (surface->snapshot_of != NULL)
-	_cairo_surface_detach_snapshot (surface);
+    status = _cairo_surface_flush (surface, 0);
+    (void) status;
 }
 
 static void
@@ -1459,6 +1455,18 @@ cairo_surface_get_font_options (cairo_surface_t       *surface,
 }
 slim_hidden_def (cairo_surface_get_font_options);
 
+cairo_status_t
+_cairo_surface_flush (cairo_surface_t *surface, unsigned flags)
+{
+    /* update the current snapshots *before* the user updates the surface */
+    _cairo_surface_detach_snapshots (surface);
+    if (surface->snapshot_of != NULL)
+	_cairo_surface_detach_snapshot (surface);
+    _cairo_surface_detach_mime_data (surface);
+
+    return __cairo_surface_flush (surface, flags);
+}
+
 /**
  * cairo_surface_flush:
  * @surface: a #cairo_surface_t
@@ -1483,15 +1491,9 @@ cairo_surface_flush (cairo_surface_t *surface)
     if (surface->finished)
 	return;
 
-    /* update the current snapshots *before* the user updates the surface */
-    _cairo_surface_detach_snapshots (surface);
-    _cairo_surface_detach_mime_data (surface);
-
-    if (surface->backend->flush) {
-	status = surface->backend->flush (surface);
-	if (unlikely (status))
-	    _cairo_surface_set_error (surface, status);
-    }
+    status = _cairo_surface_flush (surface, 0);
+    if (unlikely (status))
+	_cairo_surface_set_error (surface, status);
 }
 slim_hidden_def (cairo_surface_flush);
 
@@ -1508,7 +1510,12 @@ slim_hidden_def (cairo_surface_flush);
 void
 cairo_surface_mark_dirty (cairo_surface_t *surface)
 {
-    cairo_surface_mark_dirty_rectangle (surface, 0, 0, -1, -1);
+    cairo_rectangle_int_t extents;
+
+    _cairo_surface_get_extents (surface, &extents);
+    cairo_surface_mark_dirty_rectangle (surface,
+					extents.x, extents.y,
+					extents.width, extents.height);
 }
 slim_hidden_def (cairo_surface_mark_dirty);
 
@@ -1620,7 +1627,11 @@ _cairo_surface_set_device_scale (cairo_surface_t *surface,
 	return;
     }
 
-    _cairo_surface_begin_modification (surface);
+    status = _cairo_surface_begin_modification (surface);
+    if (unlikely (status)) {
+	_cairo_surface_set_error (surface, status);
+	return;
+    }
 
     surface->device_transform.xx = sx;
     surface->device_transform.yy = sy;
@@ -1672,7 +1683,11 @@ cairo_surface_set_device_offset (cairo_surface_t *surface,
 	return;
     }
 
-    _cairo_surface_begin_modification (surface);
+    status = _cairo_surface_begin_modification (surface);
+    if (unlikely (status)) {
+	_cairo_surface_set_error (surface, status);
+	return;
+    }
 
     surface->device_transform.x0 = x_offset;
     surface->device_transform.y0 = y_offset;
@@ -1747,6 +1762,8 @@ cairo_surface_set_fallback_resolution (cairo_surface_t	*surface,
 				       double		 x_pixels_per_inch,
 				       double		 y_pixels_per_inch)
 {
+    cairo_status_t status;
+
     if (unlikely (surface->status))
 	return;
 
@@ -1765,7 +1782,11 @@ cairo_surface_set_fallback_resolution (cairo_surface_t	*surface,
 	return;
     }
 
-    _cairo_surface_begin_modification (surface);
+    status = _cairo_surface_begin_modification (surface);
+    if (unlikely (status)) {
+	_cairo_surface_set_error (surface, status);
+	return;
+    }
 
     surface->x_fallback_resolution = x_pixels_per_inch;
     surface->y_fallback_resolution = y_pixels_per_inch;
@@ -1971,7 +1992,9 @@ _cairo_surface_paint (cairo_surface_t		*surface,
     if (nothing_to_do (surface, op, source))
 	return CAIRO_STATUS_SUCCESS;
 
-    _cairo_surface_begin_modification (surface);
+    status = _cairo_surface_begin_modification (surface);
+    if (unlikely (status))
+	return status;
 
     status = surface->backend->paint (surface, op, source, clip);
     if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
@@ -2016,7 +2039,9 @@ _cairo_surface_mask (cairo_surface_t		*surface,
     if (nothing_to_do (surface, op, source))
 	return CAIRO_STATUS_SUCCESS;
 
-    _cairo_surface_begin_modification (surface);
+    status = _cairo_surface_begin_modification (surface);
+    if (unlikely (status))
+	return status;
 
     status = surface->backend->mask (surface, op, source, mask, clip);
     if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) {
@@ -2068,7 +2093,9 @@ _cairo_surface_fill_stroke (cairo_surface_t	    *surface,
     if (unlikely (status))
 	return status;
 
-    _cairo_surface_begin_modification (surface);
+    status = _cairo_surface_begin_modification (surface);
+    if (unlikely (status))
+	return status;
 
     if (surface->backend->fill_stroke) {
 	cairo_matrix_t dev_ctm = *stroke_ctm;
@@ -2138,7 +2165,9 @@ _cairo_surface_stroke (cairo_surface_t			*surface,
     if (nothing_to_do (surface, op, source))
 	return CAIRO_STATUS_SUCCESS;
 
-    _cairo_surface_begin_modification (surface);
+    status = _cairo_surface_begin_modification (surface);
+    if (unlikely (status))
+	return status;
 
     status = surface->backend->stroke (surface, op, source,
 				       path, stroke_style,
@@ -2179,7 +2208,9 @@ _cairo_surface_fill (cairo_surface_t		*surface,
     if (nothing_to_do (surface, op, source))
 	return CAIRO_STATUS_SUCCESS;
 
-    _cairo_surface_begin_modification (surface);
+    status = _cairo_surface_begin_modification (surface);
+    if (unlikely (status))
+	return status;
 
     status = surface->backend->fill (surface, op, source,
 				     path, fill_rule,
@@ -2243,6 +2274,8 @@ slim_hidden_def (cairo_surface_copy_page);
 void
 cairo_surface_show_page (cairo_surface_t *surface)
 {
+    cairo_status_t status;
+
     if (unlikely (surface->status))
 	return;
 
@@ -2251,7 +2284,11 @@ cairo_surface_show_page (cairo_surface_t *surface)
 	return;
     }
 
-    _cairo_surface_begin_modification (surface);
+    status = _cairo_surface_begin_modification (surface);
+    if (unlikely (status)) {
+	_cairo_surface_set_error (surface, status);
+	return;
+    }
 
     /* It's fine if some backends don't implement show_page */
     if (surface->backend->show_page == NULL)
@@ -2389,7 +2426,9 @@ _cairo_surface_show_text_glyphs (cairo_surface_t	    *surface,
     if (nothing_to_do (surface, op, source))
 	return CAIRO_STATUS_SUCCESS;
 
-    _cairo_surface_begin_modification (surface);
+    status = _cairo_surface_begin_modification (surface);
+    if (unlikely (status))
+	return status;
 
     if (_cairo_surface_has_device_transform (surface) &&
 	! _cairo_matrix_is_integer_translation (&surface->device_transform, NULL, NULL))
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 1a591ca..bdd6217 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -714,11 +714,15 @@ _put_image_boxes (cairo_xcb_surface_t    *surface,
 }
 
 static cairo_status_t
-_cairo_xcb_surface_flush (void *abstract_surface)
+_cairo_xcb_surface_flush (void *abstract_surface,
+			  unsigned flags)
 {
     cairo_xcb_surface_t *surface = abstract_surface;
     cairo_status_t status;
 
+    if (flags)
+	return CAIRO_STATUS_SUCCESS;
+
     if (likely (surface->fallback == NULL)) {
 	status = CAIRO_STATUS_SUCCESS;
 	if (! surface->base.finished && surface->deferred_clear)
diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c
index 06242ff..bfe6168 100644
--- a/src/cairo-xlib-display.c
+++ b/src/cairo-xlib-display.c
@@ -95,6 +95,8 @@ _cairo_xlib_display_destroy (void *abstract_display)
 {
     cairo_xlib_display_t *display = abstract_display;
 
+    _cairo_xlib_display_fini_shm (display);
+
     free (display);
 }
 
@@ -147,15 +149,18 @@ static const cairo_device_backend_t _cairo_xlib_device_backend = {
     _cairo_xlib_display_destroy,
 };
 
-
 static void _cairo_xlib_display_select_compositor (cairo_xlib_display_t *display)
 {
+#if 1
     if (display->render_major > 0 || display->render_minor >= 4)
 	display->compositor = _cairo_xlib_traps_compositor_get ();
     else if (display->render_major > 0 || display->render_minor >= 0)
 	display->compositor = _cairo_xlib_mask_compositor_get ();
     else
 	display->compositor = _cairo_xlib_core_compositor_get ();
+#else
+    display->compositor = _cairo_xlib_fallback_compositor_get ();
+#endif
 }
 
 /**
@@ -263,6 +268,8 @@ _cairo_xlib_device_create (Display *dpy)
 
     display->force_precision = -1;
 
+    _cairo_xlib_display_init_shm (display);
+
     /* Prior to Render 0.10, there is no protocol support for gradients and
      * we call function stubs instead, which would silently consume the drawing.
      */
diff --git a/src/cairo-xlib-fallback-compositor.c b/src/cairo-xlib-fallback-compositor.c
index 7d45cd1..d573276 100644
--- a/src/cairo-xlib-fallback-compositor.c
+++ b/src/cairo-xlib-fallback-compositor.c
@@ -47,12 +47,198 @@
 #include "cairo-xlib-private.h"
 
 #include "cairo-compositor-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-surface-offset-private.h"
+
+static const cairo_compositor_t *
+_get_compositor (cairo_surface_t *surface)
+{
+    return ((cairo_image_surface_t *)surface)->compositor;
+}
+
+static cairo_bool_t
+unclipped (cairo_xlib_surface_t *xlib, cairo_clip_t *clip)
+{
+    cairo_rectangle_int_t r;
+
+    r.x = r.y = 0;
+    r.width = xlib->width;
+    r.height = xlib->height;
+    return _cairo_clip_contains_rectangle (clip, &r);
+}
+
+static cairo_int_status_t
+_cairo_xlib_shm_compositor_paint (const cairo_compositor_t	*_compositor,
+				  cairo_composite_rectangles_t	*extents)
+{
+    cairo_xlib_surface_t *xlib = (cairo_xlib_surface_t *)extents->surface;
+    cairo_int_status_t status;
+    cairo_surface_t *shm;
+
+    TRACE ((stderr, "%s\n", __FUNCTION__));
+
+    shm = _cairo_xlib_surface_get_shm (xlib);
+    if (shm == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    status = _cairo_compositor_paint (_get_compositor (shm), shm,
+				      extents->op,
+				      &extents->source_pattern.base,
+				      extents->clip);
+    if (unlikely (status))
+	return status;
+
+    xlib->base.is_clear =
+	extents->op == CAIRO_OPERATOR_CLEAR && unclipped (xlib, extents->clip);
+    xlib->base.serial++;
+    xlib->fallback++;
+    return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static cairo_int_status_t
+_cairo_xlib_shm_compositor_mask (const cairo_compositor_t	*_compositor,
+				 cairo_composite_rectangles_t	*extents)
+{
+    cairo_xlib_surface_t *xlib = (cairo_xlib_surface_t *)extents->surface;
+    cairo_int_status_t status;
+    cairo_surface_t *shm;
+
+    TRACE ((stderr, "%s\n", __FUNCTION__));
+
+    shm = _cairo_xlib_surface_get_shm (xlib);
+    if (shm == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    status = _cairo_compositor_mask (_get_compositor (shm), shm,
+				     extents->op,
+				     &extents->source_pattern.base,
+				     &extents->mask_pattern.base,
+				     extents->clip);
+    if (unlikely (status))
+	return status;
+
+    xlib->base.is_clear = FALSE;
+    xlib->base.serial++;
+    xlib->fallback++;
+    return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static cairo_int_status_t
+_cairo_xlib_shm_compositor_stroke (const cairo_compositor_t	*_compositor,
+				   cairo_composite_rectangles_t *extents,
+				   const cairo_path_fixed_t	*path,
+				   const cairo_stroke_style_t	*style,
+				   const cairo_matrix_t		*ctm,
+				   const cairo_matrix_t		*ctm_inverse,
+				   double			 tolerance,
+				   cairo_antialias_t		 antialias)
+{
+    cairo_xlib_surface_t *xlib = (cairo_xlib_surface_t *)extents->surface;
+    cairo_int_status_t status;
+    cairo_surface_t *shm;
+
+    TRACE ((stderr, "%s\n", __FUNCTION__));
+
+    shm = _cairo_xlib_surface_get_shm (xlib);
+    if (shm == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    status = _cairo_compositor_stroke (_get_compositor (shm), shm,
+				       extents->op,
+				       &extents->source_pattern.base,
+				       path, style,
+				       ctm, ctm_inverse,
+				       tolerance,
+				       antialias,
+				       extents->clip);
+    if (unlikely (status))
+	return status;
+
+    xlib->base.is_clear = FALSE;
+    xlib->base.serial++;
+    xlib->fallback++;
+    return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static cairo_int_status_t
+_cairo_xlib_shm_compositor_fill (const cairo_compositor_t	*_compositor,
+				 cairo_composite_rectangles_t *extents,
+				 const cairo_path_fixed_t	*path,
+				 cairo_fill_rule_t		 fill_rule,
+				 double				 tolerance,
+				 cairo_antialias_t		 antialias)
+{
+    cairo_xlib_surface_t *xlib = (cairo_xlib_surface_t *)extents->surface;
+    cairo_int_status_t status;
+    cairo_surface_t *shm;
+
+    TRACE ((stderr, "%s\n", __FUNCTION__));
+
+    shm = _cairo_xlib_surface_get_shm (xlib);
+    if (shm == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    status = _cairo_compositor_fill (_get_compositor (shm), shm,
+				     extents->op,
+				     &extents->source_pattern.base,
+				     path,
+				     fill_rule, tolerance, antialias,
+				     extents->clip);
+    if (unlikely (status))
+	return status;
+
+    xlib->base.is_clear = FALSE;
+    xlib->base.serial++;
+    xlib->fallback++;
+    return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static cairo_int_status_t
+_cairo_xlib_shm_compositor_glyphs (const cairo_compositor_t	*_compositor,
+				   cairo_composite_rectangles_t *extents,
+				   cairo_scaled_font_t		*scaled_font,
+				   cairo_glyph_t		*glyphs,
+				   int				 num_glyphs,
+				   cairo_bool_t			 overlap)
+{
+    cairo_xlib_surface_t *xlib = (cairo_xlib_surface_t *)extents->surface;
+    cairo_int_status_t status;
+    cairo_surface_t *shm;
+
+    TRACE ((stderr, "%s\n", __FUNCTION__));
+
+    shm = _cairo_xlib_surface_get_shm (xlib);
+    if (shm == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    status = _cairo_compositor_glyphs (_get_compositor (shm), shm,
+				       extents->op,
+				       &extents->source_pattern.base,
+				       glyphs, num_glyphs, scaled_font,
+				       extents->clip);
+    if (unlikely (status))
+	return status;
+
+    xlib->base.is_clear = FALSE;
+    xlib->base.serial++;
+    xlib->fallback++;
+    return CAIRO_INT_STATUS_NOTHING_TO_DO;
+}
+
+static const cairo_compositor_t _cairo_xlib_shm_compositor = {
+     &_cairo_fallback_compositor,
+
+     _cairo_xlib_shm_compositor_paint,
+     _cairo_xlib_shm_compositor_mask,
+     _cairo_xlib_shm_compositor_stroke,
+     _cairo_xlib_shm_compositor_fill,
+     _cairo_xlib_shm_compositor_glyphs,
+};
 
 const cairo_compositor_t *
 _cairo_xlib_fallback_compositor_get (void)
 {
-    /* XXX Do something interesting here to mitigate fallbacks ala xcb */
-    return &_cairo_fallback_compositor;
+    return &_cairo_xlib_shm_compositor;
 }
 
 #endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */
diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h
index 4522832..8e9c044 100644
--- a/src/cairo-xlib-private.h
+++ b/src/cairo-xlib-private.h
@@ -52,8 +52,10 @@
 #include <pixman.h>
 
 typedef struct _cairo_xlib_display cairo_xlib_display_t;
+typedef struct _cairo_xlib_shm_display cairo_xlib_shm_display_t;
 typedef struct _cairo_xlib_screen cairo_xlib_screen_t;
 typedef struct _cairo_xlib_source cairo_xlib_source_t;
+typedef struct _cairo_xlib_proxy cairo_xlib_proxy_t;
 typedef struct _cairo_xlib_surface cairo_xlib_surface_t;
 
 /* size of color cube */
@@ -72,6 +74,8 @@ struct _cairo_xlib_display {
     cairo_list_t screens;
     cairo_list_t fonts;
 
+    cairo_xlib_shm_display_t *shm;
+
     const cairo_compositor_t *compositor;
 
     int render_major;
@@ -168,6 +172,8 @@ struct _cairo_xlib_surface {
     Picture picture;
 
     const cairo_compositor_t *compositor;
+    cairo_surface_t *shm;
+    int fallback;
 
     cairo_xlib_display_t *display;
     cairo_xlib_screen_t *screen;
@@ -205,6 +211,11 @@ struct _cairo_xlib_surface {
     } embedded_source;
 };
 
+struct _cairo_xlib_proxy {
+    struct _cairo_xlib_source source;
+    cairo_surface_t *owner;
+};
+
 cairo_private cairo_status_t
 _cairo_xlib_surface_get_gc (cairo_xlib_display_t *display,
                             cairo_xlib_surface_t *surface,
@@ -213,6 +224,12 @@ _cairo_xlib_surface_get_gc (cairo_xlib_display_t *display,
 cairo_private cairo_device_t *
 _cairo_xlib_device_create (Display *display);
 
+cairo_private void
+_cairo_xlib_display_init_shm (cairo_xlib_display_t *display);
+
+cairo_private void
+_cairo_xlib_display_fini_shm (cairo_xlib_display_t *display);
+
 cairo_private cairo_xlib_screen_t *
 _cairo_xlib_display_get_screen (cairo_xlib_display_t *display,
 				Screen *screen);
@@ -381,4 +398,46 @@ _cairo_xlib_surface_put_gc (cairo_xlib_display_t *display,
 			       gc);
 }
 
+cairo_private cairo_surface_t *
+_cairo_xlib_surface_create_similar_shm (void *surface,
+					cairo_format_t format,
+					int width, int height);
+
+cairo_private cairo_surface_t *
+_cairo_xlib_surface_get_shm (cairo_xlib_surface_t *surface);
+
+cairo_private cairo_int_status_t
+_cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface);
+
+cairo_private cairo_surface_t *
+_cairo_xlib_surface_create_shm_image (cairo_xlib_surface_t *surface,
+				      pixman_format_code_t format,
+				      int width, int height);
+
+cairo_private void
+_cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface,
+				    XImage *ximage);
+
+cairo_private void *
+_cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface);
+
+cairo_private cairo_bool_t
+_cairo_xlib_shm_surface_is_active (cairo_surface_t *surface);
+
+cairo_private cairo_bool_t
+_cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface);
+
+cairo_private Pixmap
+_cairo_xlib_shm_surface_get_pixmap (cairo_surface_t *surface);
+
+cairo_private void
+_cairo_xlib_shm_surface_mark_active (cairo_surface_t *surface);
+
+cairo_private XRenderPictFormat *
+_cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface);
+
+cairo_private pixman_format_code_t
+_pixman_format_for_xlib_surface (cairo_xlib_surface_t *surface);
+
+
 #endif /* CAIRO_XLIB_PRIVATE_H */
diff --git a/src/cairo-xlib-render-compositor.c b/src/cairo-xlib-render-compositor.c
index a892985..f76db24 100644
--- a/src/cairo-xlib-render-compositor.c
+++ b/src/cairo-xlib-render-compositor.c
@@ -47,6 +47,7 @@
 #include "cairo-xlib-private.h"
 
 #include "cairo-compositor-private.h"
+#include "cairo-damage-private.h"
 #include "cairo-image-surface-private.h"
 #include "cairo-list-inline.h"
 #include "cairo-pattern-private.h"
@@ -125,14 +126,140 @@ set_clip_region (void *_surface,
 }
 
 static cairo_int_status_t
+copy_image_boxes (void *_dst,
+		  cairo_image_surface_t *image,
+		  cairo_boxes_t *boxes,
+		  int dx, int dy)
+{
+    cairo_xlib_surface_t *dst = _dst;
+    struct _cairo_boxes_chunk *chunk;
+    cairo_int_status_t status;
+    Pixmap src;
+    GC gc;
+    int i, j;
+
+    status = acquire (dst);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_xlib_surface_get_gc (dst->display, dst, &gc);
+    if (unlikely (status)) {
+	release (dst);
+	return status;
+    }
+
+    src = _cairo_xlib_shm_surface_get_pixmap (&image->base);
+    if (boxes->num_boxes == 1) {
+	int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x);
+	int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y);
+	int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
+	int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
+
+	XCopyArea (dst->dpy, src, dst->drawable, gc,
+		   x1 + dx, y1 + dy,
+		   x2 - x1, y2 - y1,
+		   x1,      y1);
+    } else {
+	XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)];
+	XRectangle *rects = stack_rects;
+
+	if (boxes->num_boxes > ARRAY_LENGTH (stack_rects)) {
+	    rects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle));
+	    if (unlikely (rects == NULL))
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	}
+
+	j = 0;
+	for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+	    for (i = 0; i < chunk->count; i++) {
+		int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x);
+		int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
+		int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
+		int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
+
+		rects[j].x = x1;
+		rects[j].y = y1;
+		rects[j].width  = x2 - x1;
+		rects[j].height = y2 - y1;
+		j++;
+	    }
+	}
+	assert (j == boxes->num_boxes);
+
+	XSetClipRectangles (dst->dpy, gc, 0, 0, rects, j, Unsorted);
+
+	XCopyArea (dst->dpy, src, dst->drawable, gc,
+		   dx, dy,
+		   image->width,  image->height,
+		   0,      0);
+
+	XSetClipMask (dst->dpy, gc, None);
+
+	if (rects != stack_rects)
+	    free (rects);
+    }
+
+    _cairo_xlib_shm_surface_mark_active (&image->base);
+    _cairo_xlib_surface_put_gc (dst->display, dst, gc);
+    release (dst);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
 draw_image_boxes (void *_dst,
 		  cairo_image_surface_t *image,
 		  cairo_boxes_t *boxes,
 		  int dx, int dy)
 {
+    cairo_xlib_surface_t *dst = _dst;
     struct _cairo_boxes_chunk *chunk;
+    cairo_image_surface_t *shm;
     int i;
 
+    if (image->base.device == dst->base.device &&
+	_cairo_xlib_shm_surface_get_pixmap (&image->base))
+	    return copy_image_boxes (dst, image, boxes, dx, dy);
+
+    shm = (cairo_image_surface_t *) _cairo_xlib_surface_get_shm (dst);
+    if (shm) {
+	for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
+	    for (i = 0; i < chunk->count; i++) {
+		cairo_box_t *b = &chunk->base[i];
+		cairo_rectangle_int_t r;
+
+		r.x = _cairo_fixed_integer_part (b->p1.x);
+		r.y = _cairo_fixed_integer_part (b->p1.y);
+		r.width = _cairo_fixed_integer_part (b->p2.x) - r.x;
+		r.height = _cairo_fixed_integer_part (b->p2.y) - r.y;
+
+		if (shm->pixman_format != image->pixman_format ||
+		    ! pixman_blt ((uint32_t *)image->data, (uint32_t *)shm->data,
+				  image->stride / sizeof (uint32_t),
+				  shm->stride / sizeof (uint32_t),
+				  PIXMAN_FORMAT_BPP (image->pixman_format),
+				  PIXMAN_FORMAT_BPP (shm->pixman_format),
+				  r.x + dx, r.y + dy,
+				  r.x, r.y,
+				  r.width, r.height))
+		{
+		    pixman_image_composite32 (PIXMAN_OP_SRC,
+					      image->pixman_image, NULL, shm->pixman_image,
+					      r.x + dx, r.y + dy,
+					      0, 0,
+					      r.x, r.y,
+					      r.width, r.height);
+		}
+
+		shm->base.damage =
+		    _cairo_damage_add_rectangle (shm->base.damage, &r);
+	    }
+	}
+	dst->base.is_clear = FALSE;
+	dst->fallback++;
+	dst->base.serial++;
+	return CAIRO_INT_STATUS_NOTHING_TO_DO;
+    }
+
     for (chunk = &boxes->chunks; chunk; chunk = chunk->next) {
 	for (i = 0; i < chunk->count; i++) {
 	    cairo_box_t *b = &chunk->base[i];
@@ -140,7 +267,7 @@ draw_image_boxes (void *_dst,
 	    int y1 = _cairo_fixed_integer_part (b->p1.y);
 	    int x2 = _cairo_fixed_integer_part (b->p2.x);
 	    int y2 = _cairo_fixed_integer_part (b->p2.y);
-	    if ( _cairo_xlib_surface_draw_image (_dst, image,
+	    if ( _cairo_xlib_surface_draw_image (dst, image,
 						 x1 + dx, y1 + dy,
 						 x2 - x1, y2 - y1,
 						 x1, y1))
@@ -163,6 +290,7 @@ copy_boxes (void *_dst,
     struct _cairo_boxes_chunk *chunk;
     cairo_int_status_t status;
     GC gc;
+    Drawable d;
     int i, j;
 
     if (! _cairo_xlib_surface_same_screen  (dst, src))
@@ -181,11 +309,18 @@ copy_boxes (void *_dst,
 	return status;
     }
 
-    if (! src->owns_pixmap) {
-	XGCValues gcv;
+    if (src->fallback && src->shm->damage->dirty) {
+	assert (src != dst);
+	d = _cairo_xlib_shm_surface_get_pixmap (src->shm);
+	assert (d != 0);
+    } else {
+	if (! src->owns_pixmap) {
+	    XGCValues gcv;
 
-	gcv.subwindow_mode = IncludeInferiors;
-	XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
+	    gcv.subwindow_mode = IncludeInferiors;
+	    XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv);
+	}
+	d = src->drawable;
     }
 
     if (boxes->num_boxes == 1) {
@@ -194,7 +329,7 @@ copy_boxes (void *_dst,
 	int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x);
 	int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y);
 
-	XCopyArea (dst->dpy, src->drawable, dst->drawable, gc,
+	XCopyArea (dst->dpy, d, dst->drawable, gc,
 		   x1 + dx, y1 + dy,
 		   x2 - x1, y2 - y1,
 		   x1,      y1);
@@ -215,7 +350,7 @@ copy_boxes (void *_dst,
 		    int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y);
 		    int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x);
 		    int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y);
-		    XCopyArea (dst->dpy, src->drawable, dst->drawable, gc,
+		    XCopyArea (dst->dpy, d, dst->drawable, gc,
 			       x1 + dx, y1 + dy,
 			       x2 - x1, y2 - y1,
 			       x1,      y1);
@@ -250,7 +385,7 @@ copy_boxes (void *_dst,
 
 	    XSetClipRectangles (dst->dpy, gc, 0, 0, rects, j, Unsorted);
 
-	    XCopyArea (dst->dpy, src->drawable, dst->drawable, gc,
+	    XCopyArea (dst->dpy, d, dst->drawable, gc,
 		       extents->x + dx, extents->y + dy,
 		       extents->width,  extents->height,
 		       extents->x,      extents->y);
@@ -262,7 +397,9 @@ copy_boxes (void *_dst,
 	}
     }
 
-    if (! src->owns_pixmap) {
+    if (src->fallback && src->shm->damage->dirty) {
+	_cairo_xlib_shm_surface_mark_active (src->shm);
+    } else if (! src->owns_pixmap) {
 	XGCValues gcv;
 
 	gcv.subwindow_mode = ClipByChildren;
diff --git a/src/cairo-xlib-source.c b/src/cairo-xlib-source.c
index 09f824f..42fc46a 100644
--- a/src/cairo-xlib-source.c
+++ b/src/cairo-xlib-source.c
@@ -75,11 +75,28 @@ _cairo_xlib_source_finish (void *abstract_surface)
 }
 
 static const cairo_surface_backend_t cairo_xlib_source_backend = {
-    CAIRO_SURFACE_TYPE_IMAGE,
+    CAIRO_SURFACE_TYPE_XLIB,
     _cairo_xlib_source_finish,
     NULL, /* read-only wrapper */
 };
 
+static cairo_status_t
+_cairo_xlib_proxy_finish (void *abstract_surface)
+{
+    cairo_xlib_proxy_t *proxy = abstract_surface;
+
+    XRenderFreePicture (proxy->source.dpy, proxy->source.picture);
+    _cairo_xlib_shm_surface_mark_active (proxy->owner);
+    cairo_surface_destroy (proxy->owner);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t cairo_xlib_proxy_backend = {
+    CAIRO_SURFACE_TYPE_XLIB,
+    _cairo_xlib_proxy_finish,
+    NULL, /* read-only wrapper */
+};
+
 static cairo_surface_t *
 source (cairo_xlib_surface_t *dst, Picture picture)
 {
@@ -286,6 +303,12 @@ render_pattern (cairo_xlib_surface_t *dst,
 	return _cairo_surface_create_in_error (status);
     }
 
+    status = _cairo_xlib_surface_put_shm (src);
+    if (unlikely (status)) {
+	cairo_surface_destroy (&src->base);
+	return _cairo_surface_create_in_error (status);
+    }
+
     src->picture = XRenderCreatePicture (dpy,
 					 src->drawable, src->xrender_format,
 					 0, NULL);
@@ -295,7 +318,6 @@ render_pattern (cairo_xlib_surface_t *dst,
     return &src->base;
 }
 
-
 static cairo_surface_t *
 gradient_source (cairo_xlib_surface_t *dst,
 		 const cairo_gradient_pattern_t *gradient,
@@ -538,24 +560,15 @@ solid_source (cairo_xlib_surface_t *dst,
 	return transparent_source (dst, color);
 }
 
-static cairo_surface_t *
-embedded_source (cairo_xlib_surface_t *dst,
-		 const cairo_surface_pattern_t *pattern,
-		 cairo_xlib_surface_t *src,
-		 const cairo_rectangle_int_t *extents,
-		 int *src_x, int *src_y)
+static cairo_xlib_source_t *init_source (cairo_xlib_surface_t *dst,
+					 cairo_xlib_surface_t *src)
 {
-    cairo_xlib_source_t *source;
     Display *dpy = dst->display->display;
-    cairo_int_status_t status;
-    XTransform xtransform;
-    XRenderPictureAttributes pa;
-    unsigned mask = 0;
+    cairo_xlib_source_t *source = &src->embedded_source;
 
     /* As these are frequent and meant to be fast, we track pictures for
      * native surface and minimise update requests.
      */
-    source = &src->embedded_source;
     if (source->picture == None) {
 	XRenderPictureAttributes pa;
 
@@ -576,6 +589,22 @@ embedded_source (cairo_xlib_surface_t *dst,
 	source->extend = CAIRO_EXTEND_NONE;
     }
 
+    return (cairo_xlib_source_t *) cairo_surface_reference (&source->base);
+}
+
+static cairo_surface_t *
+embedded_source (cairo_xlib_surface_t *dst,
+		 const cairo_surface_pattern_t *pattern,
+		 const cairo_rectangle_int_t *extents,
+		 int *src_x, int *src_y,
+		 cairo_xlib_source_t *source)
+{
+    Display *dpy = dst->display->display;
+    cairo_int_status_t status;
+    XTransform xtransform;
+    XRenderPictureAttributes pa;
+    unsigned mask = 0;
+
     status = _cairo_matrix_to_pixman_matrix_offset (&pattern->base.matrix,
 						    pattern->base.filter,
 						    extents->x + extents->width / 2,
@@ -614,7 +643,7 @@ embedded_source (cairo_xlib_surface_t *dst,
     if (mask)
 	XRenderChangePicture (dpy, source->picture, mask, &pa);
 
-    return cairo_surface_reference (&source->base);
+    return &source->base;
 }
 
 static cairo_surface_t *
@@ -642,6 +671,9 @@ subsurface_source (cairo_xlib_surface_t *dst,
 	sample->y + sample->height <= sub->extents.height)
     {
 	src = (cairo_xlib_surface_t *) sub->target;
+	status = _cairo_surface_flush (&src->base, 0);
+	if (unlikely (status))
+	    return _cairo_surface_create_in_error (status);
 
 	if (pattern->base.filter == CAIRO_FILTER_NEAREST &&
 	    _cairo_matrix_is_translation (&pattern->base.matrix))
@@ -658,8 +690,8 @@ subsurface_source (cairo_xlib_surface_t *dst,
 	    local_pattern.base.matrix.x0 += sub->extents.x;
 	    local_pattern.base.matrix.y0 += sub->extents.y;
 	    local_pattern.base.extend = CAIRO_EXTEND_NONE;
-	    return embedded_source (dst, &local_pattern, src, extents,
-				    src_x, src_y);
+	    return embedded_source (dst, &local_pattern, extents,
+				    src_x, src_y, init_source (dst, src));
 	}
     }
 
@@ -750,7 +782,8 @@ native_source (cairo_xlib_surface_t *dst,
 	       const cairo_rectangle_int_t *sample,
 	       int *src_x, int *src_y)
 {
-    cairo_xlib_surface_t *src = (cairo_xlib_surface_t *) pattern->surface;
+    cairo_xlib_surface_t *src;
+    cairo_int_status_t status;
 
     if (_cairo_surface_is_subsurface (pattern->surface))
 	return subsurface_source (dst, pattern, is_mask,
@@ -758,6 +791,9 @@ native_source (cairo_xlib_surface_t *dst,
 				  src_x, src_y);
 
     src = unwrap_source (pattern);
+    status = _cairo_surface_flush (&src->base, 0);
+    if (unlikely (status))
+	return _cairo_surface_create_in_error (status);
 
     if (pattern->base.filter == CAIRO_FILTER_NEAREST &&
 	sample->x >= 0 && sample->y >= 0 &&
@@ -771,65 +807,10 @@ native_source (cairo_xlib_surface_t *dst,
 	return cairo_surface_reference (&src->base);
     }
 
-    return embedded_source (dst, pattern, src, extents, src_x, src_y);
+    return embedded_source (dst, pattern, extents, src_x, src_y,
+			    init_source (dst, src));
 }
 
-#if 0
-/* It is general quicker if we let the application choose which images
- * to cache for itself and only upload the fragments required for this
- * operation.
- */
-static cairo_surface_t *
-image_source (cairo_xlib_surface_t *dst,
-	      const cairo_surface_pattern_t *pattern,
-	      const cairo_rectangle_int_t *extents,
-	      int *src_x, int *src_y)
-{
-    cairo_image_surface_t *src = (cairo_image_surface_t *) pattern->surface;
-    cairo_xlib_surface_t *snapshot;
-    cairo_surface_pattern_t local_pattern;
-    cairo_status_t status;
-
-    snapshot = (cairo_xlib_surface_t *)
-	_cairo_surface_has_snapshot (&src->base, dst->base.backend);
-    if (snapshot == NULL || snapshot->screen != dst->screen) {
-	if (snapshot)
-	    _cairo_surface_detach_snapshot (&snapshot->base);
-
-	snapshot = (cairo_xlib_surface_t *)
-	    _cairo_surface_create_similar_scratch (&dst->base,
-						   src->base.content,
-						   src->width,
-						   src->height);
-	if (snapshot->base.type != CAIRO_SURFACE_TYPE_XLIB) {
-	    cairo_surface_destroy (&snapshot->base);
-	    return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
-	}
-
-	status = _cairo_xlib_surface_draw_image (snapshot, src,
-						 0, 0,
-						 src->width, src->height,
-						 0, 0);
-	if (unlikely (status)) {
-	    cairo_surface_destroy (&snapshot->base);
-	    return _cairo_surface_create_in_error (status);
-	}
-
-	_cairo_surface_attach_snapshot (&src->base,
-					&snapshot->base,
-					cairo_surface_finish);
-
-	/* reference remains held by the snapshot from image */
-	cairo_surface_destroy (&snapshot->base);
-    }
-
-    local_pattern = *pattern;
-    local_pattern.surface = &snapshot->base;
-
-    return native_source (dst, &local_pattern, extents, src_x, src_y);
-}
-#endif
-
 static cairo_surface_t *
 recording_pattern_get_surface (const cairo_pattern_t *pattern)
 {
@@ -912,13 +893,49 @@ surface_source (cairo_xlib_surface_t *dst,
 		const cairo_rectangle_int_t *sample,
 		int *src_x, int *src_y)
 {
-    cairo_xlib_surface_t *src;
-    cairo_image_surface_t *image;
+    cairo_surface_t *src;
+    cairo_xlib_surface_t *xsrc;
     cairo_surface_pattern_t local_pattern;
     cairo_status_t status;
     cairo_rectangle_int_t upload, limit, map_extents;
     cairo_matrix_t m;
 
+    src = pattern->surface;
+    if (src->type == CAIRO_SURFACE_TYPE_IMAGE &&
+	src->device == dst->base.device &&
+	_cairo_xlib_shm_surface_get_pixmap (src)) {
+	cairo_xlib_proxy_t *proxy;
+
+	cairo_surface_reference (src);
+
+prepare_shm_image:
+	proxy = malloc (sizeof(*proxy));
+	if (unlikely (proxy == NULL)) {
+	    cairo_surface_destroy (src);
+	    return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+	}
+
+	_cairo_surface_init (&proxy->source.base,
+			     &cairo_xlib_proxy_backend,
+			     dst->base.device,
+			     CAIRO_CONTENT_COLOR_ALPHA);
+
+	proxy->source.dpy = dst->display->display;
+	proxy->source.picture = XRenderCreatePicture (proxy->source.dpy,
+						      _cairo_xlib_shm_surface_get_pixmap (src),
+						      _cairo_xlib_shm_surface_get_xrender_format (src),
+						      0, NULL);
+
+	proxy->source.has_component_alpha = 0;
+	proxy->source.has_matrix = 0;
+	proxy->source.filter = CAIRO_FILTER_NEAREST;
+	proxy->source.extend = CAIRO_EXTEND_NONE;
+	proxy->owner = src;
+
+	return embedded_source (dst, pattern, extents, src_x, src_y,
+				&proxy->source);
+    }
+
     upload = *sample;
     if (_cairo_surface_get_extents (pattern->surface, &limit)) {
 	if (pattern->base.extend == CAIRO_EXTEND_NONE) {
@@ -935,15 +952,10 @@ surface_source (cairo_xlib_surface_t *dst,
 	}
     }
 
-    src = (cairo_xlib_surface_t *)
-	_cairo_surface_create_similar_scratch (&dst->base,
-					       pattern->surface->content,
-					       upload.width,
-					       upload.height);
-    if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) {
-	cairo_surface_destroy (&src->base);
-	return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
-    }
+    src = _cairo_xlib_surface_create_similar_shm (&dst->base,
+						  _cairo_format_from_content (pattern->surface->content),
+						  upload.width,
+						  upload.height);
 
     _cairo_pattern_init_for_surface (&local_pattern, pattern->surface);
     cairo_matrix_init_translate (&local_pattern.base.matrix,
@@ -952,20 +964,18 @@ surface_source (cairo_xlib_surface_t *dst,
     map_extents = upload;
     map_extents.x = map_extents.y = 0;
 
-    image = _cairo_surface_map_to_image (&src->base, &map_extents);
-    status = _cairo_surface_paint (&image->base,
+    status = _cairo_surface_paint (src,
 				   CAIRO_OPERATOR_SOURCE,
 				   &local_pattern.base,
 				   NULL);
-    status = _cairo_surface_unmap_image (&src->base, image);
     _cairo_pattern_fini (&local_pattern.base);
 
     if (unlikely (status)) {
-	cairo_surface_destroy (&src->base);
+	cairo_surface_destroy (src);
 	return _cairo_surface_create_in_error (status);
     }
 
-    local_pattern.base.matrix = pattern->base.matrix;
+    _cairo_pattern_init_static_copy (&local_pattern.base, &pattern->base);
     if (upload.x | upload.y) {
 	cairo_matrix_init_translate (&m, -upload.x, -upload.y);
 	cairo_matrix_multiply (&local_pattern.base.matrix,
@@ -974,21 +984,44 @@ surface_source (cairo_xlib_surface_t *dst,
     }
 
     *src_x = *src_y = 0;
-    _cairo_xlib_surface_ensure_picture (src);
-    if (! picture_set_properties (src->display,
-				  src->picture,
-				  &pattern->base,
+    if (src->device == dst->base.device &&
+	_cairo_xlib_shm_surface_get_pixmap (src)) {
+	    pattern = &local_pattern;
+	    goto prepare_shm_image;
+    }
+
+    xsrc = (cairo_xlib_surface_t *)
+	    _cairo_surface_create_similar_scratch (&dst->base,
+						   src->content,
+						   upload.width,
+						   upload.height);
+    if (xsrc->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+	cairo_surface_destroy (src);
+	cairo_surface_destroy (&xsrc->base);
+	return None;
+    }
+
+    status = _cairo_xlib_surface_draw_image (xsrc, (cairo_image_surface_t *)src,
+					     0, 0,
+					     upload.width, upload.height,
+					     0, 0);
+    cairo_surface_destroy (src);
+
+    _cairo_xlib_surface_ensure_picture (xsrc);
+    if (! picture_set_properties (xsrc->display,
+				  xsrc->picture,
+				  &local_pattern.base,
 				  &local_pattern.base.matrix,
 				  extents,
 				  src_x, src_y))
     {
-	cairo_surface_destroy (&src->base);
+	cairo_surface_destroy (&xsrc->base);
 	return render_pattern (dst, &pattern->base,
 			       is_mask, extents,
 			       src_x, src_y);
     }
 
-    return &src->base;
+    return &xsrc->base;
 }
 
 static cairo_bool_t
@@ -1052,10 +1085,6 @@ _cairo_xlib_source_create_for_pattern (cairo_surface_t *_dst,
 		return record_source (dst, spattern, is_mask,
 				      extents, sample,
 				      src_x, src_y);
-#if 0
-	    if (spattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE)
-		return image_source (dst, spattern, extents, src_x, src_y);
-#endif
 
 	    return surface_source (dst, spattern, is_mask,
 				   extents, sample,
diff --git a/src/cairo-xlib-surface-shm.c b/src/cairo-xlib-surface-shm.c
new file mode 100644
index 0000000..37423d5
--- /dev/null
+++ b/src/cairo-xlib-surface-shm.c
@@ -0,0 +1,1119 @@
+/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2012 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#if !CAIRO_HAS_XLIB_XCB_FUNCTIONS
+
+#include "cairo-xlib-private.h"
+#include "cairo-xlib-surface-private.h"
+#include "cairo-image-surface-private.h"
+#include "cairo-mempool-private.h"
+
+#include "cairo-damage-private.h"
+#include "cairo-default-context-private.h"
+#include "cairo-list-inline.h"
+
+#include <X11/Xlibint.h>
+#include <X11/Xproto.h>
+#include <X11/extensions/XShm.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#define MIN_PIXMAP_SIZE 4096
+
+#define MIN_BITS 8
+#define MIN_SIZE (1<<(MIN_BITS-1))
+
+typedef struct _cairo_xlib_shm cairo_xlib_shm_t;
+typedef struct _cairo_xlib_shm_info cairo_xlib_shm_info_t;
+typedef struct _cairo_xlib_shm_surface cairo_xlib_shm_surface_t;
+
+struct _cairo_xlib_shm {
+    cairo_mempool_t mem;
+
+    XShmSegmentInfo shm;
+    unsigned long attached;
+    cairo_list_t link;
+};
+
+struct _cairo_xlib_shm_info {
+    unsigned long last_request;
+    void *mem;
+    size_t size;
+    cairo_xlib_shm_t *pool;
+};
+
+struct _cairo_xlib_shm_surface {
+    cairo_image_surface_t image;
+
+    cairo_xlib_shm_info_t *info;
+    Pixmap pixmap;
+    unsigned long active;
+    int idle;
+};
+
+/* the parent is always given by index/2 */
+#define PQ_PARENT_INDEX(i) ((i) >> 1)
+#define PQ_FIRST_ENTRY 1
+
+/* left and right children are index * 2 and (index * 2) +1 respectively */
+#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1)
+
+#define PQ_TOP(pq) ((pq)->elements[PQ_FIRST_ENTRY])
+
+struct pqueue {
+    int size, max_size;
+    cairo_xlib_shm_info_t **elements;
+};
+
+struct _cairo_xlib_shm_display {
+    int has_pixmaps;
+
+    cairo_list_t pool;
+    struct pqueue info;
+};
+
+static inline cairo_bool_t
+seqno_passed (unsigned long a, unsigned long b)
+{
+    return (long)(b - a) > 0;
+}
+
+static inline cairo_status_t
+_pqueue_init (struct pqueue *pq)
+{
+    pq->max_size = 32;
+    pq->size = 0;
+
+    pq->elements = _cairo_malloc_ab (pq->max_size,
+				     sizeof (cairo_xlib_shm_info_t *));
+    if (unlikely (pq->elements == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    PQ_TOP(pq) = NULL;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static inline void
+_pqueue_fini (struct pqueue *pq)
+{
+    free (pq->elements);
+}
+
+static cairo_status_t
+_pqueue_grow (struct pqueue *pq)
+{
+    cairo_xlib_shm_info_t **new_elements;
+
+    new_elements = _cairo_realloc_ab (pq->elements,
+				      2 * pq->max_size,
+				      sizeof (cairo_xlib_shm_info_t *));
+    if (unlikely (new_elements == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    pq->elements = new_elements;
+    pq->max_size *= 2;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_pqueue_shrink (struct pqueue *pq, int min_size)
+{
+    cairo_xlib_shm_info_t **new_elements;
+
+    if (min_size <= pq->max_size)
+	return;
+
+    new_elements = _cairo_realloc_ab (pq->elements,
+				      min_size,
+				      sizeof (cairo_xlib_shm_info_t *));
+    if (unlikely (new_elements == NULL))
+	return;
+
+    pq->elements = new_elements;
+    pq->max_size = min_size;
+}
+
+static inline cairo_status_t
+_pqueue_push (struct pqueue *pq, cairo_xlib_shm_info_t *info)
+{
+    cairo_xlib_shm_info_t **elements;
+    int i, parent;
+
+    if (unlikely (pq->size + 1 == pq->max_size)) {
+	cairo_status_t status;
+
+	status = _pqueue_grow (pq);
+	if (unlikely (status))
+	    return status;
+    }
+
+    elements = pq->elements;
+
+    for (i = ++pq->size;
+	 i != PQ_FIRST_ENTRY &&
+	 info->last_request < elements[parent = PQ_PARENT_INDEX (i)]->last_request;
+	 i = parent)
+    {
+	elements[i] = elements[parent];
+    }
+
+    elements[i] = info;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static inline void
+_pqueue_pop (struct pqueue *pq)
+{
+    cairo_xlib_shm_info_t **elements = pq->elements;
+    cairo_xlib_shm_info_t *tail;
+    int child, i;
+
+    tail = elements[pq->size--];
+    if (pq->size == 0) {
+	elements[PQ_FIRST_ENTRY] = NULL;
+	_pqueue_shrink (pq, 32);
+	return;
+    }
+
+    for (i = PQ_FIRST_ENTRY;
+	 (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size;
+	 i = child)
+    {
+	if (child != pq->size &&
+	    elements[child+1]->last_request < elements[child]->last_request)
+	{
+	    child++;
+	}
+
+	if (elements[child]->last_request >= tail->last_request)
+	    break;
+
+	elements[i] = elements[child];
+    }
+    elements[i] = tail;
+}
+
+static cairo_bool_t _x_error_occurred;
+static int
+_check_error_handler (Display     *display,
+		     XErrorEvent *event)
+{
+    _x_error_occurred = TRUE;
+    return False; /* ignored */
+}
+
+static cairo_bool_t
+can_use_shm (Display *dpy, int *has_pixmap)
+{
+    XShmSegmentInfo shm;
+    int (*old_handler) (Display *display, XErrorEvent *event);
+    Status success;
+    int major, minor;
+
+    if (! XShmQueryExtension (dpy))
+	return FALSE;
+
+    XShmQueryVersion (dpy, &major, &minor, has_pixmap);
+
+    shm.shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
+    if (shm.shmid == -1)
+	return FALSE;
+
+    shm.readOnly = FALSE;
+    shm.shmaddr = shmat (shm.shmid, NULL, 0);
+    if (shm.shmaddr == (char *) -1) {
+	shmctl (shm.shmid, IPC_RMID, NULL);
+	return FALSE;
+    }
+
+    _x_error_occurred = FALSE;
+    old_handler = XSetErrorHandler (_check_error_handler);
+
+    success = XShmAttach (dpy, &shm);
+    if (success)
+	XShmDetach (dpy, &shm);
+
+    XSync (dpy, False);
+    XSetErrorHandler (old_handler);
+
+    shmctl (shm.shmid, IPC_RMID, NULL);
+    shmdt (shm.shmaddr);
+
+    return success && ! _x_error_occurred;
+}
+
+static void trigger_event (Display *dpy)
+{
+    xReq *req;
+
+    LockDisplay(dpy);
+    GetEmptyReq(GetInputFocus, req);
+    UnlockDisplay(dpy);
+}
+
+static void
+_cairo_xlib_display_shm_pool_destroy (cairo_xlib_display_t *display,
+				      cairo_xlib_shm_t *pool)
+{
+    shmdt (pool->shm.shmaddr);
+    if (display->display) /* may be called after CloseDisplay */
+	XShmDetach (display->display, &pool->shm);
+
+    _cairo_mempool_fini (&pool->mem);
+
+    cairo_list_del (&pool->link);
+    free (pool);
+}
+
+static void
+_cairo_xlib_shm_info_cleanup (cairo_xlib_display_t *display)
+{
+    cairo_xlib_shm_info_t *info;
+    Display *dpy = display->display;
+    struct pqueue *pq = &display->shm->info;
+    unsigned long processed;
+
+    if (PQ_TOP(pq) == NULL)
+	return;
+
+    XEventsQueued (dpy, QueuedAfterReading);
+    processed = LastKnownRequestProcessed (dpy);
+
+    info = PQ_TOP(pq);
+    do {
+	if (! seqno_passed (info->last_request, processed))
+	    break;
+
+	_cairo_mempool_free (&info->pool->mem, info->mem);
+	_pqueue_pop (&display->shm->info);
+	free (info);
+    } while ((info = PQ_TOP(pq)));
+}
+
+static cairo_xlib_shm_info_t *
+_cairo_xlib_shm_info_find (cairo_xlib_display_t *display, size_t size)
+{
+    cairo_xlib_shm_info_t *info;
+    struct pqueue *pq = &display->shm->info;
+
+    if (PQ_TOP(pq) == NULL)
+	return NULL;
+
+    info = PQ_TOP(pq);
+    do {
+	_pqueue_pop (&display->shm->info);
+
+	if (info->size >= size && size <= 2*info->size)
+	    return info;
+
+	_cairo_mempool_free (&info->pool->mem, info->mem);
+	free (info);
+    } while ((info = PQ_TOP(pq)));
+
+    return NULL;
+}
+
+static cairo_xlib_shm_t *
+_cairo_xlib_shm_pool_find (cairo_xlib_display_t *display,
+			   size_t size,
+			   void **ptr)
+{
+    cairo_xlib_shm_t *pool;
+
+    cairo_list_foreach_entry (pool, cairo_xlib_shm_t, &display->shm->pool, link) {
+	if (pool->mem.free_bytes >= size) {
+	    void *mem = _cairo_mempool_alloc (&pool->mem, size);
+	    if (mem != NULL) {
+		*ptr = mem;
+		return pool;
+	    }
+	}
+    }
+
+    return NULL;
+}
+
+static void
+_cairo_xlib_shm_pool_cleanup (cairo_xlib_display_t *display)
+{
+    cairo_xlib_shm_t *pool, *next;
+    unsigned long processed;
+
+    processed = LastKnownRequestProcessed (display->display);
+
+    cairo_list_foreach_entry_safe (pool, next, cairo_xlib_shm_t,
+				   &display->shm->pool, link) {
+	if (! seqno_passed (pool->attached, processed))
+	    break;
+
+	if (pool->mem.free_bytes == pool->mem.max_bytes)
+	    _cairo_xlib_display_shm_pool_destroy (display, pool);
+    }
+}
+
+static cairo_xlib_shm_t *
+_cairo_xlib_shm_pool_create(cairo_xlib_display_t *display,
+			    size_t size, void **ptr)
+{
+    Display *dpy = display->display;
+    cairo_xlib_shm_t *pool;
+    size_t bytes, maxbits = 16, minbits = MIN_BITS;
+    Status success;
+
+    pool = malloc (sizeof (cairo_xlib_shm_t));
+    if (pool == NULL)
+	return NULL;
+
+    bytes = 1 << maxbits;
+    while (bytes <= size)
+	bytes <<= 1, maxbits++;
+    bytes <<= 3;
+
+    minbits += (maxbits - 16) / 2;
+
+    pool->shm.shmid = shmget (IPC_PRIVATE, bytes, IPC_CREAT | 0600);
+    while (pool->shm.shmid == -1 && bytes >= 2*size) {
+	bytes >>= 1;
+	pool->shm.shmid = shmget (IPC_PRIVATE, bytes, IPC_CREAT | 0600);
+    }
+    if (pool->shm.shmid == -1)
+	goto cleanup;
+
+    pool->shm.readOnly = FALSE;
+    pool->shm.shmaddr = shmat (pool->shm.shmid, NULL, 0);
+    if (pool->shm.shmaddr == (char *) -1) {
+	shmctl (pool->shm.shmid, IPC_RMID, NULL);
+	goto cleanup;
+    }
+
+    pool->attached = NextRequest (dpy);
+    success = XShmAttach (dpy, &pool->shm);
+    shmctl (pool->shm.shmid, IPC_RMID, NULL);
+
+    if (! success)
+	goto cleanup_shm;
+
+    if (_cairo_mempool_init (&pool->mem, pool->shm.shmaddr, bytes,
+			     minbits, maxbits - minbits + 1))
+	goto cleanup_detach;
+
+    cairo_list_add (&pool->link, &display->shm->pool);
+    trigger_event (display->display);
+
+    *ptr = _cairo_mempool_alloc (&pool->mem, size);
+    assert (*ptr != NULL);
+    return pool;
+
+cleanup_detach:
+    XShmDetach (dpy, &pool->shm);
+cleanup_shm:
+    shmdt (pool->shm.shmaddr);
+cleanup:
+    free (pool);
+    return NULL;
+}
+
+static cairo_xlib_shm_info_t *
+_cairo_xlib_shm_info_create (cairo_xlib_display_t *display,
+			     size_t size, cairo_bool_t will_sync)
+{
+    cairo_xlib_shm_info_t *info;
+    cairo_xlib_shm_t *pool;
+    void *mem = NULL;
+
+    if (will_sync) {
+	info = _cairo_xlib_shm_info_find (display, size);
+	if (info)
+	    return info;
+    }
+
+    _cairo_xlib_shm_info_cleanup (display);
+    pool = _cairo_xlib_shm_pool_find (display, size, &mem);
+    _cairo_xlib_shm_pool_cleanup (display);
+    if (pool == NULL)
+	pool = _cairo_xlib_shm_pool_create (display, size, &mem);
+    if (pool == NULL)
+	return NULL;
+
+    assert (mem != NULL);
+
+    info = malloc (sizeof (*info));
+    if (info == NULL) {
+	_cairo_mempool_free (&pool->mem, mem);
+	return NULL;
+    }
+
+    info->pool = pool;
+    info->mem = mem;
+    info->size = size;
+    info->last_request = 0;
+
+    return info;
+}
+
+static inline Display *
+peek_display (cairo_device_t *device)
+{
+    return ((cairo_xlib_display_t *)device)->display;
+}
+
+static inline unsigned long
+peek_processed (cairo_device_t *device)
+{
+    return LastKnownRequestProcessed (peek_display(device));
+}
+
+static cairo_status_t
+_cairo_xlib_shm_surface_flush (void *abstract_surface, unsigned flags)
+{
+    cairo_xlib_shm_surface_t *shm = abstract_surface;
+    cairo_xlib_display_t *display;
+    cairo_status_t status;
+
+    if (shm->active == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    if (shm->image.base._finishing)
+	return CAIRO_STATUS_SUCCESS;
+
+    if (seqno_passed (shm->active, peek_processed (shm->image.base.device))) {
+	shm->active = 0;
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    status = _cairo_xlib_display_acquire (shm->image.base.device, &display);
+    if (unlikely (status))
+	return status;
+
+    XEventsQueued (display->display, QueuedAfterReading);
+    if (!seqno_passed (shm->active,
+		       LastKnownRequestProcessed (display->display)))
+	XSync (display->display, False);
+
+    cairo_device_release (&display->base);
+    shm->active = 0;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static inline cairo_bool_t
+active (cairo_xlib_shm_surface_t *shm, Display *dpy)
+{
+    return (shm->active &&
+	    !seqno_passed (shm->active, LastKnownRequestProcessed (dpy)));
+}
+
+static cairo_status_t
+_cairo_xlib_shm_surface_finish (void *abstract_surface)
+{
+    cairo_xlib_shm_surface_t *shm = abstract_surface;
+    cairo_xlib_display_t *display;
+    cairo_status_t status;
+
+    status = _cairo_xlib_display_acquire (shm->image.base.device, &display);
+    if (unlikely (status))
+	return status;
+
+    if (shm->pixmap)
+	XFreePixmap (display->display, shm->pixmap);
+
+    if (active (shm, display->display)) {
+	shm->info->last_request = shm->active;
+	_pqueue_push (&display->shm->info, shm->info);
+    } else {
+	cairo_xlib_shm_t *pool = shm->info->pool;
+
+	_cairo_mempool_free (&pool->mem, shm->info->mem);
+	free (shm->info);
+
+	_cairo_xlib_shm_pool_cleanup (display);
+    }
+
+    cairo_device_release (&display->base);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t cairo_xlib_shm_surface_backend = {
+    CAIRO_SURFACE_TYPE_IMAGE,
+    _cairo_xlib_shm_surface_finish,
+
+    _cairo_default_context_create,
+
+    _cairo_image_surface_create_similar,
+    NULL, /* create similar image */
+    _cairo_image_surface_map_to_image,
+    _cairo_image_surface_unmap_image,
+
+    _cairo_image_surface_source,
+    _cairo_image_surface_acquire_source_image,
+    _cairo_image_surface_release_source_image,
+    _cairo_image_surface_snapshot,
+
+    NULL, /* copy_page */
+    NULL, /* show_page */
+
+    _cairo_image_surface_get_extents,
+    _cairo_image_surface_get_font_options,
+
+    _cairo_xlib_shm_surface_flush,
+    NULL,
+
+    _cairo_image_surface_paint,
+    _cairo_image_surface_mask,
+    _cairo_image_surface_stroke,
+    _cairo_image_surface_fill,
+    NULL, /* fill-stroke */
+    _cairo_image_surface_glyphs,
+};
+
+static cairo_bool_t
+has_shm (cairo_xlib_surface_t *surface)
+{
+    cairo_xlib_display_t *display = (cairo_xlib_display_t *)surface->base.device;
+    return display->shm != NULL;
+}
+
+static int
+has_shm_pixmaps (cairo_xlib_surface_t *surface)
+{
+    cairo_xlib_display_t *display = (cairo_xlib_display_t *)surface->base.device;
+    return display->shm->has_pixmaps;
+}
+
+static cairo_xlib_shm_surface_t *
+_cairo_xlib_shm_surface_create (cairo_xlib_surface_t *other,
+				pixman_format_code_t format,
+				int width, int height,
+				cairo_bool_t will_sync,
+				int create_pixmap)
+{
+    cairo_xlib_shm_surface_t *shm;
+    cairo_xlib_display_t *display;
+    pixman_image_t *image;
+    int stride, size;
+
+    stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP(format));
+    size = stride * height;
+    if (size < MIN_SIZE)
+	return NULL;
+
+    shm = malloc (sizeof (*shm));
+    if (unlikely (shm == NULL))
+	return (cairo_xlib_shm_surface_t *)_cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+    _cairo_surface_init (&shm->image.base,
+			 &cairo_xlib_shm_surface_backend,
+			 other->base.device,
+			 _cairo_content_from_pixman_format (format));
+
+    if (_cairo_xlib_display_acquire (other->base.device, &display))
+	goto cleanup_shm;
+
+    shm->info = _cairo_xlib_shm_info_create (display, size, will_sync);
+    if (shm->info == NULL)
+	goto cleanup_display;
+
+    image = pixman_image_create_bits (format, width, height,
+				      (uint32_t *) shm->info->mem, stride);
+    if (image == NULL)
+	goto cleanup_info;
+
+    _cairo_image_surface_init (&shm->image, image, format);
+
+    shm->pixmap = 0;
+    if (create_pixmap && size >= create_pixmap) {
+	shm->pixmap = XShmCreatePixmap (display->display,
+					other->drawable,
+					shm->info->mem,
+					&shm->info->pool->shm,
+					shm->image.width,
+					shm->image.height,
+					shm->image.depth);
+    }
+    shm->active = shm->info->last_request;
+    shm->idle = -5;
+
+    cairo_device_release (&display->base);
+
+    return shm;
+
+cleanup_info:
+    _cairo_mempool_free (&shm->info->pool->mem, shm->info->mem);
+    free(shm->info);
+cleanup_display:
+    cairo_device_release (&display->base);
+cleanup_shm:
+    free (shm);
+    return NULL;
+}
+
+static void
+_cairo_xlib_surface_update_shm (cairo_xlib_surface_t *surface)
+{
+    cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface->shm;
+    cairo_xlib_display_t *display;
+    cairo_damage_t *damage;
+    GC gc;
+
+    damage = _cairo_damage_reduce (surface->base.damage);
+    surface->base.damage = _cairo_damage_create();
+
+    if (_cairo_xlib_display_acquire (surface->base.device, &display))
+	goto cleanup_damage;
+
+    if (_cairo_xlib_surface_get_gc (display, surface, &gc))
+	goto cleanup_display;
+
+    if (damage->region) {
+	XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))];
+	XRectangle *rects = stack_rects;
+	cairo_rectangle_int_t r;
+	int n_rects, i;
+
+	n_rects = cairo_region_num_rectangles (damage->region);
+	if (n_rects == 0) {
+	} else if (n_rects == 1) {
+	    cairo_region_get_rectangle (damage->region, 0, &r);
+	    XCopyArea (display->display,
+		       surface->drawable, shm->pixmap, gc,
+		       r.x, r.y,
+		       r.width, r.height,
+		       r.x, r.y);
+	} else {
+	    if (n_rects > ARRAY_LENGTH (stack_rects)) {
+		rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
+		if (unlikely (rects == NULL)) {
+		    rects = stack_rects;
+		    n_rects = ARRAY_LENGTH (stack_rects);
+		}
+	    }
+	    for (i = 0; i < n_rects; i++) {
+		cairo_region_get_rectangle (damage->region, i, &r);
+
+		rects[i].x = r.x;
+		rects[i].y = r.y;
+		rects[i].width  = r.width;
+		rects[i].height = r.height;
+	    }
+	    XSetClipRectangles (display->display, gc, 0, 0, rects, i, YXBanded);
+
+	    XCopyArea (display->display,
+		       surface->drawable, shm->pixmap, gc,
+		       0, 0,
+		       shm->image.width, shm->image.height,
+		       0, 0);
+
+	    if (damage->status == CAIRO_STATUS_SUCCESS && damage->region)
+		XSetClipMask (display->display, gc, None);
+	}
+    } else {
+	XCopyArea (display->display,
+		   surface->drawable, shm->pixmap, gc,
+		   0, 0,
+		   shm->image.width, shm->image.height,
+		   0, 0);
+    }
+
+    XSync (display->display, False);
+    shm->active = 0;
+    shm->idle--;
+
+    _cairo_xlib_surface_put_gc (display, surface, gc);
+cleanup_display:
+    cairo_device_release (&display->base);
+cleanup_damage:
+    _cairo_damage_destroy (damage);
+}
+
+static void
+_cairo_xlib_surface_clear_shm (cairo_xlib_surface_t *surface)
+{
+    cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface->shm;
+
+    assert (shm->active == 0);
+
+    _cairo_damage_destroy (surface->base.damage);
+    surface->base.damage = _cairo_damage_create();
+
+    memset (shm->image.data, 0, shm->image.stride * shm->image.height);
+}
+
+static void inc_idle (cairo_surface_t *surface)
+{
+    cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface;
+    shm->idle++;
+}
+
+static void dec_idle (cairo_surface_t *surface)
+{
+    cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface;
+    shm->idle--;
+}
+
+cairo_surface_t *
+_cairo_xlib_surface_get_shm (cairo_xlib_surface_t *surface)
+{
+    if (surface->fallback) {
+	assert (surface->base.damage);
+	assert (surface->shm);
+	assert (surface->shm->damage);
+	goto done;
+    }
+
+    if (surface->shm == NULL) {
+	pixman_format_code_t pixman_format;
+
+	if (! has_shm_pixmaps (surface))
+	    return NULL;
+
+	if ((surface->width | surface->height) < 32)
+	    return NULL;
+
+	pixman_format = _pixman_format_for_xlib_surface (surface);
+	if (pixman_format == 0)
+	    return NULL;
+
+	surface->shm =
+	    &_cairo_xlib_shm_surface_create (surface, pixman_format,
+					     surface->width, surface->height,
+					     TRUE, 1)->image.base;
+	if (surface->shm == NULL)
+	    return NULL;
+
+	assert (surface->base.damage == NULL);
+	if (surface->base.serial || !surface->owns_pixmap) {
+	    cairo_rectangle_int_t rect;
+
+	    rect.x = rect.y = 0;
+	    rect.width = surface->width;
+	    rect.height = surface->height;
+
+	    surface->base.damage =
+		_cairo_damage_add_rectangle (NULL, &rect);
+	} else
+	    surface->base.damage = _cairo_damage_create ();
+
+	surface->shm->damage = _cairo_damage_create ();
+    }
+
+    if (!surface->base.is_clear && surface->base.damage->dirty)
+	_cairo_xlib_surface_update_shm (surface);
+
+    _cairo_xlib_shm_surface_flush (surface->shm, 1);
+
+    if (surface->base.is_clear && surface->base.damage->dirty)
+	_cairo_xlib_surface_clear_shm (surface);
+
+done:
+    dec_idle(surface->shm);
+    return surface->shm;
+}
+
+cairo_int_status_t
+_cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface)
+{
+    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
+
+    if (!surface->fallback) {
+	if (surface->shm)
+	    inc_idle (surface->shm);
+	return CAIRO_INT_STATUS_SUCCESS;
+    }
+
+    if (surface->shm->damage->dirty) {
+	cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface->shm;
+	cairo_xlib_display_t *display;
+	cairo_damage_t *damage;
+	GC gc;
+
+	status = _cairo_xlib_display_acquire (surface->base.device, &display);
+	if (unlikely (status))
+	    return status;
+
+	damage = _cairo_damage_reduce (shm->image.base.damage);
+	shm->image.base.damage = _cairo_damage_create ();
+
+	status = _cairo_xlib_surface_get_gc (display, surface, &gc);
+	if (unlikely (status))
+	    goto out;
+
+	TRACE ((stderr, "%s: flushing damage x %d\n", __FUNCTION__,
+		damage->region ? cairo_region_num_rectangles (damage->region) : 0));
+	if (damage->status == CAIRO_STATUS_SUCCESS && damage->region) {
+	    XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (sizeof (XRectangle))];
+	    XRectangle *rects = stack_rects;
+	    cairo_rectangle_int_t r;
+	    int n_rects, i;
+
+	    n_rects = cairo_region_num_rectangles (damage->region);
+	    if (n_rects == 0) {
+	    } else if (n_rects == 1) {
+		cairo_region_get_rectangle (damage->region, 0, &r);
+		XCopyArea (display->display,
+			   shm->pixmap, surface->drawable, gc,
+			   r.x, r.y,
+			   r.width, r.height,
+			   r.x, r.y);
+	    } else {
+		if (n_rects > ARRAY_LENGTH (stack_rects)) {
+		    rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle));
+		    if (unlikely (rects == NULL)) {
+			status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+			goto out;
+		    }
+		}
+		for (i = 0; i < n_rects; i++) {
+		    cairo_region_get_rectangle (damage->region, i, &r);
+
+		    rects[i].x = r.x;
+		    rects[i].y = r.y;
+		    rects[i].width  = r.width;
+		    rects[i].height = r.height;
+		}
+		XSetClipRectangles (display->display, gc, 0, 0, rects, i, YXBanded);
+
+		XCopyArea (display->display,
+			   shm->pixmap, surface->drawable, gc,
+			   0, 0,
+			   shm->image.width, shm->image.height,
+			   0, 0);
+
+		if (damage->status == CAIRO_STATUS_SUCCESS && damage->region)
+		    XSetClipMask (display->display, gc, None);
+	    }
+	}
+	_cairo_damage_destroy (damage);
+
+	_cairo_xlib_surface_put_gc (display, surface, gc);
+out:
+	cairo_device_release (&display->base);
+    }
+
+    return status;
+}
+
+cairo_surface_t *
+_cairo_xlib_surface_create_shm_image (cairo_xlib_surface_t *surface,
+				      pixman_format_code_t format,
+				      int width, int height)
+{
+    if (! has_shm(surface))
+	return NULL;
+
+    return &_cairo_xlib_shm_surface_create (surface, format,
+					    surface->width, surface->height,
+					    TRUE, 0)->image.base;
+}
+
+cairo_surface_t *
+_cairo_xlib_surface_create_similar_shm (void *other,
+					cairo_format_t format,
+					int width, int height)
+{
+    cairo_surface_t *surface;
+
+    surface = NULL;
+    if (has_shm (other))
+	surface = &_cairo_xlib_shm_surface_create (other,
+						   _cairo_format_to_pixman_format_code (format),
+						   width, height, FALSE,
+						   has_shm_pixmaps (other))->image.base;
+    if (surface  == NULL)
+	surface = cairo_image_surface_create (format, width, height);
+
+    return surface;
+}
+
+static unsigned next_request (cairo_device_t *device)
+{
+    cairo_xlib_display_t *display = (cairo_xlib_display_t *) device;
+    return NextRequest (display->display);
+}
+
+void
+_cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface,
+				    XImage *ximage)
+{
+    cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface;
+    int native_byte_order = _cairo_is_little_endian () ? LSBFirst : MSBFirst;
+    cairo_format_masks_t image_masks;
+    int ret;
+
+    ret = _pixman_format_to_masks (shm->image.pixman_format, &image_masks);
+    assert (ret);
+
+    ximage->width = shm->image.width;
+    ximage->height = shm->image.height;
+    ximage->format = ZPixmap;
+    ximage->data = (char *) shm->image.data;
+    ximage->obdata = (char *)&shm->info->pool->shm;
+    ximage->byte_order = native_byte_order;
+    ximage->bitmap_unit = 32;	/* always for libpixman */
+    ximage->bitmap_bit_order = native_byte_order;
+    ximage->bitmap_pad = 32;	/* always for libpixman */
+    ximage->depth = shm->image.depth;
+    ximage->bytes_per_line = shm->image.stride;
+    ximage->bits_per_pixel = image_masks.bpp;
+    ximage->red_mask = image_masks.red_mask;
+    ximage->green_mask = image_masks.green_mask;
+    ximage->blue_mask = image_masks.blue_mask;
+    ximage->xoffset = 0;
+
+    ret = XInitImage (ximage);
+    assert (ret != 0);
+}
+
+void *
+_cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface)
+{
+    cairo_xlib_shm_surface_t *shm;
+
+    shm = (cairo_xlib_shm_surface_t *) surface;
+    shm->active = next_request (surface->device);
+    return &shm->info->pool->shm;
+}
+
+Pixmap
+_cairo_xlib_shm_surface_get_pixmap (cairo_surface_t *surface)
+{
+    cairo_xlib_shm_surface_t *shm;
+
+    shm = (cairo_xlib_shm_surface_t *) surface;
+    return shm->pixmap;
+}
+
+void
+_cairo_xlib_shm_surface_mark_active (cairo_surface_t *surface)
+{
+    cairo_xlib_shm_surface_t *shm;
+
+    shm = (cairo_xlib_shm_surface_t *) surface;
+    shm->active = next_request (surface->device);
+    trigger_event (peek_display (surface->device));
+}
+
+XRenderPictFormat *
+_cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface)
+{
+    cairo_xlib_shm_surface_t *shm;
+
+    shm = (cairo_xlib_shm_surface_t *) surface;
+    if (shm->image.format != CAIRO_FORMAT_INVALID)
+	return _cairo_xlib_display_get_xrender_format ((cairo_xlib_display_t *)surface->device,
+						       shm->image.format);
+
+    return _cairo_xlib_display_get_xrender_format_for_pixman((cairo_xlib_display_t *)surface->device,
+							     shm->image.pixman_format);
+}
+
+cairo_bool_t
+_cairo_xlib_shm_surface_is_active (cairo_surface_t *surface)
+{
+    cairo_xlib_shm_surface_t *shm;
+
+    shm = (cairo_xlib_shm_surface_t *) surface;
+    if (shm->active == 0)
+	return FALSE;
+
+    if (seqno_passed (shm->active, peek_processed (shm->image.base.device))) {
+	shm->active = 0;
+	return FALSE;
+    }
+
+    return TRUE;
+}
+
+cairo_bool_t
+_cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface)
+{
+    cairo_xlib_shm_surface_t *shm;
+
+    shm = (cairo_xlib_shm_surface_t *) surface;
+    return shm->idle > 0;
+}
+
+void
+_cairo_xlib_display_init_shm (cairo_xlib_display_t *display)
+{
+    int has_pixmap;
+    cairo_xlib_shm_display_t *shm;
+
+    display->shm = NULL;
+
+    if (!can_use_shm (display->display, &has_pixmap))
+	return;
+
+    shm = malloc (sizeof (*shm));
+    if (unlikely (shm == NULL))
+	return;
+
+    if (unlikely (_pqueue_init (&shm->info))) {
+	free (shm);
+	return;
+    }
+
+    shm->has_pixmaps = has_pixmap ? MIN_PIXMAP_SIZE : 0;
+    cairo_list_init (&shm->pool);
+
+    display->shm = shm;
+}
+
+void
+_cairo_xlib_display_fini_shm (cairo_xlib_display_t *display)
+{
+    cairo_xlib_shm_display_t *shm = display->shm;
+
+    if (shm == NULL)
+	return;
+
+    _pqueue_fini (&shm->info);
+
+    while (!cairo_list_is_empty (&shm->pool)) {
+	cairo_xlib_shm_t *pool;
+
+	pool = cairo_list_first_entry (&shm->pool, cairo_xlib_shm_t, link);
+	_cairo_xlib_display_shm_pool_destroy (display, pool);
+    }
+
+    free (shm);
+    display->shm = NULL;
+}
+
+#endif
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 59a7885..aeff746 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -54,6 +54,7 @@
 
 #include "cairo-compositor-private.h"
 #include "cairo-clip-private.h"
+#include "cairo-damage-private.h"
 #include "cairo-default-context-private.h"
 #include "cairo-error-private.h"
 #include "cairo-image-surface-private.h"
@@ -66,6 +67,10 @@
 
 #include <X11/Xutil.h> /* for XDestroyImage */
 
+#include <X11/extensions/XShm.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
 #define XLIB_COORD_MAX 32767
 
 #define DEBUG 0
@@ -375,6 +380,8 @@ _cairo_xlib_surface_finish (void *abstract_surface)
     if (surface->owns_pixmap)
 	XFreePixmap (display->display, surface->drawable);
 
+    cairo_surface_destroy (surface->shm);
+
     cairo_device_release (&display->base);
 
     return status;
@@ -678,15 +685,32 @@ static int bits_per_pixel(cairo_xlib_surface_t *surface)
 	return 1;
 }
 
+pixman_format_code_t
+_pixman_format_for_xlib_surface (cairo_xlib_surface_t *surface)
+{
+    cairo_format_masks_t masks;
+    pixman_format_code_t format;
+
+    masks.bpp = bits_per_pixel (surface);
+    masks.alpha_mask = surface->a_mask;
+    masks.red_mask = surface->r_mask;
+    masks.green_mask = surface->g_mask;
+    masks.blue_mask = surface->b_mask;
+    if (! _pixman_format_from_masks (&masks, &format))
+	return 0;
+
+    return format;
+}
+
 static cairo_surface_t *
 _get_image_surface (cairo_xlib_surface_t    *surface,
-		    const cairo_rectangle_int_t *extents)
+		    const cairo_rectangle_int_t *extents,
+		    int try_shm)
 {
     cairo_int_status_t status;
     cairo_image_surface_t *image = NULL;
     XImage *ximage;
     pixman_format_code_t pixman_format;
-    cairo_format_masks_t xlib_masks;
     cairo_xlib_display_t *display;
 
     assert (extents->x >= 0);
@@ -697,13 +721,8 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
     if (surface->base.is_clear ||
 	(surface->base.serial == 0 && surface->owns_pixmap))
     {
-	xlib_masks.bpp = bits_per_pixel (surface);
-	xlib_masks.alpha_mask = surface->a_mask;
-	xlib_masks.red_mask = surface->r_mask;
-	xlib_masks.green_mask = surface->g_mask;
-	xlib_masks.blue_mask = surface->b_mask;
-	if (_pixman_format_from_masks (&xlib_masks, &pixman_format) &&
-	    _cairo_format_from_pixman_format (pixman_format) != CAIRO_FORMAT_INVALID)
+	pixman_format = _pixman_format_for_xlib_surface (surface);
+	if (pixman_format)
 	{
 	    return _cairo_image_surface_create_with_pixman_format (NULL,
 								   pixman_format,
@@ -713,11 +732,59 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 	}
     }
 
+    if (surface->shm) {
+	cairo_image_surface_t *src = (cairo_image_surface_t *) surface->shm;
+	cairo_surface_t *dst;
+	cairo_surface_pattern_t pattern;
+
+	dst = cairo_image_surface_create (src->format,
+					  extents->width, extents->height);
+	if (unlikely (dst->status))
+	    return dst;
+
+	_cairo_pattern_init_for_surface (&pattern, &src->base);
+	cairo_matrix_init_translate (&pattern.base.matrix,
+				     extents->x, extents->y);
+	status = _cairo_surface_paint (dst, CAIRO_OPERATOR_SOURCE, &pattern.base, NULL);
+	_cairo_pattern_fini (&pattern.base);
+	if (unlikely (status)) {
+	    cairo_surface_destroy (dst);
+	    dst = _cairo_surface_create_in_error (status);
+	}
+
+	return dst;
+    }
+
     status = _cairo_xlib_display_acquire (surface->base.device, &display);
     if (status)
         return _cairo_surface_create_in_error (status);
 
-    /* XXX: This should try to use the XShm extension if available */
+    pixman_format = _pixman_format_for_xlib_surface (surface);
+    if (try_shm && pixman_format) {
+	image = (cairo_image_surface_t *)
+	    _cairo_xlib_surface_create_shm_image (surface, pixman_format,
+						  extents->width, extents->height);
+	if (image && image->base.status == CAIRO_STATUS_SUCCESS) {
+	    cairo_xlib_error_func_t old_handler;
+	    XImage shm_image;
+	    Bool success;
+
+	    _cairo_xlib_shm_surface_get_ximage (&image->base, &shm_image);
+
+	    old_handler = XSetErrorHandler (_noop_error_handler);
+	    success = XShmGetImage (display->display,
+				    surface->drawable,
+				    &shm_image,
+				    extents->x, extents->y,
+				    AllPlanes);
+	    XSetErrorHandler (old_handler);
+
+	    if (success)
+		return &image->base;
+
+	    cairo_surface_destroy (&image->base);
+	}
+    }
 
     if (surface->use_pixmap == 0) {
 	cairo_xlib_error_func_t old_handler;
@@ -793,19 +860,13 @@ _get_image_surface (cairo_xlib_surface_t    *surface,
 
     _swap_ximage_to_native (ximage);
 
-    xlib_masks.bpp = ximage->bits_per_pixel;
-    xlib_masks.alpha_mask = surface->a_mask;
-    xlib_masks.red_mask = surface->r_mask;
-    xlib_masks.green_mask = surface->g_mask;
-    xlib_masks.blue_mask = surface->b_mask;
-
     /* We can't use pixman to simply write to image if:
      *   (a) the pixels are not appropriately aligned,
      *   (b) pixman does not the pixel format, or
      *   (c) if the image is palettized and we need to convert.
      */
-    if (ximage->bitmap_unit == 32 && ximage->bitmap_pad == 32 &&
-	_pixman_format_from_masks (&xlib_masks, &pixman_format) &&
+    if (pixman_format &&
+	ximage->bitmap_unit == 32 && ximage->bitmap_pad == 32 &&
 	(surface->visual == NULL || surface->visual->class == TrueColor))
     {
 	image = (cairo_image_surface_t*)
@@ -1024,6 +1085,7 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t   *surface,
     ximage.green_mask = surface->g_mask;
     ximage.blue_mask = surface->b_mask;
     ximage.xoffset = 0;
+    ximage.obdata = NULL;
 
     status = _cairo_xlib_display_acquire (surface->base.device, &display);
     if (unlikely (status))
@@ -1042,6 +1104,9 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t   *surface,
 	ximage.bits_per_pixel = image_masks.bpp;
 	ximage.bytes_per_line = image->stride;
 	ximage.data = (char *)image->data;
+	ximage.obdata = NULL;
+	if (image->base.device == surface->base.device)
+	    ximage.obdata = _cairo_xlib_shm_surface_get_obdata (&image->base);
 	own_data = FALSE;
 
 	ret = XInitImage (&ximage);
@@ -1207,13 +1272,16 @@ _cairo_xlib_surface_draw_image (cairo_xlib_surface_t   *surface,
     if (unlikely (status))
 	goto BAIL;
 
-    XPutImage (display->display, surface->drawable, gc, &ximage,
-	       src_x, src_y, dst_x, dst_y, width, height);
+    if (ximage.obdata)
+	XShmPutImage (display->display, surface->drawable, gc, &ximage,
+		      src_x, src_y, dst_x, dst_y, width, height, TRUE);
+    else
+	XPutImage (display->display, surface->drawable, gc, &ximage,
+		   src_x, src_y, dst_x, dst_y, width, height);
 
     _cairo_xlib_surface_put_gc (display, surface, gc);
 
   BAIL:
-
     cairo_device_release (&display->base);
 
     if (own_data)
@@ -1247,12 +1315,18 @@ _cairo_xlib_surface_acquire_source_image (void                    *abstract_surf
     cairo_xlib_surface_t *surface = abstract_surface;
     cairo_rectangle_int_t extents;
 
+    *image_extra = NULL;
+    *image_out = (cairo_image_surface_t *)
+	_cairo_xlib_surface_get_shm (abstract_surface);
+    if (*image_out) 
+	    return (*image_out)->base.status;
+
     extents.x = extents.y = 0;
     extents.width = surface->width;
     extents.height = surface->height;
 
-    *image_extra = NULL;
-    *image_out = (cairo_image_surface_t*)_get_image_surface (surface, &extents);
+    *image_out = (cairo_image_surface_t*)
+	_get_image_surface (surface, &extents, TRUE);
     return (*image_out)->base.status;
 }
 
@@ -1266,8 +1340,7 @@ _cairo_xlib_surface_snapshot (void *abstract_surface)
     extents.width = surface->width;
     extents.height = surface->height;
 
-    /* XXX notice the duplication with acquire source */
-    return _get_image_surface (surface, &extents);
+    return _get_image_surface (surface, &extents, FALSE);
 }
 
 static void
@@ -1275,6 +1348,11 @@ _cairo_xlib_surface_release_source_image (void                   *abstract_surfa
 					  cairo_image_surface_t  *image,
 					  void                   *image_extra)
 {
+    cairo_xlib_surface_t *surface = abstract_surface;
+
+    if (&image->base == surface->shm)
+	return;
+
     cairo_surface_destroy (&image->base);
 }
 
@@ -1282,9 +1360,17 @@ static cairo_image_surface_t *
 _cairo_xlib_surface_map_to_image (void                    *abstract_surface,
 				  const cairo_rectangle_int_t   *extents)
 {
+    cairo_xlib_surface_t *surface = abstract_surface;
     cairo_surface_t *image;
 
-    image = _get_image_surface (abstract_surface, extents);
+    image = _cairo_xlib_surface_get_shm (abstract_surface);
+    if (image) {
+	assert (surface->base.damage);
+	surface->fallback++;
+	return _cairo_image_surface_map_to_image (image, extents);
+    }
+
+    image = _get_image_surface (abstract_surface, extents, TRUE);
     cairo_surface_set_device_offset (image, -extents->x, -extents->y);
 
     return (cairo_image_surface_t *) image;
@@ -1294,8 +1380,28 @@ static cairo_int_status_t
 _cairo_xlib_surface_unmap_image (void *abstract_surface,
 				 cairo_image_surface_t *image)
 {
+    cairo_xlib_surface_t *surface = abstract_surface;
     cairo_int_status_t status;
 
+    if (surface->shm) {
+	cairo_rectangle_int_t r;
+
+	assert (surface->fallback);
+	assert (surface->base.damage);
+
+	r.x = image->base.device_transform_inverse.x0;
+	r.y = image->base.device_transform_inverse.y0;
+	r.width  = image->width;
+	r.height = image->height;
+
+	TRACE ((stderr, "%s: adding damage (%d,%d)x(%d,%d)\n",
+		__FUNCTION__, r.x, r.y, r.width, r.height));
+	surface->shm->damage =
+	    _cairo_damage_add_rectangle (surface->shm->damage, &r);
+
+	return _cairo_image_surface_unmap_image (surface->shm, image);
+    }
+
     status = _cairo_xlib_surface_draw_image (abstract_surface, image,
 					     0, 0,
 					     image->width, image->height,
@@ -1308,6 +1414,32 @@ _cairo_xlib_surface_unmap_image (void *abstract_surface,
     return status;
 }
 
+static cairo_status_t
+_cairo_xlib_surface_flush (void *abstract_surface,
+			   unsigned flags)
+{
+    cairo_xlib_surface_t *surface = abstract_surface;
+    cairo_int_status_t status;
+
+    if (flags)
+	return CAIRO_STATUS_SUCCESS;
+
+    status = _cairo_xlib_surface_put_shm (surface);
+    if (unlikely (status))
+	return status;
+
+    surface->fallback >>= 1;
+    if (surface->shm && _cairo_xlib_shm_surface_is_idle (surface->shm)) {
+	cairo_surface_destroy (surface->shm);
+	surface->shm = NULL;
+
+	_cairo_damage_destroy (surface->base.damage);
+	surface->base.damage = NULL;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
 static cairo_bool_t
 _cairo_xlib_surface_get_extents (void		         *abstract_surface,
 				 cairo_rectangle_int_t   *rectangle)
@@ -1332,6 +1464,31 @@ _cairo_xlib_surface_get_font_options (void                  *abstract_surface,
     *options = *_cairo_xlib_screen_get_font_options (surface->screen);
 }
 
+static inline cairo_int_status_t
+get_compositor (cairo_xlib_surface_t **surface,
+		const cairo_compositor_t **compositor)
+{
+    cairo_xlib_surface_t *s = *surface;
+    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;;
+
+    if (s->fallback) {
+	assert (s->base.damage != NULL);
+	assert (s->shm != NULL);
+	assert (s->shm->damage != NULL);
+	if (! _cairo_xlib_shm_surface_is_active (s->shm)) {
+	    *surface = (cairo_xlib_surface_t *) s->shm;
+	    *compositor = ((cairo_image_surface_t *) s->shm)->compositor;
+	    s->fallback++;
+	} else {
+	    status = _cairo_xlib_surface_put_shm (s);
+	    s->fallback = 0;
+	    *compositor = s->compositor;
+	}
+    } else
+	*compositor = s->compositor;
+
+    return status;
+}
 
 static cairo_int_status_t
 _cairo_xlib_surface_paint (void				*_surface,
@@ -1340,8 +1497,15 @@ _cairo_xlib_surface_paint (void				*_surface,
 			   const cairo_clip_t		*clip)
 {
     cairo_xlib_surface_t *surface = _surface;
-    return _cairo_compositor_paint (surface->compositor,
-				    &surface->base, op, source,
+    const cairo_compositor_t *compositor;
+    cairo_int_status_t status;
+
+    status = get_compositor (&surface, &compositor);
+    if (unlikely (status))
+	return status;
+
+    return _cairo_compositor_paint (compositor, &surface->base,
+				    op, source,
 				    clip);
 }
 
@@ -1353,8 +1517,15 @@ _cairo_xlib_surface_mask (void			*_surface,
 			  const cairo_clip_t	*clip)
 {
     cairo_xlib_surface_t *surface = _surface;
-    return _cairo_compositor_mask (surface->compositor,
-				   &surface->base, op, source, mask,
+    const cairo_compositor_t *compositor;
+    cairo_int_status_t status;
+
+    status = get_compositor (&surface, &compositor);
+    if (unlikely (status))
+	return status;
+
+    return _cairo_compositor_mask (compositor, &surface->base,
+				   op, source, mask,
 				   clip);
 }
 
@@ -1371,8 +1542,15 @@ _cairo_xlib_surface_stroke (void			*_surface,
 			    const cairo_clip_t		*clip)
 {
     cairo_xlib_surface_t *surface = _surface;
-    return _cairo_compositor_stroke (surface->compositor,
-				     &surface->base, op, source,
+    const cairo_compositor_t *compositor;
+    cairo_int_status_t status;
+
+    status = get_compositor (&surface, &compositor);
+    if (unlikely (status))
+	return status;
+
+    return _cairo_compositor_stroke (compositor, &surface->base,
+				     op, source,
 				     path, style, ctm, ctm_inverse,
 				     tolerance, antialias,
 				     clip);
@@ -1389,8 +1567,15 @@ _cairo_xlib_surface_fill (void				*_surface,
 			  const cairo_clip_t		*clip)
 {
     cairo_xlib_surface_t *surface = _surface;
-    return _cairo_compositor_fill (surface->compositor,
-				   &surface->base, op, source,
+    const cairo_compositor_t *compositor;
+    cairo_int_status_t status;
+
+    status = get_compositor (&surface, &compositor);
+    if (unlikely (status))
+	return status;
+
+    return _cairo_compositor_fill (compositor, &surface->base,
+				   op, source,
 				   path, fill_rule, tolerance, antialias,
 				   clip);
 }
@@ -1405,8 +1590,15 @@ _cairo_xlib_surface_glyphs (void			*_surface,
 			    const cairo_clip_t		*clip)
 {
     cairo_xlib_surface_t *surface = _surface;
-    return _cairo_compositor_glyphs (surface->compositor,
-				     &surface->base, op, source,
+    const cairo_compositor_t *compositor;
+    cairo_int_status_t status;
+
+    status = get_compositor (&surface, &compositor);
+    if (unlikely (status))
+	return status;
+
+    return _cairo_compositor_glyphs (compositor, &surface->base,
+				     op, source,
 				     glyphs, num_glyphs, scaled_font,
 				     clip);
 }
@@ -1418,7 +1610,7 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
     _cairo_default_context_create,
 
     _cairo_xlib_surface_create_similar,
-    NULL, //_cairo_xlib_surface_create_similar_image, /* XXX shm */
+    _cairo_xlib_surface_create_similar_shm,
     _cairo_xlib_surface_map_to_image,
     _cairo_xlib_surface_unmap_image,
 
@@ -1433,7 +1625,7 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
     _cairo_xlib_surface_get_extents,
     _cairo_xlib_surface_get_font_options,
 
-    NULL, /* flush */
+    _cairo_xlib_surface_flush,
     NULL, /* mark_dirty_rectangle */
 
     _cairo_xlib_surface_paint,
@@ -1539,6 +1731,8 @@ found:
 
     surface->screen = screen;
     surface->compositor = display->compositor;
+    surface->shm = NULL;
+    surface->fallback = 0;
 
     surface->drawable = drawable;
     surface->owns_pixmap = FALSE;
@@ -1830,6 +2024,7 @@ cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
 			     int              height)
 {
     cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface;
+    cairo_status_t status;
 
     if (unlikely (abstract_surface->status))
 	return;
@@ -1851,6 +2046,12 @@ cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
 	return;
     }
 
+    status = _cairo_surface_begin_modification (abstract_surface);
+    if (unlikely (status)) {
+	_cairo_surface_set_error (abstract_surface, status);
+	return;
+    }
+
     surface->width = width;
     surface->height = height;
 }
@@ -1903,7 +2104,13 @@ cairo_xlib_surface_set_drawable (cairo_surface_t   *abstract_surface,
     if (surface->owns_pixmap)
 	return;
 
-    if (surface->drawable != drawable) {
+    status = _cairo_surface_begin_modification (abstract_surface);
+    if (unlikely (status)) {
+	_cairo_surface_set_error (abstract_surface, status);
+	return;
+    }
+
+    if (surface->drawable == drawable) {
         cairo_xlib_display_t *display;
 
         status = _cairo_xlib_display_acquire (surface->base.device, &display);
@@ -1926,6 +2133,7 @@ cairo_xlib_surface_set_drawable (cairo_surface_t   *abstract_surface,
 
 	surface->drawable = drawable;
     }
+
     surface->width = width;
     surface->height = height;
 }
diff --git a/src/cairo-xlib-xcb-surface.c b/src/cairo-xlib-xcb-surface.c
index c106964..9c0d4b4 100644
--- a/src/cairo-xlib-xcb-surface.c
+++ b/src/cairo-xlib-xcb-surface.c
@@ -249,12 +249,11 @@ _cairo_xlib_xcb_surface_glyphs (void			*abstract_surface,
 }
 
 static cairo_status_t
-_cairo_xlib_xcb_surface_flush (void *abstract_surface)
+_cairo_xlib_xcb_surface_flush (void *abstract_surface, unsigned flags)
 {
     cairo_xlib_xcb_surface_t *surface = abstract_surface;
     /* We have to call cairo_surface_flush() to make sure snapshots are detached */
-    cairo_surface_flush (&surface->xcb->base);
-    return CAIRO_STATUS_SUCCESS;
+    return _cairo_surface_flush (&surface->xcb->base, flags);
 }
 
 static cairo_status_t
diff --git a/src/cairoint.h b/src/cairoint.h
index ff101c1..26a8de1 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1394,7 +1394,7 @@ _cairo_surface_has_snapshot (cairo_surface_t *surface,
 cairo_private void
 _cairo_surface_detach_snapshot (cairo_surface_t *snapshot);
 
-cairo_private void
+cairo_private cairo_status_t
 _cairo_surface_begin_modification (cairo_surface_t *surface);
 
 cairo_private_no_warn cairo_bool_t
diff --git a/src/drm/cairo-drm-gallium-surface.c b/src/drm/cairo-drm-gallium-surface.c
index aa3f45e..164ab03 100644
--- a/src/drm/cairo-drm-gallium-surface.c
+++ b/src/drm/cairo-drm-gallium-surface.c
@@ -314,12 +314,16 @@ gallium_surface_release_source_image (void *abstract_surface,
 }
 
 static cairo_status_t
-gallium_surface_flush (void *abstract_surface)
+gallium_surface_flush (void *abstract_surface,
+		       unsigned flags)
 {
     gallium_surface_t *surface = abstract_surface;
     gallium_device_t *device = gallium_device (surface);
     cairo_status_t status;
 
+    if (flags)
+	return CAIRO_STATUS_SUCCESS;
+
     if (surface->fallback == NULL) {
 	device->pipe->flush (device->pipe,
 			     PIPE_FLUSH_RENDER_CACHE,
diff --git a/src/drm/cairo-drm-i915-private.h b/src/drm/cairo-drm-i915-private.h
index 8b2e422..c750cf4 100644
--- a/src/drm/cairo-drm-i915-private.h
+++ b/src/drm/cairo-drm-i915-private.h
@@ -1258,7 +1258,7 @@ i915_surface_fallback_flush (i915_surface_t *surface)
     cairo_status_t status;
 
     if (unlikely (surface->intel.drm.fallback != NULL))
-	return intel_surface_flush (&surface->intel);
+	return intel_surface_flush (&surface->intel, 0);
 
     status = CAIRO_STATUS_SUCCESS;
     if (unlikely (surface->deferred_clear))
diff --git a/src/drm/cairo-drm-i915-surface.c b/src/drm/cairo-drm-i915-surface.c
index 0200121..c1a0452 100644
--- a/src/drm/cairo-drm-i915-surface.c
+++ b/src/drm/cairo-drm-i915-surface.c
@@ -716,11 +716,15 @@ i915_surface_batch_flush (i915_surface_t *surface)
 }
 
 static cairo_status_t
-i915_surface_flush (void *abstract_surface)
+i915_surface_flush (void *abstract_surface,
+		    unsigned flags)
 {
     i915_surface_t *surface = abstract_surface;
     cairo_status_t status;
 
+    if (flags)
+	return CAIRO_STATUS_SUCCESS;
+
     if (surface->intel.drm.fallback == NULL) {
 	if (surface->intel.drm.base.finished) {
 	    /* Forgo flushing on finish as the user cannot access the surface directly. */
@@ -736,7 +740,7 @@ i915_surface_flush (void *abstract_surface)
 	return i915_surface_batch_flush (surface);
     }
 
-    return intel_surface_flush (abstract_surface);
+    return intel_surface_flush (abstract_surface, flags);
 }
 
 /* rasterisation */
diff --git a/src/drm/cairo-drm-i965-shader.c b/src/drm/cairo-drm-i965-shader.c
index 5465f42..eed5f5f 100644
--- a/src/drm/cairo-drm-i965-shader.c
+++ b/src/drm/cairo-drm-i965-shader.c
@@ -415,7 +415,7 @@ i965_shader_acquire_surface (i965_shader_t *shader,
 		    int x;
 
 		    if (s->intel.drm.fallback != NULL) {
-			status = intel_surface_flush (s);
+			status = intel_surface_flush (s, 0);
 			if (unlikely (status))
 			    return status;
 		    }
@@ -489,7 +489,7 @@ i965_shader_acquire_surface (i965_shader_t *shader,
 	    if (s->intel.drm.base.device == shader->target->intel.drm.base.device) {
 		if (s != shader->target) {
 		    if (s->intel.drm.fallback != NULL) {
-			status = intel_surface_flush (s);
+			status = intel_surface_flush (s, 0);
 			if (unlikely (status))
 			    return status;
 		    }
diff --git a/src/drm/cairo-drm-i965-surface.c b/src/drm/cairo-drm-i965-surface.c
index 0891c95..ec7b595 100644
--- a/src/drm/cairo-drm-i965-surface.c
+++ b/src/drm/cairo-drm-i965-surface.c
@@ -695,11 +695,14 @@ i965_surface_finish (void *abstract_surface)
 }
 
 static cairo_status_t
-i965_surface_flush (void *abstract_surface)
+i965_surface_flush (void *abstract_surface, unsigned flags)
 {
     i965_surface_t *surface = abstract_surface;
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
+    if (flags)
+	return CAIRO_STATUS_SUCCESS;
+
     if (surface->intel.drm.fallback != NULL)
 	return intel_surface_flush (abstract_surface);
 
diff --git a/src/drm/cairo-drm-intel-private.h b/src/drm/cairo-drm-intel-private.h
index 7fe3623..343270a 100644
--- a/src/drm/cairo-drm-intel-private.h
+++ b/src/drm/cairo-drm-intel-private.h
@@ -394,7 +394,8 @@ cairo_private cairo_surface_t *
 intel_surface_map_to_image (void *abstract_surface);
 
 cairo_private cairo_status_t
-intel_surface_flush (void *abstract_surface);
+intel_surface_flush (void *abstract_surface,
+		     unsigned flags);
 
 cairo_private cairo_status_t
 intel_surface_finish (void *abstract_surface);
diff --git a/src/drm/cairo-drm-intel-surface.c b/src/drm/cairo-drm-intel-surface.c
index fe98759..88f5b8f 100644
--- a/src/drm/cairo-drm-intel-surface.c
+++ b/src/drm/cairo-drm-intel-surface.c
@@ -157,11 +157,14 @@ intel_surface_map_to_image (void *abstract_surface)
 }
 
 cairo_status_t
-intel_surface_flush (void *abstract_surface)
+intel_surface_flush (void *abstract_surface, unsigned flags)
 {
     intel_surface_t *surface = abstract_surface;
     cairo_status_t status;
 
+    if (flags)
+	return CAIRO_STATUS_SUCCESS;
+
     if (surface->drm.fallback == NULL)
 	return CAIRO_STATUS_SUCCESS;
 
diff --git a/src/drm/cairo-drm-radeon-surface.c b/src/drm/cairo-drm-radeon-surface.c
index 9f46ca1..6dbddaa 100644
--- a/src/drm/cairo-drm-radeon-surface.c
+++ b/src/drm/cairo-drm-radeon-surface.c
@@ -159,11 +159,15 @@ radeon_surface_map_to_image (radeon_surface_t *surface)
 }
 
 static cairo_status_t
-radeon_surface_flush (void *abstract_surface)
+radeon_surface_flush (void *abstract_surface,
+		      unsigned flags)
 {
     radeon_surface_t *surface = abstract_surface;
     cairo_status_t status;
 
+    if (flags)
+	return CAIRO_STATUS_SUCCESS;
+
     if (surface->base.fallback == NULL)
 	return CAIRO_STATUS_SUCCESS;
 
diff --git a/src/win32/cairo-win32-display-surface.c b/src/win32/cairo-win32-display-surface.c
index 0d4c5f9..5353fd5 100644
--- a/src/win32/cairo-win32-display-surface.c
+++ b/src/win32/cairo-win32-display-surface.c
@@ -503,11 +503,14 @@ _cairo_win32_display_surface_unmap_image (void                    *abstract_surf
 }
 
 static cairo_status_t
-_cairo_win32_display_surface_flush (void *abstract_surface)
+_cairo_win32_display_surface_flush (void *abstract_surface, unsigned flags)
 {
     cairo_win32_display_surface_t *surface = abstract_surface;
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
+    if (flags)
+	return CAIRO_STATUS_SUCCESS;
+
     TRACE ((stderr, "%s (surface=%d)\n",
 	    __FUNCTION__, surface->win32.base.unique_id));
     if (surface->fallback == NULL)
diff --git a/src/win32/cairo-win32-gdi-compositor.c b/src/win32/cairo-win32-gdi-compositor.c
index 39db674..c70b0f9 100644
--- a/src/win32/cairo-win32-gdi-compositor.c
+++ b/src/win32/cairo-win32-gdi-compositor.c
@@ -236,7 +236,7 @@ copy_boxes (cairo_win32_display_surface_t *dst,
     if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    status = _cairo_surface_flush (surface);
+    status = __cairo_surface_flush (surface, 0);
     if (status)
 	return status;
 
@@ -360,7 +360,7 @@ alpha_blend_boxes (cairo_win32_display_surface_t *dst,
     if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    status = _cairo_surface_flush (&src->win32.base);
+    status = __cairo_surface_flush (&src->win32.base, 0);
     if (status)
 	return status;
 


More information about the cairo-commit mailing list