[cairo-commit] 64 commits - boilerplate/cairo-boilerplate.c boilerplate/cairo-boilerplate-drm.c boilerplate/cairo-boilerplate-gl.c boilerplate/cairo-boilerplate-pdf.c boilerplate/cairo-boilerplate-ps.c boilerplate/cairo-boilerplate-qt.cpp boilerplate/cairo-boilerplate-script.c boilerplate/cairo-boilerplate-xcb.c boilerplate/Makefile.win32.features build/configure.ac.features build/Makefile.win32.features build/Makefile.win32.features-h configure.ac .gitignore perf/cairo-perf-trace.c perf/.gitignore perf/Makefile.am src/cairo-analysis-surface.c src/cairo-array.c src/cairo-base64-stream.c src/cairo-base85-stream.c src/cairo-bentley-ottmann.c src/cairo-bentley-ottmann-rectangular.c src/cairo-bentley-ottmann-rectilinear.c src/cairo-beos-surface.cpp src/cairo-botor-scan-converter.c src/cairo-boxes.c src/cairo-boxes-private.h src/cairo.c src/cairo-cache.c src/cairo-cff-subset.c src/cairo-clip.c src/cairo-clip-private.h src/cairo-color.c src/cairo-compiler-private.h src/cairo-composite-rectangles.c src/cairo-composite-rectangles-private.h src/cairo-debug.c src/cairo-deflate-stream.c src/cairo-device.c src/cairo-device-private.h src/cairo-directfb-surface.c src/cairo-drm.h src/cairo-eagle-context.c src/cairo-error-private.h src/cairo-fixed-private.h src/cairo-font-face.c src/cairo-font-face-twin.c src/cairo-font-options.c src/cairo-freed-pool.c src/cairo-freed-pool-private.h src/cairo-freelist.c src/cairo-freelist-private.h src/cairo-ft-font.c src/cairo-gl-glyphs.c src/cairo-gl.h src/cairo-glitz-surface.c src/cairo-gl-private.h src/cairo-gl-shaders.c src/cairo-gl-surface.c src/cairo-glx-context.c src/cairo-gstate.c src/cairo.h src/cairo-hash.c src/cairo-hull.c src/cairo-image-surface.c src/cairoint.h src/cairo-list-private.h src/cairo-lzw.c src/cairo-matrix.c src/cairo-misc.c src/cairo-mutex-impl-private.h src/cairo-mutex-list-private.h src/cairo-mutex-type-private.h src/cairo-os2-surface.c src/cairo-output-stream.c src/cairo-paginated-surface.c src/cairo-path-bounds.c src/cairo-path.c src/cairo-path-fill.c src/cairo-path-fixed.c src/cairo-path-fixed-private.h src/cairo-path-stroke.c src/cairo-pattern.c src/cairo-pdf-operators.c src/cairo-pdf-operators-private.h src/cairo-pdf-surface.c src/cairo-pdf-surface-private.h src/cairo-pen.c src/cairo-png.c src/cairo-polygon.c src/cairo-ps-surface.c src/cairo-qt-surface.cpp src/cairo-quartz-font.c src/cairo-quartz-image-surface.c src/cairo-quartz-surface.c src/cairo-recording-surface.c src/cairo-rectangle.c src/cairo-rectangular-scan-converter.c src/cairo-region.c src/cairo-rtree.c src/cairo-scaled-font.c src/cairo-scaled-font-subsets.c src/cairo-script.h src/cairo-script-surface.c src/cairo-skia-surface.cpp src/cairo-spans.c src/cairo-spans-private.h src/cairo-stroke-style.c src/cairo-surface.c src/cairo-surface-fallback.c src/cairo-surface-fallback-private.h src/cairo-surface-offset.c src/cairo-surface-offset-private.h src/cairo-surface-private.h src/cairo-surface-snapshot.c src/cairo-surface-snapshot-private.h src/cairo-surface-subsurface.c src/cairo-surface-subsurface-private.h src/cairo-surface-wrapper.c src/cairo-surface-wrapper-private.h src/cairo-svg-surface.c src/cairo-tee-surface.c src/cairo-tor-scan-converter.c src/cairo-toy-font-face.c src/cairo-traps.c src/cairo-truetype-subset.c src/cairo-type1-fallback.c src/cairo-type1-subset.c src/cairo-type3-glyph-surface.c src/cairo-types-private.h src/cairo-unicode.c src/cairo-user-font.c src/cairo-vg-surface.c src/cairo-win32-font.c src/cairo-win32-printing-surface.c src/cairo-win32-surface.c src/cairo-xcb-connection.c src/cairo-xcb-connection-core.c src/cairo-xcb-connection-render.c src/cairo-xcb-connection-shm.c src/cairo-xcb.h src/cairo-xcb-private.h src/cairo-xcb-screen.c src/cairo-xcb-shm.c src/cairo-xcb-surface.c src/cairo-xcb-surface-cairo.c src/cairo-xcb-surface-core.c src/cairo-xcb-surface-private.h src/cairo-xcb-surface-render.c src/cairo-xcb-xrender.h src/cairo-xlib-display.c src/cairo-xlib-screen.c src/cairo-xlib-surface.c src/cairo-xlib-visual.c src/cairo-xlib-xcb-surface.c src/cairo-xml.h src/cairo-xml-surface.c src/drm src/glew src/Makefile.sources src/Makefile.win32.features src/test-fallback16-surface.c src/test-fallback-surface.c src/test-null-surface.c src/test-paginated-surface.c src/test-wrapping-surface.c test/any2ppm.c test/cairo-test-trace.c test/clear-source.c test/clear-source.ref.png test/clip-fill-unbounded.argb32.ref.png test/clip-fill-unbounded.rgb24.ref.png test/clipped-group.ref.png test/clip-stroke.ref.png test/clip-stroke-unbounded.argb32.ref.png test/clip-stroke-unbounded.rgb24.ref.png test/leaky-dashed-rectangle.ref.png test/Makefile.am test/Makefile.sources test/pthread-same-source.c test/pthread-same-source.ref.png test/pthread-similar.c test/pthread-similar.ref.png test/rounded-rectangle-fill.c test/rounded-rectangle-fill.xlib.ref.png test/rounded-rectangle-stroke.c test/rounded-rectangle-stroke.xlib.ref.png test/scale-offset-image.xfail.png test/scale-offset-similar.xfail.png test/self-intersecting.ref.png test/subsurface.c test/subsurface.ref.png test/subsurface-repeat.c test/subsurface-repeat.ref.png test/subsurface-similar-repeat.c test/subsurface-similar-repeat.ref.png test/text-rotate.c test/text-rotate.ref.png test/xcb-surface-source.argb32.ref.png test/xcb-surface-source.c test/xcb-surface-source.rgb24.ref.png test/xlib-surface-source.c util/cairo-fdr util/cairo-script util/cairo-sphinx util/cairo-trace util/.gitignore util/trace-to-xml.c

Chris Wilson ickle at kemper.freedesktop.org
Fri Jan 22 15:06:05 PST 2010


 .gitignore                                   |    1 
 boilerplate/Makefile.win32.features          |   20 
 boilerplate/cairo-boilerplate-drm.c          |    2 
 boilerplate/cairo-boilerplate-gl.c           |  127 
 boilerplate/cairo-boilerplate-pdf.c          |    4 
 boilerplate/cairo-boilerplate-ps.c           |    4 
 boilerplate/cairo-boilerplate-qt.cpp         |    2 
 boilerplate/cairo-boilerplate-script.c       |    6 
 boilerplate/cairo-boilerplate-xcb.c          |  522 +++
 boilerplate/cairo-boilerplate.c              |    6 
 build/Makefile.win32.features                |    2 
 build/Makefile.win32.features-h              |    6 
 build/configure.ac.features                  |    2 
 configure.ac                                 |   29 
 perf/.gitignore                              |    1 
 perf/Makefile.am                             |    3 
 perf/cairo-perf-trace.c                      |  141 
 src/Makefile.sources                         |   56 
 src/Makefile.win32.features                  |   28 
 src/cairo-analysis-surface.c                 |   22 
 src/cairo-array.c                            |    1 
 src/cairo-base64-stream.c                    |    1 
 src/cairo-base85-stream.c                    |    1 
 src/cairo-bentley-ottmann-rectangular.c      |  779 ++--
 src/cairo-bentley-ottmann-rectilinear.c      |  123 
 src/cairo-bentley-ottmann.c                  |    1 
 src/cairo-beos-surface.cpp                   |    7 
 src/cairo-botor-scan-converter.c             | 2199 +++++++++++++
 src/cairo-boxes-private.h                    |   80 
 src/cairo-boxes.c                            |  269 +
 src/cairo-cache.c                            |    1 
 src/cairo-cff-subset.c                       |    1 
 src/cairo-clip-private.h                     |    6 
 src/cairo-clip.c                             |  369 --
 src/cairo-color.c                            |   13 
 src/cairo-compiler-private.h                 |   11 
 src/cairo-composite-rectangles-private.h     |  105 
 src/cairo-composite-rectangles.c             |  197 +
 src/cairo-debug.c                            |    6 
 src/cairo-deflate-stream.c                   |    1 
 src/cairo-device-private.h                   |   85 
 src/cairo-device.c                           |  265 +
 src/cairo-directfb-surface.c                 |    3 
 src/cairo-drm.h                              |   31 
 src/cairo-eagle-context.c                    |   26 
 src/cairo-error-private.h                    |   60 
 src/cairo-fixed-private.h                    |   22 
 src/cairo-font-face-twin.c                   |    1 
 src/cairo-font-face.c                        |    1 
 src/cairo-font-options.c                     |    1 
 src/cairo-freed-pool-private.h               |  121 
 src/cairo-freed-pool.c                       |   91 
 src/cairo-freelist-private.h                 |   16 
 src/cairo-freelist.c                         |   39 
 src/cairo-ft-font.c                          |   32 
 src/cairo-gl-glyphs.c                        |   58 
 src/cairo-gl-private.h                       |   43 
 src/cairo-gl-shaders.c                       |    1 
 src/cairo-gl-surface.c                       |  391 +-
 src/cairo-gl.h                               |   22 
 src/cairo-glitz-surface.c                    |    6 
 src/cairo-glx-context.c                      |   27 
 src/cairo-gstate.c                           |  135 
 src/cairo-hash.c                             |    1 
 src/cairo-hull.c                             |    1 
 src/cairo-image-surface.c                    | 3970 ++++++++++++++++++++---
 src/cairo-list-private.h                     |    7 
 src/cairo-lzw.c                              |    1 
 src/cairo-matrix.c                           |    5 
 src/cairo-misc.c                             |  105 
 src/cairo-mutex-impl-private.h               |   28 
 src/cairo-mutex-list-private.h               |    6 
 src/cairo-mutex-type-private.h               |    9 
 src/cairo-os2-surface.c                      |    2 
 src/cairo-output-stream.c                    |    1 
 src/cairo-paginated-surface.c                |   18 
 src/cairo-path-bounds.c                      |  159 
 src/cairo-path-fill.c                        |   77 
 src/cairo-path-fixed-private.h               |    4 
 src/cairo-path-fixed.c                       |   84 
 src/cairo-path-stroke.c                      |  231 +
 src/cairo-path.c                             |    1 
 src/cairo-pattern.c                          |  237 -
 src/cairo-pdf-operators-private.h            |   24 
 src/cairo-pdf-operators.c                    |   39 
 src/cairo-pdf-surface-private.h              |   11 
 src/cairo-pdf-surface.c                      |  265 -
 src/cairo-pen.c                              |    1 
 src/cairo-png.c                              |    2 
 src/cairo-polygon.c                          |    1 
 src/cairo-ps-surface.c                       |  279 -
 src/cairo-qt-surface.cpp                     |   27 
 src/cairo-quartz-font.c                      |    2 
 src/cairo-quartz-image-surface.c             |    3 
 src/cairo-quartz-surface.c                   |   14 
 src/cairo-recording-surface.c                |   21 
 src/cairo-rectangle.c                        |   21 
 src/cairo-rectangular-scan-converter.c       |  723 ++++
 src/cairo-region.c                           |    1 
 src/cairo-rtree.c                            |    1 
 src/cairo-scaled-font-subsets.c              |    3 
 src/cairo-scaled-font.c                      |   67 
 src/cairo-script-surface.c                   |  510 +--
 src/cairo-script.h                           |   35 
 src/cairo-skia-surface.cpp                   |    1 
 src/cairo-spans-private.h                    |   72 
 src/cairo-spans.c                            |   39 
 src/cairo-stroke-style.c                     |    3 
 src/cairo-surface-fallback-private.h         |    6 
 src/cairo-surface-fallback.c                 |  432 --
 src/cairo-surface-offset-private.h           |   95 
 src/cairo-surface-offset.c                   |  354 ++
 src/cairo-surface-private.h                  |    1 
 src/cairo-surface-snapshot-private.h         |   48 
 src/cairo-surface-snapshot.c                 |  226 +
 src/cairo-surface-subsurface-private.h       |   48 
 src/cairo-surface-subsurface.c               |  465 ++
 src/cairo-surface-wrapper-private.h          |   12 
 src/cairo-surface-wrapper.c                  |  147 
 src/cairo-surface.c                          |  165 
 src/cairo-svg-surface.c                      |   45 
 src/cairo-tee-surface.c                      |    8 
 src/cairo-tor-scan-converter.c               |  344 +-
 src/cairo-toy-font-face.c                    |    1 
 src/cairo-traps.c                            |   48 
 src/cairo-truetype-subset.c                  |    1 
 src/cairo-type1-fallback.c                   |    1 
 src/cairo-type1-subset.c                     |    1 
 src/cairo-type3-glyph-surface.c              |   11 
 src/cairo-types-private.h                    |   60 
 src/cairo-unicode.c                          |    1 
 src/cairo-user-font.c                        |    1 
 src/cairo-vg-surface.c                       |   12 
 src/cairo-win32-font.c                       |    1 
 src/cairo-win32-printing-surface.c           |   16 
 src/cairo-win32-surface.c                    |   41 
 src/cairo-xcb-connection-core.c              |  482 ++
 src/cairo-xcb-connection-render.c            |  969 +++++
 src/cairo-xcb-connection-shm.c               |  194 +
 src/cairo-xcb-connection.c                   |  867 +++++
 src/cairo-xcb-private.h                      |  760 ++++
 src/cairo-xcb-screen.c                       |  518 +++
 src/cairo-xcb-shm.c                          |  576 +++
 src/cairo-xcb-surface-cairo.c                |   94 
 src/cairo-xcb-surface-core.c                 |  613 +++
 src/cairo-xcb-surface-private.h              |   37 
 src/cairo-xcb-surface-render.c               | 4471 +++++++++++++++++++++++++++
 src/cairo-xcb-surface.c                      | 3354 +++++---------------
 src/cairo-xcb-xrender.h                      |   63 
 src/cairo-xcb.h                              |   41 
 src/cairo-xlib-display.c                     |    1 
 src/cairo-xlib-screen.c                      |    1 
 src/cairo-xlib-surface.c                     |   19 
 src/cairo-xlib-visual.c                      |    2 
 src/cairo-xlib-xcb-surface.c                 |  515 +++
 src/cairo-xml-surface.c                      |  216 -
 src/cairo-xml.h                              |   13 
 src/cairo.c                                  |    3 
 src/cairo.h                                  |  124 
 src/cairoint.h                               |  200 -
 src/drm/cairo-drm-bo.c                       |   14 
 src/drm/cairo-drm-gallium-surface.c          |    1 
 src/drm/cairo-drm-i915-glyphs.c              |  534 +++
 src/drm/cairo-drm-i915-private.h             | 1169 +++++++
 src/drm/cairo-drm-i915-shader.c              | 2674 ++++++++++++++++
 src/drm/cairo-drm-i915-spans.c               |  708 ++++
 src/drm/cairo-drm-i915-surface.c             | 1996 ++++++++++++
 src/drm/cairo-drm-i965-glyphs.c              |  500 +++
 src/drm/cairo-drm-i965-private.h             |  742 ++++
 src/drm/cairo-drm-i965-shader.c              | 2852 +++++++++++++++++
 src/drm/cairo-drm-i965-spans.c               |  408 ++
 src/drm/cairo-drm-i965-surface.c             | 1949 +++++++++++
 src/drm/cairo-drm-intel-brw-defines.h        |  824 ++++
 src/drm/cairo-drm-intel-brw-eu-emit.c        | 1089 ++++++
 src/drm/cairo-drm-intel-brw-eu-util.c        |  121 
 src/drm/cairo-drm-intel-brw-eu.c             |  250 +
 src/drm/cairo-drm-intel-brw-eu.h             | 1043 ++++++
 src/drm/cairo-drm-intel-brw-structs.h        | 1328 ++++++++
 src/drm/cairo-drm-intel-command-private.h    |  909 +++++
 src/drm/cairo-drm-intel-debug.c              | 1208 +++++++
 src/drm/cairo-drm-intel-ioctl-private.h      |  417 ++
 src/drm/cairo-drm-intel-private.h            |  427 ++
 src/drm/cairo-drm-intel-surface.c            |  424 +-
 src/drm/cairo-drm-intel.c                    | 1241 +++++--
 src/drm/cairo-drm-private.h                  |  101 
 src/drm/cairo-drm-radeon-private.h           |    3 
 src/drm/cairo-drm-radeon-surface.c           |  288 -
 src/drm/cairo-drm-radeon.c                   |    6 
 src/drm/cairo-drm-surface.c                  |  236 -
 src/drm/cairo-drm.c                          |  233 -
 src/glew/GL/glew.h                           |    2 
 src/glew/glew.c                              |    9 
 src/test-fallback-surface.c                  |    5 
 src/test-fallback16-surface.c                |    2 
 src/test-null-surface.c                      |   13 
 src/test-paginated-surface.c                 |   11 
 src/test-wrapping-surface.c                  |    8 
 test/Makefile.am                             |   17 
 test/Makefile.sources                        |   15 
 test/any2ppm.c                               |    4 
 test/cairo-test-trace.c                      |    7 
 test/clear-source.c                          |  163 
 test/clear-source.ref.png                    |binary
 test/clip-fill-unbounded.argb32.ref.png      |binary
 test/clip-fill-unbounded.rgb24.ref.png       |binary
 test/clip-stroke-unbounded.argb32.ref.png    |binary
 test/clip-stroke-unbounded.rgb24.ref.png     |binary
 test/clip-stroke.ref.png                     |binary
 test/clipped-group.ref.png                   |binary
 test/leaky-dashed-rectangle.ref.png          |binary
 test/pthread-same-source.c                   |  160 
 test/pthread-same-source.ref.png             |binary
 test/pthread-similar.c                       |  106 
 test/pthread-similar.ref.png                 |binary
 test/rounded-rectangle-fill.c                |   65 
 test/rounded-rectangle-fill.xlib.ref.png     |binary
 test/rounded-rectangle-stroke.c              |   64 
 test/rounded-rectangle-stroke.xlib.ref.png   |binary
 test/scale-offset-image.xfail.png            |binary
 test/scale-offset-similar.xfail.png          |binary
 test/self-intersecting.ref.png               |binary
 test/subsurface-repeat.c                     |   72 
 test/subsurface-repeat.ref.png               |binary
 test/subsurface-similar-repeat.c             |   83 
 test/subsurface-similar-repeat.ref.png       |binary
 test/subsurface.c                            |   80 
 test/subsurface.ref.png                      |binary
 test/text-rotate.c                           |   68 
 test/text-rotate.ref.png                     |binary
 test/xcb-surface-source.argb32.ref.png       |binary
 test/xcb-surface-source.c                    |  144 
 test/xcb-surface-source.rgb24.ref.png        |binary
 test/xlib-surface-source.c                   |    5 
 util/.gitignore                              |    2 
 util/cairo-fdr/fdr.c                         |   10 
 util/cairo-script/.gitignore                 |    1 
 util/cairo-script/cairo-script-interpreter.h |    3 
 util/cairo-script/cairo-script-operators.c   |  103 
 util/cairo-script/csi-trace.c                |   11 
 util/cairo-sphinx/fdr.c                      |    4 
 util/cairo-sphinx/sphinx.c                   |   20 
 util/cairo-trace/trace.c                     |   10 
 util/trace-to-xml.c                          |    7 
 243 files changed, 48168 insertions(+), 7269 deletions(-)

New commits:
commit 2a466ba07072cb394cfc955cfb0633b0cc278044
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jan 22 22:26:52 2010 +0000

    script: Encode octal values correctly.
    
    Oops, we were emitting the octal numerals in reverse order.

diff --git a/src/cairo-script-surface.c b/src/cairo-script-surface.c
index 53cfb7a..af4abbc 100644
--- a/src/cairo-script-surface.c
+++ b/src/cairo-script-surface.c
@@ -2841,6 +2841,15 @@ _emit_scaled_glyphs (cairo_script_surface_t *surface,
 }
 
 static void
+to_octal (int value, char *buf, size_t size)
+{
+    do {
+	buf[--size] = '0' + (value & 7);
+	value >>= 3;
+    } while (size);
+}
+
+static void
 _emit_string_literal (cairo_script_surface_t *surface,
 		      const char *utf8, int len)
 {
@@ -2885,14 +2894,10 @@ ESCAPED_CHAR:
 	    if (isprint (c) || isspace (c)) {
 		_cairo_output_stream_printf (ctx->stream, "%c", c);
 	    } else {
-		int octal = 0;
-		while (c) {
-		    octal *= 10;
-		    octal += c&7;
-		    c /= 8;
-		}
-		_cairo_output_stream_printf (ctx->stream,
-					     "\\%03d", octal);
+		char buf[4] = { '\\' };
+
+		to_octal (c, buf+1, 3);
+		_cairo_output_stream_write (ctx->stream, buf, 4);
 	    }
 	    break;
 	}
commit 87529198aa37f5eb5943eb80cc1aae858fdaadd0
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jan 22 22:21:44 2010 +0000

    scaled-font: Mark an error site with _cairo_error()

diff --git a/src/cairo-scaled-font-subsets.c b/src/cairo-scaled-font-subsets.c
index e911f31..228b65a 100644
--- a/src/cairo-scaled-font-subsets.c
+++ b/src/cairo-scaled-font-subsets.c
@@ -401,7 +401,7 @@ _cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph,
 	    /* No existing mapping. Use the requested mapping */
 	    sub_font_glyph->utf8 = malloc (utf8_len + 1);
 	    if (unlikely (sub_font_glyph->utf8 == NULL))
-		return CAIRO_STATUS_NO_MEMORY;
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
 	    memcpy (sub_font_glyph->utf8, utf8, utf8_len);
 	    sub_font_glyph->utf8[utf8_len] = 0;
commit 6544f3b25d2120b7bd04f6c956c2ea7b9c101c76
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jan 22 22:15:25 2010 +0000

    ps: Wean off the low-level image composite interface
    
    The low-level surface composite interface will disappear in the near
    future and results in much more ugly code than calling the high level
    interface - so use it when flattening images into the page background.

diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index cafa430..bbe44af 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -1662,7 +1662,7 @@ surface_pattern_supported (const cairo_surface_pattern_t *pattern)
      * don't think it's worth the extra code to support it. */
 
 /* XXX: Need to write this function here...
-    content = cairo_surface_get_content (pattern->surface);
+    content = pattern->surface->content;
     if (content == CAIRO_CONTENT_ALPHA)
 	return FALSE;
 */
@@ -1974,55 +1974,36 @@ _cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t    *surface,
 					      cairo_image_surface_t *image,
 					      cairo_image_surface_t **opaque_image)
 {
-    const cairo_color_t *background_color;
     cairo_surface_t *opaque;
     cairo_surface_pattern_t pattern;
     cairo_status_t status;
 
-    if (surface->content == CAIRO_CONTENT_COLOR_ALPHA)
-	background_color = CAIRO_COLOR_WHITE;
-    else
-	background_color = CAIRO_COLOR_BLACK;
-
     opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
 					 image->width,
 					 image->height);
-    if (opaque->status)
+    if (unlikely (opaque->status))
 	return opaque->status;
 
-    _cairo_pattern_init_for_surface (&pattern, &image->base);
-
-    status = _cairo_surface_fill_rectangle (opaque,
-					    CAIRO_OPERATOR_SOURCE,
-					    background_color,
-					    0, 0,
-					    image->width, image->height);
-    if (unlikely (status))
-	goto fail;
-
-    status = _cairo_surface_composite (CAIRO_OPERATOR_OVER,
-				       &pattern.base,
-				       NULL,
-				       opaque,
-				       0, 0,
-				       0, 0,
-				       0, 0,
-				       image->width,
-				       image->height,
+    if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) {
+	status = _cairo_surface_paint (opaque,
+				       CAIRO_OPERATOR_SOURCE,
+				       &_cairo_pattern_white.base,
 				       NULL);
-    if (unlikely (status))
-	goto fail;
+	if (unlikely (status)) {
+	    cairo_surface_destroy (opaque);
+	    return status;
+	}
+    }
 
+    _cairo_pattern_init_for_surface (&pattern, &image->base);
+    pattern.base.filter = CAIRO_FILTER_NEAREST;
+    status = _cairo_surface_paint (opaque, CAIRO_OPERATOR_OVER, &pattern.base, NULL);
     _cairo_pattern_fini (&pattern.base);
-    *opaque_image = (cairo_image_surface_t *) opaque;
+    if (unlikely (status))
+	return status;
 
+    *opaque_image = (cairo_image_surface_t *) opaque;
     return CAIRO_STATUS_SUCCESS;
-
-fail:
-    _cairo_pattern_fini (&pattern.base);
-    cairo_surface_destroy (opaque);
-
-    return status;
 }
 
 static cairo_status_t
@@ -2448,7 +2429,7 @@ _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface,
 						  &surface->cairo_to_ps);
     _cairo_output_stream_printf (surface->stream, "  q\n");
 
-    if (cairo_surface_get_content (recording_surface) == CAIRO_CONTENT_COLOR) {
+    if (recording_surface->content == CAIRO_CONTENT_COLOR) {
 	surface->content = CAIRO_CONTENT_COLOR;
 	_cairo_output_stream_printf (surface->stream,
 				     "  0 g %d %d %d %d rectfill\n",
@@ -2575,9 +2556,11 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t      *surface,
 	    x = -rect.x;
 	    y = -rect.y;
 
-	    pad_image = _cairo_image_surface_create_with_content (pattern->surface->content,
-								  rect.width,
-								  rect.height);
+	    pad_image =
+		_cairo_image_surface_create_with_pixman_format (NULL,
+								surface->acquired_image->pixman_format,
+								rect.width, rect.height,
+								0);
 	    if (pad_image->status) {
 		status = pad_image->status;
 		goto BAIL;
@@ -2586,16 +2569,10 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t      *surface,
 	    _cairo_pattern_init_for_surface (&pad_pattern, &surface->acquired_image->base);
 	    cairo_matrix_init_translate (&pad_pattern.base.matrix, -x, -y);
 	    pad_pattern.base.extend = CAIRO_EXTEND_PAD;
-	    status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
-					       &pad_pattern.base,
-					       NULL,
-					       pad_image,
-					       0, 0,
-					       0, 0,
-					       0, 0,
-					       rect.width,
-					       rect.height,
-					       NULL);
+	    status = _cairo_surface_paint (pad_image,
+					   CAIRO_OPERATOR_SOURCE,
+					   &pad_pattern.base,
+					   NULL);
 	    _cairo_pattern_fini (&pad_pattern.base);
 	    if (unlikely (status)) {
 		if (pad_image != &surface->acquired_image->base)
commit f57cb45fa9274351b36f96eb932a931493b5db94
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jan 22 22:18:35 2010 +0000

    ps: Arguments to fill_extents() were reversed.

diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index b7f3aa2..cafa430 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -3605,7 +3605,8 @@ _cairo_ps_surface_fill (void		*abstract_surface,
     /* use the more accurate extents */
     if (extents.is_bounded) {
 	_cairo_path_fixed_fill_extents (path,
-					tolerance, fill_rule,
+					fill_rule,
+					tolerance,
 					&extents.mask);
 
 	if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
commit 58540405d9bc6581c1d07f17bd5aee330f06d4a2
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jan 22 22:05:37 2010 +0000

    pdf: Arguments to fill_extents() were reversed.

diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 2b6ebc3..f0bdebd 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -5666,7 +5666,8 @@ _cairo_pdf_surface_fill (void			*abstract_surface,
     /* use the more accurate extents */
     if (extents.is_bounded) {
 	_cairo_path_fixed_fill_extents (path,
-					tolerance, fill_rule,
+					fill_rule,
+					tolerance,
 					&extents.mask);
 
 	if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
commit 34dd80632e4671f0ca245be9db4280db62bdb1f9
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Jan 21 18:39:26 2010 +0000

    glew: Silence compiler.

diff --git a/src/glew/GL/glew.h b/src/glew/GL/glew.h
index 7932a1c..e398287 100644
--- a/src/glew/GL/glew.h
+++ b/src/glew/GL/glew.h
@@ -12222,7 +12222,7 @@ GLEWAPI GLboolean glewContextIsSupported (GLEWContext* ctx, const char* name);
 
 #else /* GLEW_MX */
 
-GLEWAPI GLenum glewInit ();
+GLEWAPI GLenum glewInit (void);
 GLEWAPI GLboolean glewIsSupported (const char* name);
 #define glewIsExtensionSupported(x) glewIsSupported(x)
 
diff --git a/src/glew/glew.c b/src/glew/glew.c
index 0690583..6ef6d22 100644
--- a/src/glew/glew.c
+++ b/src/glew/glew.c
@@ -8857,7 +8857,7 @@ GLboolean glxewGetExtension (const char* name)
   return GL_FALSE;
 }
 
-GLenum glxewContextInit (GLXEW_CONTEXT_ARG_DEF_LIST)
+static GLenum glxewContextInit (GLXEW_CONTEXT_ARG_DEF_LIST)
 {
   int major, minor;
 
@@ -9102,7 +9102,7 @@ extern GLenum wglewContextInit (void);
 extern GLenum glxewContextInit (void);
 #endif /* _WIN32 */
 
-GLenum glewInit ()
+GLenum glewInit (void)
 {
   GLenum r;
   if ( (r = glewContextInit()) ) return r;
commit cf9ea9f2f0ea1e1b42dc1507ed0dac4dfbf5d387
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Jan 21 18:39:12 2010 +0000

    gl: Acquire the context whilst creating surfaces.

diff --git a/src/cairo-gl-private.h b/src/cairo-gl-private.h
index 91f1bd4..d08e545 100644
--- a/src/cairo-gl-private.h
+++ b/src/cairo-gl-private.h
@@ -158,7 +158,7 @@ _cairo_gl_operand_init (cairo_gl_composite_operand_t *operand,
 			int dst_x, int dst_y,
 			int width, int height);
 
-static inline cairo_status_t cairo_warn
+static always_inline cairo_status_t cairo_warn
 _cairo_gl_context_acquire (cairo_device_t *device,
 			   cairo_gl_context_t **ctx)
 {
@@ -172,13 +172,12 @@ _cairo_gl_context_acquire (cairo_device_t *device,
     return CAIRO_STATUS_SUCCESS;
 }
 
-static inline void
+static always_inline void
 _cairo_gl_context_release (cairo_gl_context_t *ctx)
 {
     cairo_device_release (&ctx->base);
 }
 
-
 cairo_private void
 _cairo_gl_set_destination (cairo_gl_surface_t *surface);
 
diff --git a/src/cairo-gl-surface.c b/src/cairo-gl-surface.c
index 35b946c..5c57bed 100644
--- a/src/cairo-gl-surface.c
+++ b/src/cairo-gl-surface.c
@@ -414,9 +414,6 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
     GLenum err, format;
     cairo_status_t status;
 
-    if (ctx->base.status)
-	return _cairo_surface_create_in_error (ctx->base.status);
-
     assert (width <= ctx->max_framebuffer_size && height <= ctx->max_framebuffer_size);
 
     surface = calloc (1, sizeof (cairo_gl_surface_t));
@@ -425,6 +422,12 @@ _cairo_gl_surface_create_scratch (cairo_gl_context_t   *ctx,
 
     _cairo_gl_surface_init (&ctx->base, surface, content, width, height);
 
+    /* adjust the texture size after setting our real extents */
+    if (width < 1)
+	width = 1;
+    if (height < 1)
+	height = 1;
+
     switch (content) {
     default:
 	ASSERT_NOT_REACHED;
@@ -523,15 +526,22 @@ cairo_gl_surface_create (cairo_device_t		*abstract_device,
     if (ctx->base.backend->type != CAIRO_DEVICE_TYPE_GL)
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
 
+    status = _cairo_gl_context_acquire (abstract_device, &ctx);
+    if (unlikely (status))
+	return _cairo_surface_create_in_error (status);
+
     surface = (cairo_gl_surface_t *)
 	_cairo_gl_surface_create_scratch (ctx, content, width, height);
-    if (unlikely (surface->base.status))
+    if (unlikely (surface->base.status)) {
+	_cairo_gl_context_release (ctx);
 	return &surface->base;
+    }
 
     /* Cairo surfaces start out initialized to transparent (black) */
     status = _cairo_gl_surface_clear (surface);
     if (unlikely (status)) {
 	cairo_surface_destroy (&surface->base);
+	_cairo_gl_context_release (ctx);
 	return _cairo_surface_create_in_error (status);
     }
 
@@ -603,10 +613,9 @@ _cairo_gl_surface_create_similar (void		 *abstract_surface,
 				  int		  width,
 				  int		  height)
 {
-    cairo_gl_surface_t *surface = abstract_surface;
-    cairo_gl_context_t *ctx = (cairo_gl_context_t *) surface->base.device;
-
-    assert (CAIRO_CONTENT_VALID (content));
+    cairo_surface_t *surface = abstract_surface;
+    cairo_gl_context_t *ctx = (cairo_gl_context_t *) surface->device;
+    cairo_status_t status;
 
     if (width > ctx->max_framebuffer_size ||
 	height > ctx->max_framebuffer_size)
@@ -614,12 +623,14 @@ _cairo_gl_surface_create_similar (void		 *abstract_surface,
 	return NULL;
     }
 
-    if (width < 1)
-	width = 1;
-    if (height < 1)
-	height = 1;
+    status = _cairo_gl_context_acquire (surface->device, &ctx);
+    if (unlikely (status))
+	return _cairo_surface_create_in_error (status);
+
+    surface = _cairo_gl_surface_create_scratch (ctx, content, width, height);
+    _cairo_gl_context_release (ctx);
 
-    return _cairo_gl_surface_create_scratch (ctx, content, width, height);
+    return surface;
 }
 
 cairo_status_t
commit a7e05bd602e7f8bee63f5d32cb95d65628e6e715
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Jan 21 18:22:04 2010 +0000

    glew: Do not assume that UNIX == GLX

diff --git a/src/glew/glew.c b/src/glew/glew.c
index aa2278f..0690583 100644
--- a/src/glew/glew.c
+++ b/src/glew/glew.c
@@ -8860,8 +8860,13 @@ GLboolean glxewGetExtension (const char* name)
 GLenum glxewContextInit (GLXEW_CONTEXT_ARG_DEF_LIST)
 {
   int major, minor;
+
   /* initialize core GLX 1.2 */
   if (_glewInit_GLX_VERSION_1_2(GLEW_CONTEXT_ARG_VAR_INIT)) return GLEW_ERROR_GLX_VERSION_11_ONLY;
+
+  if (glXGetCurrentDisplay() == NULL)
+      return GLEW_OK;
+
   /* initialize flags */
   CONST_CAST(GLXEW_VERSION_1_0) = GL_TRUE;
   CONST_CAST(GLXEW_VERSION_1_1) = GL_TRUE;
commit c0008242b0f162d8c7717009ba792ed61b2924d1
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jan 22 21:35:23 2010 +0000

    misc: Only use custom lround() under DISABLE_SOME_FLOATING_POINT
    
    On my Core2, the library version of lround() is faster than our
    hand-rolled non-floating point implementation. So only enable our code
    if we are trying to minimise the number of floating point operations --
    even then, it would worth investigating the library performance first.
    
    [Just a reminder that optimisation choices will change over time as our
    hardware and software evolves.]

diff --git a/src/cairo-misc.c b/src/cairo-misc.c
index 56409af..32c2428 100644
--- a/src/cairo-misc.c
+++ b/src/cairo-misc.c
@@ -463,6 +463,7 @@ _cairo_operator_bounded_by_either (cairo_operator_t op)
 
 }
 
+#if DISABLE_SOME_FLOATING_POINT
 /* This function is identical to the C99 function lround(), except that it
  * performs arithmetic rounding (floor(d + .5) instead of away-from-zero rounding) and
  * has a valid input range of (INT_MIN, INT_MAX] instead of
@@ -673,6 +674,7 @@ _cairo_lround (double d)
 #undef MSW
 #undef LSW
 }
+#endif
 
 /* Convert a 32-bit IEEE single precision floating point number to a
  * 'half' representation (s10.5)
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 3e48ebb..b7f3aa2 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -880,8 +880,8 @@ _cairo_ps_surface_get_page_media (cairo_ps_surface_t     *surface)
 	page->name = strdup (page_name);
     } else {
 	snprintf (buf, sizeof (buf), "%dx%dmm",
-		  _cairo_lround (surface->width * 25.4/72),
-		  _cairo_lround (surface->height * 25.4/72));
+		  (int) _cairo_lround (surface->width * 25.4/72),
+		  (int) _cairo_lround (surface->height * 25.4/72));
 	page->name = strdup (buf);
     }
 
diff --git a/src/cairoint.h b/src/cairoint.h
index acc5769..9cd5cfa 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -947,8 +947,13 @@ _cairo_round (double r)
     return floor (r + .5);
 }
 
+#if DISABLE_SOME_FLOATING_POINT
 cairo_private int
 _cairo_lround (double d) cairo_const;
+#else
+#define _cairo_lround lround
+#endif
+
 cairo_private uint16_t
 _cairo_half_from_float (float f) cairo_const;
 
commit 1236c41072a7966eda7db48a381fd0508e5289be
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jan 22 21:26:26 2010 +0000

    xcb: Refresh.
    
    Still an experimental backend, it's now a little too late to stabilise
    for 1.10, but this should represent a major step forward in its feature
    set and an attempt to catch up with all the bug fixes that have been
    performed on xlib. Notably not tested yet (and expected to be broken)
    are mixed-endian connections and low bitdepth servers (the dithering
    support has not been copied over for instance). However, it seems robust
    enough for daily use...
    
    Of particular note in this update is that the xcb surface is now capable
    of subverting the xlib surface through the ./configure --enable-xlib-xcb
    option. This replaces the xlib surface with a proxy that forwards all
    operations to an equivalent xcb surface whilst preserving the cairo-xlib
    API that is required for compatibility with the existing applications,
    for instance GTK+ and Mozilla. Also you can experiment with enabling a
    DRM bypass, though you need to be extremely foolhardy to do so.

diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features
index 5c1e011..8d56411 100644
--- a/boilerplate/Makefile.win32.features
+++ b/boilerplate/Makefile.win32.features
@@ -49,6 +49,16 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_xcb_private)
 enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_sources)
 endif
 
+unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xcb_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xcb_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_xlib_xcb_private)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_xlib_xcb_sources)
+ifeq ($(CAIRO_HAS_XLIB_XCB_FUNCTIONS),1)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xlib_xcb_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_xlib_xcb_private)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xlib_xcb_sources)
+endif
+
 unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_qt_headers)
 all_cairo_boilerplate_headers += $(cairo_boilerplate_qt_headers)
 all_cairo_boilerplate_private += $(cairo_boilerplate_qt_private)
@@ -159,6 +169,16 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_gallium_private)
 enabled_cairo_boilerplate_sources += $(cairo_boilerplate_gallium_sources)
 endif
 
+unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_drm_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_drm_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_xcb_drm_private)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_drm_sources)
+ifeq ($(CAIRO_HAS_XCB_DRM_FUNCTIONS),1)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_xcb_drm_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_xcb_drm_private)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_xcb_drm_sources)
+endif
+
 supported_cairo_boilerplate_headers += $(cairo_boilerplate_png_headers)
 all_cairo_boilerplate_headers += $(cairo_boilerplate_png_headers)
 all_cairo_boilerplate_private += $(cairo_boilerplate_png_private)
diff --git a/boilerplate/cairo-boilerplate-xcb.c b/boilerplate/cairo-boilerplate-xcb.c
index 0ab2026..ed173e6 100644
--- a/boilerplate/cairo-boilerplate-xcb.c
+++ b/boilerplate/cairo-boilerplate-xcb.c
@@ -26,15 +26,16 @@
 
 #include "cairo-boilerplate-private.h"
 
-#include <cairo-xcb-xrender.h>
-
-#include <xcb/xcb_renderutil.h>
+#include <cairo-xcb.h>
 
 static const cairo_user_data_key_t xcb_closure_key;
 
 typedef struct _xcb_target_closure {
     xcb_connection_t *c;
-    xcb_pixmap_t pixmap;
+    cairo_device_t *device;
+    uint32_t drawable;
+    cairo_bool_t is_pixmap;
+    cairo_surface_t *surface;
 } xcb_target_closure_t;
 
 static void
@@ -42,8 +43,17 @@ _cairo_boilerplate_xcb_cleanup (void *closure)
 {
     xcb_target_closure_t *xtc = closure;
 
-    xcb_free_pixmap (xtc->c, xtc->pixmap);
+    if (xtc->is_pixmap)
+	xcb_free_pixmap (xtc->c, xtc->drawable);
+    else
+	xcb_destroy_window (xtc->c, xtc->drawable);
+    cairo_surface_destroy (xtc->surface);
+
+    cairo_device_finish (xtc->device);
+    cairo_device_destroy (xtc->device);
+
     xcb_disconnect (xtc->c);
+
     free (xtc);
 }
 
@@ -53,10 +63,42 @@ _cairo_boilerplate_xcb_synchronize (void *closure)
     xcb_target_closure_t *xtc = closure;
     free (xcb_get_image_reply (xtc->c,
 		xcb_get_image (xtc->c, XCB_IMAGE_FORMAT_Z_PIXMAP,
-		    xtc->pixmap, 0, 0, 1, 1, /* AllPlanes */ ~0UL),
+		    xtc->drawable, 0, 0, 1, 1, /* AllPlanes */ -1),
 		0));
 }
 
+static xcb_render_pictforminfo_t *
+find_depth (xcb_connection_t *connection, int depth, void **formats_out)
+{
+    xcb_render_query_pict_formats_reply_t *formats;
+    xcb_render_query_pict_formats_cookie_t cookie;
+    xcb_render_pictforminfo_iterator_t i;
+
+    cookie = xcb_render_query_pict_formats (connection);
+    xcb_flush (connection);
+
+    formats = xcb_render_query_pict_formats_reply (connection, cookie, 0);
+    if (formats == NULL)
+	return NULL;
+
+    for (i = xcb_render_query_pict_formats_formats_iterator (formats);
+	 i.rem;
+	 xcb_render_pictforminfo_next (&i))
+    {
+	if (XCB_RENDER_PICT_TYPE_DIRECT != i.data->type)
+	    continue;
+
+	if (depth != i.data->depth)
+	    continue;
+
+	*formats_out = formats;
+	return i.data;
+    }
+
+    free (formats);
+    return NULL;
+}
+
 static cairo_surface_t *
 _cairo_boilerplate_xcb_create_surface (const char		 *name,
 				       cairo_content_t		  content,
@@ -72,10 +114,11 @@ _cairo_boilerplate_xcb_create_surface (const char		 *name,
     xcb_target_closure_t *xtc;
     xcb_connection_t *c;
     xcb_render_pictforminfo_t *render_format;
-    xcb_pict_standard_t format;
+    int depth;
     xcb_void_cookie_t cookie;
     cairo_surface_t *surface;
     cairo_status_t status;
+    void *formats;
 
     *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
 
@@ -85,32 +128,279 @@ _cairo_boilerplate_xcb_create_surface (const char		 *name,
 	height = 1;
 
     xtc->c = c = xcb_connect(NULL,NULL);
-    if (xcb_connection_has_error(c)) {
-	fprintf (stderr, "Failed to connect to X server through XCB\n");
+    if (xcb_connection_has_error(c))
+	return NULL;
+
+    root = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
+
+    xtc->surface = NULL;
+    xtc->is_pixmap = TRUE;
+    xtc->drawable = xcb_generate_id (c);
+    switch (content) {
+    case CAIRO_CONTENT_COLOR:
+	depth = 24;
+	cookie = xcb_create_pixmap_checked (c, depth,
+					    xtc->drawable, root->root,
+					    width, height);
+	break;
+
+    case CAIRO_CONTENT_COLOR_ALPHA:
+	depth = 32;
+	cookie = xcb_create_pixmap_checked (c, depth,
+					    xtc->drawable, root->root,
+					    width, height);
+	break;
+
+    case CAIRO_CONTENT_ALPHA:  /* would be XCB_PICT_STANDARD_A_8 */
+    default:
+	xcb_disconnect (c);
+	free (xtc);
+	return NULL;
+    }
+
+    /* slow, but sure */
+    if (xcb_request_check (c, cookie) != NULL) {
+	xcb_disconnect (c);
+	free (xtc);
+	return NULL;
+    }
+
+    render_format = find_depth (c, depth, &formats);
+    if (render_format == NULL) {
+	xcb_disconnect (c);
+	free (xtc);
+	return NULL;
+    }
+
+    surface = cairo_xcb_surface_create_with_xrender_format (c, root,
+							    xtc->drawable,
+							    render_format,
+							    width, height);
+    free (formats);
+
+    xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
+    status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
+    if (status == CAIRO_STATUS_SUCCESS)
+	return surface;
+
+    cairo_surface_destroy (surface);
+
+    _cairo_boilerplate_xcb_cleanup (xtc);
+    return cairo_boilerplate_surface_create_in_error (status);
+}
+
+static xcb_visualtype_t *
+lookup_visual (xcb_screen_t *s, xcb_visualid_t visual)
+{
+    xcb_depth_iterator_t d;
+
+    d = xcb_screen_allowed_depths_iterator (s);
+    for (; d.rem; xcb_depth_next (&d)) {
+	xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator (d.data);
+	for (; v.rem; xcb_visualtype_next (&v)) {
+	    if (v.data->visual_id == visual)
+		return v.data;
+	}
+    }
+
+    return 0;
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_xcb_create_window (const char		 *name,
+				      cairo_content_t		  content,
+				      double			  width,
+				      double			  height,
+				      double			  max_width,
+				      double			  max_height,
+				      cairo_boilerplate_mode_t	  mode,
+				      int                        id,
+				      void			**closure)
+{
+    xcb_target_closure_t *xtc;
+    xcb_connection_t *c;
+    xcb_screen_t *s;
+    xcb_void_cookie_t cookie;
+    cairo_surface_t *surface;
+    cairo_status_t status;
+    uint32_t values[] = { 1 };
+
+    *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+    if (width == 0)
+	width = 1;
+    if (height == 0)
+	height = 1;
+
+    xtc->c = c = xcb_connect(NULL,NULL);
+    if (xcb_connection_has_error(c))
+	return NULL;
+
+    xtc->surface = NULL;
+
+    s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
+    xtc->is_pixmap = FALSE;
+    xtc->drawable = xcb_generate_id (c);
+    cookie = xcb_create_window_checked (c,
+					s->root_depth,
+					xtc->drawable,
+					s->root,
+					0, 0, width, height, 0,
+					XCB_WINDOW_CLASS_INPUT_OUTPUT,
+					s->root_visual,
+					XCB_CW_OVERRIDE_REDIRECT,
+					values);
+    xcb_map_window (c, xtc->drawable);
+
+    /* slow, but sure */
+    if (xcb_request_check (c, cookie) != NULL) {
+	xcb_disconnect (c);
+	free (xtc);
+	return NULL;
+    }
+
+    surface = cairo_xcb_surface_create (c,
+					xtc->drawable,
+					lookup_visual (s, s->root_visual),
+					width, height);
+
+    xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
+    status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
+    if (status == CAIRO_STATUS_SUCCESS)
+	return surface;
+
+    cairo_surface_destroy (surface);
+
+    _cairo_boilerplate_xcb_cleanup (xtc);
+    return cairo_boilerplate_surface_create_in_error (status);
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_xcb_create_window_db (const char		 *name,
+					 cairo_content_t	  content,
+					 double			  width,
+					 double			  height,
+					 double			  max_width,
+					 double			  max_height,
+					 cairo_boilerplate_mode_t mode,
+					 int                      id,
+					 void			**closure)
+{
+    xcb_target_closure_t *xtc;
+    xcb_connection_t *c;
+    xcb_screen_t *s;
+    xcb_void_cookie_t cookie;
+    cairo_surface_t *surface;
+    cairo_status_t status;
+    uint32_t values[] = { 1 };
+
+    *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+    if (width == 0)
+	width = 1;
+    if (height == 0)
+	height = 1;
+
+    xtc->c = c = xcb_connect(NULL,NULL);
+    if (xcb_connection_has_error(c))
+	return NULL;
+
+    xtc->surface = NULL;
+
+    s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
+    xtc->is_pixmap = FALSE;
+    xtc->drawable = xcb_generate_id (c);
+    cookie = xcb_create_window_checked (c,
+					s->root_depth,
+					xtc->drawable,
+					s->root,
+					0, 0, width, height, 0,
+					XCB_WINDOW_CLASS_INPUT_OUTPUT,
+					s->root_visual,
+					XCB_CW_OVERRIDE_REDIRECT,
+					values);
+    xcb_map_window (c, xtc->drawable);
+
+    /* slow, but sure */
+    if (xcb_request_check (c, cookie) != NULL) {
+	xcb_disconnect (c);
+	free (xtc);
 	return NULL;
     }
 
+    xtc->surface = cairo_xcb_surface_create (c,
+					     xtc->drawable,
+					     lookup_visual (s, s->root_visual),
+					     width, height);
+    surface = cairo_surface_create_similar (xtc->surface, content, width, height);
+
+    xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
+    status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
+    if (status == CAIRO_STATUS_SUCCESS)
+	return surface;
+
+    cairo_surface_destroy (surface);
+
+    _cairo_boilerplate_xcb_cleanup (xtc);
+    return cairo_boilerplate_surface_create_in_error (status);
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_xcb_create_render_0_0 (const char		 *name,
+					  cairo_content_t	  content,
+					  double		  width,
+					  double		  height,
+					  double		  max_width,
+					  double		  max_height,
+					  cairo_boilerplate_mode_t  mode,
+					  int                       id,
+					  void			**closure)
+{
+    xcb_screen_t *root;
+    xcb_target_closure_t *xtc;
+    xcb_connection_t *c;
+    xcb_render_pictforminfo_t *render_format;
+    int depth;
+    xcb_void_cookie_t cookie;
+    cairo_surface_t *surface, *tmp;
+    cairo_status_t status;
+    void *formats;
+
+    *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+    if (width == 0)
+	width = 1;
+    if (height == 0)
+	height = 1;
+
+    xtc->c = c = xcb_connect(NULL,NULL);
+    if (xcb_connection_has_error(c))
+	return NULL;
+
     root = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
 
-    xtc->pixmap = xcb_generate_id (c);
+    xtc->surface = NULL;
+    xtc->is_pixmap = TRUE;
+    xtc->drawable = xcb_generate_id (c);
     switch (content) {
     case CAIRO_CONTENT_COLOR:
-	cookie = xcb_create_pixmap_checked (c, 24,
-					    xtc->pixmap, root->root,
+	depth = 24;
+	cookie = xcb_create_pixmap_checked (c, depth,
+					    xtc->drawable, root->root,
 					    width, height);
-	format = XCB_PICT_STANDARD_RGB_24;
 	break;
 
     case CAIRO_CONTENT_COLOR_ALPHA:
-	cookie = xcb_create_pixmap_checked (c, 32,
-					    xtc->pixmap, root->root,
+	depth = 32;
+	cookie = xcb_create_pixmap_checked (c, depth,
+					    xtc->drawable, root->root,
 					    width, height);
-	format = XCB_PICT_STANDARD_ARGB_32;
 	break;
 
     case CAIRO_CONTENT_ALPHA:  /* would be XCB_PICT_STANDARD_A_8 */
     default:
-	fprintf (stderr, "Invalid content for XCB test: %d\n", content);
+	xcb_disconnect (c);
+	free (xtc);
 	return NULL;
     }
 
@@ -121,24 +411,127 @@ _cairo_boilerplate_xcb_create_surface (const char		 *name,
 	return NULL;
     }
 
-    render_format = xcb_render_util_find_standard_format (xcb_render_util_query_formats (c), format);
-    if (render_format->id == 0)
+    render_format = find_depth (c, depth, &formats);
+    if (render_format == NULL) {
+	xcb_disconnect (c);
+	free (xtc);
 	return NULL;
+    }
 
-    surface = cairo_xcb_surface_create_with_xrender_format (c, xtc->pixmap, root,
+    tmp = cairo_xcb_surface_create_with_xrender_format (c, root,
+							xtc->drawable,
+							render_format,
+							width, height);
+
+    cairo_xcb_device_debug_cap_xrender_version (cairo_surface_get_device (tmp),
+                                                0, 0);
+    /* recreate with impaired connection */
+    surface = cairo_xcb_surface_create_with_xrender_format (c, root,
+							    xtc->drawable,
 							    render_format,
 							    width, height);
+    free (formats);
+    cairo_surface_destroy (tmp);
 
+    xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
     status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
     if (status == CAIRO_STATUS_SUCCESS)
 	return surface;
 
     cairo_surface_destroy (surface);
-    surface = cairo_boilerplate_surface_create_in_error (status);
 
     _cairo_boilerplate_xcb_cleanup (xtc);
+    return cairo_boilerplate_surface_create_in_error (status);
+}
+
+static cairo_surface_t *
+_cairo_boilerplate_xcb_create_fallback (const char		 *name,
+					cairo_content_t		  content,
+					double			  width,
+					double			  height,
+					double			  max_width,
+					double			  max_height,
+					cairo_boilerplate_mode_t  mode,
+					int                       id,
+					void			**closure)
+{
+    xcb_target_closure_t *xtc;
+    xcb_connection_t *c;
+    xcb_screen_t *s;
+    xcb_void_cookie_t cookie;
+    cairo_surface_t *tmp, *surface;
+    cairo_status_t status;
+    uint32_t values[] = { 1 };
+
+    *closure = xtc = xmalloc (sizeof (xcb_target_closure_t));
+
+    if (width == 0)
+	width = 1;
+    if (height == 0)
+	height = 1;
+
+    xtc->c = c = xcb_connect (NULL,NULL);
+    if (xcb_connection_has_error(c)) {
+	free (xtc);
+	return NULL;
+    }
+
+    s = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
+    if (width > s->width_in_pixels || height > s->height_in_pixels) {
+	xcb_disconnect (c);
+	free (xtc);
+	return NULL;
+    }
+
+    xtc->surface = NULL;
+    xtc->is_pixmap = FALSE;
+    xtc->drawable = xcb_generate_id (c);
+    cookie = xcb_create_window_checked (c,
+					s->root_depth,
+					xtc->drawable,
+					s->root,
+					0, 0, width, height, 0,
+					XCB_WINDOW_CLASS_INPUT_OUTPUT,
+					s->root_visual,
+					XCB_CW_OVERRIDE_REDIRECT,
+					values);
+    xcb_map_window (c, xtc->drawable);
+
+    /* slow, but sure */
+    if (xcb_request_check (c, cookie) != NULL) {
+	xcb_disconnect (c);
+	free (xtc);
+	return NULL;
+    }
+
+    tmp = cairo_xcb_surface_create (c,
+				    xtc->drawable,
+				    lookup_visual (s, s->root_visual),
+				    width, height);
+    if (cairo_surface_status (tmp)) {
+	xcb_disconnect (c);
+	free (xtc);
+	return tmp;
+    }
+
+    cairo_xcb_device_debug_cap_xrender_version (cairo_surface_get_device (tmp),
+						-1, -1);
+    /* recreate with impaired connection */
+    surface = cairo_xcb_surface_create (c,
+					xtc->drawable,
+					lookup_visual (s, s->root_visual),
+					width, height);
+    cairo_surface_destroy (tmp);
 
-    return surface;
+    xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
+    status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
+    if (status == CAIRO_STATUS_SUCCESS)
+	return surface;
+
+    cairo_surface_destroy (surface);
+
+    _cairo_boilerplate_xcb_cleanup (xtc);
+    return cairo_boilerplate_surface_create_in_error (status);
 }
 
 static cairo_status_t
@@ -148,20 +541,39 @@ _cairo_boilerplate_xcb_finish_surface (cairo_surface_t		*surface)
 							     &xcb_closure_key);
     xcb_generic_event_t *ev;
 
-    cairo_surface_flush (surface);
+    if (xtc->surface != NULL) {
+	cairo_t *cr;
+
+	cr = cairo_create (xtc->surface);
+	cairo_surface_set_device_offset (surface, 0, 0);
+	cairo_set_source_surface (cr, surface, 0, 0);
+	cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+	cairo_paint (cr);
+	cairo_destroy (cr);
+
+	surface = xtc->surface;
+    }
 
+    cairo_surface_flush (surface);
     if (cairo_surface_status (surface))
 	return cairo_surface_status (surface);
 
     while ((ev = xcb_poll_for_event (xtc->c)) != NULL) {
+	cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
 	if (ev->response_type == 0 /* trust me! */) {
 	    xcb_generic_error_t *error = (xcb_generic_error_t *) ev;
 
-	    fprintf (stderr, "Detected error during xcb run: %d major=%d, minor=%d\n",
+	    fprintf (stderr,
+		     "Detected error during xcb run: %d major=%d, minor=%d\n",
 		     error->error_code, error->major_code, error->minor_code);
+	    free (error);
 
-	    return CAIRO_STATUS_WRITE_ERROR;
+	    status = CAIRO_STATUS_WRITE_ERROR;
 	}
+
+	if (status)
+	    return status;
     }
 
     if (xcb_connection_has_error (xtc->c))
@@ -197,5 +609,65 @@ static const cairo_boilerplate_target_t targets[] = {
 	_cairo_boilerplate_xcb_cleanup,
 	_cairo_boilerplate_xcb_synchronize
     },
+    {
+	"xcb-window", "xlib", NULL, NULL,
+	CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
+	"cairo_xcb_surface_create_with_xrender_format",
+	_cairo_boilerplate_xcb_create_window,
+	NULL,
+	_cairo_boilerplate_xcb_finish_surface,
+	_cairo_boilerplate_get_image_surface,
+	cairo_surface_write_to_png,
+	_cairo_boilerplate_xcb_cleanup,
+	_cairo_boilerplate_xcb_synchronize
+    },
+    {
+	"xcb-window&", "xlib", NULL, NULL,
+	CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
+	"cairo_xcb_surface_create_with_xrender_format",
+	_cairo_boilerplate_xcb_create_window_db,
+	NULL,
+	_cairo_boilerplate_xcb_finish_surface,
+	_cairo_boilerplate_get_image_surface,
+	cairo_surface_write_to_png,
+	_cairo_boilerplate_xcb_cleanup,
+	_cairo_boilerplate_xcb_synchronize
+    },
+    {
+	"xcb-render-0.0", "xlib-fallback", NULL, NULL,
+	CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA, 1,
+	"cairo_xcb_surface_create_with_xrender_format",
+	_cairo_boilerplate_xcb_create_render_0_0,
+	NULL,
+	_cairo_boilerplate_xcb_finish_surface,
+	_cairo_boilerplate_get_image_surface,
+	cairo_surface_write_to_png,
+	_cairo_boilerplate_xcb_cleanup,
+	_cairo_boilerplate_xcb_synchronize
+    },
+    {
+	"xcb-render-0.0", "xlib-fallback", NULL, NULL,
+	CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
+	"cairo_xcb_surface_create_with_xrender_format",
+	_cairo_boilerplate_xcb_create_render_0_0,
+	NULL,
+	_cairo_boilerplate_xcb_finish_surface,
+	_cairo_boilerplate_get_image_surface,
+	cairo_surface_write_to_png,
+	_cairo_boilerplate_xcb_cleanup,
+	_cairo_boilerplate_xcb_synchronize
+    },
+    {
+	"xcb-fallback", "xlib-fallback", NULL, NULL,
+	CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1,
+	"cairo_xcb_surface_create_with_xrender_format",
+	_cairo_boilerplate_xcb_create_fallback,
+	NULL,
+	_cairo_boilerplate_xcb_finish_surface,
+	_cairo_boilerplate_get_image_surface,
+	cairo_surface_write_to_png,
+	_cairo_boilerplate_xcb_cleanup,
+	_cairo_boilerplate_xcb_synchronize
+    },
 };
 CAIRO_BOILERPLATE (xcb, targets)
diff --git a/build/Makefile.win32.features b/build/Makefile.win32.features
index bd314e9..b8c40a8 100644
--- a/build/Makefile.win32.features
+++ b/build/Makefile.win32.features
@@ -3,6 +3,7 @@
 CAIRO_HAS_XLIB_SURFACE=0
 CAIRO_HAS_XLIB_XRENDER_SURFACE=0
 CAIRO_HAS_XCB_SURFACE=0
+CAIRO_HAS_XLIB_XCB_FUNCTIONS=0
 CAIRO_HAS_QT_SURFACE=0
 CAIRO_HAS_QUARTZ_SURFACE=0
 CAIRO_HAS_QUARTZ_FONT=0
@@ -14,6 +15,7 @@ CAIRO_HAS_OS2_SURFACE=0
 CAIRO_HAS_BEOS_SURFACE=0
 CAIRO_HAS_DRM_SURFACE=0
 CAIRO_HAS_GALLIUM_SURFACE=0
+CAIRO_HAS_XCB_DRM_FUNCTIONS=0
 CAIRO_HAS_PNG_FUNCTIONS=1
 CAIRO_HAS_GL_SURFACE=0
 CAIRO_HAS_GLITZ_SURFACE=0
diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h
index 7e49cd6..95e9386 100644
--- a/build/Makefile.win32.features-h
+++ b/build/Makefile.win32.features-h
@@ -14,6 +14,9 @@ endif
 ifeq ($(CAIRO_HAS_XCB_SURFACE),1)
 	@echo "#define CAIRO_HAS_XCB_SURFACE 1" >> src/cairo-features.h
 endif
+ifeq ($(CAIRO_HAS_XLIB_XCB_FUNCTIONS),1)
+	@echo "#define CAIRO_HAS_XLIB_XCB_FUNCTIONS 1" >> src/cairo-features.h
+endif
 ifeq ($(CAIRO_HAS_QT_SURFACE),1)
 	@echo "#define CAIRO_HAS_QT_SURFACE 1" >> src/cairo-features.h
 endif
@@ -47,6 +50,9 @@ endif
 ifeq ($(CAIRO_HAS_GALLIUM_SURFACE),1)
 	@echo "#define CAIRO_HAS_GALLIUM_SURFACE 1" >> src/cairo-features.h
 endif
+ifeq ($(CAIRO_HAS_XCB_DRM_FUNCTIONS),1)
+	@echo "#define CAIRO_HAS_XCB_DRM_FUNCTIONS 1" >> src/cairo-features.h
+endif
 ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1)
 	@echo "#define CAIRO_HAS_PNG_FUNCTIONS 1" >> src/cairo-features.h
 endif
diff --git a/build/configure.ac.features b/build/configure.ac.features
index e057e2c..c55b4ef 100644
--- a/build/configure.ac.features
+++ b/build/configure.ac.features
@@ -393,6 +393,8 @@ AC_DEFUN([CAIRO_REPORT],
 	echo "  GLX functions:   $use_glx"
 	echo "  EGL functions:   $use_egl"
 	echo "  Eagle functions: $use_eagle"
+	echo "  X11-xcb functions: $use_xlib_xcb"
+	echo "  XCB-drm functions: $use_xcb_drm"
 	echo ""
 	echo "The following features and utilies:"
 	echo "  cairo-trace:                $use_trace"
diff --git a/configure.ac b/configure.ac
index d704353..f94d9c1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -109,10 +109,22 @@ CAIRO_ENABLE_SURFACE_BACKEND(xlib_xrender, Xlib Xrender, auto, [
 dnl ===========================================================================
 
 CAIRO_ENABLE_SURFACE_BACKEND(xcb, XCB, no, [
-  xcb_REQUIRES="xcb >= 0.9.92 xcb-render >= 0.9.92 xcb-renderutil"
-  PKG_CHECK_MODULES(xcb, $xcb_REQUIRES, , [AC_MSG_RESULT(no)
-  use_xcb="no (requires $xcb_REQUIRES http://xcb.freedesktop.org)"])
+  xcb_REQUIRES="xcb >= 0.9.92 xcb-render >= 0.9.92 xcb-shm xcb-dri2"
+  PKG_CHECK_MODULES(xcb, $xcb_REQUIRES, ,
+		    [AC_MSG_RESULT(no)
+		    use_xcb="no (requires $xcb_REQUIRES http://xcb.freedesktop.org)"])
+])
+
+CAIRO_ENABLE_FUNCTIONS(xlib_xcb, Xlib/XCB, no, [
+  if test "x$use_xcb" == "xyes" -a "x$use_xlib" == "xyes"; then
+    xlib_xcb_REQUIRES="x11-xcb"
+    PKG_CHECK_MODULES(xlib_xcb, $xlib_xcb_REQUIRES, ,
+		      [use_xlib_xcb="no (requires $xlib_xcb_REQUIRES http://xcb.freedesktop.org)"])
+  else
+    use_xlib_xcb="no (requires both --enable-xlib and --enable-xcb)"
+  fi
 ])
+AM_CONDITIONAL(BUILD_XLIB_XCB, test "x$use_xlib_xcb" = "xyes")
 
 dnl ===========================================================================
 
@@ -241,6 +253,14 @@ CAIRO_ENABLE_SURFACE_BACKEND(gallium, Gallium3D, no, [
   fi
 ])
 
+CAIRO_ENABLE_FUNCTIONS(xcb_drm, XCB/DRM, no, [
+  if test "x$use_xcb" == "xyes" -a "x$use_drm" == "xyes"; then
+    use_xcb_drm="yes"
+  else
+    use_xcb_drm="no (requires both --enable-xcb and --enable-drm)"
+  fi
+])
+
 dnl ===========================================================================
 
 CAIRO_ENABLE_FUNCTIONS(png, PNG, yes, [
diff --git a/src/Makefile.sources b/src/Makefile.sources
index f6d4fe3..0f77f0e 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -250,19 +250,33 @@ cairo_xlib_private = \
 	cairo-xlib-surface-private.h \
 	cairo-xlib-xrender-private.h \
 	$(NULL)
+if BUILD_XLIB_XCB
+cairo_xlib_sources = cairo-xlib-xcb-surface.c
+else
 cairo_xlib_sources = \
 	cairo-xlib-display.c \
 	cairo-xlib-screen.c \
 	cairo-xlib-surface.c \
 	cairo-xlib-visual.c \
 	$(NULL)
+endif
 
 cairo_xlib_xrender_headers = cairo-xlib-xrender.h
 
-# XXX split xcb-xrender.  or better yet, merge it into xcb.  xcb is so recent
-# that it's hard to imagine having xcb but not render.
-cairo_xcb_headers = cairo-xcb.h cairo-xcb-xrender.h
-cairo_xcb_sources = cairo-xcb-surface.c
+cairo_xcb_headers = cairo-xcb.h
+cairo_xcb_private = cairo-xcb-private.h
+cairo_xcb_sources = \
+		    cairo-xcb-connection.c \
+		    cairo-xcb-connection-core.c \
+		    cairo-xcb-connection-render.c \
+		    cairo-xcb-connection-shm.c \
+		    cairo-xcb-screen.c \
+		    cairo-xcb-shm.c \
+		    cairo-xcb-surface.c \
+		    cairo-xcb-surface-cairo.c \
+		    cairo-xcb-surface-core.c \
+		    cairo-xcb-surface-render.c \
+		    $(NULL)
 
 cairo_qt_headers = cairo-qt.h
 cairo_qt_sources = cairo-qt-surface.cpp
diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features
index 048c921..3575057 100644
--- a/src/Makefile.win32.features
+++ b/src/Makefile.win32.features
@@ -63,6 +63,20 @@ ifeq ($(CAIRO_HAS_XCB_SURFACE),1)
 enabled_cairo_pkgconf += cairo-xcb.pc
 endif
 
+unsupported_cairo_headers += $(cairo_xlib_xcb_headers)
+all_cairo_headers += $(cairo_xlib_xcb_headers)
+all_cairo_private += $(cairo_xlib_xcb_private)
+all_cairo_sources += $(cairo_xlib_xcb_sources)
+ifeq ($(CAIRO_HAS_XLIB_XCB_FUNCTIONS),1)
+enabled_cairo_headers += $(cairo_xlib_xcb_headers)
+enabled_cairo_private += $(cairo_xlib_xcb_private)
+enabled_cairo_sources += $(cairo_xlib_xcb_sources)
+endif
+all_cairo_pkgconf += cairo-xlib-xcb.pc
+ifeq ($(CAIRO_HAS_XLIB_XCB_FUNCTIONS),1)
+enabled_cairo_pkgconf += cairo-xlib-xcb.pc
+endif
+
 unsupported_cairo_headers += $(cairo_qt_headers)
 all_cairo_headers += $(cairo_qt_headers)
 all_cairo_private += $(cairo_qt_private)
@@ -217,6 +231,20 @@ ifeq ($(CAIRO_HAS_GALLIUM_SURFACE),1)
 enabled_cairo_pkgconf += cairo-gallium.pc
 endif
 
+unsupported_cairo_headers += $(cairo_xcb_drm_headers)
+all_cairo_headers += $(cairo_xcb_drm_headers)
+all_cairo_private += $(cairo_xcb_drm_private)
+all_cairo_sources += $(cairo_xcb_drm_sources)
+ifeq ($(CAIRO_HAS_XCB_DRM_FUNCTIONS),1)
+enabled_cairo_headers += $(cairo_xcb_drm_headers)
+enabled_cairo_private += $(cairo_xcb_drm_private)
+enabled_cairo_sources += $(cairo_xcb_drm_sources)
+endif
+all_cairo_pkgconf += cairo-xcb-drm.pc
+ifeq ($(CAIRO_HAS_XCB_DRM_FUNCTIONS),1)
+enabled_cairo_pkgconf += cairo-xcb-drm.pc
+endif
+
 supported_cairo_headers += $(cairo_png_headers)
 all_cairo_headers += $(cairo_png_headers)
 all_cairo_private += $(cairo_png_private)
diff --git a/src/cairo-list-private.h b/src/cairo-list-private.h
index b8254bb..6d65bf1 100644
--- a/src/cairo-list-private.h
+++ b/src/cairo-list-private.h
@@ -186,4 +186,11 @@ cairo_list_is_empty (const cairo_list_t *head)
     return head->next == head;
 }
 
+static inline cairo_bool_t
+cairo_list_is_singular (const cairo_list_t *head)
+{
+    cairo_list_validate (head);
+    return head->next == head || head->next == head->prev;
+}
+
 #endif /* CAIRO_LIST_PRIVATE_H */
diff --git a/src/cairo-mutex-list-private.h b/src/cairo-mutex-list-private.h
index c84cebf..aa2c8f8 100644
--- a/src/cairo-mutex-list-private.h
+++ b/src/cairo-mutex-list-private.h
@@ -54,6 +54,10 @@ CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex)
 CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex)
 #endif
 
+#if CAIRO_HAS_XCB_SURFACE
+CAIRO_MUTEX_DECLARE (_cairo_xcb_connections_mutex)
+#endif
+
 #if CAIRO_HAS_GL_SURFACE
 CAIRO_MUTEX_DECLARE (_cairo_gl_context_mutex)
 #endif
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index e77f153..aae1aa5 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -2628,23 +2628,20 @@ _cairo_gradient_color_stops_hash (unsigned long hash,
     return hash;
 }
 
-static unsigned long
+unsigned long
 _cairo_linear_pattern_hash (unsigned long hash,
-			    const cairo_pattern_t *pattern)
+			    const cairo_linear_pattern_t *linear)
 {
-    const cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
-
     hash = _cairo_hash_bytes (hash, &linear->p1, sizeof (linear->p1));
     hash = _cairo_hash_bytes (hash, &linear->p2, sizeof (linear->p2));
 
     return _cairo_gradient_color_stops_hash (hash, &linear->base);
 }
 
-static unsigned long
-_cairo_radial_pattern_hash (unsigned long hash, const cairo_pattern_t *pattern)
+unsigned long
+_cairo_radial_pattern_hash (unsigned long hash,
+			    const cairo_radial_pattern_t *radial)
 {
-    const cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
-
     hash = _cairo_hash_bytes (hash, &radial->c1, sizeof (radial->c1));
     hash = _cairo_hash_bytes (hash, &radial->r1, sizeof (radial->r1));
     hash = _cairo_hash_bytes (hash, &radial->c2, sizeof (radial->c2));
@@ -2689,9 +2686,9 @@ _cairo_pattern_hash (const cairo_pattern_t *pattern)
     case CAIRO_PATTERN_TYPE_SOLID:
 	return _cairo_solid_pattern_hash (hash, pattern);
     case CAIRO_PATTERN_TYPE_LINEAR:
-	return _cairo_linear_pattern_hash (hash, pattern);
+	return _cairo_linear_pattern_hash (hash, (cairo_linear_pattern_t *) pattern);
     case CAIRO_PATTERN_TYPE_RADIAL:
-	return _cairo_radial_pattern_hash (hash, pattern);
+	return _cairo_radial_pattern_hash (hash, (cairo_radial_pattern_t *) pattern);
     case CAIRO_PATTERN_TYPE_SURFACE:
 	return _cairo_surface_pattern_hash (hash, pattern);
     default:
@@ -2768,13 +2765,10 @@ _cairo_gradient_color_stops_equal (const cairo_gradient_pattern_t *a,
     return TRUE;
 }
 
-static cairo_bool_t
-_cairo_linear_pattern_equal (const cairo_pattern_t *A,
-			     const cairo_pattern_t *B)
+cairo_bool_t
+_cairo_linear_pattern_equal (const cairo_linear_pattern_t *a,
+			     const cairo_linear_pattern_t *b)
 {
-    const cairo_linear_pattern_t *a = (cairo_linear_pattern_t *) A;
-    const cairo_linear_pattern_t *b = (cairo_linear_pattern_t *) B;
-
     if (a->p1.x != b->p1.x)
 	return FALSE;
 
@@ -2790,13 +2784,10 @@ _cairo_linear_pattern_equal (const cairo_pattern_t *A,
     return _cairo_gradient_color_stops_equal (&a->base, &b->base);
 }
 
-static cairo_bool_t
-_cairo_radial_pattern_equal (const cairo_pattern_t *A,
-			     const cairo_pattern_t *B)
+cairo_bool_t
+_cairo_radial_pattern_equal (const cairo_radial_pattern_t *a,
+			     const cairo_radial_pattern_t *b)
 {
-    const cairo_radial_pattern_t *a = (cairo_radial_pattern_t *) A;
-    const cairo_radial_pattern_t *b = (cairo_radial_pattern_t *) B;
-
     if (a->c1.x != b->c1.x)
 	return FALSE;
 
@@ -2858,9 +2849,11 @@ _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
     case CAIRO_PATTERN_TYPE_SOLID:
 	return _cairo_solid_pattern_equal (a, b);
     case CAIRO_PATTERN_TYPE_LINEAR:
-	return _cairo_linear_pattern_equal (a, b);
+	return _cairo_linear_pattern_equal ((cairo_linear_pattern_t *) a,
+					    (cairo_linear_pattern_t *) b);
     case CAIRO_PATTERN_TYPE_RADIAL:
-	return _cairo_radial_pattern_equal (a, b);
+	return _cairo_radial_pattern_equal ((cairo_radial_pattern_t *) a,
+					    (cairo_radial_pattern_t *) b);
     case CAIRO_PATTERN_TYPE_SURFACE:
 	return _cairo_surface_pattern_equal (a, b);
     default:
diff --git a/src/cairo-xcb-connection-core.c b/src/cairo-xcb-connection-core.c
new file mode 100644
index 0000000..22a340d
--- /dev/null
+++ b/src/cairo-xcb-connection-core.c
@@ -0,0 +1,482 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xcb-private.h"
+
+#include <xcb/xcbext.h>
+
+xcb_pixmap_t
+_cairo_xcb_connection_create_pixmap (cairo_xcb_connection_t *connection,
+				     uint8_t depth,
+				     xcb_drawable_t drawable,
+				     uint16_t width,
+				     uint16_t height)
+{
+    struct {
+	uint8_t req;
+	uint8_t depth;
+	uint16_t len;
+	uint32_t pixmap;
+	uint32_t drawable;
+	uint16_t width, height;
+    } req;
+    struct iovec vec[1];
+
+    req.req = 53;
+    req.depth = depth;
+    req.len = sizeof (req) >> 2;
+
+    req.pixmap = _cairo_xcb_connection_get_xid (connection);
+    req.drawable = drawable;
+    req.width = width;
+    req.height = height;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+
+    _cairo_xcb_connection_write (connection, vec, 1);
+
+    return req.pixmap;
+}
+
+void
+_cairo_xcb_connection_free_pixmap (cairo_xcb_connection_t *connection,
+				   xcb_pixmap_t pixmap)
+{
+    struct {
+	uint8_t req;
+	uint8_t pad;
+	uint16_t len;
+	uint32_t pixmap;
+    } req;
+    struct iovec vec[1];
+
+    req.req = 54;
+    req.len = sizeof (req) >> 2;
+    req.pixmap = pixmap;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+
+    _cairo_xcb_connection_write (connection, vec, 1);
+    _cairo_xcb_connection_put_xid (connection, pixmap);
+}
+
+xcb_gcontext_t
+_cairo_xcb_connection_create_gc (cairo_xcb_connection_t *connection,
+				 xcb_drawable_t drawable,
+				 uint32_t value_mask,
+				 uint32_t *values)
+{
+    struct {
+	uint8_t req;
+	uint8_t pad;
+	uint16_t len;
+	uint32_t gc;
+	uint32_t drawable;
+	uint32_t mask;
+    } req;
+    struct iovec vec[2];
+    int len = _cairo_popcount (value_mask) * 4;
+
+    req.req = 55;
+    req.len = (sizeof (req) + len) >> 2;
+    req.gc = _cairo_xcb_connection_get_xid (connection);
+    req.drawable = drawable;
+    req.mask = value_mask;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+    vec[1].iov_base = values;
+    vec[1].iov_len = len;
+
+    _cairo_xcb_connection_write (connection, vec, 2);
+
+    return req.gc;
+}
+
+void
+_cairo_xcb_connection_free_gc (cairo_xcb_connection_t *connection,
+			       xcb_gcontext_t gc)
+{
+    struct {
+	uint8_t req;
+	uint8_t pad;
+	uint16_t len;
+	uint32_t gc;
+    } req;
+    struct iovec vec[1];
+
+    req.req = 60;
+    req.len = sizeof (req) >> 2;
+    req.gc = gc;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+
+    _cairo_xcb_connection_write (connection, vec, 1);
+    _cairo_xcb_connection_put_xid (connection, gc);
+}
+
+void
+_cairo_xcb_connection_change_gc (cairo_xcb_connection_t *connection,
+				 xcb_gcontext_t gc,
+				 uint32_t value_mask,
+				 uint32_t *values)
+{
+    struct {
+	uint8_t req;
+	uint8_t pad;
+	uint16_t len;
+	uint32_t gc;
+	uint32_t mask;
+    } req;
+    struct iovec vec[2];
+    int len = _cairo_popcount (value_mask) * 4;
+
+    req.req = 56;
+    req.len = (sizeof (req) + len) >> 2;
+    req.gc = gc;
+    req.mask = value_mask;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+    vec[1].iov_base = values;
+    vec[1].iov_len = len;
+
+    _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_copy_area (cairo_xcb_connection_t *connection,
+				 xcb_drawable_t src,
+				 xcb_drawable_t dst,
+				 xcb_gcontext_t gc,
+				 int16_t src_x,
+				 int16_t src_y,
+				 int16_t dst_x,
+				 int16_t dst_y,
+				 uint16_t width,
+				 uint16_t height)
+{
+    struct {
+	uint8_t req;
+	uint8_t pad;
+	uint16_t len;
+	uint32_t src;
+	uint32_t dst;
+	uint32_t gc;
+	int16_t src_x;
+	int16_t src_y;
+	int16_t dst_x;
+	int16_t dst_y;
+	uint16_t width;
+	uint16_t height;
+    } req;
+    struct iovec vec[1];
+
+    req.req = 62;
+    req.len = sizeof (req) >> 2;
+    req.src = src;
+    req.dst = dst;
+    req.gc = gc;
+    req.src_x = src_x;
+    req.src_y = src_y;
+    req.dst_x = dst_x;
+    req.dst_y = dst_y;
+    req.width = width;
+    req.height = height;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+
+    _cairo_xcb_connection_write (connection, vec, 1);
+}
+
+void
+_cairo_xcb_connection_poly_fill_rectangle (cairo_xcb_connection_t *connection,
+					   xcb_drawable_t dst,
+					   xcb_gcontext_t gc,
+					   uint32_t num_rectangles,
+					   xcb_rectangle_t *rectangles)
+{
+    struct {
+	uint8_t req;
+	uint8_t pad;
+	uint16_t len;
+	uint32_t dst;
+	uint32_t gc;
+    } req;
+    struct iovec vec[2];
+
+    req.req = 70;
+    req.len = (sizeof (req) + num_rectangles * sizeof (xcb_rectangle_t)) >> 2;
+    req.dst = dst;
+    req.gc = gc;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+    vec[1].iov_base = rectangles;
+    vec[1].iov_len = num_rectangles * sizeof (xcb_rectangle_t);
+
+    _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_put_image (cairo_xcb_connection_t *connection,
+				 xcb_drawable_t dst,
+				 xcb_gcontext_t gc,
+				 uint16_t width,
+				 uint16_t height,
+				 int16_t dst_x,
+				 int16_t dst_y,
+				 uint8_t depth,
+				 uint32_t stride,
+				 void *data)
+{
+    struct {
+	uint8_t req;
+	uint8_t format;
+	uint16_t len;
+	uint32_t dst;
+	uint32_t gc;
+	uint16_t width;
+	uint16_t height;
+	int16_t dst_x;
+	int16_t dst_y;
+	uint8_t left;
+	uint8_t depth;
+	uint16_t pad;
+    } req;
+    struct iovec vec[3];
+    uint32_t prefix[2];
+    uint32_t length = height * stride;
+    uint32_t len = (sizeof (req) + length) >> 2;
+
+    req.req = 72;
+    req.format = XCB_IMAGE_FORMAT_Z_PIXMAP;
+    req.len = 0;
+    req.dst = dst;
+    req.gc = gc;
+    req.width = width;
+    req.height = height;
+    req.dst_x = dst_x;
+    req.dst_y = dst_y;
+    req.left = 0;
+    req.depth = depth;
+
+    if (len < connection->root->maximum_request_length) {
+	req.len = len;
+
+	vec[0].iov_base = &req;
+	vec[0].iov_len = sizeof (req);
+	vec[1].iov_base = data;
+	vec[1].iov_len = length;
+
+	_cairo_xcb_connection_write (connection, vec, 2);
+    } else if (len < connection->maximum_request_length) {
+	prefix[0] = *(uint32_t *) &req;
+	prefix[1] = len + 1;
+	vec[0].iov_base = prefix;
+	vec[0].iov_len = sizeof (prefix);
+	vec[1].iov_base = (uint32_t *) &req + 1;
+	vec[1].iov_len = sizeof (req) - 4;
+	vec[2].iov_base = data;
+	vec[2].iov_len = length;
+
+	_cairo_xcb_connection_write (connection, vec, 3);
+    } else {
+	int rows;
+
+	rows = (connection->maximum_request_length - sizeof (req) - 4) / stride;
+	if (rows > 0) {
+	    do {
+		if (rows > height)
+		    rows = height;
+
+		length = rows * stride;
+		len = (sizeof (req) + 4 + length) >> 2;
+
+		req.height = rows;
+
+		prefix[0] = *(uint32_t *) &req;
+		prefix[1] = len;
+
+		vec[0].iov_base = prefix;
+		vec[0].iov_len = sizeof (prefix);
+		vec[1].iov_base = (uint32_t *) &req + 1;
+		vec[1].iov_len = sizeof (req) - 4;
+		vec[2].iov_base = data;
+		vec[2].iov_len = length;
+
+		/* note may modify vec */
+		_cairo_xcb_connection_write (connection, vec, 3);
+
+		height -= rows;
+		req.dst_y += rows;
+		data = (char *) data + length;
+	    } while (height);
+	} else {
+	    ASSERT_NOT_REACHED;
+	}
+    }
+}
+
+void
+_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
+				    xcb_drawable_t dst,
+				    xcb_gcontext_t gc,
+				    int16_t src_x,
+				    int16_t src_y,
+				    uint16_t width,
+				    uint16_t height,
+				    uint16_t cpp,
+				    uint16_t stride,
+				    int16_t dst_x,
+				    int16_t dst_y,
+				    uint8_t depth,
+				    void *_data)
+{
+    struct {
+	uint8_t req;
+	uint8_t format;
+	uint16_t len;
+	uint32_t dst;
+	uint32_t gc;
+	uint16_t width;
+	uint16_t height;
+	int16_t dst_x;
+	int16_t dst_y;
+	uint8_t left;
+	uint8_t depth;
+	uint16_t pad;
+    } req;
+    struct iovec vec_stack[CAIRO_STACK_ARRAY_LENGTH (struct iovec)];
+    struct iovec *vec = vec_stack;
+    uint32_t prefix[2];
+    uint32_t len = (sizeof (req) + cpp*width*height) >> 2;
+    uint8_t *data = _data;
+    int n;
+
+    req.req = 72;
+    req.format = XCB_IMAGE_FORMAT_Z_PIXMAP;
+    req.len = 0;
+    req.dst = dst;
+    req.gc = gc;
+    req.width = width;
+    req.height = height;
+    req.dst_x = dst_x;
+    req.dst_y = dst_y;
+    req.left = 0;
+    req.depth = depth;
+
+    if (height + 2 > ARRAY_LENGTH (vec_stack)) {
+	vec = _cairo_malloc_ab (height+2, sizeof (struct iovec));
+	if (unlikely (vec == NULL)) {
+	    /* XXX loop over ARRAY_LENGTH (vec_stack) */
+	    return;
+	}
+    }
+
+    data += src_y * stride + src_x * cpp;
+    if (len < connection->root->maximum_request_length) {
+	req.len = len;
+
+	vec[0].iov_base = &req;
+	vec[0].iov_len = sizeof (req);
+
+	n = 1;
+    } else if (len < connection->maximum_request_length) {
+	prefix[0] = *(uint32_t *) &req;
+	prefix[1] = len + 1;
+	vec[0].iov_base = prefix;
+	vec[0].iov_len = sizeof (prefix);
+	vec[1].iov_base = (uint32_t *) &req + 1;
+	vec[1].iov_len = sizeof (req) - 4;
+
+	n = 2;
+    } else {
+	ASSERT_NOT_REACHED;
+    }
+
+    while (height--) {
+	vec[n].iov_base = data;
+	vec[n].iov_len = cpp * width;
+	data += stride;
+	n++;
+    }
+
+    _cairo_xcb_connection_write (connection, vec, n);
+
+    if (vec != vec_stack)
+	free (vec);
+}
+
+cairo_status_t
+_cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection,
+				 xcb_drawable_t src,
+				 int16_t src_x,
+				 int16_t src_y,
+				 uint16_t width,
+				 uint16_t height,
+				 xcb_get_image_reply_t **reply)
+{
+    xcb_generic_error_t *error;
+    cairo_status_t status;
+
+    *reply = xcb_get_image_reply (connection->xcb_connection,
+				  xcb_get_image (connection->xcb_connection,
+						 XCB_IMAGE_FORMAT_Z_PIXMAP,
+						 src,
+						 src_x, src_y,
+						 width, height,
+						 (uint32_t) -1),
+
+				  &error);
+    if (error) {
+	free (error);
+
+	if (*reply)
+	    free (*reply);
+	*reply = NULL;
+    }
+
+    status = _cairo_xcb_connection_take_socket (connection);
+    if (unlikely (status)) {
+	if (*reply)
+	    free (*reply);
+	*reply = NULL;
+    }
+
+    return status;
+}
diff --git a/src/cairo-xcb-connection-render.c b/src/cairo-xcb-connection-render.c
new file mode 100644
index 0000000..2ebd6b4
--- /dev/null
+++ b/src/cairo-xcb-connection-render.c
@@ -0,0 +1,969 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xcb-private.h"
+
+#include <xcb/xcbext.h>
+
+#define X_RenderSpans 99
+#define XLIB_COORD_MAX 32767
+
+void
+_cairo_xcb_connection_render_create_picture (cairo_xcb_connection_t  *connection,
+					     xcb_render_picture_t     picture,
+					     xcb_drawable_t           drawable,
+					     xcb_render_pictformat_t  format,
+					     uint32_t                 value_mask,
+					     uint32_t	             *value_list)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint32_t picture;
+	uint32_t drawable;
+	uint32_t format;
+	uint32_t mask;
+    } req;
+    struct iovec vec[2];
+    int len = _cairo_popcount (value_mask) * 4;
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 20);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 4;
+    req.length = (sizeof (req) + len) >> 2;
+    req.picture = picture;
+    req.drawable = drawable;
+    req.format = format;
+    req.mask = value_mask;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+    vec[1].iov_base = value_list;
+    vec[1].iov_len = len;
+
+    _cairo_xcb_connection_write (connection, vec, 1 + (len != 0));
+}
+
+void
+_cairo_xcb_connection_render_change_picture (cairo_xcb_connection_t     *connection,
+					     xcb_render_picture_t  picture,
+					     uint32_t              value_mask,
+					     uint32_t             *value_list)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint32_t picture;
+	uint32_t mask;
+    } req;
+    struct iovec vec[2];
+    int len = _cairo_popcount (value_mask) * 4;
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 12);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 5;
+    req.length = (sizeof (req) + len) >> 2;
+    req.picture = picture;
+    req.mask = value_mask;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+    vec[1].iov_base = value_list;
+    vec[1].iov_len = len;
+
+    _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_set_picture_clip_rectangles (cairo_xcb_connection_t      *connection,
+							  xcb_render_picture_t   picture,
+							  int16_t                clip_x_origin,
+							  int16_t                clip_y_origin,
+							  uint32_t               rectangles_len,
+							  xcb_rectangle_t *rectangles)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint32_t picture;
+	uint16_t x;
+	uint16_t y;
+    } req;
+    struct iovec vec[2];
+    int len = sizeof (xcb_rectangle_t) * rectangles_len;
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 12);
+    assert ((len + sizeof (req)) >> 2 < connection->root->maximum_request_length);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 6;
+    req.length = (sizeof (req) + len) >> 2;
+    req.picture = picture;
+    req.x = clip_x_origin;
+    req.y = clip_y_origin;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+    vec[1].iov_base = rectangles;
+    vec[1].iov_len = len;
+
+    _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_free_picture (cairo_xcb_connection_t *connection,
+					   xcb_render_picture_t  picture)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint32_t picture;
+    } req;
+    struct iovec vec[1];
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 8);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 7;
+    req.length = sizeof (req) >> 2;
+    req.picture = picture;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+
+    _cairo_xcb_connection_write (connection, vec, 1);
+    _cairo_xcb_connection_put_xid (connection, picture);
+}
+
+void
+_cairo_xcb_connection_render_composite (cairo_xcb_connection_t     *connection,
+					uint8_t               op,
+					xcb_render_picture_t  src,
+					xcb_render_picture_t  mask,
+					xcb_render_picture_t  dst,
+					int16_t               src_x,
+					int16_t               src_y,
+					int16_t               mask_x,
+					int16_t               mask_y,
+					int16_t               dst_x,
+					int16_t               dst_y,
+					uint16_t              width,
+					uint16_t              height)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint8_t op;
+	uint8_t pad1;
+	uint16_t pad2;
+	uint32_t src;
+	uint32_t mask;
+	uint32_t dst;
+	int16_t src_x;
+	int16_t src_y;
+	int16_t mask_x;
+	int16_t mask_y;
+	int16_t dst_x;
+	int16_t dst_y;
+	uint16_t width;
+	uint16_t height;
+    } req;
+    struct iovec vec[1];
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 36);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 8;
+    req.length = sizeof (req) >> 2;
+    req.op = op;
+    req.src = src;
+    req.mask = mask;
+    req.dst = dst;
+    req.src_x = src_x;
+    req.src_y = src_y;
+    req.mask_x = mask_x;
+    req.mask_y = mask_y;
+    req.dst_x = dst_x;
+    req.dst_y = dst_y;
+    req.width = width;
+    req.height = height;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+
+    _cairo_xcb_connection_write (connection, vec, 1);
+}
+
+void
+_cairo_xcb_connection_render_trapezoids (cairo_xcb_connection_t *connection,
+					 uint8_t                       op,
+					 xcb_render_picture_t          src,
+					 xcb_render_picture_t          dst,
+					 xcb_render_pictformat_t       mask_format,
+					 int16_t                       src_x,
+					 int16_t                       src_y,
+					 uint32_t                      traps_len,
+					 xcb_render_trapezoid_t *traps)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint8_t op;
+	uint8_t pad1;
+	uint16_t pad2;
+	uint32_t src;
+	uint32_t dst;
+	uint32_t mask_format;
+	int16_t src_x;
+	int16_t src_y;
+    } req;
+    struct iovec vec[3];
+    uint32_t prefix[2];
+    uint32_t len = (sizeof (req) + traps_len * sizeof (xcb_render_trapezoid_t)) >> 2;
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 24);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 10;
+    req.length = 0;
+    req.op = op;
+    req.src = src;
+    req.dst = dst;
+    req.mask_format = mask_format;
+    req.src_x = src_x;
+    req.src_y = src_y;
+
+    if (len < connection->root->maximum_request_length) {
+	req.length = len;
+
+	vec[0].iov_base = &req;
+	vec[0].iov_len = sizeof (req);
+	vec[1].iov_base = traps;
+	vec[1].iov_len = traps_len * sizeof (xcb_render_trapezoid_t);
+
+	_cairo_xcb_connection_write (connection, vec, 2);
+    } else {
+	prefix[0] = *(uint32_t *) &req;
+	prefix[1] = len + 1;
+	vec[0].iov_base = prefix;
+	vec[0].iov_len = sizeof (prefix);
+	vec[1].iov_base = (uint32_t *) &req + 1;
+	vec[1].iov_len = sizeof (req) - 4;
+	vec[2].iov_base = traps;
+	vec[2].iov_len = traps_len * sizeof (xcb_render_trapezoid_t);
+
+	_cairo_xcb_connection_write (connection, vec, 3);
+    }
+}
+
+void
+_cairo_xcb_connection_render_spans (cairo_xcb_connection_t *connection,
+				    xcb_render_picture_t dst,
+				    int op,
+				    xcb_render_picture_t src,
+				    int16_t src_x, int16_t src_y,
+				    int16_t dst_x, int16_t dst_y,
+				    int16_t width, int16_t height,
+				    uint32_t num_spans,
+				    uint16_t *spans)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint8_t op;
+	uint8_t pad1;
+	uint16_t pad2;
+	uint32_t src;
+	uint32_t dst;
+	int16_t src_x;
+	int16_t src_y;
+	int16_t dst_x;
+	int16_t dst_y;
+	uint16_t width;
+	uint16_t height;
+    } req;
+    struct iovec vec[3];
+    uint32_t prefix[2];
+    uint32_t len = (sizeof (req) + num_spans * sizeof (uint16_t)) >> 2;
+
+    req.major = connection->render->major_opcode;
+    req.minor = X_RenderSpans;
+    req.length = 0;
+
+    req.dst = dst;
+    req.op = op;
+    req.src = src;
+    req.src_x = src_x;
+    req.src_y = src_y;
+    req.dst_x = dst_x;
+    req.dst_y = dst_y;
+    req.width = width;
+    req.height = height;
+
+    if (len < connection->root->maximum_request_length) {
+	req.length = len;
+
+	vec[0].iov_base = &req;
+	vec[0].iov_len = sizeof (req);
+	vec[1].iov_base = spans;
+	vec[1].iov_len = num_spans * sizeof (uint16_t);
+
+	_cairo_xcb_connection_write (connection, vec, 2);
+    } else {
+	prefix[0] = *(uint32_t *) &req;
+	prefix[1] = len + 1;
+	vec[0].iov_base = prefix;
+	vec[0].iov_len = sizeof (prefix);
+	vec[1].iov_base = (uint32_t *) &req + 1;
+	vec[1].iov_len = sizeof (req) - 4;
+	vec[2].iov_base = spans;
+	vec[2].iov_len = num_spans * sizeof (uint16_t);
+
+	_cairo_xcb_connection_write (connection, vec, 3);
+    }
+}
+
+void
+_cairo_xcb_connection_render_create_glyph_set (cairo_xcb_connection_t	*connection,
+					       xcb_render_glyphset_t	 id,
+					       xcb_render_pictformat_t  format)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint32_t gsid;
+	uint32_t format;
+    } req;
+    struct iovec vec[1];
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 12);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 17;
+    req.length = sizeof (req) >> 2;
+    req.gsid = id;
+    req.format = format;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+
+    _cairo_xcb_connection_write (connection, vec, 1);
+}
+
+void
+_cairo_xcb_connection_render_free_glyph_set (cairo_xcb_connection_t      *connection,
+					     xcb_render_glyphset_t  glyphset)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint32_t gsid;
+    } req;
+    struct iovec vec[1];
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 8);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 19;
+    req.length = sizeof (req) >> 2;
+    req.gsid = glyphset;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+
+    _cairo_xcb_connection_write (connection, vec, 1);
+    _cairo_xcb_connection_put_xid (connection, glyphset);
+}
+
+void
+_cairo_xcb_connection_render_add_glyphs (cairo_xcb_connection_t             *connection,
+					 xcb_render_glyphset_t         glyphset,
+					 uint32_t                      num_glyphs,
+					 uint32_t               *glyphs_id,
+					 xcb_render_glyphinfo_t *glyphs,
+					 uint32_t                      data_len,
+					 uint8_t                *data)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint32_t gsid;
+	uint32_t num_glyphs;
+    } req;
+    struct iovec vec[5];
+    uint32_t prefix[2];
+    uint32_t len = (sizeof (req) + num_glyphs * (sizeof (uint32_t) + sizeof (xcb_render_glyphinfo_t)) + data_len) >> 2;
+    int cnt;
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 12);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 20;
+    req.length = 0;
+    req.gsid = glyphset;
+    req.num_glyphs = num_glyphs;
+
+    if (len < connection->root->maximum_request_length) {
+	req.length = len;
+
+	vec[0].iov_base = &req;
+	vec[0].iov_len = sizeof (req);
+
+	cnt = 1;
+    } else {
+	prefix[0] = *(uint32_t *) &req;
+	prefix[1] = len + 1;
+	vec[0].iov_base = prefix;
+	vec[0].iov_len = sizeof (prefix);
+	vec[1].iov_base = (uint32_t *) &req + 1;
+	vec[1].iov_len = sizeof (req) - 4;
+
+	cnt = 2;
+    }
+
+    vec[cnt].iov_base = glyphs_id;
+    vec[cnt].iov_len = num_glyphs * sizeof (uint32_t);
+    cnt++;
+
+    vec[cnt].iov_base = glyphs;
+    vec[cnt].iov_len = num_glyphs * sizeof (xcb_render_glyphinfo_t);
+    cnt++;
+
+    vec[cnt].iov_base = data;
+    vec[cnt].iov_len = data_len;
+    cnt++;
+
+    _cairo_xcb_connection_write (connection, vec, cnt);
+}
+
+void
+_cairo_xcb_connection_render_free_glyphs (cairo_xcb_connection_t         *connection,
+					  xcb_render_glyphset_t     glyphset,
+					  uint32_t                  num_glyphs,
+					  xcb_render_glyph_t *glyphs)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint32_t gsid;
+    } req;
+    struct iovec vec[2];
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 8);
+    assert ( (sizeof (req) + num_glyphs * sizeof (uint32_t)) >> 2 < connection->root->maximum_request_length);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 22;
+    req.length = (sizeof (req) + num_glyphs * sizeof (uint32_t)) >> 2;
+    req.gsid = glyphset;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+    vec[1].iov_base = glyphs;
+    vec[1].iov_len = num_glyphs * sizeof (uint32_t);
+
+    _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_composite_glyphs_8 (cairo_xcb_connection_t        *connection,
+						 uint8_t                  op,
+						 xcb_render_picture_t     src,
+						 xcb_render_picture_t     dst,
+						 xcb_render_pictformat_t  mask_format,
+						 xcb_render_glyphset_t    glyphset,
+						 int16_t                  src_x,
+						 int16_t                  src_y,
+						 uint32_t                 glyphcmds_len,
+						 uint8_t           *glyphcmds)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint8_t op;
+	uint8_t pad1;
+	uint16_t pad2;
+	uint32_t src;
+	uint32_t dst;
+	uint32_t mask_format;
+	uint32_t glyphset;
+	int16_t src_x;
+	int16_t src_y;
+    } req;
+    struct iovec vec[3];
+    uint32_t prefix[2];
+    int len;
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 28);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 23;
+    req.length = 0;
+    req.op = op;
+    req.src = src;
+    req.dst = dst;
+    req.mask_format = mask_format;
+    req.glyphset = glyphset;
+    req.src_x = src_x;
+    req.src_y = src_y;
+
+    len = (sizeof (req) + glyphcmds_len) >> 2;
+    if (len < connection->root->maximum_request_length) {
+	req.length = len;
+
+	vec[0].iov_base = &req;
+	vec[0].iov_len = sizeof (req);
+
+	len = 1;
+    } else {
+	prefix[0] = *(uint32_t *) &req;
+	prefix[1] = len + 1;
+	vec[0].iov_base = prefix;
+	vec[0].iov_len = sizeof (prefix);
+	vec[1].iov_base = (uint32_t *) &req + 1;
+	vec[1].iov_len = sizeof (req) - 4;
+
+	len = 2;
+    }
+
+    vec[len].iov_base = glyphcmds;
+    vec[len].iov_len = glyphcmds_len;
+    len++;
+
+    _cairo_xcb_connection_write (connection, vec, len);
+}
+
+void
+_cairo_xcb_connection_render_composite_glyphs_16 (cairo_xcb_connection_t        *connection,
+						  uint8_t                  op,
+						  xcb_render_picture_t     src,
+						  xcb_render_picture_t     dst,
+						  xcb_render_pictformat_t  mask_format,
+						  xcb_render_glyphset_t    glyphset,
+						  int16_t                  src_x,
+						  int16_t                  src_y,
+						  uint32_t                 glyphcmds_len,
+						  uint8_t           *glyphcmds)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint8_t op;
+	uint8_t pad1;
+	uint16_t pad2;
+	uint32_t src;
+	uint32_t dst;
+	uint32_t mask_format;
+	uint32_t glyphset;
+	int16_t src_x;
+	int16_t src_y;
+    } req;
+    struct iovec vec[3];
+    uint32_t prefix[2];
+    int len;
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 28);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 24;
+    req.length = 0;
+    req.op = op;
+    req.src = src;
+    req.dst = dst;
+    req.mask_format = mask_format;
+    req.glyphset = glyphset;
+    req.src_x = src_x;
+    req.src_y = src_y;
+
+    len = (sizeof (req) + glyphcmds_len) >> 2;
+    if (len < connection->root->maximum_request_length) {
+	req.length = len;
+
+	vec[0].iov_base = &req;
+	vec[0].iov_len = sizeof (req);
+
+	len = 1;
+    } else {
+	prefix[0] = *(uint32_t *) &req;
+	prefix[1] = len + 1;
+	vec[0].iov_base = prefix;
+	vec[0].iov_len = sizeof (prefix);
+	vec[1].iov_base = (uint32_t *) &req + 1;
+	vec[1].iov_len = sizeof (req) - 4;
+
+	len = 2;
+    }
+
+    vec[len].iov_base = glyphcmds;
+    vec[len].iov_len = glyphcmds_len;
+    len++;
+
+    _cairo_xcb_connection_write (connection, vec, len);
+}
+
+void
+_cairo_xcb_connection_render_composite_glyphs_32 (cairo_xcb_connection_t        *connection,
+						  uint8_t                  op,
+						  xcb_render_picture_t     src,
+						  xcb_render_picture_t     dst,
+						  xcb_render_pictformat_t  mask_format,
+						  xcb_render_glyphset_t    glyphset,
+						  int16_t                  src_x,
+						  int16_t                  src_y,
+						  uint32_t                 glyphcmds_len,
+						  uint8_t           *glyphcmds)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint8_t op;
+	uint8_t pad1;
+	uint16_t pad2;
+	uint32_t src;
+	uint32_t dst;
+	uint32_t mask_format;
+	uint32_t glyphset;
+	int16_t src_x;
+	int16_t src_y;
+    } req;
+    struct iovec vec[2];
+    uint32_t prefix[2];
+    int len;
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 28);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 25;
+    req.length = 0;
+    req.op = op;
+    req.src = src;
+    req.dst = dst;
+    req.mask_format = mask_format;
+    req.glyphset = glyphset;
+    req.src_x = src_x;
+    req.src_y = src_y;
+
+    len = (sizeof (req) + glyphcmds_len) >> 2;
+    if (len < connection->root->maximum_request_length) {
+	req.length = len;
+
+	vec[0].iov_base = &req;
+	vec[0].iov_len = sizeof (req);
+
+	len = 1;
+    } else {
+	prefix[0] = *(uint32_t *) &req;
+	prefix[1] = len + 1;
+	vec[0].iov_base = prefix;
+	vec[0].iov_len = sizeof (prefix);
+	vec[1].iov_base = (uint32_t *) &req + 1;
+	vec[1].iov_len = sizeof (req) - 4;
+
+	len = 2;
+    }
+
+    vec[len].iov_base = glyphcmds;
+    vec[len].iov_len = glyphcmds_len;
+    len++;
+
+    _cairo_xcb_connection_write (connection, vec, len);
+}
+
+void
+_cairo_xcb_connection_render_fill_rectangles (cairo_xcb_connection_t      *connection,
+					      uint8_t                op,
+					      xcb_render_picture_t   dst,
+					      xcb_render_color_t     color,
+					      uint32_t               num_rects,
+					      xcb_rectangle_t *rects)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint8_t op;
+	uint8_t pad1;
+	uint16_t pad2;
+	uint32_t dst;
+	xcb_render_color_t     color;
+    } req;
+    struct iovec vec[2];
+    uint32_t len = (sizeof (req) + num_rects * sizeof (xcb_rectangle_t)) >> 2;
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 20);
+    assert(len < connection->root->maximum_request_length);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 26;
+    req.length = (sizeof (req) + num_rects * sizeof (xcb_rectangle_t)) >> 2;
+    req.op = op;
+    req.dst = dst;
+    req.color = color;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+    vec[1].iov_base = rects;
+    vec[1].iov_len = num_rects * sizeof (xcb_rectangle_t);
+
+    _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_set_picture_transform (cairo_xcb_connection_t       *connection,
+						    xcb_render_picture_t    picture,
+						    xcb_render_transform_t  *transform)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint32_t picture;
+    } req;
+    struct iovec vec[2];
+
+    req.major = connection->render->major_opcode;
+    req.minor = 28;
+    req.length = (sizeof (req) + sizeof (xcb_render_transform_t)) >> 2;
+    req.picture = picture;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+    vec[1].iov_base = transform;
+    vec[1].iov_len = sizeof (xcb_render_transform_t);
+
+    _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_set_picture_filter (cairo_xcb_connection_t         *connection,
+						 xcb_render_picture_t      picture,
+						 uint16_t                  filter_len,
+						 char               *filter)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint32_t picture;
+	uint16_t nbytes;
+	uint16_t pad;
+    } req;
+    struct iovec vec[2];
+
+    req.nbytes = filter_len;
+    filter_len = (filter_len + 3) & ~3;
+
+    req.major = connection->render->major_opcode;
+    req.minor = 30;
+    req.length = (sizeof (req) + filter_len) >> 2;
+    req.picture = picture;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+    vec[1].iov_base = filter;
+    vec[1].iov_len = filter_len;
+
+    _cairo_xcb_connection_write (connection, vec, 2);
+}
+
+void
+_cairo_xcb_connection_render_create_solid_fill (cairo_xcb_connection_t     *connection,
+						xcb_render_picture_t  picture,
+						xcb_render_color_t    color)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint32_t picture;
+	xcb_render_color_t color;
+    } req;
+    struct iovec vec[1];
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 16);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 33;
+    req.length = sizeof (req) >> 2;
+    req.picture = picture;
+    req.color = color;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+
+    _cairo_xcb_connection_write (connection, vec, 1);
+}
+
+void
+_cairo_xcb_connection_render_create_linear_gradient (cairo_xcb_connection_t         *connection,
+						     xcb_render_picture_t      picture,
+						     xcb_render_pointfix_t     p1,
+						     xcb_render_pointfix_t     p2,
+						     uint32_t                  num_stops,
+						     xcb_render_fixed_t *stops,
+						     xcb_render_color_t *colors)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint32_t picture;
+	xcb_render_pointfix_t p1, p2;
+	uint32_t num_stops;
+    } req;
+    struct iovec vec[3];
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 28);
+    assert((sizeof (req)  + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2 < connection->root->maximum_request_length);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 34;
+    req.length = (sizeof (req)  + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2;
+    req.picture = picture;
+    req.p1 = p1;
+    req.p2 = p2;
+    req.num_stops = num_stops;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+    vec[1].iov_base = stops;
+    vec[1].iov_len = num_stops * sizeof (xcb_render_fixed_t);
+    vec[2].iov_base = colors;
+    vec[2].iov_len = num_stops * sizeof (xcb_render_color_t);
+
+    _cairo_xcb_connection_write (connection, vec, 3);
+}
+
+void
+_cairo_xcb_connection_render_create_radial_gradient (cairo_xcb_connection_t         *connection,
+						     xcb_render_picture_t      picture,
+						     xcb_render_pointfix_t     inner,
+						     xcb_render_pointfix_t     outer,
+						     xcb_render_fixed_t        inner_radius,
+						     xcb_render_fixed_t        outer_radius,
+						     uint32_t                  num_stops,
+						     xcb_render_fixed_t *stops,
+						     xcb_render_color_t *colors)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint32_t picture;
+	xcb_render_pointfix_t     inner;
+	xcb_render_pointfix_t     outer;
+	xcb_render_fixed_t        inner_radius;
+	xcb_render_fixed_t        outer_radius;
+	uint32_t num_stops;
+    } req;
+    struct iovec vec[3];
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 36);
+    assert((sizeof (req)  + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2 < connection->root->maximum_request_length);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 35;
+    req.length = (sizeof (req)  + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2;
+    req.picture = picture;
+    req.inner = inner;
+    req.outer = outer;
+    req.inner_radius = inner_radius;
+    req.outer_radius = outer_radius;
+    req.num_stops = num_stops;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+    vec[1].iov_base = stops;
+    vec[1].iov_len = num_stops * sizeof (xcb_render_fixed_t);
+    vec[2].iov_base = colors;
+    vec[2].iov_len = num_stops * sizeof (xcb_render_color_t);
+
+    _cairo_xcb_connection_write (connection, vec, 3);
+}
+
+void
+_cairo_xcb_connection_render_create_conical_gradient (cairo_xcb_connection_t         *connection,
+						      xcb_render_picture_t      picture,
+						      xcb_render_pointfix_t     center,
+						      xcb_render_fixed_t        angle,
+						      uint32_t                  num_stops,
+						      xcb_render_fixed_t *stops,
+						      xcb_render_color_t *colors)
+{
+    struct {
+	uint8_t major;
+	uint8_t minor;
+	uint16_t length;
+	uint32_t picture;
+	xcb_render_pointfix_t     center;
+	xcb_render_fixed_t        angle;
+	uint32_t num_stops;
+    } req;
+    struct iovec vec[3];
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 24);
+    assert((sizeof (req)  + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2 < connection->root->maximum_request_length);
+
+    req.major = connection->render->major_opcode;
+    req.minor = 36;
+    req.length = (sizeof (req)  + num_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t))) >> 2;
+    req.picture = picture;
+    req.center = center;
+    req.angle = angle;
+    req.num_stops = num_stops;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+    vec[1].iov_base = stops;
+    vec[1].iov_len = num_stops * sizeof (xcb_render_fixed_t);
+    vec[2].iov_base = colors;
+    vec[2].iov_len = num_stops * sizeof (xcb_render_color_t);
+
+    _cairo_xcb_connection_write (connection, vec, 3);
+}
diff --git a/src/cairo-xcb-connection-shm.c b/src/cairo-xcb-connection-shm.c
new file mode 100644
index 0000000..2c13b1b
--- /dev/null
+++ b/src/cairo-xcb-connection-shm.c
@@ -0,0 +1,194 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xcb-private.h"
+
+#include <xcb/xcbext.h>
+#include <xcb/shm.h>
+
+uint32_t
+_cairo_xcb_connection_shm_attach (cairo_xcb_connection_t *connection,
+				  uint32_t id,
+				  cairo_bool_t readonly)
+{
+    struct {
+	uint8_t req;
+	uint8_t shm_req;
+	uint16_t length;
+	uint32_t segment;
+	uint32_t id;
+	uint8_t readonly;
+	uint8_t pad1;
+	uint16_t pad2;
+    } req;
+    struct iovec vec[1];
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 16);
+
+    req.req = connection->shm->major_opcode;
+    req.shm_req = 1;
+    req.length = sizeof (req) >> 2;
+    req.segment = _cairo_xcb_connection_get_xid (connection);
+    req.id = id;
+    req.readonly = readonly;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+
+    _cairo_xcb_connection_write (connection, vec, 1);
+    return req.segment;
+}
+
+uint64_t
+_cairo_xcb_connection_shm_put_image (cairo_xcb_connection_t *connection,
+				     xcb_drawable_t dst,
+				     xcb_gcontext_t gc,
+				     uint16_t total_width,
+				     uint16_t total_height,
+				     int16_t src_x,
+				     int16_t src_y,
+				     uint16_t width,
+				     uint16_t height,
+				     int16_t dst_x,
+				     int16_t dst_y,
+				     uint8_t depth,
+				     uint32_t shm,
+				     uint32_t offset)
+{
+    struct {
+	uint8_t req;
+	uint8_t shm_req;
+	uint16_t len;
+	uint32_t dst;
+	uint32_t gc;
+	uint16_t total_width;
+	uint16_t total_height;
+	int16_t src_x;
+	int16_t src_y;
+	uint16_t src_width;
+	uint16_t src_height;
+	int16_t dst_x;
+	int16_t dst_y;
+	uint8_t depth;
+	uint8_t format;
+	uint8_t send_event;
+	uint8_t pad;
+	uint32_t shm;
+	uint32_t offset;
+    } req;
+    struct iovec vec[2];
+
+    req.req = connection->shm->major_opcode;
+    req.shm_req = 3;
+    req.len = sizeof (req) >> 2;
+    req.dst = dst;
+    req.gc = gc;
+    req.total_width = total_width;
+    req.total_height = total_height;
+    req.src_x = src_x;
+    req.src_y = src_y;
+    req.src_width = width;
+    req.src_height = height;
+    req.dst_x = dst_x;
+    req.dst_y = dst_y;
+    req.depth = depth;
+    req.format = XCB_IMAGE_FORMAT_Z_PIXMAP;
+    req.send_event = 0;
+    req.shm = shm;
+    req.offset = offset;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+
+    _cairo_xcb_connection_write (connection, vec, 1);
+    return connection->seqno;
+}
+
+cairo_status_t
+_cairo_xcb_connection_shm_get_image (cairo_xcb_connection_t *connection,
+				     xcb_drawable_t src,
+				     int16_t src_x,
+				     int16_t src_y,
+				     uint16_t width,
+				     uint16_t height,
+				     uint32_t shmseg,
+				     uint32_t offset)
+{
+    xcb_shm_get_image_reply_t *reply;
+    xcb_generic_error_t *error;
+
+    reply = xcb_shm_get_image_reply (connection->xcb_connection,
+				     xcb_shm_get_image (connection->xcb_connection,
+							src,
+							src_x, src_y,
+							width, height,
+							(uint32_t) -1,
+							XCB_IMAGE_FORMAT_Z_PIXMAP,
+							shmseg, offset),
+				     &error);
+    free (reply);
+
+    if (error) {
+	/* an error here should be impossible */
+	free (error);
+	return _cairo_error (CAIRO_STATUS_READ_ERROR);
+    }
+
+    return _cairo_xcb_connection_take_socket (connection);
+}
+
+void
+_cairo_xcb_connection_shm_detach (cairo_xcb_connection_t *connection,
+				  uint32_t segment)
+{
+    struct {
+	uint8_t req;
+	uint8_t shm_req;
+	uint16_t length;
+	uint32_t segment;
+    } req;
+    struct iovec vec[1];
+
+    COMPILE_TIME_ASSERT (sizeof (req) == 8);
+
+    req.req = connection->shm->major_opcode;
+    req.shm_req = 2;
+    req.length = sizeof (req) >> 2;
+    req.segment = segment;
+
+    vec[0].iov_base = &req;
+    vec[0].iov_len = sizeof (req);
+
+    _cairo_xcb_connection_write (connection, vec, 1);
+    _cairo_xcb_connection_put_xid (connection, segment);
+}
diff --git a/src/cairo-xcb-connection.c b/src/cairo-xcb-connection.c
new file mode 100644
index 0000000..6721e92
--- /dev/null
+++ b/src/cairo-xcb-connection.c
@@ -0,0 +1,867 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+ *
+ * Authors:
+ *    Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+
+#include "cairoint.h"
+
+#include "cairo-xcb-private.h"
+#include "cairo-hash-private.h"
+#include "cairo-freelist-private.h"
+#include "cairo-list-private.h"
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <xcb/xcbext.h>
+#include <xcb/bigreq.h>
+#include <xcb/dri2.h>
+#include <xcb/shm.h>
+#include <errno.h>
+
+typedef struct _cairo_xcb_xrender_format {
+    cairo_hash_entry_t key;
+    xcb_render_pictformat_t xrender_format;
+} cairo_xcb_xrender_format_t;
+
+typedef struct _cairo_xcb_xid {
+    cairo_list_t link;
+    uint32_t xid;
+} cairo_xcb_xid_t;
+
+#define XCB_RENDER_AT_LEAST(V, major, minor)	\
+	(((V)->major_version > major) ||			\
+	 (((V)->major_version == major) && ((V)->minor_version >= minor)))
+
+#define XCB_RENDER_HAS_CREATE_PICTURE(surface)		XCB_RENDER_AT_LEAST((surface), 0, 0)
+#define XCB_RENDER_HAS_COMPOSITE(surface)		XCB_RENDER_AT_LEAST((surface), 0, 0)
+#define XCB_RENDER_HAS_COMPOSITE_TEXT(surface)		XCB_RENDER_AT_LEAST((surface), 0, 0)
+
+#define XCB_RENDER_HAS_FILL_RECTANGLES(surface)		XCB_RENDER_AT_LEAST((surface), 0, 1)
+
+#define XCB_RENDER_HAS_DISJOINT(surface)		XCB_RENDER_AT_LEAST((surface), 0, 2)
+#define XCB_RENDER_HAS_CONJOINT(surface)		XCB_RENDER_AT_LEAST((surface), 0, 2)
+
+#define XCB_RENDER_HAS_TRAPEZOIDS(surface)		XCB_RENDER_AT_LEAST((surface), 0, 4)
+#define XCB_RENDER_HAS_TRIANGLES(surface)		XCB_RENDER_AT_LEAST((surface), 0, 4)
+#define XCB_RENDER_HAS_TRISTRIP(surface)		XCB_RENDER_AT_LEAST((surface), 0, 4)
+#define XCB_RENDER_HAS_TRIFAN(surface)			XCB_RENDER_AT_LEAST((surface), 0, 4)
+#define XCB_RENDER_HAS_SPANS(surface)			XCB_RENDER_AT_LEAST((surface), 0, 12)
+
+#define XCB_RENDER_HAS_PICTURE_TRANSFORM(surface)	XCB_RENDER_AT_LEAST((surface), 0, 6)
+#define XCB_RENDER_HAS_FILTERS(surface)			XCB_RENDER_AT_LEAST((surface), 0, 6)
+
+#define XCB_RENDER_HAS_EXTENDED_REPEAT(surface)	XCB_RENDER_AT_LEAST((surface), 0, 10)
+#define XCB_RENDER_HAS_GRADIENTS(surface)	XCB_RENDER_AT_LEAST((surface), 0, 10)
+
+#define XCB_RENDER_HAS_PDF_OPERATORS(surface)	XCB_RENDER_AT_LEAST((surface), 0, 11)
+
+static cairo_list_t connections;
+
+static cairo_status_t
+_cairo_xcb_connection_find_visual_formats (cairo_xcb_connection_t *connection,
+					  const xcb_render_query_pict_formats_reply_t *formats)
+{
+    xcb_render_pictscreen_iterator_t screens;
+    xcb_render_pictdepth_iterator_t depths;
+    xcb_render_pictvisual_iterator_t visuals;
+
+    for (screens = xcb_render_query_pict_formats_screens_iterator (formats);
+	 screens.rem;
+	 xcb_render_pictscreen_next (&screens))
+    {
+	for (depths = xcb_render_pictscreen_depths_iterator (screens.data);
+	     depths.rem;
+	     xcb_render_pictdepth_next (&depths))
+	{
+	    for (visuals = xcb_render_pictdepth_visuals_iterator (depths.data);
+		 visuals.rem;
+		 xcb_render_pictvisual_next (&visuals))
+	    {
+		cairo_xcb_xrender_format_t *f;
+		cairo_status_t status;
+
+		f = malloc (sizeof (cairo_xcb_xrender_format_t));
+		if (unlikely (f == NULL))
+		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+		f->key.hash = visuals.data->visual;
+		f->xrender_format = visuals.data->format;
+		status = _cairo_hash_table_insert (connection->visual_to_xrender_format,
+						   &f->key);
+		if (unlikely (status))
+		    return status;
+	    }
+	}
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+#if 0
+static xcb_format_t *
+find_format_for_depth (const xcb_setup_t *setup, uint8_t depth)
+{
+    xcb_format_t *fmt = xcb_setup_pixmap_formats (setup);
+    xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length (setup);
+
+    for (; fmt != fmtend; ++fmt)
+	if (fmt->depth == depth)
+	    return fmt;
+
+    return 0;
+}
+#endif
+
+static cairo_status_t
+_cairo_xcb_connection_parse_xrender_formats (cairo_xcb_connection_t *connection,
+					     const xcb_render_query_pict_formats_reply_t *formats)
+{
+    xcb_render_pictforminfo_iterator_t i;
+    cairo_status_t status;
+
+    for (i = xcb_render_query_pict_formats_formats_iterator (formats);
+	 i.rem;
+	 xcb_render_pictforminfo_next (&i))
+    {
+	cairo_format_masks_t masks;
+	pixman_format_code_t pixman_format;
+
+	if (i.data->type != XCB_RENDER_PICT_TYPE_DIRECT)
+	    continue;
+
+	masks.alpha_mask =
+	    (unsigned long) i.data->direct.alpha_mask << i.data->direct.alpha_shift;
+	masks.red_mask =
+	    (unsigned long) i.data->direct.red_mask << i.data->direct.red_shift;
+	masks.green_mask =
+	    (unsigned long) i.data->direct.green_mask << i.data->direct.green_shift;
+	masks.blue_mask =
+	    (unsigned long) i.data->direct.blue_mask << i.data->direct.blue_shift;
+	masks.bpp = i.data->depth;
+
+	if (_pixman_format_from_masks (&masks, &pixman_format)) {
+	    cairo_hash_entry_t key;
+
+	    key.hash = pixman_format;
+	    if (! _cairo_hash_table_lookup (connection->xrender_formats, &key)) {
+		cairo_xcb_xrender_format_t *f;
+
+		f = malloc (sizeof (cairo_xcb_xrender_format_t));
+		if (unlikely (f == NULL))
+		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+		f->key.hash = pixman_format;
+		f->xrender_format = i.data->id;
+		status = _cairo_hash_table_insert (connection->xrender_formats,
+						   &f->key);
+		if (unlikely (status))
+		    return status;
+
+#if 0
+		printf ("xrender %x -> (%lx, %lx, %lx, %lx, %d) %x [%d, %d]\n",
+			i.data->id,
+			masks.alpha_mask,
+			masks.red_mask,
+			masks.green_mask,
+			masks.blue_mask,
+			masks.bpp,
+			pixman_format,
+			PIXMAN_FORMAT_DEPTH(pixman_format),
+			PIXMAN_FORMAT_BPP(pixman_format));
+#endif
+	    }
+	}
+    }
+
+    status = _cairo_xcb_connection_find_visual_formats (connection, formats);
+    if (unlikely (status))
+	return status;
+
+    connection->standard_formats[CAIRO_FORMAT_A1] =
+	_cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a1);
+
+    connection->standard_formats[CAIRO_FORMAT_A8] =
+	_cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8);
+
+    connection->standard_formats[CAIRO_FORMAT_RGB24] =
+	_cairo_xcb_connection_get_xrender_format (connection,
+						  PIXMAN_FORMAT (24,
+								 PIXMAN_TYPE_ARGB,
+								 0, 8, 8, 8));
+    if (connection->standard_formats[CAIRO_FORMAT_RGB24] == XCB_NONE) {
+	connection->standard_formats[CAIRO_FORMAT_RGB24] =
+	    _cairo_xcb_connection_get_xrender_format (connection,
+						      PIXMAN_FORMAT (24, PIXMAN_TYPE_ABGR,
+								     0, 8, 8, 8));
+    }
+
+    connection->standard_formats[CAIRO_FORMAT_ARGB32] =
+	_cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8r8g8b8);
+    if (connection->standard_formats[CAIRO_FORMAT_ARGB32] == XCB_NONE) {
+	connection->standard_formats[CAIRO_FORMAT_ARGB32] =
+	    _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8b8g8r8);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+/*
+ * We require support for depth 1, 8, 24 and 32 pixmaps
+ */
+#define DEPTH_MASK(d)	(1 << ((d) - 1))
+#define REQUIRED_DEPTHS	(DEPTH_MASK(1) | \
+			 DEPTH_MASK(8) | \
+			 DEPTH_MASK(24) | \
+			 DEPTH_MASK(32))
+static cairo_bool_t
+pixmap_depths_usable (cairo_xcb_connection_t *connection,
+		      uint32_t missing,
+		      xcb_drawable_t root)
+{
+    xcb_connection_t *c = connection->xcb_connection;
+    xcb_void_cookie_t create_cookie[32];
+    xcb_pixmap_t pixmap;
+    cairo_bool_t success = TRUE;
+    int depth, i, j;
+
+    pixmap = _cairo_xcb_connection_get_xid (connection);
+
+    for (depth = 1, i = 0; depth <= 32; depth++) {
+	if (missing & DEPTH_MASK(depth)) {
+	    create_cookie[i] = xcb_create_pixmap_checked (c, depth, pixmap, root, 1, 1);
+	    xcb_free_pixmap (c, pixmap);
+	    if (!create_cookie[i].sequence) {
+		success = FALSE;
+		break;
+	    }
+	    i++;
+	}
+    }
+
+    for (j = 0; j < i; j++) {
+	xcb_generic_error_t *create_error = xcb_request_check (c, create_cookie[j]);
+	success &= create_error == NULL;
+	free (create_error);
+    }
+
+    _cairo_xcb_connection_put_xid (connection, pixmap);
+
+    return success;
+}
+
+static cairo_bool_t
+has_required_depths (cairo_xcb_connection_t *connection)
+{
+    xcb_screen_iterator_t screens;
+
+    for (screens = xcb_setup_roots_iterator (connection->root);
+	 screens.rem;
+	 xcb_screen_next (&screens))
+    {
+	xcb_depth_iterator_t depths;
+	uint32_t missing = REQUIRED_DEPTHS;
+
+	for (depths = xcb_screen_allowed_depths_iterator (screens.data);
+	     depths.rem;
+	     xcb_depth_next (&depths))
+	{
+	    missing &= ~DEPTH_MASK (depths.data->depth);
+	}
+	if (missing == 0)
+	    continue;
+
+	/*
+	 * Ok, this is ugly.  It should be sufficient at this
+	 * point to just return false, but Xinerama is broken at
+	 * this point and only advertises depths which have an
+	 * associated visual.  Of course, the other depths still
+	 * work, but the only way to find out is to try them.
+	 */
+	if (! pixmap_depths_usable (connection, missing, screens.data->root))
+	    return FALSE;
+    }
+
+    return TRUE;
+}
+
+static cairo_status_t
+_cairo_xcb_connection_query_render (cairo_xcb_connection_t *connection)
+{
+    xcb_connection_t *c = connection->xcb_connection;
+    xcb_render_query_version_cookie_t version_cookie;
+    xcb_render_query_pict_formats_cookie_t formats_cookie;
+    xcb_render_query_version_reply_t *version;
+    xcb_render_query_pict_formats_reply_t *formats;
+    cairo_status_t status;
+    cairo_bool_t present;
+
+    version_cookie = xcb_render_query_version (c, 0, 10);
+    formats_cookie = xcb_render_query_pict_formats (c);
+
+    present = has_required_depths (connection);
+    version = xcb_render_query_version_reply (c, version_cookie, 0);
+    formats = xcb_render_query_pict_formats_reply (c, formats_cookie, 0);
+    if (! present || version == NULL || formats == NULL) {
+	free (version);
+	free (formats);
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    /* always true if the extension is present (i.e. >= 0.0) */
+    connection->flags |= CAIRO_XCB_HAS_RENDER;
+    connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE;
+    connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS;
+
+    if (XCB_RENDER_HAS_FILL_RECTANGLES (version))
+	connection->flags |= CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES;
+
+    if (XCB_RENDER_HAS_TRAPEZOIDS (version))
+	connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS;
+
+    if (XCB_RENDER_HAS_PICTURE_TRANSFORM (version))
+	connection->flags |= CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM;
+
+    if (XCB_RENDER_HAS_FILTERS (version))
+	connection->flags |= CAIRO_XCB_RENDER_HAS_FILTERS;
+
+    if (XCB_RENDER_HAS_PDF_OPERATORS (version))
+	connection->flags |= CAIRO_XCB_RENDER_HAS_PDF_OPERATORS;
+
+    if (XCB_RENDER_HAS_EXTENDED_REPEAT (version))
+	connection->flags |= CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT;
+
+    if (XCB_RENDER_HAS_GRADIENTS (version))
+	connection->flags |= CAIRO_XCB_RENDER_HAS_GRADIENTS;
+
+    free (version);
+
+    status = _cairo_xcb_connection_parse_xrender_formats (connection, formats);
+    free (formats);
+
+    return status;
+}
+
+#if 0
+static void
+_cairo_xcb_connection_query_cairo (cairo_xcb_connection_t *connection)
+{
+    xcb_connection_t *c = connection->xcb_connection;
+    xcb_cairo_query_version_reply_t *version;
+
+    version = xcb_cairo_query_version_reply (c,
+					     xcb_cairo_query_version (c, 0, 0),
+					     0);
+
+    free (version);
+}
+#endif
+
+static cairo_bool_t
+can_use_shm (cairo_xcb_connection_t *connection)
+{
+    cairo_bool_t success = TRUE;
+    xcb_connection_t *c = connection->xcb_connection;
+    xcb_void_cookie_t cookie[2];
+    xcb_generic_error_t *error;
+    int shmid;
+    uint32_t shmseg;
+    void *ptr;
+
+    shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600);
+    if (shmid == -1)
+	return FALSE;
+
+    ptr = shmat (shmid, NULL, 0);
+    if (ptr == (char *) -1) {
+	shmctl (shmid, IPC_RMID, NULL);
+	return FALSE;
+    }
+
+    shmseg = _cairo_xcb_connection_get_xid (connection);
+    cookie[0] = xcb_shm_attach_checked (c, shmseg, shmid, FALSE);
+    cookie[1] = xcb_shm_detach_checked (c, shmseg);
+    _cairo_xcb_connection_put_xid (connection, shmseg);
+
+    error = xcb_request_check (c, cookie[0]);
+    if (error != NULL)
+	success = FALSE;
+
+    error = xcb_request_check (c, cookie[1]);
+    if (error != NULL)
+	success = FALSE;
+
+    shmctl (shmid, IPC_RMID, NULL);
+    shmdt (ptr);
+
+    return success;
+}
+
+static void
+_cairo_xcb_connection_query_shm (cairo_xcb_connection_t *connection)
+{
+    xcb_connection_t *c = connection->xcb_connection;
+    xcb_shm_query_version_reply_t *version;
+
+    version = xcb_shm_query_version_reply (c, xcb_shm_query_version (c), 0);
+    if (version == NULL)
+	return;
+
+    free (version);
+
+    if (can_use_shm (connection))
+	connection->flags |= CAIRO_XCB_HAS_SHM;
+}
+
+#if CAIRO_HAS_XCB_DRM_FUNCTIONS
+static void
+_cairo_xcb_connection_query_dri2 (cairo_xcb_connection_t *connection)
+{
+    xcb_connection_t *c = connection->xcb_connection;
+    xcb_dri2_query_version_reply_t *version;
+
+    version = xcb_dri2_query_version_reply (c,
+					    xcb_dri2_query_version (c,
+								    XCB_DRI2_MAJOR_VERSION,
+								    XCB_DRI2_MINOR_VERSION),
+					    0);
+    if (version == NULL)
+	return;
+
+    free (version);
+
+    connection->flags |= CAIRO_XCB_HAS_DRI2;
+}
+#endif
+
+static void
+_device_flush (void *device)
+{
+    cairo_xcb_connection_t *connection = device;
+    cairo_xcb_screen_t *screen;
+    cairo_status_t status;
+
+    status = cairo_device_acquire (&connection->device);
+    if (unlikely (status))
+	return;
+
+    CAIRO_MUTEX_LOCK (connection->screens_mutex);
+    cairo_list_foreach_entry (screen, cairo_xcb_screen_t,
+			      &connection->screens, link)
+    {
+	if (screen->device != NULL)
+	    cairo_device_flush (screen->device);
+    }
+    CAIRO_MUTEX_UNLOCK (connection->screens_mutex);
+
+    xcb_flush (connection->xcb_connection);
+
+    cairo_device_release (&connection->device);
+}
+
+static cairo_bool_t
+_xrender_formats_equal (const void *A, const void *B)
+{
+    const cairo_xcb_xrender_format_t *a = A, *b = B;
+    return a->key.hash == b->key.hash;
+}
+
+static void
+_pluck_xrender_format (void *entry,
+		       void *closure)
+{
+    _cairo_hash_table_remove (closure, entry);
+    free (entry);
+}
+
+static void
+_device_finish (void *device)
+{
+    cairo_xcb_connection_t *connection = device;
+
+    if (! cairo_list_is_empty (&connection->link)) {
+	CAIRO_MUTEX_LOCK (_cairo_xcb_connections_mutex);
+	cairo_list_del (&connection->link);
+	CAIRO_MUTEX_UNLOCK (_cairo_xcb_connections_mutex);
+    }
+
+    while (! cairo_list_is_empty (&connection->fonts)) {
+	cairo_xcb_font_t *font;
+
+	font = cairo_list_first_entry (&connection->fonts,
+				       cairo_xcb_font_t,
+				       link);
+	_cairo_xcb_font_finish (font);
+    }
+
+    while (! cairo_list_is_empty (&connection->screens)) {
+	cairo_xcb_screen_t *screen;
+
+	screen = cairo_list_first_entry (&connection->screens,
+					 cairo_xcb_screen_t,
+					 link);
+	_cairo_xcb_screen_finish (screen);
+    }
+}
+
+static void
+_device_destroy (void *device)
+{
+    cairo_xcb_connection_t *connection = device;
+
+    _cairo_hash_table_foreach (connection->xrender_formats,
+			       _pluck_xrender_format, connection->xrender_formats);
+    _cairo_hash_table_destroy (connection->xrender_formats);
+
+    _cairo_hash_table_foreach (connection->visual_to_xrender_format,
+			       _pluck_xrender_format,
+			       connection->visual_to_xrender_format);
+    _cairo_hash_table_destroy (connection->visual_to_xrender_format);
+
+    _cairo_xcb_connection_shm_mem_pools_fini (connection);
+    _cairo_freepool_fini (&connection->shm_info_freelist);
+
+    _cairo_freepool_fini (&connection->xid_pool);
+
+    CAIRO_MUTEX_FINI (connection->shm_mutex);
+    CAIRO_MUTEX_FINI (connection->screens_mutex);
+
+    free (connection);
+}
+
+static const cairo_device_backend_t _cairo_xcb_device_backend = {
+    CAIRO_DEVICE_TYPE_XCB,
+
+    NULL, NULL, /* lock, unlock */
+
+    _device_flush,
+    _device_finish,
+    _device_destroy,
+};
+
+cairo_xcb_connection_t *
+_cairo_xcb_connection_get (xcb_connection_t *xcb_connection)
+{
+    cairo_xcb_connection_t *connection;
+    const xcb_query_extension_reply_t *ext;
+    cairo_status_t status;
+
+    CAIRO_MUTEX_LOCK (_cairo_xcb_connections_mutex);
+    if (connections.next == NULL) {
+	/* XXX _cairo_init () */
+	cairo_list_init (&connections);
+    }
+
+    cairo_list_foreach_entry (connection,
+			      cairo_xcb_connection_t,
+			      &connections,
+			      link)
+    {
+	if (connection->xcb_connection == xcb_connection) {
+	    /* Maintain MRU order. */
+	    if (connections.next != &connection->link)
+		cairo_list_move (&connection->link, &connections);
+
+	    goto unlock;
+	}
+    }
+
+    connection = malloc (sizeof (cairo_xcb_connection_t));
+    if (unlikely (connection == NULL))
+	goto unlock;
+
+    _cairo_device_init (&connection->device, &_cairo_xcb_device_backend);
+    CAIRO_MUTEX_INIT (connection->shm_mutex);
+    CAIRO_MUTEX_INIT (connection->screens_mutex);
+
+    connection->xcb_connection = xcb_connection;
+    connection->has_socket = FALSE;
+
+    xcb_prefetch_extension_data (xcb_connection, &xcb_big_requests_id);
+    xcb_prefetch_extension_data (xcb_connection, &xcb_shm_id);
+    xcb_prefetch_extension_data (xcb_connection, &xcb_render_id);
+#if 0
+    xcb_prefetch_extension_data (xcb_connection, &xcb_cairo_id);
+#endif
+#if CAIRO_HAS_XCB_DRM_FUNCTIONS
+    xcb_prefetch_extension_data (xcb_connection, &xcb_dri2_id);
+#endif
+
+    xcb_prefetch_maximum_request_length (xcb_connection);
+
+    cairo_list_init (&connection->fonts);
+    cairo_list_init (&connection->screens);
+    cairo_list_add (&connection->link, &connections);
+    connection->xrender_formats = _cairo_hash_table_create (_xrender_formats_equal);
+    connection->visual_to_xrender_format = _cairo_hash_table_create (_xrender_formats_equal);
+
+    cairo_list_init (&connection->free_xids);
+    _cairo_freepool_init (&connection->xid_pool,
+			  sizeof (cairo_xcb_xid_t));
+
+    cairo_list_init (&connection->shm_pools);
+    _cairo_freepool_init (&connection->shm_info_freelist,
+			  sizeof (cairo_xcb_shm_info_t));
+
+    connection->maximum_request_length =
+	xcb_get_maximum_request_length (xcb_connection);
+
+    connection->flags = 0;
+
+    connection->root = xcb_get_setup (xcb_connection);
+    connection->render = NULL;
+    ext = xcb_get_extension_data (xcb_connection, &xcb_render_id);
+    if (ext != NULL && ext->present) {
+	status = _cairo_xcb_connection_query_render (connection);
+	if (unlikely (status)) {
+	    _cairo_xcb_connection_destroy (connection);
+	    connection = NULL;
+	    goto unlock;
+	}
+
+	connection->render = ext;
+    }
+
+#if 0
+    ext = xcb_get_extension_data (connection, &xcb_cairo_id);
+    if (ext != NULL && ext->present)
+	_cairo_xcb_connection_query_cairo (connection);
+#endif
+
+    connection->shm = NULL;
+    ext = xcb_get_extension_data (xcb_connection, &xcb_shm_id);
+    if (ext != NULL && ext->present) {
+	_cairo_xcb_connection_query_shm (connection);
+	connection->shm = ext;
+    }
+
+    connection->dri2 = NULL;
+#if CAIRO_HAS_XCB_DRM_FUNCTIONS
+    ext = xcb_get_extension_data (xcb_connection, &xcb_dri2_id);
+    if (ext != NULL && ext->present) {
+	_cairo_xcb_connection_query_dri2 (connection);
+	connection->dri2 = ext;
+    }
+#endif
+
+unlock:
+    CAIRO_MUTEX_UNLOCK (_cairo_xcb_connections_mutex);
+
+    return connection;
+}
+
+xcb_render_pictformat_t
+_cairo_xcb_connection_get_xrender_format (cairo_xcb_connection_t *connection,
+					  pixman_format_code_t pixman_format)
+{
+    cairo_hash_entry_t key;
+    cairo_xcb_xrender_format_t *format;
+
+    key.hash = pixman_format;
+    format = _cairo_hash_table_lookup (connection->xrender_formats, &key);
+    return format ? format->xrender_format : XCB_NONE;
+}
+
+xcb_render_pictformat_t
+_cairo_xcb_connection_get_xrender_format_for_visual (cairo_xcb_connection_t *connection,
+						     const xcb_visualid_t visual)
+{
+    cairo_hash_entry_t key;
+    cairo_xcb_xrender_format_t *format;
+
+    key.hash = visual;
+    format = _cairo_hash_table_lookup (connection->visual_to_xrender_format, &key);
+    return format ? format->xrender_format : XCB_NONE;
+}
+
+void
+_cairo_xcb_connection_put_xid (cairo_xcb_connection_t *connection,
+			       uint32_t xid)
+{
+    cairo_xcb_xid_t *cache;
+
+    assert (CAIRO_MUTEX_IS_LOCKED (connection->mutex));
+    cache = _cairo_freepool_alloc (&connection->xid_pool);
+    if (likely (cache != NULL)) {
+	cache->xid = xid;
+	cairo_list_add (&cache->link, &connection->free_xids);
+    }
+}
+
+uint32_t
+_cairo_xcb_connection_get_xid (cairo_xcb_connection_t *connection)
+{
+    uint32_t xid;
+
+    assert (CAIRO_MUTEX_IS_LOCKED (connection->mutex));
+    if (! cairo_list_is_empty (&connection->free_xids)) {
+	cairo_xcb_xid_t *cache;
+
+	cache = cairo_list_first_entry (&connection->free_xids,
+					cairo_xcb_xid_t,
+					link);
+	xid = cache->xid;
+
+	cairo_list_del (&cache->link);
+	_cairo_freepool_free (&connection->xid_pool, cache);
+    } else {
+	xid = xcb_generate_id (connection->xcb_connection);
+    }
+
+    return xid;
+}
+
+static void
+_cairo_xcb_return_socket (void *closure)
+{
+    cairo_xcb_connection_t *connection = closure;
+
+    CAIRO_MUTEX_LOCK (connection->device.mutex);
+    connection->has_socket = FALSE;
+    CAIRO_MUTEX_UNLOCK (connection->device.mutex);
+}
+
+cairo_status_t
+_cairo_xcb_connection_take_socket (cairo_xcb_connection_t *connection)
+{
+    assert (CAIRO_MUTEX_IS_LOCKED (connection->mutex));
+
+    if (unlikely (connection->device.status))
+	return connection->device.status;
+
+    if (! connection->has_socket) {
+	if (! xcb_take_socket (connection->xcb_connection,
+			       _cairo_xcb_return_socket,
+			       connection,
+			       0, &connection->seqno))
+	{
+	    return connection->device.status = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
+	}
+
+	connection->has_socket = TRUE;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+/* public (debug) interface */
+
+void
+cairo_xcb_device_debug_cap_xshm_version (cairo_device_t *device,
+                                         int major_version,
+                                         int minor_version)
+{
+    cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device;
+    cairo_status_t status;
+
+    if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
+	status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
+	return;
+    }
+
+    /* clear any flags that are inappropriate for the desired version */
+    if (major_version < 0 && minor_version < 0) {
+	connection->flags &= ~(CAIRO_XCB_HAS_SHM);
+    }
+}
+
+void
+cairo_xcb_device_debug_cap_xrender_version (cairo_device_t *device,
+                                            int major_version,
+                                            int minor_version)
+{
+    cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device;
+    cairo_status_t status;
+
+    if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
+	status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
+	return;
+    }
+
+    /* clear any flags that are inappropriate for the desired version */
+    if (major_version < 0 && minor_version < 0) {
+	connection->flags &= ~(CAIRO_XCB_HAS_RENDER |
+			       CAIRO_XCB_RENDER_HAS_COMPOSITE |
+			       CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS |
+			       CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES |
+			       CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
+			       CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM |
+			       CAIRO_XCB_RENDER_HAS_FILTERS |
+			       CAIRO_XCB_RENDER_HAS_PDF_OPERATORS |
+			       CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT |
+			       CAIRO_XCB_RENDER_HAS_GRADIENTS);
+    } else {
+	xcb_render_query_version_reply_t version;
+
+	version.major_version = major_version;
+	version.minor_version = minor_version;
+
+	if (! XCB_RENDER_HAS_FILL_RECTANGLES (&version))
+	    connection->flags &= ~CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES;
+
+	if (! XCB_RENDER_HAS_TRAPEZOIDS (&version))
+	    connection->flags &= ~CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS;
+
+	if (! XCB_RENDER_HAS_PICTURE_TRANSFORM (&version))
+	    connection->flags &= ~CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM;
+
+	if (! XCB_RENDER_HAS_FILTERS (&version))
+	    connection->flags &= ~CAIRO_XCB_RENDER_HAS_FILTERS;
+
+	if (! XCB_RENDER_HAS_PDF_OPERATORS (&version))
+	    connection->flags &= ~CAIRO_XCB_RENDER_HAS_PDF_OPERATORS;
+
+	if (! XCB_RENDER_HAS_EXTENDED_REPEAT (&version))
+	    connection->flags &= ~CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT;
+
+	if (! XCB_RENDER_HAS_GRADIENTS (&version))
+	    connection->flags &= ~CAIRO_XCB_RENDER_HAS_GRADIENTS;
+    }
+}
+
+#if 0
+void
+cairo_xcb_device_debug_cap_xcairo_version (cairo_device_t *device,
+                                           int major_version,
+                                           int minor_version)
+{
+    cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device;
+    cairo_status_t status;
+
+    if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) {
+	status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH);
+	return;
+    }
+
+    /* clear any flags that are inappropriate for the desired version */
+    if (major_version < 0 && minor_version < 0) {
+	connection->flags &= ~(CAIRO_XCB_HAS_CAIRO);
+    }
+}
+#endif
diff --git a/src/cairo-xcb-private.h b/src/cairo-xcb-private.h
new file mode 100644
index 0000000..18a485c
--- /dev/null
+++ b/src/cairo-xcb-private.h
@@ -0,0 +1,760 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2005 Red Hat, Inc.
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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_XCB_PRIVATE_H
+#define CAIRO_XCB_PRIVATE_H
+
+#include "cairo-xcb.h"
+
+#include "cairo-cache-private.h"
+#include "cairo-compiler-private.h"
+#include "cairo-device-private.h"
+#include "cairo-error-private.h"
+#include "cairo-freelist-private.h"
+#include "cairo-list-private.h"
+#include "cairo-mutex-private.h"
+#include "cairo-reference-count-private.h"
+#include "cairo-spans-private.h"
+#include "cairo-surface-private.h"
+
+#include <xcb/xcb.h>
+#include <xcb/render.h>
+#include <xcb/xcbext.h>
+#include <pixman.h>
+
+typedef struct _cairo_xcb_connection cairo_xcb_connection_t;
+typedef struct _cairo_xcb_font cairo_xcb_font_t;
+typedef struct _cairo_xcb_screen cairo_xcb_screen_t;
+typedef struct _cairo_xcb_surface cairo_xcb_surface_t;
+typedef struct _cairo_xcb_shm_mem_pool cairo_xcb_shm_mem_pool_t;
+typedef struct _cairo_xcb_shm_info cairo_xcb_shm_info_t;
+
+struct _cairo_xcb_shm_info {
+    cairo_xcb_connection_t *connection;
+    uint32_t shm;
+    uint32_t offset;
+    uint64_t seqno;
+    void *mem;
+    cairo_xcb_shm_mem_pool_t *pool;
+};
+
+struct _cairo_xcb_surface {
+    cairo_surface_t base;
+    cairo_surface_t *fallback;
+
+    cairo_xcb_connection_t *connection;
+    cairo_xcb_screen_t *screen;
+
+    cairo_surface_t *drm;
+    cairo_bool_t marked_dirty;
+
+    xcb_drawable_t drawable;
+    cairo_bool_t owns_pixmap;
+    int use_pixmap;
+
+    int width;
+    int height;
+    int depth;
+
+    unsigned int flags;
+    xcb_render_picture_t picture;
+    xcb_render_pictformat_t xrender_format;
+    pixman_format_code_t pixman_format;
+
+    cairo_list_t link;
+};
+
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+typedef struct _cairo_xlib_xcb_surface {
+    cairo_surface_t base;
+
+    cairo_xcb_surface_t *xcb;
+
+    /* original settings for query */
+    void *display;
+    void *screen;
+    void *visual;
+    void *format;
+} cairo_xlib_xcb_surface_t;
+#endif
+
+
+enum {
+    GLYPHSET_INDEX_ARGB32,
+    GLYPHSET_INDEX_A8,
+    GLYPHSET_INDEX_A1,
+    NUM_GLYPHSETS
+};
+
+typedef struct _cairo_xcb_font_glyphset_free_glyphs {
+    xcb_render_glyphset_t   glyphset;
+    int			    glyph_count;
+    xcb_render_glyph_t	    glyph_indices[128];
+} cairo_xcb_font_glyphset_free_glyphs_t;
+
+typedef struct _cairo_xcb_font_glyphset_info {
+    xcb_render_glyphset_t   glyphset;
+    cairo_format_t	    format;
+    xcb_render_pictformat_t xrender_format;
+    cairo_xcb_font_glyphset_free_glyphs_t *pending_free_glyphs;
+} cairo_xcb_font_glyphset_info_t;
+
+struct _cairo_xcb_font {
+    cairo_scaled_font_t		    *scaled_font;
+    cairo_xcb_connection_t	    *connection;
+    cairo_xcb_font_glyphset_info_t  glyphset_info[NUM_GLYPHSETS];
+    cairo_list_t link;
+};
+
+struct _cairo_xcb_screen {
+    cairo_xcb_connection_t *connection;
+
+    xcb_screen_t	    *xcb_screen;
+    cairo_device_t	    *device;
+
+    xcb_gcontext_t gc[4];
+    int gc_depths; /* 4 x uint8_t */
+
+    cairo_surface_t *stock_colors[CAIRO_STOCK_NUM_COLORS];
+    struct {
+	cairo_surface_t *picture;
+	cairo_color_t color;
+    } solid_cache[16];
+    int solid_cache_size;
+
+    cairo_cache_t surface_pattern_cache;
+    cairo_cache_t linear_pattern_cache;
+    cairo_cache_t radial_pattern_cache;
+    cairo_freelist_t pattern_cache_entry_freelist;
+
+    cairo_list_t link;
+    cairo_list_t surfaces;
+};
+
+struct _cairo_xcb_connection {
+    cairo_device_t device;
+
+    xcb_connection_t *xcb_connection;
+    cairo_bool_t has_socket;
+
+    xcb_render_pictformat_t standard_formats[5];
+    cairo_hash_table_t *xrender_formats;
+    cairo_hash_table_t *visual_to_xrender_format;
+
+    unsigned int maximum_request_length;
+    unsigned int flags;
+
+    const xcb_setup_t *root;
+    const xcb_query_extension_reply_t *render;
+    const xcb_query_extension_reply_t *shm;
+    const xcb_query_extension_reply_t *dri2;
+    uint64_t seqno;
+
+    cairo_list_t free_xids;
+    cairo_freepool_t xid_pool;
+
+    cairo_mutex_t shm_mutex;
+    cairo_list_t shm_pools;
+    cairo_freepool_t shm_info_freelist;
+
+    cairo_mutex_t screens_mutex;
+    cairo_list_t screens;
+
+    cairo_list_t fonts;
+
+    cairo_list_t link;
+};
+
+enum {
+    CAIRO_XCB_HAS_RENDER			= 0x0001,
+    CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES	= 0x0002,
+    CAIRO_XCB_RENDER_HAS_COMPOSITE		= 0x0004,
+    CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS	= 0x0008,
+    CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS	= 0x0010,
+    CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS	= 0x0020,
+    CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM	= 0x0040,
+    CAIRO_XCB_RENDER_HAS_FILTERS		= 0x0080,
+    CAIRO_XCB_RENDER_HAS_PDF_OPERATORS		= 0x0100,
+    CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT	= 0x0200,
+    CAIRO_XCB_RENDER_HAS_GRADIENTS		= 0x0400,
+
+    CAIRO_XCB_HAS_CAIRO				= 0x10000,
+
+    CAIRO_XCB_HAS_DRI2				= 0x40000000,
+    CAIRO_XCB_HAS_SHM				= 0x80000000
+};
+
+#define CAIRO_XCB_SHM_SMALL_IMAGE 8192
+
+cairo_private extern const cairo_surface_backend_t _cairo_xcb_surface_backend;
+
+cairo_private cairo_xcb_connection_t *
+_cairo_xcb_connection_get (xcb_connection_t *connection);
+
+static inline cairo_xcb_connection_t *
+_cairo_xcb_connection_reference (cairo_xcb_connection_t *connection)
+{
+    return (cairo_xcb_connection_t *) cairo_device_reference (&connection->device);
+}
+
+cairo_private xcb_render_pictformat_t
+_cairo_xcb_connection_get_xrender_format (cairo_xcb_connection_t *connection,
+					  pixman_format_code_t pixman_format);
+
+cairo_private xcb_render_pictformat_t
+_cairo_xcb_connection_get_xrender_format_for_visual (cairo_xcb_connection_t *connection,
+						     const xcb_visualid_t visual);
+
+static inline cairo_status_t cairo_warn
+_cairo_xcb_connection_acquire (cairo_xcb_connection_t *connection)
+{
+    return cairo_device_acquire (&connection->device);
+}
+
+cairo_private cairo_status_t
+_cairo_xcb_connection_take_socket (cairo_xcb_connection_t *connection);
+
+cairo_private uint32_t
+_cairo_xcb_connection_get_xid (cairo_xcb_connection_t *connection);
+
+cairo_private void
+_cairo_xcb_connection_put_xid (cairo_xcb_connection_t *connection,
+			       uint32_t xid);
+
+static inline void
+_cairo_xcb_connection_release (cairo_xcb_connection_t *connection)
+{
+    cairo_device_release (&connection->device);
+}
+
+static inline void
+_cairo_xcb_connection_destroy (cairo_xcb_connection_t *connection)
+{
+    cairo_device_destroy (&connection->device);
+}
+
+cairo_private cairo_int_status_t
+_cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *display,
+					 size_t size,
+					 cairo_xcb_shm_info_t **shm_info_out);
+
+cairo_private void
+_cairo_xcb_shm_info_destroy (cairo_xcb_shm_info_t *shm_info);
+
+cairo_private void
+_cairo_xcb_connection_shm_mem_pools_fini (cairo_xcb_connection_t *connection);
+
+cairo_private void
+_cairo_xcb_font_finish (cairo_xcb_font_t *font);
+
+cairo_private cairo_xcb_screen_t *
+_cairo_xcb_screen_get (xcb_connection_t *connection,
+		       xcb_screen_t *screen);
+
+cairo_private void
+_cairo_xcb_screen_finish (cairo_xcb_screen_t *screen);
+
+cairo_private xcb_gcontext_t
+_cairo_xcb_screen_get_gc (cairo_xcb_screen_t *screen,
+			  xcb_drawable_t drawable,
+			  int depth);
+
+cairo_private void
+_cairo_xcb_screen_put_gc (cairo_xcb_screen_t *screen, int depth, xcb_gcontext_t gc);
+
+cairo_private cairo_status_t
+_cairo_xcb_screen_store_surface_picture (cairo_xcb_screen_t *screen,
+					 cairo_surface_t *picture,
+					 unsigned int size);
+cairo_private void
+_cairo_xcb_screen_remove_surface_picture (cairo_xcb_screen_t *screen,
+					  cairo_surface_t *picture);
+
+cairo_private cairo_status_t
+_cairo_xcb_screen_store_linear_picture (cairo_xcb_screen_t *screen,
+					const cairo_linear_pattern_t *linear,
+					cairo_surface_t *picture);
+
+cairo_private cairo_surface_t *
+_cairo_xcb_screen_lookup_linear_picture (cairo_xcb_screen_t *screen,
+					 const cairo_linear_pattern_t *linear);
+
+cairo_private cairo_status_t
+_cairo_xcb_screen_store_radial_picture (cairo_xcb_screen_t *screen,
+					const cairo_radial_pattern_t *radial,
+					cairo_surface_t *picture);
+
+cairo_private cairo_surface_t *
+_cairo_xcb_screen_lookup_radial_picture (cairo_xcb_screen_t *screen,
+					 const cairo_radial_pattern_t *radial);
+
+cairo_private cairo_surface_t *
+_cairo_xcb_surface_create_similar_image (cairo_xcb_surface_t *other,
+					 cairo_content_t content,
+					 int width, int height);
+
+cairo_private cairo_surface_t *
+_cairo_xcb_surface_create_similar (void			*abstract_other,
+				   cairo_content_t	 content,
+				   int			 width,
+				   int			 height);
+
+cairo_private cairo_surface_t *
+_cairo_xcb_surface_create_internal (cairo_xcb_screen_t		*screen,
+				    xcb_drawable_t		 drawable,
+				    cairo_bool_t		 owns_pixmap,
+				    pixman_format_code_t	 pixman_format,
+				    xcb_render_pictformat_t	 xrender_format,
+				    int				 width,
+				    int				 height);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_cairo_paint (cairo_xcb_surface_t	*surface,
+				cairo_operator_t	 op,
+				const cairo_pattern_t	*source,
+				cairo_clip_t		*clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_cairo_mask (cairo_xcb_surface_t	*surface,
+			       cairo_operator_t		 op,
+			       const cairo_pattern_t	*source,
+			       const cairo_pattern_t	*mask,
+			       cairo_clip_t		*clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_cairo_stroke (cairo_xcb_surface_t	*surface,
+				 cairo_operator_t	 op,
+				 const cairo_pattern_t	*source,
+				 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_clip_t		*clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_cairo_fill (cairo_xcb_surface_t	*surface,
+			       cairo_operator_t		 op,
+			       const cairo_pattern_t	*source,
+			       cairo_path_fixed_t	*path,
+			       cairo_fill_rule_t	 fill_rule,
+			       double			 tolerance,
+			       cairo_antialias_t	 antialias,
+			       cairo_clip_t		*clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_cairo_glyphs (cairo_xcb_surface_t	*surface,
+				 cairo_operator_t		 op,
+				 const cairo_pattern_t	*source,
+				 cairo_scaled_font_t	*scaled_font,
+				 cairo_glyph_t		*glyphs,
+				 int			 num_glyphs,
+				 cairo_clip_t		*clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_render_paint (cairo_xcb_surface_t	*surface,
+				 cairo_operator_t	 op,
+				 const cairo_pattern_t	*source,
+				 cairo_clip_t		*clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_render_mask (cairo_xcb_surface_t	*surface,
+				cairo_operator_t		 op,
+				const cairo_pattern_t	*source,
+				const cairo_pattern_t	*mask,
+				cairo_clip_t		*clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_render_stroke (cairo_xcb_surface_t	*surface,
+				  cairo_operator_t	 op,
+				  const cairo_pattern_t	*source,
+				  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_clip_t		*clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_render_fill (cairo_xcb_surface_t	*surface,
+				cairo_operator_t		 op,
+				const cairo_pattern_t	*source,
+				cairo_path_fixed_t	*path,
+				cairo_fill_rule_t	 fill_rule,
+				double			 tolerance,
+				cairo_antialias_t	 antialias,
+				cairo_clip_t		*clip);
+
+cairo_private cairo_int_status_t
+_cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t	*surface,
+				  cairo_operator_t		 op,
+				  const cairo_pattern_t	*source,
+				  cairo_scaled_font_t	*scaled_font,
+				  cairo_glyph_t		*glyphs,
+				  int			 num_glyphs,
+				  cairo_clip_t		*clip);
+cairo_private void
+_cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
+
+cairo_private void
+_cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
+				      cairo_scaled_font_t  *scaled_font);
+
+cairo_private cairo_status_t
+_cairo_xcb_surface_core_copy_boxes (cairo_xcb_surface_t		*dst,
+				   const cairo_pattern_t	*src_pattern,
+				   const cairo_rectangle_int_t	*extents,
+				   const cairo_boxes_t		*boxes);
+
+cairo_private cairo_status_t
+_cairo_xcb_surface_core_fill_boxes (cairo_xcb_surface_t *dst,
+				    const cairo_color_t	*color,
+				    cairo_boxes_t *boxes);
+
+static inline void
+_cairo_xcb_connection_write (cairo_xcb_connection_t *connection,
+			     struct iovec *vec,
+			     int count)
+{
+    if (unlikely (connection->device.status))
+	return;
+
+    connection->seqno++;
+    if (unlikely (! xcb_writev (connection->xcb_connection, vec, count, 1)))
+	connection->device.status = _cairo_error (CAIRO_STATUS_WRITE_ERROR);
+}
+
+cairo_private xcb_pixmap_t
+_cairo_xcb_connection_create_pixmap (cairo_xcb_connection_t *connection,
+				     uint8_t depth,
+				     xcb_drawable_t drawable,
+				     uint16_t width,
+				     uint16_t height);
+
+cairo_private void
+_cairo_xcb_connection_free_pixmap (cairo_xcb_connection_t *connection,
+				   xcb_pixmap_t pixmap);
+
+cairo_private xcb_gcontext_t
+_cairo_xcb_connection_create_gc (cairo_xcb_connection_t *connection,
+				 xcb_drawable_t drawable,
+				 uint32_t value_mask,
+				 uint32_t *values);
+
+cairo_private void
+_cairo_xcb_connection_free_gc (cairo_xcb_connection_t *connection,
+			       xcb_gcontext_t gc);
+
+cairo_private void
+_cairo_xcb_connection_change_gc (cairo_xcb_connection_t *connection,
+				 xcb_gcontext_t gc,
+				 uint32_t value_mask,
+				 uint32_t *values);
+
+cairo_private void
+_cairo_xcb_connection_copy_area (cairo_xcb_connection_t *connection,
+				 xcb_drawable_t src,
+				 xcb_drawable_t dst,
+				 xcb_gcontext_t gc,
+				 int16_t src_x,
+				 int16_t src_y,
+				 int16_t dst_x,
+				 int16_t dst_y,
+				 uint16_t width,
+				 uint16_t height);
+
+cairo_private void
+_cairo_xcb_connection_put_image (cairo_xcb_connection_t *connection,
+				 xcb_drawable_t dst,
+				 xcb_gcontext_t gc,
+				 uint16_t width,
+				 uint16_t height,
+				 int16_t dst_x,
+				 int16_t dst_y,
+				 uint8_t depth,
+				 uint32_t length,
+				 void *data);
+
+cairo_private void
+_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection,
+				    xcb_drawable_t dst,
+				    xcb_gcontext_t gc,
+				    int16_t src_x,
+				    int16_t src_y,
+				    uint16_t width,
+				    uint16_t height,
+				    uint16_t cpp,
+				    uint16_t stride,
+				    int16_t dst_x,
+				    int16_t dst_y,
+				    uint8_t depth,
+				    void *data);
+
+cairo_private cairo_status_t
+_cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection,
+				 xcb_drawable_t src,
+				 int16_t src_x,
+				 int16_t src_y,
+				 uint16_t width,
+				 uint16_t height,
+				 xcb_get_image_reply_t **reply);
+
+cairo_private void
+_cairo_xcb_connection_poly_fill_rectangle (cairo_xcb_connection_t *connection,
+					   xcb_drawable_t dst,
+					   xcb_gcontext_t gc,
+					   uint32_t num_rectangles,
+					   xcb_rectangle_t *rectangles);
+
+cairo_private uint32_t
+_cairo_xcb_connection_shm_attach (cairo_xcb_connection_t *connection,
+				  uint32_t id,
+				  cairo_bool_t readonly);
+
+cairo_private uint64_t
+_cairo_xcb_connection_shm_put_image (cairo_xcb_connection_t *connection,
+				     xcb_drawable_t dst,
+				     xcb_gcontext_t gc,
+				     uint16_t total_width,
+				     uint16_t total_height,
+				     int16_t src_x,
+				     int16_t src_y,
+				     uint16_t width,
+				     uint16_t height,
+				     int16_t dst_x,
+				     int16_t dst_y,
+				     uint8_t depth,
+				     uint32_t shm,
+				     uint32_t offset);
+
+cairo_private cairo_status_t
+_cairo_xcb_connection_shm_get_image (cairo_xcb_connection_t *connection,
+				     xcb_drawable_t src,
+				     int16_t src_x,
+				     int16_t src_y,
+				     uint16_t width,
+				     uint16_t height,
+				     uint32_t shmseg,
+				     uint32_t offset);
+
+cairo_private void
+_cairo_xcb_connection_shm_detach (cairo_xcb_connection_t *connection,
+				  uint32_t segment);
+
+cairo_private void
+_cairo_xcb_connection_render_spans (cairo_xcb_connection_t *connection,
+				    xcb_render_picture_t dst,
+				    int op,
+				    xcb_render_picture_t src,
+				    int16_t src_x, int16_t src_y,
+				    int16_t dst_x, int16_t dst_y,
+				    int16_t width, int16_t height,
+				    unsigned int length,
+				    uint16_t *spans);
+cairo_private void
+_cairo_xcb_connection_render_create_picture (cairo_xcb_connection_t  *connection,
+					     xcb_render_picture_t     picture,
+					     xcb_drawable_t           drawable,
+					     xcb_render_pictformat_t  format,
+					     uint32_t                 value_mask,
+					     uint32_t	             *value_list);
+
+cairo_private void
+_cairo_xcb_connection_render_change_picture (cairo_xcb_connection_t     *connection,
+					     xcb_render_picture_t  picture,
+					     uint32_t              value_mask,
+					     uint32_t             *value_list);
+
+cairo_private void
+_cairo_xcb_connection_render_set_picture_clip_rectangles (cairo_xcb_connection_t      *connection,
+							  xcb_render_picture_t   picture,
+							  int16_t                clip_x_origin,
+							  int16_t                clip_y_origin,
+							  uint32_t               rectangles_len,
+							  xcb_rectangle_t       *rectangles);
+
+cairo_private void
+_cairo_xcb_connection_render_free_picture (cairo_xcb_connection_t *connection,
+					   xcb_render_picture_t  picture);
+
+cairo_private void
+_cairo_xcb_connection_render_composite (cairo_xcb_connection_t     *connection,
+					uint8_t               op,
+					xcb_render_picture_t  src,
+					xcb_render_picture_t  mask,
+					xcb_render_picture_t  dst,
+					int16_t               src_x,
+					int16_t               src_y,
+					int16_t               mask_x,
+					int16_t               mask_y,
+					int16_t               dst_x,
+					int16_t               dst_y,
+					uint16_t              width,
+					uint16_t              height);
+
+cairo_private void
+_cairo_xcb_connection_render_trapezoids (cairo_xcb_connection_t *connection,
+					 uint8_t                       op,
+					 xcb_render_picture_t          src,
+					 xcb_render_picture_t          dst,
+					 xcb_render_pictformat_t       mask_format,
+					 int16_t                       src_x,
+					 int16_t                       src_y,
+					 uint32_t                      traps_len,
+					 xcb_render_trapezoid_t       *traps);
+
+cairo_private void
+_cairo_xcb_connection_render_create_glyph_set (cairo_xcb_connection_t	*connection,
+					       xcb_render_glyphset_t	 id,
+					       xcb_render_pictformat_t  format);
+
+cairo_private void
+_cairo_xcb_connection_render_free_glyph_set (cairo_xcb_connection_t      *connection,
+					     xcb_render_glyphset_t  glyphset);
+
+cairo_private void
+_cairo_xcb_connection_render_add_glyphs (cairo_xcb_connection_t             *connection,
+					 xcb_render_glyphset_t         glyphset,
+					 uint32_t                      num_glyphs,
+					 uint32_t                     *glyphs_id,
+					 xcb_render_glyphinfo_t       *glyphs,
+					 uint32_t                      data_len,
+					 uint8_t                      *data);
+
+cairo_private void
+_cairo_xcb_connection_render_free_glyphs (cairo_xcb_connection_t         *connection,
+					  xcb_render_glyphset_t     glyphset,
+					  uint32_t                  num_glyphs,
+					  xcb_render_glyph_t       *glyphs);
+
+cairo_private void
+_cairo_xcb_connection_render_composite_glyphs_8 (cairo_xcb_connection_t        *connection,
+						 uint8_t                  op,
+						 xcb_render_picture_t     src,
+						 xcb_render_picture_t     dst,
+						 xcb_render_pictformat_t  mask_format,
+						 xcb_render_glyphset_t    glyphset,
+						 int16_t                  src_x,
+						 int16_t                  src_y,
+						 uint32_t                 glyphcmds_len,
+						 uint8_t                 *glyphcmds);
+
+cairo_private void
+_cairo_xcb_connection_render_composite_glyphs_16 (cairo_xcb_connection_t        *connection,
+						  uint8_t                  op,
+						  xcb_render_picture_t     src,
+						  xcb_render_picture_t     dst,
+						  xcb_render_pictformat_t  mask_format,
+						  xcb_render_glyphset_t    glyphset,
+						  int16_t                  src_x,
+						  int16_t                  src_y,
+						  uint32_t                 glyphcmds_len,
+						  uint8_t                 *glyphcmds);
+
+cairo_private void
+_cairo_xcb_connection_render_composite_glyphs_32 (cairo_xcb_connection_t        *connection,
+						  uint8_t                  op,
+						  xcb_render_picture_t     src,
+						  xcb_render_picture_t     dst,
+						  xcb_render_pictformat_t  mask_format,
+						  xcb_render_glyphset_t    glyphset,
+						  int16_t                  src_x,
+						  int16_t                  src_y,
+						  uint32_t                 glyphcmds_len,
+						  uint8_t                 *glyphcmds);
+
+cairo_private void
+_cairo_xcb_connection_render_fill_rectangles (cairo_xcb_connection_t      *connection,
+					      uint8_t                op,
+					      xcb_render_picture_t   dst,
+					      xcb_render_color_t     color,
+					      uint32_t               num_rects,
+					      xcb_rectangle_t       *rects);
+
+cairo_private void
+_cairo_xcb_connection_render_set_picture_transform (cairo_xcb_connection_t       *connection,
+						    xcb_render_picture_t    picture,
+						    xcb_render_transform_t  *transform);
+
+cairo_private void
+_cairo_xcb_connection_render_set_picture_filter (cairo_xcb_connection_t         *connection,
+						 xcb_render_picture_t      picture,
+						 uint16_t                  filter_len,
+						 char                     *filter);
+
+cairo_private void
+_cairo_xcb_connection_render_create_solid_fill (cairo_xcb_connection_t     *connection,
+						xcb_render_picture_t  picture,
+						xcb_render_color_t    color);
+
+cairo_private void
+_cairo_xcb_connection_render_create_linear_gradient (cairo_xcb_connection_t         *connection,
+						     xcb_render_picture_t      picture,
+						     xcb_render_pointfix_t     p1,
+						     xcb_render_pointfix_t     p2,
+						     uint32_t                  num_stops,
+						     xcb_render_fixed_t *stops,
+						     xcb_render_color_t *colors);
+
+cairo_private void
+_cairo_xcb_connection_render_create_radial_gradient (cairo_xcb_connection_t         *connection,
+						     xcb_render_picture_t      picture,
+						     xcb_render_pointfix_t     inner,
+						     xcb_render_pointfix_t     outer,
+						     xcb_render_fixed_t        inner_radius,
+						     xcb_render_fixed_t        outer_radius,
+						     uint32_t                  num_stops,
+						     xcb_render_fixed_t *stops,
+						     xcb_render_color_t *colors);
+
+cairo_private void
+_cairo_xcb_connection_render_create_conical_gradient (cairo_xcb_connection_t         *c,
+						      xcb_render_picture_t      picture,
+						      xcb_render_pointfix_t     center,
+						      xcb_render_fixed_t        angle,
+						      uint32_t                  num_stops,
+						      xcb_render_fixed_t *stops,
+						      xcb_render_color_t *colors);
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+slim_hidden_proto (cairo_xcb_surface_create);
+slim_hidden_proto (cairo_xcb_surface_create_for_bitmap);
+slim_hidden_proto (cairo_xcb_surface_create_with_xrender_format);
+slim_hidden_proto (cairo_xcb_surface_set_size);
+#endif
+
+#endif /* CAIRO_XCB_PRIVATE_H */
diff --git a/src/cairo-xcb-screen.c b/src/cairo-xcb-screen.c
new file mode 100644
index 0000000..06c07a5
--- /dev/null
+++ b/src/cairo-xcb-screen.c
@@ -0,0 +1,518 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2008 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+ *
+ * Authors:
+ *    Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xcb-private.h"
+
+struct pattern_cache_entry {
+    cairo_cache_entry_t key;
+    cairo_xcb_screen_t *screen;
+    cairo_pattern_union_t pattern;
+    cairo_surface_t *picture;
+};
+
+void
+_cairo_xcb_screen_finish (cairo_xcb_screen_t *screen)
+{
+    int i;
+
+    CAIRO_MUTEX_LOCK (screen->connection->screens_mutex);
+    cairo_list_del (&screen->link);
+    CAIRO_MUTEX_UNLOCK (screen->connection->screens_mutex);
+
+    while (! cairo_list_is_empty (&screen->surfaces)) {
+	cairo_surface_t *surface;
+
+	surface = &cairo_list_first_entry (&screen->surfaces,
+					   cairo_xcb_surface_t,
+					   link)->base;
+
+	cairo_surface_reference (surface);
+	cairo_surface_finish (surface);
+	cairo_surface_destroy (surface);
+    }
+
+    for (i = 0; i < screen->solid_cache_size; i++)
+	cairo_surface_destroy (screen->solid_cache[i].picture);
+
+    for (i = 0; i < ARRAY_LENGTH (screen->stock_colors); i++)
+	cairo_surface_destroy (screen->stock_colors[i]);
+
+    _cairo_cache_fini (&screen->surface_pattern_cache);
+    _cairo_cache_fini (&screen->linear_pattern_cache);
+    _cairo_cache_fini (&screen->radial_pattern_cache);
+    _cairo_freelist_fini (&screen->pattern_cache_entry_freelist);
+
+    cairo_device_finish (screen->device);
+    cairo_device_destroy (screen->device);
+
+    free (screen);
+}
+
+static cairo_bool_t
+_surface_pattern_cache_entry_equal (const void *A, const void *B)
+{
+    const struct pattern_cache_entry *a = A, *b = B;
+
+    return a->key.hash == b->key.hash;
+}
+
+static cairo_bool_t
+_linear_pattern_cache_entry_equal (const void *A, const void *B)
+{
+    const struct pattern_cache_entry *a = A, *b = B;
+
+    if (a->key.hash != b->key.hash)
+	return FALSE;
+
+    return _cairo_linear_pattern_equal (&a->pattern.gradient.linear,
+					&b->pattern.gradient.linear);
+}
+
+static cairo_bool_t
+_radial_pattern_cache_entry_equal (const void *A, const void *B)
+{
+    const struct pattern_cache_entry *a = A, *b = B;
+
+    if (a->key.hash != b->key.hash)
+	return FALSE;
+
+    return _cairo_radial_pattern_equal (&a->pattern.gradient.radial,
+					&b->pattern.gradient.radial);
+}
+
+static void
+_surface_cache_entry_destroy (void *closure)
+{
+    struct pattern_cache_entry *entry = closure;
+
+    cairo_surface_finish (entry->picture);
+    cairo_surface_destroy (entry->picture);
+    _cairo_freelist_free (&entry->screen->pattern_cache_entry_freelist, entry);
+}
+
+static void
+_pattern_cache_entry_destroy (void *closure)
+{
+    struct pattern_cache_entry *entry = closure;
+
+    _cairo_pattern_fini (&entry->pattern.base);
+    cairo_surface_destroy (entry->picture);
+    _cairo_freelist_free (&entry->screen->pattern_cache_entry_freelist, entry);
+}
+
+#if CAIRO_HAS_DRM_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+#include "drm/cairo-drm-private.h"
+
+#include <drm/drm.h>
+#include <sys/ioctl.h>
+#include <xcb/dri2.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+static int drm_magic (int fd, uint32_t *magic)
+{
+    drm_auth_t auth;
+
+    if (ioctl (fd, DRM_IOCTL_GET_MAGIC, &auth))
+	return -errno;
+
+    *magic = auth.magic;
+    return 0;
+}
+
+static cairo_device_t *
+_xcb_drm_device (xcb_connection_t	*xcb_connection,
+		 xcb_screen_t		*xcb_screen)
+{
+    cairo_device_t *device = NULL;
+    xcb_dri2_connect_reply_t *connect;
+    drm_magic_t magic;
+    int fd;
+
+    connect = xcb_dri2_connect_reply (xcb_connection,
+				      xcb_dri2_connect (xcb_connection,
+							xcb_screen->root,
+							0),
+				      0);
+    if (connect == NULL)
+	return NULL;
+
+    fd = open (xcb_dri2_connect_device_name (connect), O_RDWR);
+    free (connect);
+
+    if (fd < 0)
+	return NULL;
+
+    device = cairo_drm_device_get_for_fd (fd);
+    close (fd);
+
+    if (device != NULL) {
+	xcb_dri2_authenticate_reply_t *authenticate;
+
+	if (drm_magic (((cairo_drm_device_t *) device)->fd, &magic) < 0) {
+	    cairo_device_destroy (device);
+	    return NULL;
+	}
+
+	authenticate = xcb_dri2_authenticate_reply (xcb_connection,
+						    xcb_dri2_authenticate (xcb_connection,
+									   xcb_screen->root,
+									   magic),
+						    0);
+	if (authenticate == NULL) {
+	    cairo_device_destroy (device);
+	    return NULL;
+	}
+
+	free (authenticate);
+    }
+
+    return device;
+}
+#else
+static cairo_device_t *
+_xcb_drm_device (xcb_connection_t	*xcb_connection,
+		 xcb_screen_t		*xcb_screen)
+{
+    return NULL;
+}
+#endif
+
+cairo_xcb_screen_t *
+_cairo_xcb_screen_get (xcb_connection_t *xcb_connection,
+		       xcb_screen_t *xcb_screen)
+{
+    cairo_xcb_connection_t *connection;
+    cairo_xcb_screen_t *screen;
+    cairo_status_t status;
+    int i;
+
+    connection = _cairo_xcb_connection_get (xcb_connection);
+    if (unlikely (connection == NULL))
+	return NULL;
+
+    CAIRO_MUTEX_LOCK (connection->screens_mutex);
+
+    cairo_list_foreach_entry (screen,
+			      cairo_xcb_screen_t,
+			      &connection->screens,
+			      link)
+    {
+	if (screen->xcb_screen == xcb_screen) {
+	    /* Maintain list in MRU order */
+	    if (&screen->link != connection->screens.next)
+		cairo_list_move (&screen->link, &connection->screens);
+
+	    goto unlock;
+	}
+    }
+
+    screen = malloc (sizeof (cairo_xcb_screen_t));
+    if (unlikely (screen == NULL))
+	goto unlock;
+
+    screen->connection = connection;
+    screen->xcb_screen = xcb_screen;
+
+    if (connection->flags & CAIRO_XCB_HAS_DRI2)
+	screen->device = _xcb_drm_device (xcb_connection, xcb_screen);
+    else
+	screen->device = NULL;
+
+    screen->gc_depths = 0;
+    memset (screen->gc, 0, sizeof (screen->gc));
+
+    screen->solid_cache_size = 0;
+    for (i = 0; i < ARRAY_LENGTH (screen->stock_colors); i++)
+	screen->stock_colors[i] = NULL;
+
+    status = _cairo_cache_init (&screen->surface_pattern_cache,
+				_surface_pattern_cache_entry_equal,
+				NULL,
+				_surface_cache_entry_destroy,
+				16*1024*1024);
+    if (unlikely (status))
+	goto error_screen;
+
+    status = _cairo_cache_init (&screen->linear_pattern_cache,
+				_linear_pattern_cache_entry_equal,
+				NULL,
+				_pattern_cache_entry_destroy,
+				16);
+    if (unlikely (status))
+	goto error_surface;
+
+    status = _cairo_cache_init (&screen->radial_pattern_cache,
+				_radial_pattern_cache_entry_equal,
+				NULL,
+				_pattern_cache_entry_destroy,
+				4);
+    if (unlikely (status))
+	goto error_linear;
+
+    _cairo_freelist_init (&screen->pattern_cache_entry_freelist,
+			  sizeof (struct pattern_cache_entry));
+
+    cairo_list_add (&screen->link, &connection->screens);
+    cairo_list_init (&screen->surfaces);
+
+unlock:
+    CAIRO_MUTEX_UNLOCK (connection->screens_mutex);
+
+    return screen;
+
+error_surface:
+    _cairo_cache_fini (&screen->surface_pattern_cache);
+error_linear:
+    _cairo_cache_fini (&screen->linear_pattern_cache);
+error_screen:
+    cairo_device_destroy (screen->device);
+    free (screen);
+    CAIRO_MUTEX_UNLOCK (connection->screens_mutex);
+
+    return NULL;
+}
+
+static xcb_gcontext_t
+_create_gc (cairo_xcb_screen_t *screen,
+	    xcb_drawable_t drawable)
+{
+    uint32_t values[] = { 0 };
+
+    return _cairo_xcb_connection_create_gc (screen->connection, drawable,
+					    XCB_GC_GRAPHICS_EXPOSURES,
+					    values);
+}
+
+xcb_gcontext_t
+_cairo_xcb_screen_get_gc (cairo_xcb_screen_t *screen,
+			  xcb_drawable_t drawable,
+			  int depth)
+{
+    int i;
+
+    assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+    for (i = 0; i < ARRAY_LENGTH (screen->gc); i++) {
+	if (((screen->gc_depths >> (8*i)) & 0xff) == depth) {
+	    screen->gc_depths &= ~(0xff << (8*i));
+	    return screen->gc[i];
+	}
+    }
+
+    return _create_gc (screen, drawable);
+}
+
+void
+_cairo_xcb_screen_put_gc (cairo_xcb_screen_t *screen, int depth, xcb_gcontext_t gc)
+{
+    int i;
+
+    assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+    for (i = 0; i < ARRAY_LENGTH (screen->gc); i++) {
+	if (((screen->gc_depths >> (8*i)) & 0xff) == 0)
+	    break;
+    }
+
+    if (i == ARRAY_LENGTH (screen->gc)) {
+	/* perform random substitution to ensure fair caching over depths */
+	i = rand () % ARRAY_LENGTH (screen->gc);
+	_cairo_xcb_connection_free_gc (screen->connection, screen->gc[i]);
+    }
+
+    screen->gc[i] = gc;
+    screen->gc_depths &= ~(0xff << (8*i));
+    screen->gc_depths |= depth << (8*i);
+}
+
+cairo_status_t
+_cairo_xcb_screen_store_surface_picture (cairo_xcb_screen_t *screen,
+					 cairo_surface_t *picture,
+					 unsigned int size)
+{
+    struct pattern_cache_entry *entry;
+    cairo_status_t status;
+
+    assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+    entry = _cairo_freelist_alloc (&screen->pattern_cache_entry_freelist);
+    if (unlikely (entry == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    entry->key.hash = picture->unique_id;
+    entry->key.size = size;
+
+    entry->picture = cairo_surface_reference (picture);
+    entry->screen = screen;
+
+    status = _cairo_cache_insert (&screen->surface_pattern_cache,
+				  &entry->key);
+    if (unlikely (status)) {
+	_cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
+	return status;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_xcb_screen_remove_surface_picture (cairo_xcb_screen_t *screen,
+					  cairo_surface_t *picture)
+{
+    struct pattern_cache_entry tmpl;
+    struct pattern_cache_entry *entry;
+
+    assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+    tmpl.key.hash = picture->unique_id;
+
+    entry = _cairo_cache_lookup (&screen->surface_pattern_cache, &tmpl.key);
+    if (entry != NULL)
+	_cairo_cache_remove (&screen->surface_pattern_cache, &entry->key);
+}
+
+cairo_status_t
+_cairo_xcb_screen_store_linear_picture (cairo_xcb_screen_t *screen,
+					const cairo_linear_pattern_t *linear,
+					cairo_surface_t *picture)
+{
+    struct pattern_cache_entry *entry;
+    cairo_status_t status;
+
+    assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+    entry = _cairo_freelist_alloc (&screen->pattern_cache_entry_freelist);
+    if (unlikely (entry == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    entry->key.hash = _cairo_linear_pattern_hash (_CAIRO_HASH_INIT_VALUE, linear);
+    entry->key.size = 1;
+
+    status = _cairo_pattern_init_copy (&entry->pattern.base, &linear->base.base);
+    if (unlikely (status)) {
+	_cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
+	return status;
+    }
+
+    entry->picture = cairo_surface_reference (picture);
+    entry->screen = screen;
+
+    status = _cairo_cache_insert (&screen->linear_pattern_cache,
+				  &entry->key);
+    if (unlikely (status)) {
+	cairo_surface_destroy (picture);
+	_cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
+	return status;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_surface_t *
+_cairo_xcb_screen_lookup_linear_picture (cairo_xcb_screen_t *screen,
+					 const cairo_linear_pattern_t *linear)
+{
+    cairo_surface_t *picture = NULL;
+    struct pattern_cache_entry tmpl;
+    struct pattern_cache_entry *entry;
+
+    assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+    tmpl.key.hash = _cairo_linear_pattern_hash (_CAIRO_HASH_INIT_VALUE, linear);
+    _cairo_pattern_init_static_copy (&tmpl.pattern.base, &linear->base.base);
+
+    entry = _cairo_cache_lookup (&screen->linear_pattern_cache, &tmpl.key);
+    if (entry != NULL)
+	picture = cairo_surface_reference (entry->picture);
+
+    return picture;
+}
+
+cairo_status_t
+_cairo_xcb_screen_store_radial_picture (cairo_xcb_screen_t *screen,
+					const cairo_radial_pattern_t *radial,
+					cairo_surface_t *picture)
+{
+    struct pattern_cache_entry *entry;
+    cairo_status_t status;
+
+    assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+    entry = _cairo_freelist_alloc (&screen->pattern_cache_entry_freelist);
+    if (unlikely (entry == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    entry->key.hash = _cairo_radial_pattern_hash (_CAIRO_HASH_INIT_VALUE, radial);
+    entry->key.size = 1;
+
+    status = _cairo_pattern_init_copy (&entry->pattern.base, &radial->base.base);
+    if (unlikely (status)) {
+	_cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
+	return status;
+    }
+
+    entry->picture = cairo_surface_reference (picture);
+    entry->screen = screen;
+
+    status = _cairo_cache_insert (&screen->radial_pattern_cache, &entry->key);
+    if (unlikely (status)) {
+	cairo_surface_destroy (picture);
+	_cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry);
+	return status;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_surface_t *
+_cairo_xcb_screen_lookup_radial_picture (cairo_xcb_screen_t *screen,
+					 const cairo_radial_pattern_t *radial)
+{
+    cairo_surface_t *picture = NULL;
+    struct pattern_cache_entry tmpl;
+    struct pattern_cache_entry *entry;
+
+    assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->mutex));
+
+    tmpl.key.hash = _cairo_radial_pattern_hash (_CAIRO_HASH_INIT_VALUE, radial);
+    _cairo_pattern_init_static_copy (&tmpl.pattern.base, &radial->base.base);
+
+    entry = _cairo_cache_lookup (&screen->radial_pattern_cache, &tmpl.key);
+    if (entry != NULL)
+	picture = cairo_surface_reference (entry->picture);
+
+    return picture;
+}
diff --git a/src/cairo-xcb-shm.c b/src/cairo-xcb-shm.c
new file mode 100644
index 0000000..7a47f33
--- /dev/null
+++ b/src/cairo-xcb-shm.c
@@ -0,0 +1,576 @@
+/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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-xcb-private.h"
+
+#include <xcb/shm.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <errno.h>
+
+/* a simple buddy allocator for memory pools
+ * XXX fragmentation? use Doug Lea's malloc?
+ */
+
+typedef struct _cairo_xcb_shm_mem_block cairo_xcb_shm_mem_block_t;
+
+struct _cairo_xcb_shm_mem_block {
+    unsigned int bits;
+    cairo_list_t link;
+};
+
+struct _cairo_xcb_shm_mem_pool {
+    int shmid;
+    uint32_t shmseg;
+
+    char *base;
+    unsigned int nBlocks;
+    cairo_xcb_shm_mem_block_t *blocks;
+    cairo_list_t free[32];
+    unsigned char *map;
+
+    unsigned int min_bits;     /* Minimum block size is 1 << min_bits */
+    unsigned int num_sizes;
+
+    size_t free_bytes;
+    size_t max_bytes;
+    unsigned int max_free_bits;
+
+    cairo_list_t link;
+};
+
+#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_xcb_shm_mem_pool_t *pi, 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 (pi, i);
+
+    if (past_full > first_full) {
+	bytes = past_full - first_full;
+	bytes = bytes >> 3;
+	memset (pi->map + (first_full >> 3), 0, bytes);
+    }
+
+    if (past_full < n)
+	past_full = n;
+    for (i = past_full; i < last; i++)
+	BITCLEAR (pi, i);
+}
+
+static void
+free_bits (cairo_xcb_shm_mem_pool_t *pi,
+	   size_t start,
+	   unsigned int bits,
+	   cairo_bool_t clear)
+{
+    cairo_xcb_shm_mem_block_t *block;
+
+    if (clear)
+	clear_bits (pi, start, start + (1 << bits));
+
+    block = pi->blocks + start;
+    block->bits = bits;
+
+    cairo_list_add (&block->link, &pi->free[bits]);
+
+    pi->free_bytes += 1 << (bits + pi->min_bits);
+    if (bits > pi->max_free_bits)
+	pi->max_free_bits = bits;
+}
+
+/* Add a chunk to the free list */
+static void
+free_blocks (cairo_xcb_shm_mem_pool_t *pi,
+	     size_t first,
+	     size_t last,
+	     cairo_bool_t clear)
+{
+    size_t i;
+    size_t bits = 0;
+    size_t len = 1;
+
+    i = first;
+    while (i < last) {
+        /* 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 < pi->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 */
+	        continue;
+
+	    if (i & (len - 1)) /* block would not be on boundary */
+	        continue;
+
+	    /* OK */
+	    break;
+
+	    bits--;
+	    len >>=1;
+	} while (len > 0);
+
+	if (len == 0)
+	    break;
+
+	free_bits (pi, i, bits, clear);
+	i += len;
+    }
+}
+
+static cairo_status_t
+_cairo_xcb_shm_mem_pool_init (cairo_xcb_shm_mem_pool_t *pi,
+			      size_t bytes,
+			      unsigned int min_bits,
+			      unsigned int num_sizes)
+{
+    size_t setBits;
+    int i;
+
+    assert ((((unsigned long) pi->base) & ((1 << min_bits) - 1)) == 0);
+    assert (num_sizes < ARRAY_LENGTH (pi->free));
+
+    pi->free_bytes = 0;
+    pi->max_bytes = bytes;
+    pi->max_free_bits = 0;
+
+    setBits = bytes >> min_bits;
+    pi->blocks = calloc (setBits, sizeof (cairo_xcb_shm_mem_block_t));
+    if (pi->blocks == NULL)
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    pi->nBlocks = setBits;
+    pi->min_bits = min_bits;
+    pi->num_sizes = num_sizes;
+
+    for (i = 0; i < ARRAY_LENGTH (pi->free); i++)
+	cairo_list_init (&pi->free[i]);
+
+    pi->map = malloc ((setBits + 7) >> 3);
+    if (pi->map == NULL) {
+	free (pi->blocks);
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    memset (pi->map, -1, (setBits + 7) >> 3);
+    clear_bits (pi, 0, setBits);
+
+    /* Now add all blocks to the free list */
+    free_blocks (pi, 0, setBits, 1);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_xcb_shm_mem_block_t *
+get_buddy (cairo_xcb_shm_mem_pool_t *pi,
+	   size_t offset,
+	   unsigned int bits)
+{
+    cairo_xcb_shm_mem_block_t *block;
+
+    assert (offset + (1 << bits) <= pi->nBlocks);
+
+    if (BITTEST (pi, offset + (1 << bits) - 1))
+	return NULL; /* buddy is allocated */
+
+    block = pi->blocks + offset;
+    if (block->bits != bits)
+	return NULL; /* buddy is partially allocated */
+
+    return block;
+}
+
+static void
+merge_buddies (cairo_xcb_shm_mem_pool_t *pi,
+	       cairo_xcb_shm_mem_block_t *block,
+	       unsigned int max_bits)
+{
+    size_t block_offset = block_offset = block - pi->blocks;
+    unsigned 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 (pi, 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 = pi->blocks + block_offset;
+    block->bits = bits;
+    cairo_list_add (&block->link, &pi->free[bits]);
+
+    if (bits > pi->max_free_bits)
+	pi->max_free_bits = bits;
+}
+
+/* attempt to merge all available buddies up to a particular size */
+static unsigned int
+merge_bits (cairo_xcb_shm_mem_pool_t *pi,
+	    unsigned int max_bits)
+{
+    cairo_xcb_shm_mem_block_t *block, *buddy, *next;
+    unsigned int bits;
+
+    for (bits = 0; bits < max_bits - 1; bits++) {
+	cairo_list_foreach_entry_safe (block, next,
+				       cairo_xcb_shm_mem_block_t,
+				       &pi->free[bits],
+				       link)
+	{
+	    size_t buddy_offset = (block - pi->blocks) ^ (1 << bits);
+
+	    buddy = get_buddy (pi, buddy_offset, bits);
+	    if (buddy == NULL)
+		continue;
+
+	    if (buddy == next) {
+		next = cairo_container_of (buddy->link.next,
+					   cairo_xcb_shm_mem_block_t,
+					   link);
+	    }
+
+	    cairo_list_del (&block->link);
+	    merge_buddies (pi, block, max_bits);
+	}
+    }
+
+    return pi->max_free_bits;
+}
+
+/* find store for 1 << bits blocks */
+static void *
+buddy_malloc (cairo_xcb_shm_mem_pool_t *pi,
+	      unsigned int bits)
+{
+    unsigned int b;
+    size_t offset;
+    size_t past;
+    cairo_xcb_shm_mem_block_t *block;
+
+    if (bits > pi->max_free_bits && bits > merge_bits (pi, bits))
+	return NULL;
+
+    /* Find a list with blocks big enough on it */
+    block = NULL;
+    for (b = bits; b <= pi->max_free_bits; b++) {
+	if (! cairo_list_is_empty (&pi->free[b])) {
+	    block = cairo_list_first_entry (&pi->free[b],
+					    cairo_xcb_shm_mem_block_t,
+					    link);
+	    break;
+	}
+    }
+    assert (block != NULL);
+
+    cairo_list_del (&block->link);
+
+    while (cairo_list_is_empty (&pi->free[pi->max_free_bits])) {
+	if (--pi->max_free_bits == 0)
+	    break;
+    }
+
+    /* Mark end of allocated area */
+    offset = block - pi->blocks;
+    past = offset + (1 << bits);
+    BITSET (pi, past - 1);
+    block->bits = bits;
+
+    /* If we used a larger free block than we needed, free the rest */
+    pi->free_bytes -= 1 << (b + pi->min_bits);
+    free_blocks (pi, past, offset + (1 << b), 0);
+
+    return pi->base + ((block - pi->blocks) << pi->min_bits);
+}
+
+static void *
+_cairo_xcb_shm_mem_pool_malloc (cairo_xcb_shm_mem_pool_t *pi,
+				size_t bytes)
+{
+    unsigned int bits;
+    size_t size;
+
+    size = 1 << pi->min_bits;
+    for (bits = 0; size < bytes; bits++)
+	size <<= 1;
+    if (bits >= pi->num_sizes)
+	return NULL;
+
+    return buddy_malloc (pi, bits);
+}
+
+static void
+_cairo_xcb_shm_mem_pool_free (cairo_xcb_shm_mem_pool_t *pi,
+			      char *storage)
+{
+    size_t block_offset;
+    cairo_xcb_shm_mem_block_t *block;
+
+    block_offset = (storage - pi->base) >> pi->min_bits;
+    block = pi->blocks + block_offset;
+
+    BITCLEAR (pi, block_offset + ((1 << block->bits) - 1));
+    pi->free_bytes += 1 << (block->bits + pi->min_bits);
+
+    merge_buddies (pi, block, pi->num_sizes);
+}
+
+static void
+_cairo_xcb_shm_mem_pool_destroy (cairo_xcb_shm_mem_pool_t *pool)
+{
+    shmdt (pool->base);
+    cairo_list_del (&pool->link);
+
+    free (pool->map);
+    free (pool->blocks);
+    free (pool);
+}
+
+cairo_int_status_t
+_cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *connection,
+					 size_t size,
+					 cairo_xcb_shm_info_t **shm_info_out)
+{
+    cairo_xcb_shm_info_t *shm_info;
+    cairo_xcb_shm_mem_pool_t *pool, *next;
+    size_t bytes, maxbits = 16, minbits = 8;
+    void *mem = NULL;
+    cairo_status_t status;
+
+    assert (connection->flags & CAIRO_XCB_HAS_SHM);
+
+    CAIRO_MUTEX_LOCK (connection->shm_mutex);
+    cairo_list_foreach_entry_safe (pool, next, cairo_xcb_shm_mem_pool_t,
+				   &connection->shm_pools, link)
+    {
+	if (pool->free_bytes > size) {
+	    mem = _cairo_xcb_shm_mem_pool_malloc (pool, size);
+	    if (mem != NULL) {
+		/* keep the active pools towards the front */
+		cairo_list_move (&pool->link, &connection->shm_pools);
+		goto allocate_shm_info;
+	    }
+	}
+	/* scan for old, unused pools */
+	if (pool->free_bytes == pool->max_bytes) {
+	    _cairo_xcb_connection_shm_detach (connection,
+					      pool->shmseg);
+	    _cairo_xcb_shm_mem_pool_destroy (pool);
+	}
+    }
+
+    pool = malloc (sizeof (cairo_xcb_shm_mem_pool_t));
+    if (unlikely (pool == NULL)) {
+	CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    bytes = 1 << maxbits;
+    while (bytes <= size)
+	bytes <<= 1, maxbits++;
+    bytes <<= 3;
+
+    do {
+	pool->shmid = shmget (IPC_PRIVATE, bytes, IPC_CREAT | 0600);
+	if (pool->shmid != -1)
+	    break;
+
+	if (errno == EINVAL && bytes > size) {
+	    bytes >>= 1;
+	    continue;
+	}
+    } while (FALSE);
+    if (pool->shmid == -1) {
+	int err = errno;
+	if (! (err == EINVAL || err == ENOMEM))
+	    connection->flags &= ~CAIRO_XCB_HAS_SHM;
+	free (pool);
+	CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    pool->base = shmat (pool->shmid, NULL, 0);
+    if (unlikely (pool->base == (char *) -1)) {
+	shmctl (pool->shmid, IPC_RMID, NULL);
+	free (pool);
+	CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    status = _cairo_xcb_shm_mem_pool_init (pool,
+					   bytes,
+					   minbits,
+					   maxbits - minbits + 1);
+    if (unlikely (status)) {
+	shmdt (pool->base);
+	free (pool);
+	CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+	return status;
+    }
+
+    pool->shmseg = _cairo_xcb_connection_shm_attach (connection, pool->shmid, FALSE);
+    shmctl (pool->shmid, IPC_RMID, NULL);
+
+    cairo_list_add (&pool->link, &connection->shm_pools);
+    mem = _cairo_xcb_shm_mem_pool_malloc (pool, size);
+
+  allocate_shm_info:
+    shm_info = _cairo_freepool_alloc (&connection->shm_info_freelist);
+    if (unlikely (shm_info == NULL)) {
+	_cairo_xcb_shm_mem_pool_free (pool, mem);
+	CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    shm_info->connection = connection;
+    shm_info->pool = pool;
+    shm_info->shm = pool->shmseg;
+    shm_info->offset = (char *) mem - (char *) pool->base;
+    shm_info->mem = mem;
+
+    /* scan for old, unused pools */
+    cairo_list_foreach_entry_safe (pool, next, cairo_xcb_shm_mem_pool_t,
+				   &connection->shm_pools, link)
+    {
+	if (pool->free_bytes == pool->max_bytes) {
+	    _cairo_xcb_connection_shm_detach (connection,
+					      pool->shmseg);
+	    _cairo_xcb_shm_mem_pool_destroy (pool);
+	}
+    }
+    CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+
+    *shm_info_out = shm_info;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+void
+_cairo_xcb_shm_info_destroy (cairo_xcb_shm_info_t *shm_info)
+{
+    cairo_xcb_connection_t *connection = shm_info->connection;
+
+    CAIRO_MUTEX_LOCK (connection->shm_mutex);
+
+    _cairo_xcb_shm_mem_pool_free (shm_info->pool, shm_info->mem);
+    _cairo_freepool_free (&connection->shm_info_freelist, shm_info);
+
+    /* scan for old, unused pools - hold at least one in reserve */
+    if (! cairo_list_is_singular (&connection->shm_pools) &&
+	_cairo_xcb_connection_take_socket (connection) == CAIRO_STATUS_SUCCESS)
+    {
+	cairo_xcb_shm_mem_pool_t *pool, *next;
+	cairo_list_t head;
+
+	cairo_list_init (&head);
+	cairo_list_move (connection->shm_pools.next, &head);
+
+	cairo_list_foreach_entry_safe (pool, next, cairo_xcb_shm_mem_pool_t,
+				       &connection->shm_pools, link)
+	{
+	    if (pool->free_bytes == pool->max_bytes) {
+		_cairo_xcb_connection_shm_detach (connection, pool->shmseg);
+		_cairo_xcb_shm_mem_pool_destroy (pool);
+	    }
+	}
+
+	cairo_list_move (head.next, &connection->shm_pools);
+    }
+
+    CAIRO_MUTEX_UNLOCK (connection->shm_mutex);
+}
+
+void
+_cairo_xcb_connection_shm_mem_pools_fini (cairo_xcb_connection_t *connection)
+{
+    while (! cairo_list_is_empty (&connection->shm_pools)) {
+	_cairo_xcb_shm_mem_pool_destroy (cairo_list_first_entry (&connection->shm_pools,
+								 cairo_xcb_shm_mem_pool_t,
+								 link));
+    }
+}
diff --git a/src/cairo-xcb-surface-cairo.c b/src/cairo-xcb-surface-cairo.c
new file mode 100644
index 0000000..c8305cf
--- /dev/null
+++ b/src/cairo-xcb-surface-cairo.c
@@ -0,0 +1,94 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-clip-private.h"
+#include "cairo-xcb-private.h"
+
+cairo_int_status_t
+_cairo_xcb_surface_cairo_paint (cairo_xcb_surface_t	*surface,
+				cairo_operator_t	 op,
+				const cairo_pattern_t	*source,
+				cairo_clip_t		*clip)
+{
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_cairo_mask (cairo_xcb_surface_t	*surface,
+			       cairo_operator_t		 op,
+			       const cairo_pattern_t	*source,
+			       const cairo_pattern_t	*mask,
+			       cairo_clip_t		*clip)
+{
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_cairo_stroke (cairo_xcb_surface_t	*surface,
+				 cairo_operator_t	 op,
+				 const cairo_pattern_t	*source,
+				 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_clip_t		*clip)
+{
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_cairo_fill (cairo_xcb_surface_t	*surface,
+			       cairo_operator_t		 op,
+			       const cairo_pattern_t	*source,
+			       cairo_path_fixed_t	*path,
+			       cairo_fill_rule_t	 fill_rule,
+			       double			 tolerance,
+			       cairo_antialias_t	 antialias,
+			       cairo_clip_t		*clip)
+{
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_cairo_glyphs (cairo_xcb_surface_t	*surface,
+				 cairo_operator_t		 op,
+				 const cairo_pattern_t	*source,
+				 cairo_scaled_font_t	*scaled_font,
+				 cairo_glyph_t		*glyphs,
+				 int			 num_glyphs,
+				 cairo_clip_t		*clip)
+{
+    return CAIRO_INT_STATUS_UNSUPPORTED;
+}
diff --git a/src/cairo-xcb-surface-core.c b/src/cairo-xcb-surface-core.c
new file mode 100644
index 0000000..6f1002a
--- /dev/null
+++ b/src/cairo-xcb-surface-core.c
@@ -0,0 +1,613 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-boxes-private.h"
+#include "cairo-xcb-private.h"
+
+/* XXX dithering */
+
+typedef struct _cairo_xcb_pixmap {
+    cairo_surface_t base;
+
+    cairo_xcb_connection_t *connection;
+    cairo_xcb_screen_t *screen;
+
+    cairo_surface_t *owner;
+    xcb_pixmap_t pixmap;
+    int width;
+    int height;
+    int depth;
+    int x0, y0;
+    cairo_bool_t repeat;
+} cairo_xcb_pixmap_t;
+
+static cairo_status_t
+_cairo_xcb_pixmap_finish (void *abstract_surface)
+{
+    cairo_xcb_pixmap_t *surface = abstract_surface;
+    cairo_status_t status;
+
+    if (surface->owner != NULL) {
+	cairo_surface_destroy (surface->owner);
+    } else {
+	status = _cairo_xcb_connection_acquire (surface->connection);
+	if (unlikely (status))
+	    return status;
+
+	if (_cairo_xcb_connection_take_socket (surface->connection) == CAIRO_STATUS_SUCCESS) {
+	    _cairo_xcb_connection_free_pixmap (surface->connection,
+					       surface->pixmap);
+	}
+	_cairo_xcb_connection_release (surface->connection);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t _cairo_xcb_pixmap_backend = {
+    CAIRO_SURFACE_TYPE_XCB,
+    NULL,
+    _cairo_xcb_pixmap_finish,
+};
+
+static cairo_xcb_pixmap_t *
+_cairo_xcb_pixmap_create (cairo_xcb_surface_t *target,
+			  int width, int height)
+{
+    cairo_xcb_pixmap_t *surface;
+
+    surface = malloc (sizeof (cairo_xcb_pixmap_t));
+    if (unlikely (surface == NULL))
+	return (cairo_xcb_pixmap_t *)
+	    _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    _cairo_surface_init (&surface->base,
+			 &_cairo_xcb_pixmap_backend,
+			 NULL,
+			 target->base.content);
+
+    surface->connection = target->connection;
+    surface->screen = target->screen;
+    surface->owner = NULL;
+    surface->width = width;
+    surface->height = height;
+    surface->depth = target->depth;
+    surface->x0 = surface->y0 = 0;
+    surface->repeat = FALSE;
+
+    surface->pixmap =
+	_cairo_xcb_connection_create_pixmap (surface->connection,
+					     surface->depth,
+					     target->drawable,
+					     width, height);
+
+    return surface;
+}
+
+static cairo_xcb_pixmap_t *
+_cairo_xcb_pixmap_copy (cairo_xcb_surface_t *target)
+{
+    cairo_xcb_pixmap_t *surface;
+
+    surface = malloc (sizeof (cairo_xcb_pixmap_t));
+    if (unlikely (surface == NULL))
+	return (cairo_xcb_pixmap_t *)
+	    _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    _cairo_surface_init (&surface->base,
+			 &_cairo_xcb_pixmap_backend,
+			 NULL,
+			 target->base.content);
+
+    surface->connection = target->connection;
+    surface->screen = target->screen;
+    surface->pixmap = target->drawable;
+    surface->owner = cairo_surface_reference (&target->base);
+    surface->width = target->width;
+    surface->height = target->height;
+    surface->depth = target->depth;
+    surface->x0 = surface->y0 = 0;
+    surface->repeat = FALSE;
+
+    return surface;
+}
+
+static cairo_status_t
+_cairo_xcb_shm_image_create (cairo_xcb_connection_t *connection,
+			     pixman_format_code_t pixman_format,
+			     int width, int height,
+			     cairo_image_surface_t **image_out,
+			     cairo_xcb_shm_info_t **shm_info_out)
+{
+    cairo_surface_t *image = NULL;
+    cairo_xcb_shm_info_t *shm_info = NULL;
+    cairo_status_t status;
+
+    if ((connection->flags & CAIRO_XCB_HAS_SHM)) {
+	size_t size, stride;
+
+	stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (pixman_format));
+	size = stride * height;
+	if (size > CAIRO_XCB_SHM_SMALL_IMAGE) {
+	    status = _cairo_xcb_connection_allocate_shm_info (connection,
+							      size, &shm_info);
+	    if (unlikely (status))
+		return status;
+
+	    image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
+								    pixman_format,
+								    width, height,
+								    stride);
+	    status = image->status;
+	    if (unlikely (status)) {
+		_cairo_xcb_shm_info_destroy (shm_info);
+		return status;
+	    }
+
+	    status = _cairo_user_data_array_set_data (&image->user_data,
+						      (const cairo_user_data_key_t *) connection,
+						      shm_info,
+						      (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
+	    if (unlikely (status)) {
+		cairo_surface_destroy (image);
+		_cairo_xcb_shm_info_destroy (shm_info);
+		return status;
+	    }
+	}
+    }
+
+    if (image == NULL) {
+	image = _cairo_image_surface_create_with_pixman_format (NULL,
+								pixman_format,
+								width, height,
+								0);
+	status = image->status;
+	if (unlikely (status))
+	    return status;
+    }
+
+
+    *image_out = (cairo_image_surface_t *) image;
+    *shm_info_out = shm_info;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_xcb_pixmap_t *
+_pixmap_from_image (cairo_xcb_surface_t *target,
+		    xcb_render_pictformat_t format,
+		    cairo_image_surface_t *image,
+		    cairo_xcb_shm_info_t *shm_info)
+{
+    xcb_gcontext_t gc;
+    cairo_xcb_pixmap_t *pixmap;
+
+    pixmap = _cairo_xcb_pixmap_create (target,
+				       image->width,
+				       image->height);
+    if (unlikely (pixmap->base.status))
+	return pixmap;
+
+    gc = _cairo_xcb_screen_get_gc (target->screen, pixmap->pixmap, image->depth);
+
+    if (shm_info != NULL) {
+	shm_info->seqno =
+	    _cairo_xcb_connection_shm_put_image (target->connection,
+						 pixmap->pixmap, gc,
+						 image->width, image->height,
+						 0, 0,
+						 image->width, image->height,
+						 0, 0,
+						 image->depth,
+						 shm_info->shm,
+						 shm_info->offset);
+    } else {
+	int len;
+
+	/* Do we need to trim the image? */
+	len = CAIRO_STRIDE_FOR_WIDTH_BPP (image->width,
+					  PIXMAN_FORMAT_BPP (image->pixman_format));
+	if (len == image->stride) {
+	    _cairo_xcb_connection_put_image (target->connection,
+					     pixmap->pixmap, gc,
+					     image->width, image->height,
+					     0, 0,
+					     image->depth,
+					     image->stride,
+					     image->data);
+	} else {
+	    _cairo_xcb_connection_put_subimage (target->connection,
+						pixmap->pixmap, gc,
+						0, 0,
+						image->width, image->height,
+						PIXMAN_FORMAT_BPP (image->pixman_format) / 8,
+						image->stride,
+						0, 0,
+						image->depth,
+						image->data);
+
+	}
+    }
+
+    _cairo_xcb_screen_put_gc (target->screen, image->depth, gc);
+
+    return pixmap;
+}
+
+static cairo_xcb_pixmap_t *
+_render_to_pixmap (cairo_xcb_surface_t *target,
+		   const cairo_pattern_t *pattern,
+		   const cairo_rectangle_int_t *extents)
+{
+    cairo_image_surface_t *image;
+    cairo_xcb_shm_info_t *shm_info;
+    cairo_pattern_union_t copy;
+    cairo_status_t status;
+    cairo_xcb_pixmap_t *pixmap;
+
+    status = _cairo_xcb_shm_image_create (target->screen->connection,
+					  target->pixman_format,
+					  extents->width, extents->height,
+					  &image, &shm_info);
+    if (unlikely (status))
+	return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
+
+    _cairo_pattern_init_static_copy (&copy.base, pattern);
+    cairo_matrix_translate (&copy.base.matrix, -extents->x, -extents->y);
+    status = _cairo_surface_paint (&image->base,
+				   CAIRO_OPERATOR_SOURCE,
+				   &copy.base,
+				   NULL);
+    if (unlikely (status)) {
+	cairo_surface_destroy (&image->base);
+	return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
+    }
+
+    pixmap = _pixmap_from_image (target, target->xrender_format, image, shm_info);
+    cairo_surface_destroy (&image->base);
+
+    if (unlikely (pixmap->base.status))
+	return pixmap;
+
+    pixmap->x0 = -extents->x;
+    pixmap->y0 = -extents->y;
+    return pixmap;
+}
+
+static cairo_xcb_pixmap_t *
+_copy_to_pixmap (cairo_xcb_surface_t *source)
+{
+    cairo_xcb_pixmap_t *pixmap;
+
+    /* If the source may be a window, we need to copy it and its children
+     * via a temporary pixmap so that we can IncludeInferiors on the source
+     * and use ClipByChildren on the destination.
+     */
+    if (source->owns_pixmap) {
+	pixmap = _cairo_xcb_pixmap_copy (source);
+	if (unlikely (pixmap->base.status))
+	    return pixmap;
+    } else {
+	uint32_t values[1];
+	xcb_gcontext_t gc;
+
+	pixmap = _cairo_xcb_pixmap_create (source,
+					   source->width,
+					   source->height);
+	if (unlikely (pixmap->base.status))
+	    return pixmap;
+
+	gc = _cairo_xcb_screen_get_gc (source->screen,
+				       pixmap->pixmap,
+				       pixmap->depth);
+
+	values[0] = TRUE;
+	_cairo_xcb_connection_change_gc (pixmap->connection, gc,
+					 XCB_GC_SUBWINDOW_MODE, values);
+
+	_cairo_xcb_connection_copy_area (pixmap->connection,
+					 source->drawable,
+					 pixmap->pixmap, gc,
+					 0, 0,
+					 0, 0,
+					 source->width,
+					 source->height);
+
+	values[0] = FALSE;
+	_cairo_xcb_connection_change_gc (pixmap->connection, gc,
+					 XCB_GC_SUBWINDOW_MODE, values);
+
+	_cairo_xcb_screen_put_gc (source->screen,
+				  pixmap->depth,
+				  gc);
+    }
+
+    return pixmap;
+}
+static cairo_xcb_pixmap_t *
+_cairo_xcb_surface_pixmap (cairo_xcb_surface_t *target,
+			   const cairo_surface_pattern_t *pattern,
+			   const cairo_rectangle_int_t *extents,
+			   int tx, int ty)
+{
+    cairo_surface_t *source;
+    cairo_xcb_pixmap_t *pixmap;
+    cairo_status_t status;
+
+    source =  pattern->surface;
+    pixmap = (cairo_xcb_pixmap_t *)
+	_cairo_surface_has_snapshot (source, &_cairo_xcb_pixmap_backend);
+    if (pixmap != NULL && pixmap->screen == target->screen)
+	return (cairo_xcb_pixmap_t *) cairo_surface_reference (&pixmap->base);
+
+    if (source->type == CAIRO_SURFACE_TYPE_XCB &&
+	((cairo_xcb_surface_t *) source)->screen == target->screen)
+    {
+	cairo_xcb_surface_t *xcb_source = (cairo_xcb_surface_t *) source;
+
+	if (xcb_source->depth == target->depth)
+	    pixmap = _copy_to_pixmap (xcb_source);
+    }
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+    else if (source->type == CAIRO_SURFACE_TYPE_XLIB &&
+	     ((cairo_xlib_xcb_surface_t *) source)->xcb->screen == target->screen)
+    {
+	cairo_xcb_surface_t *xcb_source = ((cairo_xlib_xcb_surface_t *) source)->xcb;
+
+	if (xcb_source->depth == target->depth)
+	    pixmap = _copy_to_pixmap (xcb_source);
+    }
+#endif
+
+    if (pixmap == NULL) {
+	cairo_rectangle_int_t rect;
+
+	if (! _cairo_surface_get_extents (source, &rect)) {
+	    rect.x = rect.y = 0;
+	    rect.width  = target->width;
+	    rect.height = target->height;
+	}
+
+	pixmap = _render_to_pixmap (target, &pattern->base, &rect);
+    }
+
+    if (unlikely (pixmap->base.status))
+	return pixmap;
+
+    status = _cairo_surface_attach_snapshot (source, &pixmap->base, NULL);
+    if (unlikely (status)) {
+	cairo_surface_destroy (&pixmap->base);
+	return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status);
+    }
+
+    if (pattern->base.extend != CAIRO_EXTEND_NONE) {
+	if (extents->x < 0 || extents->y < 0 ||
+	    extents->x + extents->width  > pixmap->width ||
+	    extents->y + extents->height > pixmap->height)
+	{
+	    pixmap->repeat = TRUE;
+	}
+    }
+
+    pixmap->x0 += tx;
+    pixmap->y0 += ty;
+
+    return pixmap;
+}
+
+static cairo_xcb_pixmap_t *
+_cairo_xcb_pixmap_for_pattern (cairo_xcb_surface_t *target,
+			       const cairo_pattern_t *pattern,
+			       const cairo_rectangle_int_t *extents)
+{
+    int tx, ty;
+
+    switch (pattern->type) {
+    case CAIRO_PATTERN_TYPE_SURFACE:
+	/* Core can only perform a native, unscaled blit, but can handle tiles */
+	if (_cairo_matrix_is_integer_translation (&pattern->matrix, &tx, &ty)) {
+	    switch (pattern->extend) {
+	    case CAIRO_EXTEND_NONE:
+	    case CAIRO_EXTEND_REPEAT:
+		return _cairo_xcb_surface_pixmap (target,
+						  (cairo_surface_pattern_t *) pattern,
+						  extents, tx, ty);
+
+	    default:
+	    case CAIRO_EXTEND_PAD:
+	    case CAIRO_EXTEND_REFLECT:
+		break;
+	    }
+	}
+	/* fallthrough */
+    case CAIRO_PATTERN_TYPE_LINEAR:
+    case CAIRO_PATTERN_TYPE_RADIAL:
+	return _render_to_pixmap (target, pattern, extents);
+
+    default:
+    case CAIRO_PATTERN_TYPE_SOLID:
+	ASSERT_NOT_REACHED;
+	return NULL;
+    }
+}
+
+cairo_status_t
+_cairo_xcb_surface_core_copy_boxes (cairo_xcb_surface_t		*dst,
+				   const cairo_pattern_t	*src_pattern,
+				   const cairo_rectangle_int_t	*extents,
+				   const cairo_boxes_t		*boxes)
+{
+    cairo_xcb_pixmap_t *src;
+    const struct _cairo_boxes_chunk *chunk;
+    xcb_gcontext_t gc;
+    cairo_status_t status;
+
+    status = _cairo_xcb_connection_acquire (dst->connection);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_xcb_connection_take_socket (dst->connection);
+    if (unlikely (status))
+	goto CLEANUP_CONNECTION;
+
+    src = _cairo_xcb_pixmap_for_pattern (dst, src_pattern, extents);
+    status = src->base.status;
+    if (unlikely (status))
+	goto CLEANUP_CONNECTION;
+
+    assert (src->depth == dst->depth);
+
+    gc = _cairo_xcb_screen_get_gc (dst->screen, src->pixmap, src->depth);
+
+    if (src->repeat) {
+	uint32_t mask =
+	    XCB_GC_FILL_STYLE |
+	    XCB_GC_TILE |
+	    XCB_GC_TILE_STIPPLE_ORIGIN_X |
+	    XCB_GC_TILE_STIPPLE_ORIGIN_Y;
+	uint32_t values[] = {
+	    XCB_FILL_STYLE_TILED,
+	    src->pixmap,
+	    - src->x0, - src->y0,
+	};
+	xcb_rectangle_t *xcb_rects;
+
+	_cairo_xcb_connection_change_gc (dst->connection, gc, mask, values);
+
+	for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	    xcb_rects = (xcb_rectangle_t *) chunk->base;
+	    int i;
+
+	    for (i = 0; i < chunk->count; i++) {
+		int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
+		int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
+		int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
+		int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
+
+		xcb_rects[i].x = x1;
+		xcb_rects[i].y = y1;
+		xcb_rects[i].width  = x2 - x1;
+		xcb_rects[i].height = y2 - y1;
+	    }
+	    _cairo_xcb_connection_poly_fill_rectangle (dst->connection,
+						       dst->drawable,
+						       gc, chunk->count, xcb_rects);
+	}
+
+	values[0] = 0;
+	_cairo_xcb_connection_change_gc (dst->connection, gc, XCB_GC_FILL_STYLE, values);
+    } else {
+	for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	    int i;
+
+	    for (i = 0; i < chunk->count; i++) {
+		int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
+		int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
+		int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
+		int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
+
+		_cairo_xcb_connection_copy_area (dst->connection,
+						 src->pixmap,
+						 dst->drawable, gc,
+						 src->x0 + x1,
+						 src->y0 + y1,
+						 x1, y1,
+						 x2 - x2, y2 - x2);
+	    }
+	}
+    }
+
+    _cairo_xcb_screen_put_gc (dst->screen, src->depth, gc);
+    cairo_surface_destroy (&src->base);
+
+  CLEANUP_CONNECTION:
+    _cairo_xcb_connection_release (dst->connection);
+
+    return status;
+}
+
+cairo_status_t
+_cairo_xcb_surface_core_fill_boxes (cairo_xcb_surface_t *dst,
+				    const cairo_color_t	*color,
+				    cairo_boxes_t *boxes)
+{
+    struct _cairo_boxes_chunk *chunk;
+    xcb_gcontext_t gc;
+    cairo_status_t status;
+
+    status = _cairo_xcb_connection_acquire (dst->connection);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_xcb_connection_take_socket (dst->connection);
+    if (unlikely (status)) {
+	_cairo_xcb_connection_release (dst->connection);
+	return status;
+    }
+
+    gc = _cairo_xcb_screen_get_gc (dst->screen, dst->drawable, dst->depth);
+
+#if 0
+    xcb_pixmap_t source;
+
+    source = _dither_source (dst, color);
+    XSetTSOrigin (surface->dpy, gc, 0, 0);
+    XSetTile (surface->dpy, gc, source);
+#endif
+
+    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	xcb_rectangle_t *xcb_rects;
+	int i;
+
+	xcb_rects = (xcb_rectangle_t *) chunk->base;
+	for (i = 0; i < chunk->count; i++) {
+	    int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
+	    int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
+	    int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
+	    int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
+
+	    xcb_rects[i].x = x1;
+	    xcb_rects[i].y = y1;
+	    xcb_rects[i].width  = x2 - x1;
+	    xcb_rects[i].height = y2 - y1;
+	}
+
+	_cairo_xcb_connection_poly_fill_rectangle (dst->connection,
+						   dst->drawable, gc,
+						   chunk->count, xcb_rects);
+    }
+
+    _cairo_xcb_screen_put_gc (dst->screen, dst->depth, gc);
+    _cairo_xcb_connection_release (dst->connection);
+
+    return CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/cairo-xcb-surface-private.h b/src/cairo-xcb-surface-private.h
new file mode 100644
index 0000000..1ef4900
--- /dev/null
+++ b/src/cairo-xcb-surface-private.h
@@ -0,0 +1,37 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+ *
+ * Contributors(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_XCB_SURFACE_PRIVATE_H
+#define CAIRO_XCB_SURFACE_PRIVATE_H
+
+#include "cairo-xcb-private.h"
+
+#endif
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
new file mode 100644
index 0000000..e07f575
--- /dev/null
+++ b/src/cairo-xcb-surface-render.c
@@ -0,0 +1,4471 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-boxes-private.h"
+#include "cairo-clip-private.h"
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-region-private.h"
+#include "cairo-surface-offset-private.h"
+#include "cairo-surface-snapshot-private.h"
+#include "cairo-surface-subsurface-private.h"
+#include "cairo-xcb-private.h"
+
+#if CAIRO_HAS_XCB_DRM_FUNCTIONS && CAIRO_HAS_DRM_SURFACE
+#include "drm/cairo-drm-private.h"
+#endif
+
+#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
+
+typedef struct _cairo_xcb_picture {
+    cairo_surface_t base;
+
+    cairo_surface_t *owner;
+
+    cairo_xcb_connection_t *connection;
+    cairo_xcb_screen_t *screen;
+    xcb_render_picture_t picture;
+    xcb_render_pictformat_t xrender_format;
+    pixman_format_code_t pixman_format;
+
+    int width, height;
+
+    cairo_extend_t extend;
+    cairo_filter_t filter;
+    cairo_bool_t has_component_alpha;
+    xcb_render_transform_t transform;
+
+    int x0, y0;
+    int x, y;
+} cairo_xcb_picture_t;
+
+static void
+_cairo_xcb_surface_ensure_picture (cairo_xcb_surface_t *surface);
+
+static uint32_t
+hars_petruska_f54_1_random (void)
+{
+#define rol(x,k) ((x << k) | (x >> (32-k)))
+    static uint32_t x;
+    return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849;
+#undef rol
+}
+
+static cairo_status_t
+_cairo_xcb_picture_finish (void *abstract_surface)
+{
+    cairo_xcb_picture_t *surface = abstract_surface;
+    cairo_status_t status;
+
+    if (surface->owner != NULL) {
+	cairo_surface_destroy (surface->owner);
+    } else {
+	status = _cairo_xcb_connection_acquire (surface->connection);
+	if (unlikely (status))
+	    return status;
+
+	if (_cairo_xcb_connection_take_socket (surface->connection) == CAIRO_STATUS_SUCCESS) {
+	    _cairo_xcb_connection_render_free_picture (surface->connection,
+						       surface->picture);
+	}
+	_cairo_xcb_connection_release (surface->connection);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t _cairo_xcb_picture_backend = {
+    CAIRO_SURFACE_TYPE_XCB,
+    NULL,
+    _cairo_xcb_picture_finish,
+};
+
+static const struct xcb_render_transform_t identity_transform = {
+    1 << 16, 0, 0,
+    0, 1 << 16, 0,
+    0, 0, 1 << 16,
+};
+
+static cairo_xcb_picture_t *
+_cairo_xcb_picture_create (cairo_xcb_screen_t *screen,
+			   pixman_format_code_t pixman_format,
+			   xcb_render_pictformat_t xrender_format,
+			   int width, int height)
+{
+    cairo_xcb_picture_t *surface;
+
+    surface = malloc (sizeof (cairo_xcb_picture_t));
+    if (unlikely (surface == NULL))
+	return (cairo_xcb_picture_t *)
+	    _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    _cairo_surface_init (&surface->base,
+			 &_cairo_xcb_picture_backend,
+			 NULL,
+			 _cairo_content_from_pixman_format (pixman_format));
+
+    surface->connection = screen->connection;
+    surface->screen = screen;
+    surface->owner = NULL;
+    surface->picture = _cairo_xcb_connection_get_xid (screen->connection);
+    surface->pixman_format = pixman_format;
+    surface->xrender_format = xrender_format;
+
+    surface->x0 = surface->y0 = 0;
+    surface->x = surface->y = 0;
+    surface->width = width;
+    surface->height = height;
+
+    surface->transform = identity_transform;
+    surface->extend = CAIRO_EXTEND_NONE;
+    surface->filter = CAIRO_FILTER_NEAREST;
+    surface->has_component_alpha = FALSE;
+
+    return surface;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_picture_copy (cairo_xcb_surface_t *target)
+{
+    cairo_xcb_picture_t *surface;
+
+    surface = malloc (sizeof (cairo_xcb_picture_t));
+    if (unlikely (surface == NULL))
+	return (cairo_xcb_picture_t *)
+	    _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    _cairo_surface_init (&surface->base,
+			 &_cairo_xcb_picture_backend,
+			 NULL,
+			 target->base.content);
+
+    surface->connection = target->connection;
+    surface->screen = target->screen;
+    surface->owner = cairo_surface_reference (&target->base);
+    _cairo_xcb_surface_ensure_picture (target);
+    surface->picture = target->picture;
+    surface->pixman_format = target->pixman_format;
+    surface->xrender_format = target->xrender_format;
+
+    surface->x0 = surface->y0 = 0;
+    surface->x = surface->y = 0;
+    surface->width = target->width;
+    surface->height = target->height;
+
+    surface->transform = identity_transform;
+    surface->extend = CAIRO_EXTEND_NONE;
+    surface->filter = CAIRO_FILTER_NEAREST;
+    surface->has_component_alpha = FALSE;
+
+    return surface;
+}
+
+static inline cairo_bool_t
+_operator_is_supported (uint32_t flags, cairo_operator_t op)
+{
+    if (op <= CAIRO_OPERATOR_SATURATE)
+	return TRUE;
+
+    return flags & CAIRO_XCB_RENDER_HAS_PDF_OPERATORS;
+}
+
+static int
+_render_operator (cairo_operator_t op)
+{
+#define C(x,y) case CAIRO_OPERATOR_##x: return XCB_RENDER_PICT_OP_##y
+    switch (op) {
+    C(CLEAR, CLEAR);
+    C(SOURCE, SRC);
+
+    C(OVER, OVER);
+    C(IN, IN);
+    C(OUT, OUT);
+    C(ATOP, ATOP);
+
+    C(DEST, DST);
+    C(DEST_OVER, OVER_REVERSE);
+    C(DEST_IN, IN_REVERSE);
+    C(DEST_OUT, OUT_REVERSE);
+    C(DEST_ATOP, ATOP_REVERSE);
+
+    C(XOR, XOR);
+    C(ADD, ADD);
+    C(SATURATE, SATURATE);
+
+    case CAIRO_OPERATOR_MULTIPLY:
+    case CAIRO_OPERATOR_SCREEN:
+    case CAIRO_OPERATOR_OVERLAY:
+    case CAIRO_OPERATOR_DARKEN:
+    case CAIRO_OPERATOR_LIGHTEN:
+    case CAIRO_OPERATOR_COLOR_DODGE:
+    case CAIRO_OPERATOR_COLOR_BURN:
+    case CAIRO_OPERATOR_HARD_LIGHT:
+    case CAIRO_OPERATOR_SOFT_LIGHT:
+    case CAIRO_OPERATOR_DIFFERENCE:
+    case CAIRO_OPERATOR_EXCLUSION:
+    case CAIRO_OPERATOR_HSL_HUE:
+    case CAIRO_OPERATOR_HSL_SATURATION:
+    case CAIRO_OPERATOR_HSL_COLOR:
+    case CAIRO_OPERATOR_HSL_LUMINOSITY:
+    default:
+	ASSERT_NOT_REACHED;
+	return XCB_RENDER_PICT_OP_OVER;
+    }
+}
+
+static void
+_cairo_xcb_surface_set_clip_region (cairo_xcb_surface_t *surface,
+				    cairo_region_t	*region)
+{
+    xcb_rectangle_t rects[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t)];
+    int i, num_rects;
+
+    num_rects = cairo_region_num_rectangles (region);
+    assert (num_rects < ARRAY_LENGTH (rects)); /* XXX somebody will! */
+
+    for (i = 0; i < num_rects; i++) {
+	cairo_rectangle_int_t rect;
+
+	cairo_region_get_rectangle (region, i, &rect);
+
+	rects[i].x = rect.x;
+	rects[i].y = rect.y;
+	rects[i].width  = rect.width;
+	rects[i].height = rect.height;
+    }
+
+    _cairo_xcb_connection_render_set_picture_clip_rectangles (surface->connection,
+							      surface->picture,
+							      0, 0,
+							      num_rects, rects);
+}
+
+static void
+_cairo_xcb_surface_clear_clip_region (cairo_xcb_surface_t *surface)
+{
+    uint32_t values[] = { XCB_NONE };
+    _cairo_xcb_connection_render_change_picture (surface->connection,
+						 surface->picture,
+						 XCB_RENDER_CP_CLIP_MASK, values);
+}
+
+static void
+_cairo_xcb_surface_ensure_picture (cairo_xcb_surface_t *surface)
+{
+    if (surface->picture == XCB_NONE) {
+	surface->picture = _cairo_xcb_connection_get_xid (surface->connection);
+	_cairo_xcb_connection_render_create_picture (surface->connection,
+						     surface->picture,
+						     surface->drawable,
+						     surface->xrender_format,
+						     0, NULL);
+    }
+}
+
+static cairo_xcb_picture_t *
+_picture_from_image (cairo_xcb_surface_t *target,
+		     xcb_render_pictformat_t format,
+		     cairo_image_surface_t *image,
+		     cairo_xcb_shm_info_t *shm_info)
+{
+    xcb_pixmap_t pixmap;
+    xcb_gcontext_t gc;
+    cairo_xcb_picture_t *picture;
+
+    pixmap = _cairo_xcb_connection_create_pixmap (target->connection,
+						  image->depth,
+						  target->drawable,
+						  image->width, image->height);
+
+    gc = _cairo_xcb_screen_get_gc (target->screen, pixmap, image->depth);
+
+    if (shm_info != NULL) {
+	shm_info->seqno =
+	    _cairo_xcb_connection_shm_put_image (target->connection,
+						 pixmap, gc,
+						 image->width, image->height,
+						 0, 0,
+						 image->width, image->height,
+						 0, 0,
+						 image->depth,
+						 shm_info->shm,
+						 shm_info->offset);
+    } else {
+	int len;
+
+	/* Do we need to trim the image? */
+	len = CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format));
+	if (len == image->stride) {
+	    _cairo_xcb_connection_put_image (target->connection,
+					     pixmap, gc,
+					     image->width, image->height,
+					     0, 0,
+					     image->depth,
+					     image->stride,
+					     image->data);
+	} else {
+	    _cairo_xcb_connection_put_subimage (target->connection,
+						pixmap, gc,
+						0, 0,
+						image->width, image->height,
+						PIXMAN_FORMAT_BPP (image->pixman_format) / 8,
+						image->stride,
+						0, 0,
+						image->depth,
+						image->data);
+
+	}
+    }
+
+    _cairo_xcb_screen_put_gc (target->screen, image->depth, gc);
+
+    picture = _cairo_xcb_picture_create (target->screen,
+					 image->pixman_format, format,
+					 image->width, image->height);
+    if (likely (picture->base.status == CAIRO_STATUS_SUCCESS)) {
+	_cairo_xcb_connection_render_create_picture (target->connection,
+						     picture->picture, pixmap, format,
+						     0, 0);
+    }
+
+    _cairo_xcb_connection_free_pixmap (target->connection, pixmap);
+
+    return picture;
+}
+
+static cairo_bool_t
+_pattern_is_supported (uint32_t flags,
+		       const cairo_pattern_t *pattern)
+
+{
+    if (pattern->type == CAIRO_PATTERN_TYPE_SOLID)
+	return TRUE;
+
+    if (! _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL)) {
+	if ((flags & CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM) == 0)
+	    return FALSE;
+    }
+
+    switch (pattern->extend) {
+    default:
+	ASSERT_NOT_REACHED;
+    case CAIRO_EXTEND_NONE:
+    case CAIRO_EXTEND_REPEAT:
+	break;
+    case CAIRO_EXTEND_PAD:
+    case CAIRO_EXTEND_REFLECT:
+	if ((flags & CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT) == 0)
+	    return FALSE;
+    }
+
+    if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	cairo_filter_t filter;
+
+	filter = pattern->filter;
+	if (_cairo_matrix_has_unity_scale (&pattern->matrix) &&
+	    _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL))
+	{
+	    filter = CAIRO_FILTER_NEAREST;
+	}
+
+	if (! (filter == CAIRO_FILTER_NEAREST || filter == CAIRO_FILTER_FAST)) {
+	    if ((flags & CAIRO_XCB_RENDER_HAS_FILTERS) == 0)
+		return FALSE;
+	}
+    } else { /* gradient */
+	if ((flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) == 0)
+	    return FALSE;
+    }
+
+    return TRUE;
+}
+
+static double
+_pixman_nearest_sample (double d)
+{
+    return ceil (d - .5);
+}
+
+static cairo_bool_t
+_nearest_sample (const cairo_matrix_t *m,
+		 cairo_filter_t filter,
+		 double *tx, double *ty)
+{
+    *tx = m->x0;
+    *ty = m->y0;
+    if ((filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
+       && _cairo_matrix_has_unity_scale (m))
+    {
+	*tx = _pixman_nearest_sample (*tx);
+	*ty = _pixman_nearest_sample (*ty);
+    }
+    else
+    {
+	if (*tx != floor (*tx) || *ty != floor (*ty))
+	    return FALSE;
+    }
+    return fabs (*tx) < PIXMAN_MAX_INT && fabs (*ty) < PIXMAN_MAX_INT;
+}
+
+static void
+_cairo_xcb_picture_set_matrix (cairo_xcb_picture_t *picture,
+			       const cairo_matrix_t *matrix,
+			       cairo_filter_t filter,
+			       double xc, double yc)
+{
+    cairo_matrix_t m;
+    double tx, ty;
+
+    m = *matrix;
+    if (_nearest_sample (&m, filter, &tx, &ty))
+	m.x0 = m.y0 = 0;
+    else
+	tx = ty = 0;
+
+    if (! _cairo_matrix_is_identity (&m)) {
+	xcb_render_transform_t transform;
+	cairo_matrix_t inv;
+	cairo_status_t status;
+
+	inv = m;
+	status = cairo_matrix_invert (&inv);
+	assert (status == CAIRO_STATUS_SUCCESS);
+
+	if (m.x0 != 0. || m.y0 != 0.) {
+	    double x, y;
+
+	    /* pixman also limits the [xy]_offset to 16 bits so evenly
+	     * spread the bits between the two.
+	     */
+	    x = floor (inv.x0 / 2);
+	    y = floor (inv.y0 / 2);
+	    tx = -x;
+	    ty = -y;
+	    cairo_matrix_init_translate (&inv, x, y);
+	    cairo_matrix_multiply (&m, &inv, &m);
+	} else {
+	    if (tx != 0. || ty != 0.)
+		cairo_matrix_transform_point (&inv, &tx, &ty);
+	}
+
+	/* Casting between pixman_transform_t and XTransform is safe because
+	 * they happen to be the exact same type.
+	 */
+	_cairo_matrix_to_pixman_matrix (&m,
+					(pixman_transform_t *) &transform, xc, yc);
+
+	if (memcmp (&picture->transform, &transform, sizeof (xcb_render_transform_t))) {
+	    _cairo_xcb_connection_render_set_picture_transform (picture->connection,
+								picture->picture,
+								&transform);
+
+	    picture->transform = transform;
+	}
+    }
+
+    picture->x = picture->x0 + tx;
+    picture->y = picture->y0 + ty;
+}
+
+static void
+_cairo_xcb_picture_set_filter (cairo_xcb_picture_t *picture,
+			       cairo_filter_t filter)
+{
+    const char *render_filter;
+    int len;
+
+    if (picture->filter == filter)
+	return;
+
+    switch (filter) {
+    case CAIRO_FILTER_FAST:
+	render_filter = "fast";
+	len = strlen ("fast");
+	break;
+
+    case CAIRO_FILTER_GOOD:
+	render_filter = "good";
+	len = strlen ("good");
+	break;
+
+    case CAIRO_FILTER_BEST:
+	render_filter = "best";
+	len = strlen ("best");
+	break;
+
+    case CAIRO_FILTER_NEAREST:
+	render_filter = "nearest";
+	len = strlen ("nearest");
+	break;
+
+    case CAIRO_FILTER_BILINEAR:
+	render_filter = "bilinear";
+	len = strlen ("bilinear");
+	break;
+
+    default:
+	ASSERT_NOT_REACHED;
+    case CAIRO_FILTER_GAUSSIAN:
+	render_filter = "best";
+	len = strlen ("best");
+	break;
+    }
+
+    _cairo_xcb_connection_render_set_picture_filter (picture->connection,
+						     picture->picture,
+						     len, (char *) render_filter);
+    picture->filter = filter;
+}
+
+static void
+_cairo_xcb_picture_set_extend (cairo_xcb_picture_t *picture,
+			       cairo_extend_t extend)
+{
+    uint32_t pa[1];
+
+    if (picture->extend == extend)
+	return;
+
+    switch (extend) {
+    default:
+	ASSERT_NOT_REACHED;
+    case CAIRO_EXTEND_NONE:
+	pa[0] = XCB_RENDER_REPEAT_NONE;
+	break;
+
+    case CAIRO_EXTEND_REPEAT:
+	pa[0] = XCB_RENDER_REPEAT_NORMAL;
+	break;
+
+    case CAIRO_EXTEND_REFLECT:
+	pa[0] = XCB_RENDER_REPEAT_REFLECT;
+	break;
+
+    case CAIRO_EXTEND_PAD:
+	pa[0] = XCB_RENDER_REPEAT_PAD;
+	break;
+    }
+
+    _cairo_xcb_connection_render_change_picture (picture->connection,
+						 picture->picture,
+						 XCB_RENDER_CP_REPEAT, pa);
+    picture->extend = extend;
+}
+
+static void
+_cairo_xcb_picture_set_component_alpha (cairo_xcb_picture_t *picture,
+					cairo_bool_t ca)
+{
+    uint32_t pa[1];
+
+    if (picture->has_component_alpha == ca)
+	return;
+
+    pa[0] = ca;
+
+    _cairo_xcb_connection_render_change_picture (picture->connection,
+						 picture->picture,
+						 XCB_RENDER_CP_COMPONENT_ALPHA,
+						 pa);
+    picture->has_component_alpha = ca;
+}
+
+static cairo_xcb_picture_t *
+_solid_picture (cairo_xcb_surface_t *target,
+		const cairo_color_t *color)
+{
+    xcb_render_color_t xcb_color;
+    xcb_render_pictformat_t xrender_format;
+    cairo_xcb_picture_t *picture;
+
+    xcb_color.red   = color->red_short;
+    xcb_color.green = color->green_short;
+    xcb_color.blue  = color->blue_short;
+    xcb_color.alpha = color->alpha_short;
+
+    xrender_format = target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32];
+    picture = _cairo_xcb_picture_create (target->screen,
+					 PIXMAN_a8r8g8b8,
+					 xrender_format,
+					 -1, -1);
+    if (unlikely (picture->base.status))
+	return picture;
+
+    if (target->flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) {
+	_cairo_xcb_connection_render_create_solid_fill (target->connection,
+							picture->picture,
+							xcb_color);
+    } else {
+	xcb_pixmap_t pixmap;
+	uint32_t values[] = { XCB_RENDER_REPEAT_NORMAL };
+
+	pixmap = _cairo_xcb_connection_create_pixmap (target->connection,
+						      32, target->drawable, 1, 1);
+	_cairo_xcb_connection_render_create_picture (target->connection,
+						     picture->picture,
+						     pixmap,
+						     xrender_format,
+						     XCB_RENDER_CP_REPEAT,
+						     values);
+	if (target->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
+	    xcb_rectangle_t rect;
+
+	    rect.x = rect.y = 0;
+	    rect.width = rect.height = 1;
+
+	    _cairo_xcb_connection_render_fill_rectangles (picture->connection,
+							  XCB_RENDER_PICT_OP_SRC,
+							  picture->picture,
+							  xcb_color, 1, &rect);
+	} else {
+	    xcb_gcontext_t gc;
+	    uint32_t pixel;
+
+	    gc = _cairo_xcb_screen_get_gc (target->screen, pixmap, 32);
+
+	    /* XXX byte ordering? */
+	    pixel = ((color->alpha_short >> 8) << 24) |
+		    ((color->red_short   >> 8) << 16) |
+		    ((color->green_short >> 8) << 8) |
+		    ((color->blue_short  >> 8) << 0);
+
+	    _cairo_xcb_connection_put_image (target->connection,
+					     pixmap, gc,
+					     1, 1, 0, 0,
+					     32, 4, &pixel);
+
+	    _cairo_xcb_screen_put_gc (target->screen, 32, gc);
+	}
+
+	_cairo_xcb_connection_free_pixmap (target->connection, pixmap);
+    }
+
+    return picture;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_transparent_picture (cairo_xcb_surface_t *target)
+{
+    cairo_xcb_picture_t *picture;
+
+    picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_TRANSPARENT];
+    if (picture == NULL) {
+	picture = _solid_picture (target, CAIRO_COLOR_TRANSPARENT);
+	target->screen->stock_colors[CAIRO_STOCK_TRANSPARENT] = &picture->base;
+    }
+
+    return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_black_picture (cairo_xcb_surface_t *target)
+{
+    cairo_xcb_picture_t *picture;
+
+    picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_BLACK];
+    if (picture == NULL) {
+	picture = _solid_picture (target, CAIRO_COLOR_BLACK);
+	target->screen->stock_colors[CAIRO_STOCK_BLACK] = &picture->base;
+    }
+
+    return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_white_picture (cairo_xcb_surface_t *target)
+{
+    cairo_xcb_picture_t *picture;
+
+    picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_WHITE];
+    if (picture == NULL) {
+	picture = _solid_picture (target, CAIRO_COLOR_WHITE);
+	target->screen->stock_colors[CAIRO_STOCK_WHITE] = &picture->base;
+    }
+
+    return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_solid_picture (cairo_xcb_surface_t *target,
+			  const cairo_solid_pattern_t *pattern)
+{
+    cairo_xcb_picture_t *picture;
+    cairo_xcb_screen_t *screen;
+    int i, n_cached;
+
+    if (pattern->color.alpha_short <= 0x00ff)
+	return _cairo_xcb_transparent_picture (target);
+
+    if (pattern->color.alpha_short >= 0xff00) {
+	if (pattern->color.red_short <= 0x00ff &&
+	    pattern->color.green_short <= 0x00ff &&
+	    pattern->color.blue_short <= 0x00ff)
+	{
+	    return _cairo_xcb_black_picture (target);
+	}
+
+	if (pattern->color.red_short >= 0xff00 &&
+	    pattern->color.green_short >= 0xff00 &&
+	    pattern->color.blue_short >= 0xff00)
+	{
+	    return _cairo_xcb_white_picture (target);
+	}
+    }
+
+    screen = target->screen;
+    n_cached = screen->solid_cache_size;
+    for (i = 0; i < n_cached; i++) {
+	if (_cairo_color_equal (&screen->solid_cache[i].color, &pattern->color)) {
+	    return (cairo_xcb_picture_t *) cairo_surface_reference (screen->solid_cache[i].picture);
+	}
+    }
+
+    picture = _solid_picture (target, &pattern->color);
+    if (unlikely (picture->base.status))
+	return picture;
+
+    if (screen->solid_cache_size < ARRAY_LENGTH (screen->solid_cache)) {
+	i = screen->solid_cache_size++;
+    } else {
+	i = hars_petruska_f54_1_random () % ARRAY_LENGTH (screen->solid_cache);
+	cairo_surface_destroy (screen->solid_cache[i].picture);
+    }
+    screen->solid_cache[i].picture = cairo_surface_reference (&picture->base);
+    screen->solid_cache[i].color = pattern->color;
+
+    return picture;
+}
+
+static cairo_status_t
+_cairo_xcb_shm_image_create (cairo_xcb_connection_t *connection,
+			     pixman_format_code_t pixman_format,
+			     int width, int height,
+			     cairo_image_surface_t **image_out,
+			     cairo_xcb_shm_info_t **shm_info_out)
+{
+    cairo_surface_t *image = NULL;
+    cairo_xcb_shm_info_t *shm_info = NULL;
+    cairo_status_t status;
+
+    if ((connection->flags & CAIRO_XCB_HAS_SHM)) {
+	size_t size, stride;
+
+	stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (pixman_format));
+	size = stride * height;
+	if (size > CAIRO_XCB_SHM_SMALL_IMAGE) {
+	    status = _cairo_xcb_connection_allocate_shm_info (connection,
+							      size, &shm_info);
+	    if (unlikely (status))
+		return status;
+
+	    image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
+								    pixman_format,
+								    width, height,
+								    stride);
+	    status = image->status;
+	    if (unlikely (status)) {
+		_cairo_xcb_shm_info_destroy (shm_info);
+		return status;
+	    }
+
+	    status = _cairo_user_data_array_set_data (&image->user_data,
+						      (const cairo_user_data_key_t *) connection,
+						      shm_info,
+						      (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
+	    if (unlikely (status)) {
+		cairo_surface_destroy (image);
+		_cairo_xcb_shm_info_destroy (shm_info);
+		return status;
+	    }
+	}
+    }
+
+    if (image == NULL) {
+	image = _cairo_image_surface_create_with_pixman_format (NULL,
+								pixman_format,
+								width, height,
+								0);
+	status = image->status;
+	if (unlikely (status))
+	    return status;
+    }
+
+    *image_out = (cairo_image_surface_t *) image;
+    *shm_info_out = shm_info;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_xcb_picture_t *
+_render_to_picture (cairo_xcb_surface_t *target,
+		    const cairo_pattern_t *pattern,
+		    const cairo_rectangle_int_t *extents)
+{
+    cairo_image_surface_t *image;
+    cairo_xcb_shm_info_t *shm_info;
+    cairo_pattern_union_t copy;
+    cairo_status_t status;
+    cairo_xcb_picture_t *picture;
+    pixman_format_code_t pixman_format;
+    xcb_render_pictformat_t xrender_format;
+
+    /* XXX handle extend modes via tiling? */
+    /* XXX alpha-only masks? */
+
+    pixman_format = PIXMAN_a8r8g8b8;
+    xrender_format = target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32];
+
+    status = _cairo_xcb_shm_image_create (target->screen->connection,
+					  pixman_format,
+					  extents->width, extents->height,
+					  &image, &shm_info);
+    if (unlikely (status))
+	return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+
+    _cairo_pattern_init_static_copy (&copy.base, pattern);
+    cairo_matrix_translate (&copy.base.matrix, extents->x, extents->y);
+    status = _cairo_surface_paint (&image->base,
+				   CAIRO_OPERATOR_SOURCE,
+				   &copy.base,
+				   NULL);
+    if (unlikely (status)) {
+	cairo_surface_destroy (&image->base);
+	return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+    }
+
+    picture = _picture_from_image (target, xrender_format, image, shm_info);
+    cairo_surface_destroy (&image->base);
+
+    if (unlikely (picture->base.status))
+	return picture;
+
+    _cairo_xcb_picture_set_component_alpha (picture, pattern->has_component_alpha);
+    picture->x = -extents->x;
+    picture->y = -extents->y;
+
+    return picture;
+}
+
+static xcb_render_fixed_t *
+_gradient_to_xcb (const cairo_gradient_pattern_t *gradient,
+		  char *buf, unsigned int buflen)
+{
+    xcb_render_fixed_t *stops;
+    xcb_render_color_t *colors;
+    unsigned int i;
+
+    if (gradient->n_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t)) < buflen)
+    {
+	stops = (xcb_render_fixed_t *) buf;
+    }
+    else
+    {
+	stops =
+	    _cairo_malloc_ab (gradient->n_stops,
+			      sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t));
+	if (unlikely (stops == NULL))
+	    return NULL;
+    }
+
+    colors = (xcb_render_color_t *) (stops + gradient->n_stops);
+    for (i = 0; i < gradient->n_stops; i++) {
+	stops[i] =
+	    _cairo_fixed_16_16_from_double (gradient->stops[i].offset);
+
+	colors[i].red   = gradient->stops[i].color.red_short;
+	colors[i].green = gradient->stops[i].color.green_short;
+	colors[i].blue  = gradient->stops[i].color.blue_short;
+	colors[i].alpha = gradient->stops[i].color.alpha_short;
+    }
+
+    return stops;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_linear_picture (cairo_xcb_surface_t *target,
+			   const cairo_linear_pattern_t *pattern,
+			   const cairo_rectangle_int_t *extents)
+{
+    char buf[CAIRO_STACK_BUFFER_SIZE];
+    cairo_fixed_t xdim, ydim;
+    xcb_render_fixed_t *stops;
+    xcb_render_color_t *colors;
+    xcb_render_pointfix_t p1, p2;
+    cairo_matrix_t matrix = pattern->base.base.matrix;
+    cairo_xcb_picture_t *picture;
+    cairo_status_t status;
+
+    picture = (cairo_xcb_picture_t *)
+	_cairo_xcb_screen_lookup_linear_picture (target->screen, pattern);
+    if (picture != NULL)
+	goto setup_picture;
+
+    stops = _gradient_to_xcb (&pattern->base, buf, sizeof (buf));
+    if (unlikely (stops == NULL))
+	return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+    picture = _cairo_xcb_picture_create (target->screen,
+					 target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32],
+					 PIXMAN_a8r8g8b8,
+					 -1, -1);
+    if (unlikely (picture->base.status)) {
+	if (stops != (xcb_render_fixed_t *) buf)
+	    free (stops);
+	return picture;
+    }
+    picture->filter = CAIRO_FILTER_DEFAULT;
+
+    xdim = pattern->p2.x - pattern->p1.x;
+    ydim = pattern->p2.y - pattern->p1.y;
+
+    /*
+     * Transform the matrix to avoid overflow when converting between
+     * cairo_fixed_t and pixman_fixed_t (without incurring performance
+     * loss when the transformation is unnecessary).
+     *
+     * XXX: Consider converting out-of-range co-ordinates and transforms.
+     * Having a function to compute the required transformation to
+     * "normalize" a given bounding box would be generally useful -
+     * cf linear patterns, gradient patterns, surface patterns...
+     */
+#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
+    if (unlikely (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
+		  _cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT))
+    {
+	double sf;
+
+	if (xdim > ydim)
+	    sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
+	else
+	    sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
+
+	p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p1.x) * sf);
+	p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p1.y) * sf);
+	p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p2.x) * sf);
+	p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (pattern->p2.y) * sf);
+
+	cairo_matrix_scale (&matrix, sf, sf);
+    }
+    else
+    {
+	p1.x = _cairo_fixed_to_16_16 (pattern->p1.x);
+	p1.y = _cairo_fixed_to_16_16 (pattern->p1.y);
+	p2.x = _cairo_fixed_to_16_16 (pattern->p2.x);
+	p2.y = _cairo_fixed_to_16_16 (pattern->p2.y);
+    }
+
+    colors = (xcb_render_color_t *) (stops + pattern->base.n_stops);
+    _cairo_xcb_connection_render_create_linear_gradient (target->connection,
+							 picture->picture,
+							 p1, p2,
+							 pattern->base.n_stops,
+							 stops, colors);
+
+    if (stops != (xcb_render_fixed_t *) buf)
+	free (stops);
+
+    status = _cairo_xcb_screen_store_linear_picture (target->screen,
+						     pattern,
+						     &picture->base);
+    if (unlikely (status)) {
+	cairo_surface_destroy (&picture->base);
+	return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+    }
+
+setup_picture:
+    _cairo_xcb_picture_set_matrix (picture, &matrix,
+				   pattern->base.base.filter,
+				   extents->x + extents->width/2.,
+				   extents->y + extents->height/2.);
+    _cairo_xcb_picture_set_filter (picture, pattern->base.base.filter);
+    _cairo_xcb_picture_set_extend (picture, pattern->base.base.extend);
+    _cairo_xcb_picture_set_component_alpha (picture,
+					    pattern->base.base.has_component_alpha);
+
+    return picture;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_radial_picture (cairo_xcb_surface_t *target,
+			   const cairo_radial_pattern_t *pattern,
+			   const cairo_rectangle_int_t *extents)
+{
+    char buf[CAIRO_STACK_BUFFER_SIZE];
+    xcb_render_fixed_t *stops;
+    xcb_render_color_t *colors;
+    xcb_render_pointfix_t c1, c2;
+    xcb_render_fixed_t r1, r2;
+    cairo_xcb_picture_t *picture;
+    cairo_status_t status;
+
+    picture = (cairo_xcb_picture_t *)
+	_cairo_xcb_screen_lookup_radial_picture (target->screen, pattern);
+    if (picture != NULL)
+	goto setup_picture;
+
+    stops = _gradient_to_xcb (&pattern->base, buf, sizeof (buf));
+    if (unlikely (stops == NULL))
+	return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+    picture = _cairo_xcb_picture_create (target->screen,
+					 target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32],
+					 PIXMAN_a8r8g8b8,
+					 -1, -1);
+    if (unlikely (picture->base.status)) {
+	if (stops != (xcb_render_fixed_t *) buf)
+	    free (stops);
+	return picture;
+    }
+    picture->filter = CAIRO_FILTER_DEFAULT;
+
+    c1.x = _cairo_fixed_to_16_16 (pattern->c1.x);
+    c1.y = _cairo_fixed_to_16_16 (pattern->c1.y);
+    r1 = _cairo_fixed_to_16_16 (pattern->r1);
+    c2.x = _cairo_fixed_to_16_16 (pattern->c2.x);
+    c2.y = _cairo_fixed_to_16_16 (pattern->c2.y);
+    r2 = _cairo_fixed_to_16_16 (pattern->r2);
+
+    colors = (xcb_render_color_t *) (stops + pattern->base.n_stops);
+    _cairo_xcb_connection_render_create_radial_gradient (target->connection,
+							 picture->picture,
+							 c1, c2, r1, r2,
+							 pattern->base.n_stops,
+							 stops, colors);
+
+    if (stops != (xcb_render_fixed_t *) buf)
+	free (stops);
+
+    status = _cairo_xcb_screen_store_radial_picture (target->screen,
+						     pattern,
+						     &picture->base);
+    if (unlikely (status)) {
+	cairo_surface_destroy (&picture->base);
+	return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+    }
+
+setup_picture:
+    _cairo_xcb_picture_set_matrix (picture, &pattern->base.base.matrix,
+				   pattern->base.base.filter,
+				   extents->x + extents->width/2.,
+				   extents->y + extents->height/2.);
+    _cairo_xcb_picture_set_filter (picture, pattern->base.base.filter);
+    _cairo_xcb_picture_set_extend (picture, pattern->base.base.extend);
+    _cairo_xcb_picture_set_component_alpha (picture,
+					    pattern->base.base.has_component_alpha);
+
+    return picture;
+}
+
+static void
+_decouple_cached_picture (cairo_surface_t *surface)
+{
+    cairo_xcb_picture_t *picture = (cairo_xcb_picture_t *) surface;
+
+    if (! picture->base.finished)
+	_cairo_xcb_screen_remove_surface_picture (picture->screen, &picture->base);
+}
+
+static cairo_xcb_picture_t *
+_copy_to_picture (cairo_xcb_surface_t *source,
+		  cairo_bool_t force)
+{
+    cairo_xcb_picture_t *picture;
+    uint32_t values[] = { 0, 1 };
+
+    /* XXX two level device locking, ensure we release the xcb device mutex? */
+    if (source->drm != NULL)
+	cairo_surface_flush (source->drm);
+
+    if (source->owns_pixmap && ! force) {
+	picture = _cairo_xcb_picture_copy (source);
+    } else {
+	picture = _cairo_xcb_picture_create (source->screen,
+					     source->xrender_format,
+					     source->pixman_format,
+					     source->width,
+					     source->height);
+	if (unlikely (picture->base.status))
+	    return picture;
+
+	_cairo_xcb_connection_render_create_picture (source->connection,
+						     picture->picture,
+						     source->drawable,
+						     source->xrender_format,
+						     XCB_RENDER_CP_GRAPHICS_EXPOSURE |
+						     XCB_RENDER_CP_SUBWINDOW_MODE,
+						     values);
+    }
+
+    return picture;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_surface_picture (cairo_xcb_surface_t *target,
+			    const cairo_surface_pattern_t *pattern,
+			    const cairo_rectangle_int_t *extents)
+{
+    cairo_surface_t *source;
+    cairo_xcb_picture_t *picture;
+    cairo_filter_t filter;
+    cairo_extend_t extend;
+    cairo_status_t status;
+
+    source = pattern->surface;
+    if (source->is_clear) {
+        if (source->content & CAIRO_CONTENT_ALPHA)
+	    return _cairo_xcb_transparent_picture (target);
+        else
+            return _cairo_xcb_black_picture (target);
+    }
+
+    picture = (cairo_xcb_picture_t *)
+	_cairo_surface_has_snapshot (source, &_cairo_xcb_picture_backend);
+    if (picture != NULL) {
+	if (picture->screen == target->screen) {
+	    picture = (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base);
+	    goto setup_picture;
+	}
+    }
+
+    if (source->type == CAIRO_SURFACE_TYPE_XCB)
+    {
+	if (source->backend->type == CAIRO_SURFACE_TYPE_XCB) {
+	    if (((cairo_xcb_surface_t *) source)->screen == target->screen) {
+		picture = _copy_to_picture ((cairo_xcb_surface_t *) source, FALSE);
+		if (unlikely (picture->base.status))
+		    return picture;
+	    }
+	} else if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+	    cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
+	    cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) sub->target;
+
+	    /* XXX repeat interval with source clipping? */
+	    if (FALSE && xcb->screen == target->screen) {
+		xcb_rectangle_t rect;
+
+		picture = _copy_to_picture (xcb, TRUE);
+		if (unlikely (picture->base.status))
+		    return picture;
+
+		rect.x = sub->extents.x;
+		rect.y = sub->extents.y;
+		rect.width  = sub->extents.width;
+		rect.height = sub->extents.height;
+
+		_cairo_xcb_connection_render_set_picture_clip_rectangles (xcb->connection,
+									  picture->picture,
+									  0, 0,
+									  1, &rect);
+		picture->x0 = rect.x;
+		picture->y0 = rect.y;
+		picture->width  = rect.width;
+		picture->height = rect.height;
+	    }
+	} else if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
+	    cairo_surface_snapshot_t *snap = (cairo_surface_snapshot_t *) source;
+	    cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) snap->target;
+
+	    if (xcb->screen == target->screen) {
+		picture = _copy_to_picture (xcb, TRUE);
+		if (unlikely (picture->base.status))
+		    return picture;
+	    }
+	}
+    }
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+    else if (source->type == CAIRO_SURFACE_TYPE_XLIB)
+    {
+	if (source->backend->type == CAIRO_SURFACE_TYPE_XLIB) {
+	    if (((cairo_xlib_xcb_surface_t *) source)->xcb->screen == target->screen) {
+		picture = _copy_to_picture (((cairo_xlib_xcb_surface_t *) source)->xcb,
+					    FALSE);
+		if (unlikely (picture->base.status))
+		    return picture;
+	    }
+	} else if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+	    cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
+	    cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) sub->target)->xcb;
+
+	    if (FALSE && xcb->screen == target->screen) {
+		xcb_rectangle_t rect;
+
+		picture = _copy_to_picture (xcb, TRUE);
+		if (unlikely (picture->base.status))
+		    return picture;
+
+		rect.x = sub->extents.x;
+		rect.y = sub->extents.y;
+		rect.width  = sub->extents.width;
+		rect.height = sub->extents.height;
+
+		_cairo_xcb_connection_render_set_picture_clip_rectangles (xcb->connection,
+									  picture->picture,
+									  0, 0,
+									  1, &rect);
+		picture->x0 = rect.x;
+		picture->y0 = rect.y;
+		picture->width  = rect.width;
+		picture->height = rect.height;
+	    }
+	} else if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
+	    cairo_surface_snapshot_t *snap = (cairo_surface_snapshot_t *) source;
+	    cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) snap->target)->xcb;
+
+	    if (xcb->screen == target->screen) {
+		picture = _copy_to_picture (xcb, TRUE);
+		if (unlikely (picture->base.status))
+		    return picture;
+	    }
+	}
+    }
+#endif
+#if CAIRO_HAS_XCB_DRM_FUNCTIONS && CAIRO_HAS_DRM_SURFACE
+    else if (source->type == CAIRO_SURFACE_TYPE_DRM &&
+	     target->drm != NULL &&
+	     target->drm->device == source->device)
+    {
+	cairo_drm_surface_t *drm = (cairo_drm_surface_t *) source;
+	cairo_xcb_surface_t *tmp;
+	xcb_pixmap_t pixmap;
+	pixman_format_code_t pixman_format;
+	cairo_surface_pattern_t pattern;
+
+	/* XXX XRenderCreatePictureForNative:
+	 * Copy the source to a temporary pixmap if possible.
+	 * Still cheaper than pushing the image via the CPU.
+	 */
+
+	switch (drm->format) {
+	case CAIRO_FORMAT_A1:
+	    pixman_format = PIXMAN_a1;
+	    break;
+	case CAIRO_FORMAT_A8:
+	    pixman_format = PIXMAN_a8;
+	    break;
+	case CAIRO_FORMAT_RGB24:
+	    pixman_format = PIXMAN_x8r8g8b8;
+	    break;
+	default:
+	case CAIRO_FORMAT_ARGB32:
+	    pixman_format = PIXMAN_a8r8g8b8;
+	    break;
+	}
+
+	pixmap =
+	    _cairo_xcb_connection_create_pixmap (target->connection,
+						 PIXMAN_FORMAT_DEPTH (pixman_format),
+						 target->drawable,
+						 drm->width, drm->height);
+
+	tmp = (cairo_xcb_surface_t *)
+	    _cairo_xcb_surface_create_internal (target->screen,
+						pixmap, TRUE,
+						pixman_format,
+						target->connection->standard_formats[drm->format],
+						drm->width, drm->height);
+	if (unlikely (tmp->base.status)) {
+	    _cairo_xcb_connection_free_pixmap (target->connection, pixmap);
+	    return (cairo_xcb_picture_t *) tmp;
+	}
+
+	_cairo_pattern_init_for_surface (&pattern, source);
+	status = _cairo_surface_paint (&tmp->base,
+				       CAIRO_OPERATOR_SOURCE,
+				       &pattern.base,
+				       NULL);
+	_cairo_pattern_fini (&pattern.base);
+
+	if (unlikely (status)) {
+	    cairo_surface_destroy (&tmp->base);
+	    return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+	}
+
+	picture = _copy_to_picture (tmp, FALSE);
+	cairo_surface_destroy (&tmp->base);
+
+	if (unlikely (picture->base.status))
+	    return picture;
+    }
+#endif
+#if CAIRO_HAS_GL_FUNCTIONS
+    else if (source->type == CAIRO_SURFACE_TYPE_GL)
+    {
+	/* pixmap from texture */
+    }
+#endif
+
+    if (picture == NULL) {
+	cairo_image_surface_t *image;
+	void *image_extra;
+	cairo_status_t status;
+
+	status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
+	if (unlikely (status))
+	    return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+
+	if (image->format != CAIRO_FORMAT_INVALID) {
+	    xcb_render_pictformat_t format;
+
+	    format = target->screen->connection->standard_formats[image->format];
+
+	    picture = _picture_from_image (target, format, image, NULL);
+	    _cairo_surface_release_source_image (source, image, image_extra);
+	} else {
+	    cairo_image_surface_t *conv;
+	    cairo_format_t format;
+	    xcb_render_pictformat_t render_format;
+
+	    /* XXX XRenderPutImage! */
+
+	    switch (image->base.content) {
+	    case CAIRO_CONTENT_ALPHA:
+		format = CAIRO_FORMAT_A8;
+		break;
+	    case CAIRO_CONTENT_COLOR:
+		format = CAIRO_FORMAT_RGB24;
+		break;
+	    case CAIRO_CONTENT_COLOR_ALPHA:
+		format = CAIRO_FORMAT_ARGB32;
+		break;
+	    }
+
+	    conv = _cairo_image_surface_coerce (image, format);
+	    _cairo_surface_release_source_image (source, image, image_extra);
+	    if (unlikely (conv->base.status))
+		return (cairo_xcb_picture_t *) conv;
+
+	    render_format = target->screen->connection->standard_formats[format];
+	    picture = _picture_from_image (target, render_format, conv, NULL);
+	    cairo_surface_destroy (&conv->base);
+	}
+
+	if (unlikely (picture->base.status))
+	    return picture;
+    }
+
+    status = _cairo_xcb_screen_store_surface_picture (target->screen,
+						      &picture->base,
+						      CAIRO_STRIDE_FOR_WIDTH_BPP (picture->width,
+										  PIXMAN_FORMAT_BPP (picture->pixman_format))
+						      * picture->height);
+    if (unlikely (status)) {
+	cairo_surface_destroy (&picture->base);
+	return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+    }
+
+    status = _cairo_surface_attach_snapshot (source,
+					     &picture->base,
+					     _decouple_cached_picture);
+    if (unlikely (status)) {
+	cairo_surface_destroy (&picture->base);
+	return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status);
+    }
+
+setup_picture:
+    filter = pattern->base.filter;
+    if (filter != CAIRO_FILTER_NEAREST &&
+	_cairo_matrix_has_unity_scale (&pattern->base.matrix) &&
+	_cairo_fixed_is_integer (_cairo_fixed_from_double (pattern->base.matrix.x0)) &&
+	_cairo_fixed_is_integer (_cairo_fixed_from_double (pattern->base.matrix.y0)))
+    {
+	filter = CAIRO_FILTER_NEAREST;
+    }
+    _cairo_xcb_picture_set_filter (picture, filter);
+
+    _cairo_xcb_picture_set_matrix (picture,
+				   &pattern->base.matrix, filter,
+				   extents->x + extents->width/2.,
+				   extents->y + extents->height/2.);
+
+
+    extend = pattern->base.extend;
+    if (extents->x >= 0 && extents->x + extents->width <= picture->width &&
+	extents->y >= 0 && extents->y + extents->height <= picture->height)
+    {
+	extend = CAIRO_EXTEND_NONE;
+    }
+    _cairo_xcb_picture_set_extend (picture, extend);
+    _cairo_xcb_picture_set_component_alpha (picture, pattern->base.has_component_alpha);
+
+    return picture;
+}
+
+static cairo_xcb_picture_t *
+_cairo_xcb_picture_for_pattern (cairo_xcb_surface_t *target,
+				const cairo_pattern_t *pattern,
+				const cairo_rectangle_int_t *extents)
+{
+    if (pattern == NULL)
+	return _cairo_xcb_white_picture (target);
+
+    if (! _pattern_is_supported (target->flags, pattern))
+	return _render_to_picture (target, pattern, extents);
+
+    switch (pattern->type) {
+    case CAIRO_PATTERN_TYPE_SOLID:
+	return _cairo_xcb_solid_picture (target, (cairo_solid_pattern_t *) pattern);
+
+    case CAIRO_PATTERN_TYPE_LINEAR:
+	return _cairo_xcb_linear_picture (target,
+					  (cairo_linear_pattern_t *) pattern,
+					  extents);
+
+    case CAIRO_PATTERN_TYPE_RADIAL:
+	return _cairo_xcb_radial_picture (target,
+					  (cairo_radial_pattern_t *) pattern,
+					  extents);
+
+    case CAIRO_PATTERN_TYPE_SURFACE:
+	return _cairo_xcb_surface_picture (target,
+					   (cairo_surface_pattern_t *) pattern,
+					   extents);
+    default:
+	ASSERT_NOT_REACHED;
+	return _render_to_picture (target, pattern, extents);
+    }
+}
+
+COMPILE_TIME_ASSERT (sizeof (xcb_rectangle_t) <= sizeof (cairo_box_t));
+
+static cairo_status_t
+_render_fill_boxes (void			*abstract_dst,
+		    cairo_operator_t		 op,
+		    const cairo_color_t	*color,
+		    cairo_boxes_t		*boxes)
+{
+    cairo_xcb_surface_t *dst = abstract_dst;
+    xcb_rectangle_t stack_xrects[CAIRO_STACK_ARRAY_LENGTH (sizeof (xcb_rectangle_t))];
+    xcb_rectangle_t *xrects = stack_xrects;
+    xcb_render_color_t render_color;
+    int render_op = _render_operator (op);
+    struct _cairo_boxes_chunk *chunk;
+    int max_count;
+
+    render_color.red   = color->red_short;
+    render_color.green = color->green_short;
+    render_color.blue  = color->blue_short;
+    render_color.alpha = color->alpha_short;
+
+    max_count = 0;
+    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	if (chunk->count > max_count)
+	    max_count = chunk->count;
+    }
+    if (max_count > ARRAY_LENGTH (stack_xrects)) {
+	xrects = _cairo_malloc_ab (max_count, sizeof (xcb_rectangle_t));
+	if (unlikely (xrects == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	int i, j;
+
+	for (i = j = 0; i < chunk->count; i++) {
+	    int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x);
+	    int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y);
+	    int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x);
+	    int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y);
+
+	    if (x2 > x1 && y2 > y1) {
+		xrects[j].x = x1;
+		xrects[j].y = y1;
+		xrects[j].width  = x2 - x1;
+		xrects[j].height = y2 - y1;
+		j++;
+	    }
+	}
+
+	if (j) {
+	    _cairo_xcb_connection_render_fill_rectangles
+		(dst->connection,
+		 render_op, dst->picture,
+		 render_color, j, xrects);
+	}
+    }
+
+    if (xrects != stack_xrects)
+	free (xrects);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_render_composite_boxes (cairo_xcb_surface_t	*dst,
+			 cairo_operator_t	 op,
+			 const cairo_pattern_t	*src_pattern,
+			 const cairo_pattern_t	*mask_pattern,
+			 const cairo_rectangle_int_t *extents,
+			 const cairo_boxes_t *boxes)
+{
+    cairo_xcb_picture_t *src, *mask;
+    const struct _cairo_boxes_chunk *chunk;
+    int render_op;
+
+    render_op = _render_operator (op);
+
+    if (src_pattern == NULL) {
+	src_pattern = mask_pattern;
+	mask_pattern = NULL;
+    }
+
+    src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents);
+    if (unlikely (src->base.status))
+	return src->base.status;
+
+    if (mask_pattern != NULL) {
+	mask = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
+	if (unlikely (mask->base.status)) {
+	    cairo_surface_destroy (&src->base);
+	    return mask->base.status;
+	}
+
+	for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	    const cairo_box_t *box = chunk->base;
+	    int i;
+
+	    for (i = 0; i < chunk->count; i++) {
+		int x = _cairo_fixed_integer_round (box[i].p1.x);
+		int y = _cairo_fixed_integer_round (box[i].p1.y);
+		int width  = _cairo_fixed_integer_round (box[i].p2.x) - x;
+		int height = _cairo_fixed_integer_round (box[i].p2.y) - y;
+
+		if (width && height) {
+		    _cairo_xcb_connection_render_composite (dst->connection,
+							    render_op,
+							    src->picture,
+							    mask->picture,
+							    dst->picture,
+							    x + src->x,
+							    y + src->y,
+							    x + mask->x,
+							    y + mask->y,
+							    x, y,
+							    width, height);
+		}
+	    }
+	}
+
+	cairo_surface_destroy (&mask->base);
+    } else {
+	for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	    const cairo_box_t *box = chunk->base;
+	    int i;
+
+	    for (i = 0; i < chunk->count; i++) {
+		int x = _cairo_fixed_integer_round (box[i].p1.x);
+		int y = _cairo_fixed_integer_round (box[i].p1.y);
+		int width  = _cairo_fixed_integer_round (box[i].p2.x) - x;
+		int height = _cairo_fixed_integer_round (box[i].p2.y) - y;
+
+		if (width && height) {
+		    _cairo_xcb_connection_render_composite (dst->connection,
+							    render_op,
+							    src->picture,
+							    XCB_NONE,
+							    dst->picture,
+							    x + src->x,
+							    y + src->y,
+							    0, 0,
+							    x, y,
+							    width, height);
+		}
+	    }
+	}
+    }
+
+    cairo_surface_destroy (&src->base);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+
+#define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768)
+#define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767)
+
+static cairo_bool_t
+_line_exceeds_16_16 (const cairo_line_t *line)
+{
+    return
+	line->p1.x <= CAIRO_FIXED_16_16_MIN ||
+	line->p1.x >= CAIRO_FIXED_16_16_MAX ||
+
+	line->p2.x <= CAIRO_FIXED_16_16_MIN ||
+	line->p2.x >= CAIRO_FIXED_16_16_MAX ||
+
+	line->p1.y <= CAIRO_FIXED_16_16_MIN ||
+	line->p1.y >= CAIRO_FIXED_16_16_MAX ||
+
+	line->p2.y <= CAIRO_FIXED_16_16_MIN ||
+	line->p2.y >= CAIRO_FIXED_16_16_MAX;
+}
+
+static void
+_project_line_x_onto_16_16 (const cairo_line_t *line,
+			    cairo_fixed_t top,
+			    cairo_fixed_t bottom,
+			    xcb_render_linefix_t *out)
+{
+    cairo_point_double_t p1, p2;
+    double m;
+
+    p1.x = _cairo_fixed_to_double (line->p1.x);
+    p1.y = _cairo_fixed_to_double (line->p1.y);
+
+    p2.x = _cairo_fixed_to_double (line->p2.x);
+    p2.y = _cairo_fixed_to_double (line->p2.y);
+
+    m = (p2.x - p1.x) / (p2.y - p1.y);
+    out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y));
+    out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y));
+}
+
+typedef struct {
+    cairo_traps_t traps;
+    cairo_antialias_t antialias;
+} composite_traps_info_t;
+
+COMPILE_TIME_ASSERT (sizeof (xcb_render_trapezoid_t) <= sizeof (cairo_trapezoid_t));
+
+static cairo_status_t
+_composite_traps (void *closure,
+		  cairo_xcb_surface_t	*dst,
+		  cairo_operator_t	 op,
+		  const cairo_pattern_t	*pattern,
+		  int dst_x, int dst_y,
+		  const cairo_rectangle_int_t *extents,
+		  cairo_region_t		*clip_region)
+{
+    composite_traps_info_t *info = closure;
+    const cairo_traps_t *traps = &info->traps;
+    cairo_xcb_picture_t *src;
+    cairo_format_t format;
+    xcb_render_pictformat_t xrender_format;
+    xcb_render_trapezoid_t *xtraps;
+    int render_reference_x, render_reference_y;
+    int i;
+
+    src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
+    if (unlikely (src->base.status))
+	return src->base.status;
+
+    if (info->antialias == CAIRO_ANTIALIAS_NONE)
+	format = CAIRO_FORMAT_A1;
+    else
+	format = CAIRO_FORMAT_A8;
+    xrender_format = dst->screen->connection->standard_formats[format];
+
+    xtraps = (xcb_render_trapezoid_t *) traps->traps;
+    for (i = 0; i < traps->num_traps; i++) {
+	cairo_trapezoid_t t = traps->traps[i];
+
+	/* top/bottom will be clamped to surface bounds */
+	xtraps[i].top = _cairo_fixed_to_16_16 (t.top);
+	xtraps[i].top -= dst_y << 16;
+	xtraps[i].bottom = _cairo_fixed_to_16_16 (t.bottom);
+	xtraps[i].bottom -= dst_y << 16;
+
+	/* However, all the other coordinates will have been left untouched so
+	 * as not to introduce numerical error. Recompute them if they
+	 * exceed the 16.16 limits.
+	 */
+	if (unlikely (_line_exceeds_16_16 (&t.left))) {
+	    _project_line_x_onto_16_16 (&t.left,
+					t.top,
+					t.bottom,
+					&xtraps[i].left);
+	    xtraps[i].left.p1.y = xtraps[i].top;
+	    xtraps[i].left.p2.y = xtraps[i].bottom;
+	} else {
+	    xtraps[i].left.p1.x = _cairo_fixed_to_16_16 (t.left.p1.x);
+	    xtraps[i].left.p1.y = _cairo_fixed_to_16_16 (t.left.p1.y);
+	    xtraps[i].left.p2.x = _cairo_fixed_to_16_16 (t.left.p2.x);
+	    xtraps[i].left.p2.y = _cairo_fixed_to_16_16 (t.left.p2.y);
+	}
+	xtraps[i].left.p1.x -= dst_x << 16;
+	xtraps[i].left.p1.y -= dst_y << 16;
+	xtraps[i].left.p2.x -= dst_x << 16;
+	xtraps[i].left.p2.y -= dst_y << 16;
+
+	if (unlikely (_line_exceeds_16_16 (&t.right))) {
+	    _project_line_x_onto_16_16 (&t.right,
+					t.top,
+					t.bottom,
+					&xtraps[i].right);
+	    xtraps[i].right.p1.y = xtraps[i].top;
+	    xtraps[i].right.p2.y = xtraps[i].bottom;
+	} else {
+	    xtraps[i].right.p1.x = _cairo_fixed_to_16_16 (t.right.p1.x);
+	    xtraps[i].right.p1.y = _cairo_fixed_to_16_16 (t.right.p1.y);
+	    xtraps[i].right.p2.x = _cairo_fixed_to_16_16 (t.right.p2.x);
+	    xtraps[i].right.p2.y = _cairo_fixed_to_16_16 (t.right.p2.y);
+	}
+	xtraps[i].right.p1.x -= dst_x << 16;
+	xtraps[i].right.p1.y -= dst_y << 16;
+	xtraps[i].right.p2.x -= dst_x << 16;
+	xtraps[i].right.p2.y -= dst_y << 16;
+    }
+
+    if (xtraps[0].left.p1.y < xtraps[0].left.p2.y) {
+	render_reference_x = xtraps[0].left.p1.x >> 16;
+	render_reference_y = xtraps[0].left.p1.y >> 16;
+    } else {
+	render_reference_x = xtraps[0].left.p2.x >> 16;
+	render_reference_y = xtraps[0].left.p2.y >> 16;
+    }
+
+    _cairo_xcb_connection_render_trapezoids (dst->connection,
+					     _render_operator (op),
+					     src->picture,
+					     dst->picture,
+					     xrender_format,
+					     src->x + render_reference_x,
+					     src->y + render_reference_y,
+					     traps->num_traps, xtraps);
+
+    cairo_surface_destroy (&src->base);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+/* low-level composite driver */
+
+typedef cairo_status_t
+(*xcb_draw_func_t) (void				*closure,
+		    cairo_xcb_surface_t			*dst,
+		    cairo_operator_t			 op,
+		    const cairo_pattern_t		*src,
+		    int					 dst_x,
+		    int					 dst_y,
+		    const cairo_rectangle_int_t		*extents,
+		    cairo_region_t			*clip_region);
+
+static cairo_xcb_surface_t *
+_create_composite_mask (cairo_clip_t		*clip,
+			xcb_draw_func_t		 draw_func,
+			void			*draw_closure,
+			cairo_xcb_surface_t	*dst,
+			const cairo_rectangle_int_t*extents)
+{
+    cairo_xcb_surface_t *surface;
+    cairo_bool_t clip_surface = FALSE;
+    cairo_status_t status;
+
+    if (clip != NULL) {
+	cairo_region_t *clip_region;
+
+	status = _cairo_clip_get_region (clip, &clip_region);
+	assert (! _cairo_status_is_error (status));
+	clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    surface = (cairo_xcb_surface_t *)
+	_cairo_xcb_surface_create_similar (dst, CAIRO_CONTENT_ALPHA,
+					   extents->width, extents->height);
+    if (unlikely (surface->base.status))
+	return surface;
+
+    _cairo_xcb_surface_ensure_picture (surface);
+
+    if (surface->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
+	xcb_render_color_t clear;
+	xcb_rectangle_t xrect;
+
+	clear.red = clear.green = clear.blue = clear.alpha = 0;
+
+	xrect.x = xrect.y = 0;
+	xrect.width  = extents->width;
+	xrect.height = extents->height;
+
+	_cairo_xcb_connection_render_fill_rectangles (surface->connection,
+						      XCB_RENDER_PICT_OP_CLEAR,
+						      surface->picture,
+						      clear, 1, &xrect);
+    } else {
+	status = _cairo_xcb_surface_render_paint (surface,
+						  CAIRO_OPERATOR_CLEAR,
+						  &_cairo_pattern_clear.base,
+						  NULL);
+	if (unlikely (status)) {
+	    cairo_surface_destroy (&surface->base);
+	    return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status);
+	}
+    }
+
+    /* Is it worth setting the clip region here? */
+    status = draw_func (draw_closure, surface,
+			CAIRO_OPERATOR_ADD, NULL,
+			extents->x, extents->y,
+			extents, NULL);
+    if (unlikely (status)) {
+	cairo_surface_destroy (&surface->base);
+	return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status);
+    }
+
+    if (clip_surface) {
+	status = _cairo_clip_combine_with_surface (clip, &surface->base,
+						   extents->x, extents->y);
+	if (unlikely (status)) {
+	    cairo_surface_destroy (&surface->base);
+	    return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status);
+	}
+    }
+
+    return surface;
+}
+
+/* Handles compositing with a clip surface when the operator allows
+ * us to combine the clip with the mask
+ */
+static cairo_status_t
+_clip_and_composite_with_mask (cairo_clip_t		*clip,
+			       cairo_operator_t		 op,
+			       const cairo_pattern_t	*pattern,
+			       xcb_draw_func_t		 draw_func,
+			       void			*draw_closure,
+			       cairo_xcb_surface_t	*dst,
+			       const cairo_rectangle_int_t*extents)
+{
+    cairo_xcb_surface_t *mask;
+    cairo_xcb_picture_t *src;
+
+    mask = _create_composite_mask (clip, draw_func, draw_closure, dst, extents);
+    if (unlikely (mask->base.status))
+	return mask->base.status;
+
+    if (pattern != NULL || dst->base.content != CAIRO_CONTENT_ALPHA) {
+	src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
+	if (unlikely (src->base.status)) {
+	    cairo_surface_destroy (&mask->base);
+	    return src->base.status;
+	}
+
+	_cairo_xcb_connection_render_composite (dst->connection,
+						_render_operator (op),
+						src->picture,
+						mask->picture,
+						dst->picture,
+						extents->x + src->x, extents->y + src->y,
+						0, 0,
+						extents->x,      extents->y,
+						extents->width,  extents->height);
+
+	cairo_surface_destroy (&src->base);
+    } else {
+	_cairo_xcb_connection_render_composite (dst->connection,
+						_render_operator (op),
+						mask->picture,
+						XCB_NONE,
+						dst->picture,
+						0, 0,
+						0, 0,
+						extents->x,      extents->y,
+						extents->width,  extents->height);
+    }
+    cairo_surface_destroy (&mask->base);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+/* Handles compositing with a clip surface when we have to do the operation
+ * in two pieces and combine them together.
+ */
+static cairo_status_t
+_clip_and_composite_combine (cairo_clip_t		*clip,
+			     cairo_operator_t		 op,
+			     const cairo_pattern_t	*pattern,
+			     xcb_draw_func_t		 draw_func,
+			     void			*draw_closure,
+			     cairo_xcb_surface_t	*dst,
+			     const cairo_rectangle_int_t*extents)
+{
+    cairo_xcb_surface_t *tmp;
+    cairo_surface_t *clip_surface;
+    xcb_render_picture_t clip_picture;
+    cairo_status_t status;
+
+    tmp = (cairo_xcb_surface_t *)
+	_cairo_xcb_surface_create_similar (dst, dst->base.content,
+					   extents->width, extents->height);
+    if (unlikely (tmp->base.status))
+	return tmp->base.status;
+
+    _cairo_xcb_surface_ensure_picture (tmp);
+
+    if (pattern == NULL) {
+	status = (*draw_func) (draw_closure, tmp,
+			       CAIRO_OPERATOR_ADD, NULL,
+			       extents->x, extents->y,
+			       extents, NULL);
+    } else {
+	/* Initialize the temporary surface from the destination surface */
+	if (! dst->base.is_clear ||
+	    (dst->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) == 0)
+	{
+	    /* XCopyArea may actually be quicker here.
+	     * A good driver should translate if appropriate.
+	     */
+	    _cairo_xcb_connection_render_composite (dst->connection,
+						    XCB_RENDER_PICT_OP_SRC,
+						    dst->picture,
+						    XCB_NONE,
+						    tmp->picture,
+						    extents->x,      extents->y,
+						    0, 0,
+						    0, 0,
+						    extents->width,  extents->height);
+	}
+	else
+	{
+	    xcb_render_color_t clear;
+	    xcb_rectangle_t xrect;
+
+	    clear.red = clear.green = clear.blue = clear.alpha = 0;
+
+	    xrect.x = xrect.y = 0;
+	    xrect.width  = extents->width;
+	    xrect.height = extents->height;
+
+	    _cairo_xcb_connection_render_fill_rectangles (dst->connection,
+							  XCB_RENDER_PICT_OP_CLEAR,
+							  dst->picture,
+							  clear, 1, &xrect);
+	}
+
+	status = (*draw_func) (draw_closure, tmp, op, pattern,
+			       extents->x, extents->y,
+			       extents, NULL);
+    }
+    if (unlikely (status))
+	goto CLEANUP_SURFACE;
+
+    clip_surface = _cairo_clip_get_surface (clip, &dst->base);
+    if (unlikely (clip_surface->status))
+	goto CLEANUP_SURFACE;
+
+    clip_picture = ((cairo_xcb_surface_t *) clip_surface)->picture;
+    assert (clip_picture != XCB_NONE);
+
+    if (dst->base.is_clear) {
+	_cairo_xcb_connection_render_composite (dst->connection,
+						XCB_RENDER_PICT_OP_SRC,
+						tmp->picture, clip_picture, dst->picture,
+						0, 0,
+						0, 0,
+						extents->x,      extents->y,
+						extents->width,  extents->height);
+    } else {
+	/* Punch the clip out of the destination */
+	_cairo_xcb_connection_render_composite (dst->connection,
+						XCB_RENDER_PICT_OP_OUT_REVERSE,
+						clip_picture, XCB_NONE, dst->picture,
+						extents->x - clip->path->extents.x,
+						extents->y - clip->path->extents.y,
+						0, 0,
+						extents->x,     extents->y,
+						extents->width, extents->height);
+
+	/* Now add the two results together */
+	_cairo_xcb_connection_render_composite (dst->connection,
+						XCB_RENDER_PICT_OP_ADD,
+						tmp->picture, clip_picture, dst->picture,
+						0, 0,
+						extents->x - clip->path->extents.x,
+						extents->y - clip->path->extents.y,
+						extents->x,     extents->y,
+						extents->width, extents->height);
+    }
+
+ CLEANUP_SURFACE:
+    cairo_surface_destroy (&tmp->base);
+
+    return status;
+}
+
+/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
+ * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
+ */
+static cairo_status_t
+_clip_and_composite_source (cairo_clip_t		*clip,
+			    const cairo_pattern_t	*pattern,
+			    xcb_draw_func_t		 draw_func,
+			    void			*draw_closure,
+			    cairo_xcb_surface_t		*dst,
+			    const cairo_rectangle_int_t	*extents)
+{
+    cairo_xcb_surface_t *mask;
+    cairo_xcb_picture_t *src;
+
+    /* Create a surface that is mask IN clip */
+    mask = _create_composite_mask (clip, draw_func, draw_closure, dst, extents);
+    if (unlikely (mask->base.status))
+	return mask->base.status;
+
+    src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
+    if (unlikely (src->base.status)) {
+	cairo_surface_destroy (&mask->base);
+	return src->base.status;
+    }
+
+    if (dst->base.is_clear) {
+	_cairo_xcb_connection_render_composite (dst->connection,
+						XCB_RENDER_PICT_OP_SRC,
+						src->picture,
+						mask->picture,
+						dst->picture,
+						extents->x + src->x, extents->y + src->y,
+						0, 0,
+						extents->x,      extents->y,
+						extents->width,  extents->height);
+    } else {
+	/* Compute dest' = dest OUT (mask IN clip) */
+	_cairo_xcb_connection_render_composite (dst->connection,
+						XCB_RENDER_PICT_OP_OUT_REVERSE,
+						mask->picture,
+						XCB_NONE,
+						dst->picture,
+						0, 0, 0, 0,
+						extents->x,     extents->y,
+						extents->width, extents->height);
+
+	/* Now compute (src IN (mask IN clip)) ADD dest' */
+	_cairo_xcb_connection_render_composite (dst->connection,
+						XCB_RENDER_PICT_OP_ADD,
+						src->picture,
+						mask->picture,
+						dst->picture,
+						extents->x + src->x, extents->y + src->y,
+						0, 0,
+						extents->x,     extents->y,
+						extents->width, extents->height);
+    }
+
+    cairo_surface_destroy (&src->base);
+    cairo_surface_destroy (&mask->base);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_bool_t
+can_reduce_alpha_op (cairo_operator_t op)
+{
+    int iop = op;
+    switch (iop) {
+    case CAIRO_OPERATOR_OVER:
+    case CAIRO_OPERATOR_SOURCE:
+    case CAIRO_OPERATOR_ADD:
+	return TRUE;
+    default:
+	return FALSE;
+    }
+}
+
+static cairo_bool_t
+reduce_alpha_op (cairo_surface_t *dst,
+		 cairo_operator_t op,
+		 const cairo_pattern_t *pattern)
+{
+    return dst->is_clear &&
+	   dst->content == CAIRO_CONTENT_ALPHA &&
+	   _cairo_pattern_is_opaque_solid (pattern) &&
+	   can_reduce_alpha_op (op);
+}
+
+static cairo_status_t
+_cairo_xcb_surface_fixup_unbounded (cairo_xcb_surface_t *dst,
+				    const cairo_composite_rectangles_t *rects)
+{
+    xcb_rectangle_t xrects[4];
+    int n;
+
+    if (rects->bounded.width  == rects->unbounded.width &&
+	rects->bounded.height == rects->unbounded.height)
+    {
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    n = 0;
+    /* top */
+    if (rects->bounded.y != rects->unbounded.y) {
+	xrects[n].x = rects->unbounded.x;
+	xrects[n].width = rects->unbounded.width;
+	xrects[n].y = rects->unbounded.y;
+	xrects[n].height = rects->bounded.y - rects->unbounded.y;
+	n++;
+    }
+    /* left */
+    if (rects->bounded.x != rects->unbounded.x) {
+	xrects[n].x = rects->unbounded.x;
+	xrects[n].width = rects->bounded.x - rects->unbounded.x;
+	xrects[n].y = rects->bounded.y;
+	xrects[n].height = rects->bounded.height;
+	n++;
+    }
+    /* right */
+    if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
+	xrects[n].x = rects->bounded.x + rects->bounded.width;
+	xrects[n].width = rects->unbounded.x + rects->unbounded.width - xrects[n].x;
+	xrects[n].y = rects->bounded.y;
+	xrects[n].height = rects->bounded.height;
+	n++;
+    }
+    /* bottom */
+    if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
+	xrects[n].x = rects->unbounded.x;
+	xrects[n].width = rects->unbounded.width;
+	xrects[n].y = rects->bounded.y + rects->bounded.height;
+	xrects[n].height = rects->unbounded.y + rects->unbounded.height - xrects[n].y;
+	n++;
+    }
+
+    if (dst->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) {
+	xcb_render_color_t color;
+
+	color.red   = 0;
+	color.green = 0;
+	color.blue  = 0;
+	color.alpha = 0;
+
+	_cairo_xcb_connection_render_fill_rectangles (dst->connection,
+						      XCB_RENDER_PICT_OP_CLEAR,
+						      dst->picture,
+						      color, n, xrects);
+    } else {
+	int i;
+	cairo_xcb_picture_t *src;
+
+	src = _cairo_xcb_transparent_picture (dst);
+	if (unlikely (src->base.status))
+	    return src->base.status;
+
+	for (i = 0; i < n; i++) {
+	    _cairo_xcb_connection_render_composite (dst->connection,
+						    XCB_RENDER_PICT_OP_CLEAR,
+						    src->picture, XCB_NONE, dst->picture,
+						    0, 0,
+						    0, 0,
+						    xrects[i].x, xrects[i].y,
+						    xrects[i].width, xrects[i].height);
+	}
+	cairo_surface_destroy (&src->base);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_fixup_unbounded_with_mask (cairo_xcb_surface_t *dst,
+					      const cairo_composite_rectangles_t *rects,
+					      cairo_clip_t *clip)
+{
+    cairo_xcb_surface_t *mask;
+    int mask_x, mask_y;
+
+    mask = (cairo_xcb_surface_t *) _cairo_clip_get_surface (clip, &dst->base);
+    if (unlikely (mask->base.status))
+	return mask->base.status;
+
+    mask_x = - clip->path->extents.x;
+    mask_y = - clip->path->extents.y;
+
+    /* top */
+    if (rects->bounded.y != rects->unbounded.y) {
+	int x = rects->unbounded.x;
+	int y = rects->unbounded.y;
+	int width = rects->unbounded.width;
+	int height = rects->bounded.y - y;
+
+	_cairo_xcb_connection_render_composite (dst->connection,
+						XCB_RENDER_PICT_OP_OUT_REVERSE,
+						mask->picture, XCB_NONE, dst->picture,
+						x + mask_x, y + mask_y,
+						0, 0,
+						x, y,
+						width, height);
+    }
+
+    /* left */
+    if (rects->bounded.x != rects->unbounded.x) {
+	int x = rects->unbounded.x;
+	int y = rects->bounded.y;
+	int width = rects->bounded.x - x;
+	int height = rects->bounded.height;
+
+	_cairo_xcb_connection_render_composite (dst->connection,
+						XCB_RENDER_PICT_OP_OUT_REVERSE,
+						mask->picture, XCB_NONE, dst->picture,
+						x + mask_x, y + mask_y,
+						0, 0,
+						x, y,
+						width, height);
+    }
+
+    /* right */
+    if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) {
+	int x = rects->bounded.x + rects->bounded.width;
+	int y = rects->bounded.y;
+	int width = rects->unbounded.x + rects->unbounded.width - x;
+	int height = rects->bounded.height;
+
+	_cairo_xcb_connection_render_composite (dst->connection,
+						XCB_RENDER_PICT_OP_OUT_REVERSE,
+						mask->picture, XCB_NONE, dst->picture,
+						x + mask_x, y + mask_y,
+						0, 0,
+						x, y,
+						width, height);
+    }
+
+    /* bottom */
+    if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) {
+	int x = rects->unbounded.x;
+	int y = rects->bounded.y + rects->bounded.height;
+	int width = rects->unbounded.width;
+	int height = rects->unbounded.y + rects->unbounded.height - y;
+
+	_cairo_xcb_connection_render_composite (dst->connection,
+						XCB_RENDER_PICT_OP_OUT_REVERSE,
+						mask->picture, XCB_NONE, dst->picture,
+						x + mask_x, y + mask_y,
+						0, 0,
+						x, y,
+						width, height);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_fixup_unbounded_boxes (cairo_xcb_surface_t *dst,
+					  const cairo_composite_rectangles_t *extents,
+					  cairo_region_t *clip_region,
+					  cairo_boxes_t *boxes)
+{
+    cairo_boxes_t clear;
+    cairo_box_t box;
+    cairo_status_t status;
+    struct _cairo_boxes_chunk *chunk;
+    int i;
+
+    if (boxes->num_boxes <= 1 && clip_region == NULL)
+	return _cairo_xcb_surface_fixup_unbounded (dst, extents);
+
+    _cairo_boxes_init (&clear);
+
+    box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
+    box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
+    box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
+    box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
+
+    if (clip_region == NULL) {
+	cairo_boxes_t tmp;
+
+	_cairo_boxes_init (&tmp);
+
+	status = _cairo_boxes_add (&tmp, &box);
+	assert (status == CAIRO_STATUS_SUCCESS);
+
+	tmp.chunks.next = &boxes->chunks;
+	tmp.num_boxes += boxes->num_boxes;
+
+	status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
+							  CAIRO_FILL_RULE_WINDING,
+							  &clear);
+
+	tmp.chunks.next = NULL;
+    } else {
+	pixman_box32_t *pbox;
+
+	pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
+	_cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
+
+	status = _cairo_boxes_add (&clear, &box);
+	assert (status == CAIRO_STATUS_SUCCESS);
+
+	for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	    for (i = 0; i < chunk->count; i++) {
+		status = _cairo_boxes_add (&clear, &chunk->base[i]);
+		if (unlikely (status)) {
+		    _cairo_boxes_fini (&clear);
+		    return status;
+		}
+	    }
+	}
+
+	status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
+							  CAIRO_FILL_RULE_WINDING,
+							  &clear);
+    }
+
+    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	status = _render_fill_boxes (dst,
+				     CAIRO_OPERATOR_CLEAR,
+				     CAIRO_COLOR_TRANSPARENT,
+				     boxes);
+    }
+
+    _cairo_boxes_fini (&clear);
+
+    return status;
+}
+
+static cairo_status_t
+_clip_and_composite (cairo_xcb_surface_t	*dst,
+		     cairo_operator_t		 op,
+		     const cairo_pattern_t	*src,
+		     xcb_draw_func_t		 draw_func,
+		     void			*draw_closure,
+		     const cairo_composite_rectangles_t*extents,
+		     cairo_clip_t		*clip)
+{
+    cairo_status_t status;
+    cairo_region_t *clip_region = NULL;
+    cairo_bool_t need_clip_surface = FALSE;
+
+    if (clip != NULL) {
+	status = _cairo_clip_get_region (clip, &clip_region);
+	if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
+	    return CAIRO_STATUS_SUCCESS;
+
+	assert (! _cairo_status_is_error (status));
+	need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+
+	if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+	    clip_region = NULL;
+    }
+
+    status = _cairo_xcb_connection_acquire (dst->connection);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_xcb_connection_take_socket (dst->connection);
+    if (unlikely (status)) {
+	_cairo_xcb_connection_release (dst->connection);
+	return status;
+    }
+
+    _cairo_xcb_surface_ensure_picture (dst);
+
+    if (clip_region != NULL)
+	_cairo_xcb_surface_set_clip_region (dst, clip_region);
+
+    if (reduce_alpha_op (&dst->base, op, src)) {
+	op = CAIRO_OPERATOR_ADD;
+	src = NULL;
+    }
+
+    if (op == CAIRO_OPERATOR_SOURCE) {
+	status = _clip_and_composite_source (clip, src,
+					     draw_func, draw_closure,
+					     dst, &extents->bounded);
+    } else {
+	if (op == CAIRO_OPERATOR_CLEAR) {
+	    op = CAIRO_OPERATOR_DEST_OUT;
+	    src = NULL;
+	}
+
+	if (need_clip_surface) {
+	    if (extents->is_bounded) {
+		status = _clip_and_composite_with_mask (clip, op, src,
+							draw_func, draw_closure,
+							dst, &extents->bounded);
+	    } else {
+		status = _clip_and_composite_combine (clip, op, src,
+						      draw_func, draw_closure,
+						      dst, &extents->bounded);
+	    }
+	} else {
+	    status = draw_func (draw_closure,
+				dst, op, src,
+				0, 0,
+				&extents->bounded,
+				clip_region);
+	}
+    }
+
+    if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
+	if (need_clip_surface)
+	    status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst, extents, clip);
+	else
+	    status = _cairo_xcb_surface_fixup_unbounded (dst, extents);
+    }
+
+    if (clip_region != NULL)
+	_cairo_xcb_surface_clear_clip_region (dst);
+
+    _cairo_xcb_connection_release (dst->connection);
+
+    return status;
+}
+
+static cairo_status_t
+_core_boxes (cairo_xcb_surface_t *dst,
+	     cairo_operator_t op,
+	     const cairo_pattern_t *src,
+	     cairo_boxes_t *boxes,
+	     cairo_antialias_t antialias,
+	     cairo_clip_t *clip,
+	     const cairo_composite_rectangles_t *extents)
+{
+    if (antialias != CAIRO_ANTIALIAS_NONE) {
+	if (! boxes->is_pixel_aligned)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    if (clip != NULL) {
+	cairo_region_t *clip_region;
+	cairo_status_t status;
+
+	status = _cairo_clip_get_region (clip, &clip_region);
+	assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+
+	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    if (op == CAIRO_OPERATOR_CLEAR)
+	return _cairo_xcb_surface_core_fill_boxes (dst, CAIRO_COLOR_TRANSPARENT, boxes);
+
+    if (op == CAIRO_OPERATOR_OVER) {
+	if (_cairo_pattern_is_opaque (src, &extents->bounded))
+	    op = CAIRO_OPERATOR_SOURCE;
+    }
+    if (op != CAIRO_OPERATOR_SOURCE)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (src->type == CAIRO_PATTERN_TYPE_SOLID) {
+	return _cairo_xcb_surface_core_fill_boxes (dst,
+						   &((cairo_solid_pattern_t *) src)->color,
+						   boxes);
+    }
+
+    return _cairo_xcb_surface_core_copy_boxes (dst, src, &extents->bounded, boxes);
+}
+
+static cairo_status_t
+_composite_boxes (cairo_xcb_surface_t *dst,
+		  cairo_operator_t op,
+		  const cairo_pattern_t *src,
+		  cairo_boxes_t *boxes,
+		  cairo_antialias_t antialias,
+		  cairo_clip_t *clip,
+		  const cairo_composite_rectangles_t *extents)
+{
+    cairo_bool_t need_clip_mask = FALSE;
+    cairo_region_t *clip_region = NULL;
+    cairo_status_t status;
+
+    /* If the boxes are not pixel-aligned, we will need to compute a real mask */
+    if (antialias != CAIRO_ANTIALIAS_NONE) {
+	if (! boxes->is_pixel_aligned)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    if (clip != NULL) {
+	status = _cairo_clip_get_region (clip, &clip_region);
+	assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+
+	need_clip_mask = status == CAIRO_INT_STATUS_UNSUPPORTED;
+	if (need_clip_mask &&
+	    (! extents->is_bounded || op == CAIRO_OPERATOR_SOURCE))
+	{
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+	}
+
+	if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+	    clip_region = NULL;
+    }
+
+    status = _cairo_xcb_connection_acquire (dst->connection);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_xcb_connection_take_socket (dst->connection);
+    if (unlikely (status)) {
+	_cairo_xcb_connection_release (dst->connection);
+	return status;
+    }
+
+    _cairo_xcb_surface_ensure_picture (dst);
+    if (dst->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES && ! need_clip_mask &&
+	(op == CAIRO_OPERATOR_CLEAR || src->type == CAIRO_PATTERN_TYPE_SOLID))
+    {
+	const cairo_color_t *color;
+
+	if (op == CAIRO_OPERATOR_CLEAR)
+	    color = CAIRO_COLOR_TRANSPARENT;
+	else
+	    color = &((cairo_solid_pattern_t *) src)->color;
+
+	if (! (op == CAIRO_OPERATOR_IN && color->alpha >= 0xff00))
+	    status = _render_fill_boxes (dst, op, color, boxes);
+    }
+    else
+    {
+	cairo_surface_pattern_t mask;
+
+	if (need_clip_mask) {
+	    cairo_surface_t *clip_surface;
+
+	    clip_surface = _cairo_clip_get_surface (clip, &dst->base);
+	    if (unlikely (clip_surface->status))
+		return clip_surface->status;
+
+	    _cairo_pattern_init_for_surface (&mask, clip_surface);
+	    mask.base.filter = CAIRO_FILTER_NEAREST;
+	    cairo_matrix_init_translate (&mask.base.matrix,
+					 -clip->path->extents.x,
+					 -clip->path->extents.y);
+
+	    if (op == CAIRO_OPERATOR_CLEAR) {
+		src = NULL;
+		op = CAIRO_OPERATOR_DEST_OUT;
+	    }
+	}
+
+	status = _render_composite_boxes (dst, op, src,
+					  need_clip_mask ? &mask.base : NULL,
+					  &extents->bounded, boxes);
+    }
+
+    if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) {
+	status =
+	    _cairo_xcb_surface_fixup_unbounded_boxes (dst, extents,
+						      clip_region, boxes);
+    }
+
+    _cairo_xcb_connection_release (dst->connection);
+
+    return status;
+}
+
+static cairo_status_t
+_clip_and_composite_boxes (cairo_xcb_surface_t *dst,
+			   cairo_operator_t op,
+			   const cairo_pattern_t *src,
+			   cairo_boxes_t *boxes,
+			   cairo_antialias_t antialias,
+			   const cairo_composite_rectangles_t *extents,
+			   cairo_clip_t *clip)
+{
+    composite_traps_info_t info;
+    cairo_status_t status;
+
+    if (boxes->num_boxes == 0 && extents->is_bounded)
+	return CAIRO_STATUS_SUCCESS;
+
+    if ((dst->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
+	return _core_boxes (dst, op, src, boxes, antialias, clip, extents);
+
+    /* Use a fast path if the boxes are pixel aligned */
+    status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents);
+    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	return status;
+
+    if ((dst->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) == 0)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    /* Otherwise render via a mask and composite in the usual fashion.  */
+    status = _cairo_traps_init_boxes (&info.traps, boxes);
+    if (unlikely (status))
+	return status;
+
+    info.antialias = antialias;
+    return _clip_and_composite (dst, op, src,
+				_composite_traps, &info,
+				extents, clip);
+}
+
+static cairo_bool_t
+_mono_edge_is_vertical (const cairo_line_t *line)
+{
+    return _cairo_fixed_integer_round (line->p1.x) == _cairo_fixed_integer_round (line->p2.x);
+}
+
+static cairo_bool_t
+_traps_are_pixel_aligned (cairo_traps_t *traps,
+			  cairo_antialias_t antialias)
+{
+    int i;
+
+    if (antialias == CAIRO_ANTIALIAS_NONE) {
+	for (i = 0; i < traps->num_traps; i++) {
+	    if (! _mono_edge_is_vertical (&traps->traps[i].left)   ||
+		! _mono_edge_is_vertical (&traps->traps[i].right))
+	    {
+		traps->maybe_region = FALSE;
+		return FALSE;
+	    }
+	}
+    } else {
+	for (i = 0; i < traps->num_traps; i++) {
+	    if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x   ||
+		traps->traps[i].right.p1.x != traps->traps[i].right.p2.x ||
+		! _cairo_fixed_is_integer (traps->traps[i].top)          ||
+		! _cairo_fixed_is_integer (traps->traps[i].bottom)       ||
+		! _cairo_fixed_is_integer (traps->traps[i].left.p1.x)    ||
+		! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
+	    {
+		traps->maybe_region = FALSE;
+		return FALSE;
+	    }
+	}
+    }
+
+    return TRUE;
+}
+
+static void
+_boxes_for_traps (cairo_boxes_t *boxes,
+		  cairo_traps_t *traps)
+{
+    int i;
+
+    _cairo_boxes_init (boxes);
+
+    boxes->num_boxes    = traps->num_traps;
+    boxes->chunks.base  = (cairo_box_t *) traps->traps;
+    boxes->chunks.count = traps->num_traps;
+    boxes->chunks.size  = traps->num_traps;
+
+    for (i = 0; i < traps->num_traps; i++) {
+	cairo_fixed_t x1 = traps->traps[i].left.p1.x;
+	cairo_fixed_t x2 = traps->traps[i].right.p1.x;
+	cairo_fixed_t y1 = traps->traps[i].top;
+	cairo_fixed_t y2 = traps->traps[i].bottom;
+
+	boxes->chunks.base[i].p1.x = x1;
+	boxes->chunks.base[i].p1.y = y1;
+	boxes->chunks.base[i].p2.x = x2;
+	boxes->chunks.base[i].p2.y = y2;
+
+	if (boxes->is_pixel_aligned) {
+	    boxes->is_pixel_aligned =
+		_cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) &&
+		_cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2);
+	}
+    }
+}
+
+typedef struct _cairo_xcb_surface_span_renderer {
+    cairo_span_renderer_t base;
+
+    void *spans;
+    unsigned len;
+    unsigned size;
+    uint16_t spans_embedded[1024];
+} cairo_xcb_surface_span_renderer_t;
+
+static cairo_status_t
+_cairo_xcb_surface_span_renderer_accumulate (void	*abstract_renderer,
+					     int	 y,
+					     int	 height,
+					     const cairo_half_open_span_t *spans,
+					     unsigned	 num_spans)
+{
+    cairo_xcb_surface_span_renderer_t *renderer = abstract_renderer;
+    uint16_t *u16;
+    int len;
+
+    len = 4 * (2 + num_spans);
+    if (renderer->size < renderer->len + len) {
+	char *new_spans;
+
+	do {
+	    renderer->size <<= 1;
+	} while (renderer->size < renderer->len + len);
+
+	if (renderer->spans == renderer->spans_embedded) {
+	    new_spans = malloc (renderer->size);
+	    if (unlikely (new_spans == NULL))
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+	    memcpy (new_spans, renderer->spans, renderer->len);
+	} else {
+	    new_spans = realloc (renderer->spans, renderer->size);
+	    if (unlikely (new_spans == NULL))
+		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	}
+
+	renderer->spans = new_spans;
+    }
+
+    u16 = (uint16_t *) ((char *) renderer->spans + renderer->len);
+    *u16++ = y;
+    *u16++ = height;
+    *u16++ = num_spans;
+    *u16++ = 0;
+    while (num_spans--) {
+	*u16++ = spans->x;
+	*u16++ = spans->coverage * 0x0101;
+	spans++;
+    }
+    renderer->len += len;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+typedef struct {
+    cairo_polygon_t		*polygon;
+    cairo_fill_rule_t		 fill_rule;
+    cairo_antialias_t		 antialias;
+} composite_spans_info_t;
+
+static cairo_status_t
+_composite_spans (void *closure,
+		  cairo_xcb_surface_t *dst,
+		  cairo_operator_t op,
+		  const cairo_pattern_t         *pattern,
+		  int                            dst_x,
+		  int                            dst_y,
+		  const cairo_rectangle_int_t   *extents,
+		  cairo_region_t		*clip_region)
+{
+    composite_spans_info_t *info = closure;
+    cairo_xcb_surface_span_renderer_t renderer;
+    cairo_scan_converter_t *converter;
+    cairo_status_t status;
+    cairo_xcb_picture_t *src;
+
+    renderer.base.render_rows = _cairo_xcb_surface_span_renderer_accumulate;
+    renderer.spans = renderer.spans_embedded;
+    renderer.size = ARRAY_LENGTH (renderer.spans_embedded);
+    renderer.len = 0;
+
+    converter = _cairo_tor_scan_converter_create (extents->x,
+						  extents->x + extents->width,
+						  extents->y,
+						  extents->y + extents->height,
+						  info->fill_rule);
+    status = converter->add_polygon (converter, info->polygon);
+    if (unlikely (status))
+	goto CLEANUP_RENDERER;
+
+    status = converter->generate (converter, &renderer.base);
+    if (unlikely (status))
+	goto CLEANUP_CONVERTER;
+
+    src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
+    status = src->base.status;
+    if (unlikely (status))
+	goto CLEANUP_CONVERTER;
+
+    _cairo_xcb_connection_render_spans (dst->connection,
+					dst->picture,
+					_render_operator (op),
+					src->picture,
+					extents->x + src->x, extents->y + src->y,
+					extents->x + dst_x, extents->y + dst_y,
+					extents->width, extents->height,
+					renderer.len >> 1, renderer.spans);
+    cairo_surface_destroy (&src->base);
+
+ CLEANUP_CONVERTER:
+    converter->destroy (converter);
+ CLEANUP_RENDERER:
+    if (renderer.spans != renderer.spans_embedded)
+	free (renderer.spans);
+
+    return status;
+}
+
+static cairo_status_t
+_composite_mask (void				*closure,
+		 cairo_xcb_surface_t		*dst,
+		 cairo_operator_t		 op,
+		 const cairo_pattern_t		*src_pattern,
+		 int				 dst_x,
+		 int				 dst_y,
+		 const cairo_rectangle_int_t	*extents,
+		 cairo_region_t			*clip_region)
+{
+    const cairo_pattern_t *mask_pattern = closure;
+    cairo_xcb_picture_t *src, *mask = NULL;
+
+    if (src_pattern != NULL) {
+	src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents);
+	if (unlikely (src->base.status))
+	    return src->base.status;
+
+	mask = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
+	if (unlikely (mask->base.status)) {
+	    cairo_surface_destroy (&src->base);
+	    return mask->base.status;
+	}
+
+	_cairo_xcb_connection_render_composite (dst->connection,
+						_render_operator (op),
+						src->picture,
+						mask->picture,
+						dst->picture,
+						extents->x + src->x,  extents->y + src->y,
+						extents->x + mask->x, extents->y + mask->y,
+						extents->x - dst_x,   extents->y - dst_y,
+						extents->width,       extents->height);
+	cairo_surface_destroy (&mask->base);
+	cairo_surface_destroy (&src->base);
+    } else {
+	src = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents);
+	if (unlikely (src->base.status))
+	    return src->base.status;
+
+	_cairo_xcb_connection_render_composite (dst->connection,
+						_render_operator (op),
+						src->picture,
+						XCB_NONE,
+						dst->picture,
+						extents->x + src->x,  extents->y + src->y,
+						0, 0,
+						extents->x - dst_x,   extents->y - dst_y,
+						extents->width,       extents->height);
+	cairo_surface_destroy (&src->base);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+/* high level rasteriser -> compositor */
+
+static cairo_bool_t
+box_is_aligned (const cairo_box_t *box)
+{
+    return
+	_cairo_fixed_is_integer (box->p1.x) &&
+	_cairo_fixed_is_integer (box->p1.y) &&
+	_cairo_fixed_is_integer (box->p2.x) &&
+	_cairo_fixed_is_integer (box->p2.y);
+}
+
+static inline cairo_status_t
+_clip_to_boxes (cairo_clip_t **clip,
+		const cairo_composite_rectangles_t *extents,
+		cairo_box_t **boxes,
+		int *num_boxes)
+{
+    cairo_status_t status;
+    const cairo_rectangle_int_t *rect;
+
+    rect = extents->is_bounded ? &extents->bounded: &extents->unbounded;
+
+    if (*clip == NULL)
+	goto EXTENTS;
+
+    status = _cairo_clip_rectangle (*clip, rect);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_clip_get_boxes (*clip, boxes, num_boxes);
+    switch ((int) status) {
+    case CAIRO_STATUS_SUCCESS:
+	if (extents->is_bounded || (*num_boxes == 1 && box_is_aligned (*boxes)))
+	    *clip = NULL;
+	goto DONE;
+
+    case  CAIRO_INT_STATUS_UNSUPPORTED:
+	goto EXTENTS;
+
+    default:
+	return status;
+    }
+
+  EXTENTS:
+    status = CAIRO_STATUS_SUCCESS;
+    _cairo_box_from_rectangle (&(*boxes)[0], rect);
+    *num_boxes = 1;
+  DONE:
+    return status;
+}
+
+static cairo_clip_path_t *
+_clip_get_single_path (cairo_clip_t *clip)
+{
+    cairo_clip_path_t *iter = clip->path;
+    cairo_clip_path_t *path = NULL;
+
+    do {
+	if ((iter->flags & CAIRO_CLIP_PATH_IS_BOX) == 0) {
+	    if (path != NULL)
+		return FALSE;
+
+	    path = iter;
+	}
+	iter = iter->prev;
+    } while (iter != NULL);
+
+    return path;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_render_paint (cairo_xcb_surface_t	*surface,
+				 cairo_operator_t	 op,
+				 const cairo_pattern_t	*source,
+				 cairo_clip_t		*clip)
+{
+    cairo_composite_rectangles_t extents;
+    cairo_boxes_t boxes;
+    cairo_box_t *clip_boxes = boxes.boxes_embedded;
+    cairo_clip_t local_clip;
+    cairo_clip_path_t *clip_path;
+    cairo_bool_t have_clip = FALSE;
+    int num_boxes = ARRAY_LENGTH (boxes.boxes_embedded);
+    cairo_status_t status;
+
+    if (unlikely (! _operator_is_supported (surface->flags, op)))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if ((surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS |
+			   CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
+			   CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
+    {
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    status = _cairo_composite_rectangles_init_for_paint (&extents,
+							 surface->width,
+							 surface->height,
+							 op, source,
+							 clip);
+    if (unlikely (status))
+	return status;
+
+    if (_cairo_clip_contains_rectangle (clip, &extents))
+	clip = NULL;
+
+    if (clip != NULL) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	have_clip = TRUE;
+    }
+
+    status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+    if (unlikely (status)) {
+	if (have_clip)
+	    _cairo_clip_fini (&local_clip);
+
+	return status;
+    }
+
+    if (clip != NULL &&
+	extents.is_bounded &&
+	(clip_path = _clip_get_single_path (clip)) != NULL)
+    {
+	status = _cairo_xcb_surface_render_fill (surface, op, source,
+						 &clip_path->path,
+						 clip_path->fill_rule,
+						 clip_path->tolerance,
+						 clip_path->antialias,
+						 NULL);
+    }
+    else
+    {
+	_cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
+	status = _clip_and_composite_boxes (surface, op, source,
+					    &boxes, CAIRO_ANTIALIAS_DEFAULT,
+					    &extents, clip);
+	if (clip_boxes != boxes.boxes_embedded)
+	    free (clip_boxes);
+    }
+
+    if (have_clip)
+	_cairo_clip_fini (&local_clip);
+
+    return status;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_render_mask (cairo_xcb_surface_t	*surface,
+				cairo_operator_t	 op,
+				const cairo_pattern_t	*source,
+				const cairo_pattern_t	*mask,
+				cairo_clip_t		*clip)
+{
+    cairo_composite_rectangles_t extents;
+    cairo_clip_t local_clip;
+    cairo_bool_t have_clip = FALSE;
+    cairo_status_t status;
+
+    if (unlikely (! _operator_is_supported (surface->flags, op)))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if ((surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    status = _cairo_composite_rectangles_init_for_mask (&extents,
+							surface->width, surface->height,
+							op, source, mask, clip);
+    if (unlikely (status))
+	return status;
+
+    if (_cairo_clip_contains_rectangle (clip, &extents))
+	clip = NULL;
+
+    if (clip != NULL && extents.is_bounded) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	status = _cairo_clip_rectangle (clip, &extents.bounded);
+	if (unlikely (status)) {
+	    _cairo_clip_fini (&local_clip);
+	    return status;
+	}
+	have_clip = TRUE;
+    }
+
+    status = _clip_and_composite (surface, op, source,
+				  _composite_mask, (void *) mask,
+				  &extents, clip);
+
+    if (have_clip)
+	_cairo_clip_fini (&local_clip);
+
+    return status;
+}
+
+typedef struct {
+    cairo_polygon_t	polygon;
+    cairo_fill_rule_t	fill_rule;
+    cairo_antialias_t	antialias;
+} composite_polygon_info_t;
+
+static cairo_status_t
+_cairo_xcb_surface_render_composite_polygon (cairo_xcb_surface_t *dst,
+					     cairo_operator_t op,
+					     const cairo_pattern_t *source,
+					     cairo_polygon_t *polygon,
+					     cairo_antialias_t antialias,
+					     cairo_fill_rule_t fill_rule,
+					     cairo_composite_rectangles_t *extents,
+					     cairo_clip_t *clip)
+{
+    composite_traps_info_t traps;
+    cairo_bool_t clip_surface = FALSE;
+    cairo_status_t status;
+    cairo_bool_t is_not_empty;
+
+    if (polygon->num_edges == 0) {
+	status = CAIRO_STATUS_SUCCESS;
+
+	if (! extents->is_bounded) {
+	    cairo_region_t *clip_region = NULL;
+
+	    if (clip != NULL) {
+		status = _cairo_clip_get_region (clip, &clip_region);
+		clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+
+		if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+		    clip_region = NULL;
+	    }
+
+	    if (clip_surface == FALSE) {
+		if (clip_region != NULL)
+		    _cairo_xcb_surface_set_clip_region (dst, clip_region);
+
+		status = _cairo_xcb_surface_fixup_unbounded (dst, extents);
+
+		if (clip_region != NULL)
+		    _cairo_xcb_surface_clear_clip_region (dst);
+	    } else {
+		status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst,
+								       extents,
+								       clip);
+	    }
+	}
+
+	return status;
+    }
+
+    _cairo_box_round_to_rectangle (&polygon->extents, &extents->mask);
+    is_not_empty = _cairo_rectangle_intersect (&extents->bounded, &extents->mask);
+    if (extents->is_bounded && ! is_not_empty)
+	return CAIRO_STATUS_SUCCESS;
+
+    if (dst->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS) {
+	composite_spans_info_t spans;
+
+	spans.polygon = polygon;
+	spans.fill_rule = CAIRO_FILL_RULE_WINDING;
+	spans.antialias = antialias;
+
+	return _clip_and_composite (dst, op, source,
+				    _composite_spans, &spans,
+				    extents, clip);
+    }
+
+    _cairo_traps_init (&traps.traps);
+
+    status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule);
+    if (unlikely (status))
+	goto CLEANUP_TRAPS;
+
+    if (clip != NULL) {
+	cairo_region_t *clip_region;
+
+	status = _cairo_clip_get_region (clip, &clip_region);
+	clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    if (traps.traps.has_intersections) {
+	if (traps.traps.is_rectangular)
+	    status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
+	else if (traps.traps.is_rectilinear)
+	    status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
+	else
+	    status = _cairo_bentley_ottmann_tessellate_traps (&traps.traps, CAIRO_FILL_RULE_WINDING);
+	if (unlikely (status))
+	    goto CLEANUP_TRAPS;
+    }
+
+    /* Use a fast path if the trapezoids consist of a simple region,
+     * but we can only do this if we do not have a clip surface, or can
+     * substitute the mask with the clip.
+     */
+    if (traps.traps.maybe_region &&
+	_traps_are_pixel_aligned (&traps.traps, antialias) &&
+	(! clip_surface ||
+	 (extents->is_bounded && op != CAIRO_OPERATOR_SOURCE)))
+    {
+	cairo_boxes_t boxes;
+
+	_boxes_for_traps (&boxes, &traps.traps);
+	status = _clip_and_composite_boxes (dst, op, source,
+					    &boxes, antialias,
+					    extents, clip);
+    }
+    else
+    {
+	/* Otherwise render the trapezoids to a mask and composite in the usual
+	 * fashion.
+	 */
+	traps.antialias = antialias;
+	status = _clip_and_composite (dst, op, source,
+				      _composite_traps, &traps,
+				      extents, clip);
+    }
+
+CLEANUP_TRAPS:
+    _cairo_traps_fini (&traps.traps);
+
+    return status;
+}
+
+static cairo_int_status_t
+_cairo_xcb_surface_render_stroke_as_polygon (cairo_xcb_surface_t	*dst,
+					     cairo_operator_t		 op,
+					     const cairo_pattern_t	*source,
+					     cairo_path_fixed_t		*path,
+					     const cairo_stroke_style_t	*stroke_style,
+					     const cairo_matrix_t	*ctm,
+					     const cairo_matrix_t	*ctm_inverse,
+					     double			 tolerance,
+					     cairo_antialias_t		 antialias,
+					     cairo_clip_t		*clip,
+					     const cairo_box_t		*clip_boxes,
+					     int			 num_boxes,
+					     cairo_composite_rectangles_t *extents)
+{
+    cairo_polygon_t polygon;
+    cairo_status_t status;
+
+    _cairo_polygon_init (&polygon);
+    _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
+
+    status = _cairo_path_fixed_stroke_to_polygon (path,
+						  stroke_style,
+						  ctm, ctm_inverse,
+						  tolerance,
+						  &polygon);
+    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	status = _cairo_xcb_surface_render_composite_polygon (dst, op, source,
+							      &polygon, antialias,
+							      CAIRO_FILL_RULE_WINDING,
+							      extents, clip);
+    }
+
+    _cairo_polygon_fini (&polygon);
+
+    return status;
+}
+
+static void
+_clear_image (cairo_surface_t *surface)
+{
+    cairo_image_surface_t *image = (cairo_image_surface_t *) surface;
+    memset (image->data, 0, image->stride * image->height);
+    surface->is_clear = TRUE;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t		*dst,
+					   cairo_operator_t		 op,
+					   const cairo_pattern_t	*source,
+					   cairo_path_fixed_t		*path,
+					   const cairo_stroke_style_t	*stroke_style,
+					   const cairo_matrix_t		*ctm,
+					   const cairo_matrix_t		*ctm_inverse,
+					   double			 tolerance,
+					   cairo_antialias_t		 antialias,
+					   cairo_clip_t			*clip,
+					   const cairo_composite_rectangles_t *extents)
+{
+    cairo_surface_t *image;
+    cairo_status_t status;
+    int x, y;
+
+    x = extents->bounded.x;
+    y = extents->bounded.y;
+    image = _cairo_xcb_surface_create_similar_image (dst, CAIRO_CONTENT_ALPHA,
+						     extents->bounded.width,
+						     extents->bounded.height);
+    if (unlikely (image->status))
+	return image->status;
+
+    _clear_image (image);
+
+    status = _cairo_surface_offset_stroke (image, x, y,
+					   CAIRO_OPERATOR_ADD,
+					   &_cairo_pattern_white.base,
+					   path, stroke_style,
+					   ctm, ctm_inverse,
+					   tolerance, antialias,
+					   NULL);
+    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	cairo_surface_pattern_t mask;
+
+	_cairo_pattern_init_for_surface (&mask, image);
+	mask.base.filter = CAIRO_FILTER_NEAREST;
+
+	cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
+	status = _clip_and_composite (dst, op, source,
+				      _composite_mask, (void *) &mask.base,
+				      extents, clip);
+	_cairo_pattern_fini (&mask.base);
+    }
+
+    cairo_surface_finish (image);
+    cairo_surface_destroy (image);
+
+    return status;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_render_stroke (cairo_xcb_surface_t	*surface,
+				  cairo_operator_t	 op,
+				  const cairo_pattern_t	*source,
+				  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_clip_t		*clip)
+{
+    cairo_composite_rectangles_t extents;
+    cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+    int num_boxes = ARRAY_LENGTH (boxes_stack);
+    cairo_clip_t local_clip;
+    cairo_bool_t have_clip = FALSE;
+    cairo_status_t status;
+
+    if (unlikely (! _operator_is_supported (surface->flags, op)))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if ((surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS |
+			   CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
+			   CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
+    {
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    status = _cairo_composite_rectangles_init_for_stroke (&extents,
+							  surface->width,
+							  surface->height,
+							  op, source,
+							  path, style, ctm,
+							  clip);
+    if (unlikely (status))
+	return status;
+
+    if (_cairo_clip_contains_rectangle (clip, &extents))
+	clip = NULL;
+
+    if (clip != NULL) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	have_clip = TRUE;
+    }
+
+    status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+    if (unlikely (status)) {
+	if (have_clip)
+	    _cairo_clip_fini (&local_clip);
+
+	return status;
+    }
+
+    status = CAIRO_INT_STATUS_UNSUPPORTED;
+    if (path->is_rectilinear) {
+	cairo_boxes_t boxes;
+
+	_cairo_boxes_init (&boxes);
+	_cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
+
+	status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
+								style,
+								ctm,
+								&boxes);
+	if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	    status = _clip_and_composite_boxes (surface, op, source,
+						&boxes, antialias,
+						&extents, clip);
+	}
+
+	_cairo_boxes_fini (&boxes);
+    }
+
+    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+	if (surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS | CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS)) {
+	    status = _cairo_xcb_surface_render_stroke_as_polygon (surface, op, source,
+								  path, style,
+								  ctm, ctm_inverse,
+								  tolerance, antialias,
+								  clip, clip_boxes, num_boxes,
+								  &extents);
+	} else if (surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) {
+	    status = _cairo_xcb_surface_render_stroke_via_mask (surface, op, source,
+								path, style,
+								ctm, ctm_inverse,
+								tolerance, antialias,
+								have_clip ? &local_clip : NULL,
+								&extents);
+	} else {
+	    ASSERT_NOT_REACHED;
+	}
+    }
+
+    if (clip_boxes != boxes_stack)
+	free (clip_boxes);
+
+    if (have_clip)
+	_cairo_clip_fini (&local_clip);
+
+    return status;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_render_fill_as_polygon (cairo_xcb_surface_t	*dst,
+					   cairo_operator_t	 op,
+					   const cairo_pattern_t*source,
+					   cairo_path_fixed_t	*path,
+					   cairo_fill_rule_t	 fill_rule,
+					   double		 tolerance,
+					   cairo_antialias_t	 antialias,
+					   cairo_clip_t		*clip,
+					   cairo_box_t		*clip_boxes,
+					   int			 num_boxes,
+					   cairo_composite_rectangles_t *extents)
+{
+    cairo_polygon_t polygon;
+    cairo_status_t status;
+
+    _cairo_polygon_init (&polygon);
+    _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
+
+    status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
+    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	status = _cairo_xcb_surface_render_composite_polygon (dst, op, source,
+							      &polygon, antialias,
+							      fill_rule,
+							      extents, clip);
+    }
+
+    _cairo_polygon_fini (&polygon);
+
+    return status;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_render_fill_via_mask (cairo_xcb_surface_t	*dst,
+					 cairo_operator_t	 op,
+					 const cairo_pattern_t	*source,
+					 cairo_path_fixed_t	*path,
+					 cairo_fill_rule_t	 fill_rule,
+					 double			 tolerance,
+					 cairo_antialias_t	 antialias,
+					 cairo_clip_t		*clip,
+					 const cairo_composite_rectangles_t *extents)
+{
+    cairo_surface_t *image;
+    cairo_status_t status;
+    int x, y;
+
+    x = extents->bounded.x;
+    y = extents->bounded.y;
+    image = _cairo_xcb_surface_create_similar_image (dst,
+						     CAIRO_CONTENT_ALPHA,
+						     extents->bounded.width,
+						     extents->bounded.height);
+    if (unlikely (image->status))
+	return image->status;
+
+    _clear_image (image);
+
+    status = _cairo_surface_offset_fill (image, x, y,
+					 CAIRO_OPERATOR_ADD,
+					 &_cairo_pattern_white.base,
+					 path, fill_rule, tolerance, antialias,
+					 NULL);
+    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	cairo_surface_pattern_t mask;
+
+	_cairo_pattern_init_for_surface (&mask, image);
+	mask.base.filter = CAIRO_FILTER_NEAREST;
+
+	cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
+	status = _clip_and_composite (dst, op, source,
+				      _composite_mask, (void *) &mask.base,
+				      extents, clip);
+
+	_cairo_pattern_fini (&mask.base);
+    }
+
+    cairo_surface_finish (image);
+    cairo_surface_destroy (image);
+
+    return status;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_render_fill (cairo_xcb_surface_t	*surface,
+			       cairo_operator_t		 op,
+			       const cairo_pattern_t	*source,
+			       cairo_path_fixed_t	*path,
+			       cairo_fill_rule_t	 fill_rule,
+			       double			 tolerance,
+			       cairo_antialias_t	 antialias,
+			       cairo_clip_t		*clip)
+{
+    cairo_composite_rectangles_t extents;
+    cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+    int num_boxes = ARRAY_LENGTH (boxes_stack);
+    cairo_clip_t local_clip;
+    cairo_bool_t have_clip = FALSE;
+    cairo_status_t status;
+
+    if (unlikely (! _operator_is_supported (surface->flags, op)))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if ((surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS |
+			   CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS |
+			   CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
+    {
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    status = _cairo_composite_rectangles_init_for_fill (&extents,
+							surface->width,
+							surface->height,
+							op, source, path,
+							clip);
+    if (unlikely (status))
+	return status;
+
+    if (_cairo_clip_contains_rectangle (clip, &extents))
+	clip = NULL;
+
+    if (clip != NULL) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	have_clip = TRUE;
+    }
+
+    status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+    if (unlikely (status)) {
+	if (have_clip)
+	    _cairo_clip_fini (&local_clip);
+
+	return status;
+    }
+
+    status = CAIRO_INT_STATUS_UNSUPPORTED;
+    if (_cairo_path_fixed_is_rectilinear_fill (path)) {
+	cairo_boxes_t boxes;
+
+	_cairo_boxes_init (&boxes);
+	_cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
+
+	status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
+							      fill_rule,
+							      &boxes);
+	if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	    status = _clip_and_composite_boxes (surface, op, source,
+						&boxes, antialias,
+						&extents, clip);
+	}
+
+	_cairo_boxes_fini (&boxes);
+    }
+
+    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+	if (surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_SPANS | CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS)) {
+	    status = _cairo_xcb_surface_render_fill_as_polygon (surface, op, source, path,
+								fill_rule, tolerance, antialias,
+								clip, clip_boxes, num_boxes,
+								&extents);
+	} else if (surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) {
+	    status = _cairo_xcb_surface_render_fill_via_mask (surface, op, source, path,
+							      fill_rule, tolerance, antialias,
+							      have_clip ? &local_clip : NULL,
+							      &extents);
+	} else {
+	    ASSERT_NOT_REACHED;
+	}
+    }
+
+    if (clip_boxes != boxes_stack)
+	free (clip_boxes);
+
+    if (have_clip)
+	_cairo_clip_fini (&local_clip);
+
+    return status;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_render_glyphs_via_mask (cairo_xcb_surface_t		*dst,
+					   cairo_operator_t		 op,
+					   const cairo_pattern_t	*source,
+					   cairo_scaled_font_t		*scaled_font,
+					   cairo_glyph_t		*glyphs,
+					   int				 num_glyphs,
+					   cairo_clip_t			*clip,
+					   const cairo_composite_rectangles_t *extents)
+{
+    cairo_surface_t *image;
+    cairo_content_t content;
+    cairo_status_t status;
+    int x, y;
+
+    content = CAIRO_CONTENT_ALPHA;
+    if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
+	content = CAIRO_CONTENT_COLOR_ALPHA;
+
+    x = extents->bounded.x;
+    y = extents->bounded.y;
+    image = _cairo_xcb_surface_create_similar_image (dst, content,
+						     extents->bounded.width,
+						     extents->bounded.height);
+    if (unlikely (image->status))
+	return image->status;
+
+    _clear_image (image);
+
+    status = _cairo_surface_offset_glyphs (image, x, y,
+					   CAIRO_OPERATOR_ADD,
+					   &_cairo_pattern_white.base,
+					   scaled_font, glyphs, num_glyphs,
+					   NULL);
+    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	cairo_surface_pattern_t mask;
+
+	_cairo_pattern_init_for_surface (&mask, image);
+	mask.base.filter = CAIRO_FILTER_NEAREST;
+	if (content & CAIRO_CONTENT_COLOR)
+	    mask.base.has_component_alpha = TRUE;
+
+	cairo_matrix_init_translate (&mask.base.matrix, -x, -y);
+	status = _clip_and_composite (dst, op, source,
+				      _composite_mask, (void *) &mask.base,
+				      extents, clip);
+
+	_cairo_pattern_fini (&mask.base);
+    }
+
+    cairo_surface_finish (image);
+    cairo_surface_destroy (image);
+
+    return status;
+}
+
+/* Build a struct of the same size of #cairo_glyph_t that can be used both as
+ * an input glyph with double coordinates, and as "working" glyph with
+ * integer from-current-point offsets. */
+typedef union {
+    cairo_glyph_t d;
+    unsigned long index;
+    struct {
+        unsigned long index;
+        int x;
+        int y;
+    } i;
+} cairo_xcb_glyph_t;
+
+/* compile-time assert that #cairo_xcb_glyph_t is the same size as #cairo_glyph_t */
+COMPILE_TIME_ASSERT (sizeof (cairo_xcb_glyph_t) == sizeof (cairo_glyph_t));
+
+typedef struct {
+    cairo_scaled_font_t *font;
+    cairo_xcb_glyph_t *glyphs;
+    int num_glyphs;
+} composite_glyphs_info_t;
+
+static cairo_status_t
+_can_composite_glyphs (cairo_xcb_surface_t *dst,
+		       cairo_scaled_font_t *scaled_font,
+		       cairo_glyph_t *glyphs,
+		       int num_glyphs)
+{
+    cairo_status_t status;
+    const int max_glyph_size = dst->connection->maximum_request_length - 64;
+    int i;
+
+    /* first scan for oversized glyphs, and fallback in that case */
+    for (i = 0; i < num_glyphs; i++) {
+	cairo_scaled_glyph_t *scaled_glyph;
+	int width, height, len;
+
+	status = _cairo_scaled_glyph_lookup (scaled_font,
+					     glyphs[i].index,
+					     CAIRO_SCALED_GLYPH_INFO_METRICS,
+					     &scaled_glyph);
+	if (unlikely (status))
+	    return status;
+
+	/* XRenderAddGlyph does not handle a glyph surface larger than
+	 * the extended maximum XRequest size.
+	 */
+	width  =
+	    _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x - scaled_glyph->bbox.p1.x);
+	height =
+	    _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y - scaled_glyph->bbox.p1.y);
+	len = CAIRO_STRIDE_FOR_WIDTH_BPP (width, 32) * height;
+	if (len >= max_glyph_size)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+/* Start a new element for the first glyph,
+ * or for any glyph that has unexpected position,
+ * or if current element has too many glyphs
+ * (Xrender limits each element to 252 glyphs, we limit them to 128)
+ *
+ * These same conditions need to be mirrored between
+ * _cairo_xcb_surface_emit_glyphs and _emit_glyph_chunks
+ */
+#define _start_new_glyph_elt(count, glyph) \
+    (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y)
+
+/* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have
+ * enough room for padding */
+typedef struct {
+    uint8_t   len;
+    uint8_t   pad1;
+    uint16_t  pad2;
+    int16_t   deltax;
+    int16_t   deltay;
+} x_glyph_elt_t;
+#define _cairo_sz_x_glyph_elt_t (sizeof (x_glyph_elt_t) + 4)
+
+static cairo_xcb_font_glyphset_info_t *
+_cairo_xcb_scaled_glyph_get_glyphset_info (cairo_scaled_glyph_t *scaled_glyph)
+{
+    return scaled_glyph->surface_private;
+}
+
+static void
+_cairo_xcb_scaled_glyph_set_glyphset_info (cairo_scaled_glyph_t            *scaled_glyph,
+					   cairo_xcb_font_glyphset_info_t *glyphset_info)
+{
+    scaled_glyph->surface_private = glyphset_info;
+}
+
+static cairo_status_t
+_cairo_xcb_surface_font_init (cairo_xcb_connection_t *connection,
+			      cairo_scaled_font_t  *scaled_font)
+{
+    cairo_xcb_font_t	*font_private;
+    int i;
+
+    font_private = malloc (sizeof (cairo_xcb_font_t));
+    if (unlikely (font_private == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    font_private->scaled_font = scaled_font;
+    font_private->connection = _cairo_xcb_connection_reference (connection);
+    for (i = 0; i < NUM_GLYPHSETS; i++) {
+	cairo_xcb_font_glyphset_info_t *glyphset_info = &font_private->glyphset_info[i];
+	switch (i) {
+	case GLYPHSET_INDEX_ARGB32: glyphset_info->format = CAIRO_FORMAT_ARGB32; break;
+	case GLYPHSET_INDEX_A8:     glyphset_info->format = CAIRO_FORMAT_A8;     break;
+	case GLYPHSET_INDEX_A1:     glyphset_info->format = CAIRO_FORMAT_A1;     break;
+	default:                    ASSERT_NOT_REACHED;                          break;
+	}
+	glyphset_info->xrender_format = 0;
+	glyphset_info->glyphset = XCB_NONE;
+	glyphset_info->pending_free_glyphs = NULL;
+    }
+
+    scaled_font->surface_private = font_private;
+    scaled_font->surface_backend = &_cairo_xcb_surface_backend;
+
+    cairo_list_add (&font_private->link, &connection->fonts);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+_cairo_xcb_font_destroy (cairo_xcb_font_t *font)
+{
+    int i;
+
+    for (i = 0; i < NUM_GLYPHSETS; i++) {
+	cairo_xcb_font_glyphset_info_t *glyphset_info;
+
+	glyphset_info = &font->glyphset_info[i];
+
+	if (glyphset_info->pending_free_glyphs != NULL)
+	    free (glyphset_info->pending_free_glyphs);
+    }
+
+    cairo_list_del (&font->link);
+    _cairo_xcb_connection_destroy (font->connection);
+
+    free (font);
+}
+
+void
+_cairo_xcb_font_finish (cairo_xcb_font_t *font)
+{
+    cairo_scaled_font_t	*scaled_font;
+
+    scaled_font = font->scaled_font;
+
+    CAIRO_MUTEX_LOCK (scaled_font->mutex);
+    scaled_font->surface_private = NULL;
+    _cairo_scaled_font_reset_cache (scaled_font);
+    CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
+
+    _cairo_xcb_font_destroy (font);
+}
+
+void
+_cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
+{
+    cairo_xcb_font_t *font_private;
+    cairo_xcb_connection_t *connection;
+    cairo_bool_t have_connection;
+    cairo_status_t status;
+    int i;
+
+    font_private = scaled_font->surface_private;
+    if (font_private == NULL)
+	return;
+
+    connection = font_private->connection;
+
+    status = _cairo_xcb_connection_acquire (connection);
+    have_connection = status == CAIRO_STATUS_SUCCESS;
+    if (likely (have_connection))
+	status = _cairo_xcb_connection_take_socket (connection);
+
+    for (i = 0; i < NUM_GLYPHSETS; i++) {
+	cairo_xcb_font_glyphset_info_t *glyphset_info;
+
+	glyphset_info = &font_private->glyphset_info[i];
+	if (glyphset_info->glyphset && status == CAIRO_STATUS_SUCCESS) {
+	    _cairo_xcb_connection_render_free_glyph_set (connection,
+							 glyphset_info->glyphset);
+	}
+    }
+
+    if (have_connection)
+	_cairo_xcb_connection_release (connection);
+
+
+    _cairo_xcb_font_destroy (font_private);
+}
+
+static void
+_cairo_xcb_render_free_glyphs (cairo_xcb_connection_t *connection,
+			       cairo_xcb_font_glyphset_free_glyphs_t *to_free)
+{
+    _cairo_xcb_connection_render_free_glyphs (connection,
+					      to_free->glyphset,
+					      to_free->glyph_count,
+					      to_free->glyph_indices);
+}
+
+void
+_cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
+				      cairo_scaled_font_t  *scaled_font)
+{
+    cairo_xcb_font_t *font_private;
+    cairo_xcb_font_glyphset_info_t *glyphset_info;
+
+    if (scaled_font->finished)
+	return;
+
+    font_private = scaled_font->surface_private;
+    glyphset_info = _cairo_xcb_scaled_glyph_get_glyphset_info (scaled_glyph);
+    if (font_private != NULL && glyphset_info != NULL) {
+	cairo_xcb_font_glyphset_free_glyphs_t *to_free;
+
+	to_free = glyphset_info->pending_free_glyphs;
+	if (to_free != NULL &&
+	    to_free->glyph_count == ARRAY_LENGTH (to_free->glyph_indices))
+	{
+	    _cairo_xcb_render_free_glyphs (font_private->connection, to_free);
+	    to_free = glyphset_info->pending_free_glyphs = NULL;
+	}
+
+	if (to_free == NULL) {
+	    to_free = malloc (sizeof (cairo_xcb_font_glyphset_free_glyphs_t));
+	    if (unlikely (to_free == NULL)) {
+		_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+		return; /* XXX cannot propagate failure */
+	    }
+
+	    to_free->glyphset = glyphset_info->glyphset;
+	    to_free->glyph_count = 0;
+	    glyphset_info->pending_free_glyphs = to_free;
+	}
+
+	to_free->glyph_indices[to_free->glyph_count++] =
+	    _cairo_scaled_glyph_index (scaled_glyph);
+    }
+}
+
+static cairo_bool_t
+_native_byte_order_lsb (void)
+{
+    int	x = 1;
+
+    return *((char *) &x) == 1;
+}
+
+static cairo_xcb_font_glyphset_info_t *
+_cairo_xcb_scaled_font_get_glyphset_info_for_format (cairo_scaled_font_t *scaled_font,
+						     cairo_format_t       format)
+{
+    cairo_xcb_font_t *font_private;
+    cairo_xcb_font_glyphset_info_t *glyphset_info;
+    int glyphset_index;
+
+    switch (format) {
+    default:
+    case CAIRO_FORMAT_RGB24:
+    case CAIRO_FORMAT_ARGB32: glyphset_index = GLYPHSET_INDEX_ARGB32; break;
+    case CAIRO_FORMAT_A8:     glyphset_index = GLYPHSET_INDEX_A8;     break;
+    case CAIRO_FORMAT_A1:     glyphset_index = GLYPHSET_INDEX_A1;     break;
+    }
+
+    font_private = scaled_font->surface_private;
+    glyphset_info = &font_private->glyphset_info[glyphset_index];
+    if (glyphset_info->glyphset == XCB_NONE) {
+	cairo_xcb_connection_t *connection = font_private->connection;
+
+	glyphset_info->glyphset = _cairo_xcb_connection_get_xid (font_private->connection);
+	glyphset_info->xrender_format =
+	    connection->standard_formats[glyphset_info->format];
+
+	_cairo_xcb_connection_render_create_glyph_set (font_private->connection,
+						       glyphset_info->glyphset,
+						       glyphset_info->xrender_format);
+    }
+
+    return glyphset_info;
+}
+
+static cairo_bool_t
+_cairo_xcb_glyphset_info_has_pending_free_glyph (
+				cairo_xcb_font_glyphset_info_t *glyphset_info,
+				unsigned long glyph_index)
+{
+    if (glyphset_info->pending_free_glyphs != NULL) {
+	cairo_xcb_font_glyphset_free_glyphs_t *to_free;
+	int i;
+
+	to_free = glyphset_info->pending_free_glyphs;
+	for (i = 0; i < to_free->glyph_count; i++) {
+	    if (to_free->glyph_indices[i] == glyph_index) {
+		to_free->glyph_count--;
+		memmove (&to_free->glyph_indices[i],
+			 &to_free->glyph_indices[i+1],
+			 (to_free->glyph_count - i) * sizeof (to_free->glyph_indices[0]));
+		return TRUE;
+	    }
+	}
+    }
+
+    return FALSE;
+}
+
+static cairo_xcb_font_glyphset_info_t *
+_cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (
+					       cairo_scaled_font_t *scaled_font,
+					       unsigned long glyph_index,
+					       cairo_image_surface_t *surface)
+{
+    cairo_xcb_font_t *font_private;
+    int i;
+
+    font_private = scaled_font->surface_private;
+    if (font_private == NULL)
+	return NULL;
+
+    if (surface != NULL) {
+	switch (surface->format) {
+	default:
+	case CAIRO_FORMAT_RGB24:
+	case CAIRO_FORMAT_ARGB32: i = GLYPHSET_INDEX_ARGB32; break;
+	case CAIRO_FORMAT_A8:     i = GLYPHSET_INDEX_A8;     break;
+	case CAIRO_FORMAT_A1:     i = GLYPHSET_INDEX_A1;     break;
+	}
+
+	if (_cairo_xcb_glyphset_info_has_pending_free_glyph (
+						&font_private->glyphset_info[i],
+						glyph_index))
+	{
+	    return &font_private->glyphset_info[i];
+	}
+    } else {
+	for (i = 0; i < NUM_GLYPHSETS; i++) {
+	    if (_cairo_xcb_glyphset_info_has_pending_free_glyph (
+						&font_private->glyphset_info[i],
+						glyph_index))
+	    {
+		return &font_private->glyphset_info[i];
+	    }
+	}
+    }
+
+    return NULL;
+}
+static cairo_status_t
+_cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection,
+			       cairo_scaled_font_t   *scaled_font,
+			       cairo_scaled_glyph_t **scaled_glyph_out)
+{
+    xcb_render_glyphinfo_t glyph_info;
+    uint32_t glyph_index;
+    uint8_t *data;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+    cairo_scaled_glyph_t *scaled_glyph = *scaled_glyph_out;
+    cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
+    cairo_bool_t already_had_glyph_surface;
+    cairo_xcb_font_glyphset_info_t *glyphset_info;
+
+    glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
+
+    /* check to see if we have a pending XRenderFreeGlyph for this glyph */
+    glyphset_info = _cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (scaled_font, glyph_index, glyph_surface);
+    if (glyphset_info != NULL) {
+	_cairo_xcb_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    if (glyph_surface == NULL) {
+	status = _cairo_scaled_glyph_lookup (scaled_font,
+					     glyph_index,
+					     CAIRO_SCALED_GLYPH_INFO_METRICS |
+					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
+					     scaled_glyph_out);
+	if (unlikely (status))
+	    return status;
+
+	scaled_glyph = *scaled_glyph_out;
+	glyph_surface = scaled_glyph->surface;
+	already_had_glyph_surface = FALSE;
+    } else {
+	already_had_glyph_surface = TRUE;
+    }
+
+    if (scaled_font->surface_private == NULL) {
+	status = _cairo_xcb_surface_font_init (connection, scaled_font);
+	if (unlikely (status))
+	    return status;
+    }
+
+    glyphset_info = _cairo_xcb_scaled_font_get_glyphset_info_for_format (scaled_font,
+									 glyph_surface->format);
+
+    /* If the glyph surface has zero height or width, we create
+     * a clear 1x1 surface, to avoid various X server bugs.
+     */
+    if (glyph_surface->width == 0 || glyph_surface->height == 0) {
+	cairo_surface_t *tmp_surface;
+
+	tmp_surface = cairo_image_surface_create (glyphset_info->format, 1, 1);
+	status = tmp_surface->status;
+	if (unlikely (status))
+	    goto BAIL;
+
+	tmp_surface->device_transform = glyph_surface->base.device_transform;
+	tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
+
+	glyph_surface = (cairo_image_surface_t *) tmp_surface;
+    }
+
+    /* If the glyph format does not match the font format, then we
+     * create a temporary surface for the glyph image with the font's
+     * format.
+     */
+    if (glyph_surface->format != glyphset_info->format) {
+	glyph_surface = _cairo_image_surface_coerce (glyph_surface,
+						     glyphset_info->format);
+	status = glyph_surface->base.status;
+	if (unlikely (status))
+	    goto BAIL;
+    }
+
+    /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
+    glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
+    glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
+    glyph_info.width  = glyph_surface->width;
+    glyph_info.height = glyph_surface->height;
+    glyph_info.x_off = scaled_glyph->x_advance;
+    glyph_info.y_off = scaled_glyph->y_advance;
+
+    data = glyph_surface->data;
+
+    /* flip formats around */
+    switch (scaled_glyph->surface->format) {
+    case CAIRO_FORMAT_A1:
+	/* local bitmaps are always stored with bit == byte */
+	if (_native_byte_order_lsb() != (connection->root->bitmap_format_bit_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
+	    int		    c = glyph_surface->stride * glyph_surface->height;
+	    const uint8_t *d;
+	    uint8_t *new, *n;
+
+	    new = malloc (c);
+	    if (unlikely (new == NULL)) {
+		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+		goto BAIL;
+	    }
+
+	    n = new;
+	    d = data;
+	    do {
+		uint8_t b = *d++;
+		b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
+		b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
+		b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
+		*n++ = b;
+	    } while (--c);
+	    data = new;
+	}
+	break;
+
+    case CAIRO_FORMAT_A8:
+	break;
+
+    case CAIRO_FORMAT_ARGB32:
+	if (_native_byte_order_lsb() != (connection->root->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
+	    unsigned int c = glyph_surface->stride * glyph_surface->height / 4;
+	    const uint32_t *d;
+	    uint32_t *new, *n;
+
+	    new = malloc (4 * c);
+	    if (unlikely (new == NULL)) {
+		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+		goto BAIL;
+	    }
+
+	    n = new;
+	    d = (uint32_t *) data;
+	    do {
+		*n++ = bswap_32 (*d);
+		d++;
+	    } while (--c);
+	    data = (uint8_t *) new;
+	}
+	break;
+
+    case CAIRO_FORMAT_RGB24:
+    default:
+	ASSERT_NOT_REACHED;
+	break;
+    }
+    /* XXX assume X server wants pixman padding. Xft assumes this as well */
+
+    _cairo_xcb_connection_render_add_glyphs (connection,
+					     glyphset_info->glyphset,
+					     1, &glyph_index, &glyph_info,
+					     glyph_surface->stride * glyph_surface->height,
+					     data);
+
+    if (data != glyph_surface->data)
+	free (data);
+
+    _cairo_xcb_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
+
+ BAIL:
+    if (glyph_surface != scaled_glyph->surface)
+	cairo_surface_destroy (&glyph_surface->base);
+
+    /* If the scaled glyph didn't already have a surface attached
+     * to it, release the created surface now that we have it
+     * uploaded to the X server.  If the surface has already been
+     * there (e.g. because image backend requested it), leave it in
+     * the cache
+     */
+    if (! already_had_glyph_surface)
+	_cairo_scaled_glyph_set_surface (scaled_glyph, scaled_font, NULL);
+
+    return status;
+}
+
+typedef void (*cairo_xcb_render_composite_text_func_t)
+	      (cairo_xcb_connection_t       *connection,
+	       uint8_t                          op,
+	       xcb_render_picture_t src,
+	       xcb_render_picture_t dst,
+	       xcb_render_pictformat_t mask_format,
+	       xcb_render_glyphset_t glyphset,
+	       int16_t                          src_x,
+	       int16_t                          src_y,
+	       uint32_t                          len,
+	       uint8_t                        *cmd);
+
+
+static cairo_status_t
+_emit_glyphs_chunk (cairo_xcb_surface_t *dst,
+		    cairo_operator_t op,
+		    cairo_xcb_picture_t *src,
+		    /* info for this chunk */
+		    cairo_xcb_glyph_t *glyphs,
+		    int num_glyphs,
+		    int width,
+		    int estimated_req_size,
+		    cairo_xcb_font_glyphset_info_t *glyphset_info)
+{
+    cairo_xcb_render_composite_text_func_t composite_text_func;
+    uint8_t stack_buf[CAIRO_STACK_BUFFER_SIZE];
+    uint8_t *buf = stack_buf;
+    x_glyph_elt_t *elt = NULL; /* silence compiler */
+    uint32_t len;
+    int i;
+
+    if (estimated_req_size > ARRAY_LENGTH (stack_buf)) {
+	buf = malloc (estimated_req_size);
+	if (unlikely (buf == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    len = 0;
+    for (i = 0; i < num_glyphs; i++) {
+      if (_start_new_glyph_elt (i, &glyphs[i])) {
+	  if (len & 3)
+	      len += 4 - (len & 3);
+
+	  elt = (x_glyph_elt_t *) (buf + len);
+	  elt->len = 0;
+	  elt->deltax = glyphs[i].i.x;
+	  elt->deltay = glyphs[i].i.y;
+	  len += sizeof (x_glyph_elt_t);
+      }
+
+      switch (width) {
+      case 1: *(uint8_t *) (buf + len) = glyphs[i].index; break;
+      case 2: *(uint16_t *) (buf + len) = glyphs[i].index; break;
+      default:
+      case 4: *(uint32_t *) (buf + len) = glyphs[i].index; break;
+      }
+      len += width;
+      elt->len++;
+    }
+    if (len & 3)
+	len += 4 - (len & 3);
+
+    switch (width) {
+    case 1:
+	composite_text_func = _cairo_xcb_connection_render_composite_glyphs_8;
+	break;
+    case 2:
+	composite_text_func = _cairo_xcb_connection_render_composite_glyphs_16;
+	break;
+    default:
+    case 4:
+	composite_text_func = _cairo_xcb_connection_render_composite_glyphs_32;
+	break;
+    }
+    composite_text_func (dst->connection,
+			 _render_operator (op),
+			 src->picture,
+			 dst->picture,
+			 glyphset_info->xrender_format,
+			 glyphset_info->glyphset,
+			 src->x + glyphs[0].i.x,
+			 src->y + glyphs[0].i.y,
+			 len, buf);
+
+    if (buf != stack_buf)
+      free (buf);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_composite_glyphs (void				*closure,
+		  cairo_xcb_surface_t	*dst,
+		  cairo_operator_t	 op,
+		  const cairo_pattern_t	*pattern,
+		  int dst_x, int dst_y,
+		  const cairo_rectangle_int_t *extents,
+		  cairo_region_t		*clip_region)
+{
+    composite_glyphs_info_t *info = closure;
+    cairo_scaled_glyph_t *glyph_cache[64];
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+    cairo_fixed_t x = 0, y = 0;
+    cairo_xcb_font_glyphset_info_t *glyphset_info = NULL, *this_glyphset_info;
+    const unsigned int max_request_size = dst->connection->maximum_request_length - 64;
+    cairo_xcb_picture_t *src;
+
+    unsigned long max_index = 0;
+    int width = 1;
+
+    unsigned int request_size = 0;
+    int i;
+
+    src = _cairo_xcb_picture_for_pattern (dst, pattern, extents);
+    if (unlikely (src->base.status))
+	return src->base.status;
+
+    memset (glyph_cache, 0, sizeof (glyph_cache));
+
+    for (i = 0; i < info->num_glyphs; i++) {
+	cairo_scaled_glyph_t *scaled_glyph;
+	unsigned long glyph_index = info->glyphs[i].index;
+	int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache);
+	int old_width = width;
+	int this_x, this_y;
+
+	scaled_glyph = glyph_cache[cache_index];
+	if (scaled_glyph == NULL ||
+	    _cairo_scaled_glyph_index (scaled_glyph) != glyph_index)
+	{
+	    status = _cairo_scaled_glyph_lookup (info->font,
+						 glyph_index,
+						 CAIRO_SCALED_GLYPH_INFO_METRICS,
+						 &scaled_glyph);
+	    if (unlikely (status))
+		return status;
+
+	    /* Send unseen glyphs to the server */
+	    if (_cairo_xcb_scaled_glyph_get_glyphset_info (scaled_glyph) == NULL) {
+		status = _cairo_xcb_surface_add_glyph (dst->connection,
+						       info->font,
+						       &scaled_glyph);
+		if (unlikely (status))
+		    return status;
+	    }
+
+	    glyph_cache[cache_index] = scaled_glyph;
+	}
+
+	/* Glyph skipping:
+	 *
+	 * We skip any glyphs that have troublesome coordinates.  We want
+	 * to make sure that (glyph2.x - (glyph1.x + glyph1.width)) fits in
+	 * a signed 16bit integer, otherwise it will overflow in the render
+	 * protocol.
+	 * To ensure this, we'll make sure that (glyph2.x - glyph1.x) fits in
+	 * a signed 15bit integer.  The trivial option would be to allow
+	 * coordinates -8192..8192, but that's kinda dull.  It probably will
+	 * take a decade or so to get monitors 8192x4096 or something.  A
+	 * negative value of -8192 on the other hand, is absolutely useless.
+	 * Note that we do want to allow some negative positions.  The glyph
+	 * may start off the screen but part of it make it to the screen.
+	 * Anyway, we will allow positions in the range -4096..122887.  That
+	 * will buy us a few more years before this stops working.
+	 */
+	this_x = _cairo_lround (info->glyphs[i].d.x) - dst_x;
+	this_y = _cairo_lround (info->glyphs[i].d.y) - dst_y;
+	assert (! (((this_x+4096) | (this_y+4096)) & ~0x3fffu));
+
+	this_glyphset_info = _cairo_xcb_scaled_glyph_get_glyphset_info (scaled_glyph);
+	if (glyphset_info == NULL)
+	    glyphset_info = this_glyphset_info;
+
+	/* Update max glyph index */
+	if (glyph_index > max_index) {
+	    max_index = glyph_index;
+	    if (max_index >= 65536)
+		width = 4;
+	    else if (max_index >= 256)
+		width = 2;
+	    if (width != old_width)
+		request_size += (width - old_width) * i;
+	}
+
+	/* If we will pass the max request size by adding this glyph,
+	 * flush current glyphs.  Note that we account for a
+	 * possible element being added below.
+	 *
+	 * Also flush if changing glyphsets, as Xrender limits one mask
+	 * format per request, so we can either break up, or use a
+	 * wide-enough mask format.  We do the former.  One reason to
+	 * prefer the latter is the fact that Xserver ADDs all glyphs
+	 * to the mask first, and then composes that to final surface,
+	 * though it's not a big deal.
+	 */
+	if (request_size + width > max_request_size - _cairo_sz_x_glyph_elt_t ||
+	    this_glyphset_info != glyphset_info)
+	{
+	    status = _emit_glyphs_chunk (dst, op, src,
+					 info->glyphs, i,
+					 old_width, request_size,
+					 glyphset_info);
+	    if (unlikely (status))
+		return status;
+
+	    info->glyphs += i;
+	    info->num_glyphs -= i;
+	    i = 0;
+
+	    max_index = info->glyphs[0].index;
+	    width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
+
+	    request_size = 0;
+
+	    x = y = 0;
+	    glyphset_info = this_glyphset_info;
+	}
+
+	/* Convert absolute glyph position to relative-to-current-point
+	 * position */
+	info->glyphs[i].i.x = this_x - x;
+	info->glyphs[i].i.y = this_y - y;
+
+	/* Start a new element for the first glyph,
+	 * or for any glyph that has unexpected position,
+	 * or if current element has too many glyphs.
+	 *
+	 * These same conditions are mirrored in _emit_glyphs_chunk().
+	 */
+      if (_start_new_glyph_elt (i, &info->glyphs[i]))
+	    request_size += _cairo_sz_x_glyph_elt_t;
+
+	/* adjust current-position */
+	x = this_x + scaled_glyph->x_advance;
+	y = this_y + scaled_glyph->y_advance;
+
+	request_size += width;
+    }
+
+    if (i) {
+	status = _emit_glyphs_chunk (dst, op, src,
+				     info->glyphs, i,
+				     width, request_size,
+				     glyphset_info);
+    }
+
+    return status;
+}
+
+cairo_int_status_t
+_cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t	*surface,
+				  cairo_operator_t	 op,
+				  const cairo_pattern_t	*source,
+				  cairo_scaled_font_t	*scaled_font,
+				  cairo_glyph_t		*glyphs,
+				  int			 num_glyphs,
+				  cairo_clip_t		*clip)
+{
+    cairo_composite_rectangles_t extents;
+    cairo_clip_t local_clip;
+    cairo_bool_t have_clip = FALSE;
+    cairo_status_t status;
+
+    if (unlikely (! _operator_is_supported (surface->flags, op)))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if ((surface->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS | CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    status = _cairo_composite_rectangles_init_for_glyphs (&extents,
+							  surface->width,
+							  surface->height,
+							  op, source,
+							  scaled_font,
+							  glyphs, num_glyphs,
+							  clip, NULL);
+    if (unlikely (status))
+	return status;
+
+    if (_cairo_clip_contains_rectangle (clip, &extents))
+	clip = NULL;
+
+    if (clip != NULL) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	have_clip = TRUE;
+    }
+
+    if (clip != NULL && extents.is_bounded) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	status = _cairo_clip_rectangle (clip, &extents.bounded);
+	if (unlikely (status)) {
+	    _cairo_clip_fini (&local_clip);
+	    return status;
+	}
+	have_clip = TRUE;
+    }
+
+    status = CAIRO_INT_STATUS_UNSUPPORTED;
+    if (surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS) {
+	_cairo_scaled_font_freeze_cache (scaled_font);
+
+	status = _can_composite_glyphs (surface, scaled_font, glyphs, num_glyphs);
+	if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	    composite_glyphs_info_t info;
+
+	    info.font = scaled_font;
+	    info.glyphs = (cairo_xcb_glyph_t *) glyphs;
+	    info.num_glyphs = num_glyphs;
+
+	    status = _clip_and_composite (surface, op, source,
+					  _composite_glyphs, &info,
+					  &extents, clip);
+	}
+
+	_cairo_scaled_font_thaw_cache (scaled_font);
+    }
+
+    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+	assert (surface->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE);
+	status =
+	    _cairo_xcb_surface_render_glyphs_via_mask (surface, op, source,
+						       scaled_font, glyphs, num_glyphs,
+						       have_clip ? &local_clip : NULL,
+						       &extents);
+    }
+
+    if (have_clip)
+	_cairo_clip_fini (&local_clip);
+
+    return status;
+}
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 666abc9..2e08c64 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -1,6 +1,7 @@
 /* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2002 University of Southern California
+ * 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
@@ -31,308 +32,215 @@
  * California.
  *
  * Contributor(s):
+ *	Behdad Esfahbod <behdad at behdad.org>
  *	Carl D. Worth <cworth at cworth.org>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ *	Karl Tomlinson <karlt+ at karlt.net>, Mozilla Corporation
  */
 
 #include "cairoint.h"
-#include "cairo-xcb.h"
-#include "cairo-xcb-xrender.h"
-#include "cairo-clip-private.h"
-#include "cairo-error-private.h"
-#include "cairo-freelist-private.h"
-#include "cairo-list-private.h"
-#include <xcb/xcb_renderutil.h>
-
-#define AllPlanes               ((unsigned long)~0L)
-
-slim_hidden_proto (cairo_xcb_surface_create_with_xrender_format);
-
-/*
- * Instead of taking two round trips for each blending request,
- * assume that if a particular drawable fails GetImage that it will
- * fail for a "while"; use temporary pixmaps to avoid the errors
- */
-
-#define CAIRO_ASSUME_PIXMAP	20
 
-typedef struct cairo_xcb_surface {
-    cairo_surface_t base;
-
-    xcb_connection_t *dpy;
-    xcb_screen_t *screen;
-
-    xcb_gcontext_t gc;
-    xcb_drawable_t drawable;
-    cairo_bool_t owns_pixmap;
-    xcb_visualtype_t *visual;
-
-    int use_pixmap;
-
-    int render_major;
-    int render_minor;
-
-    int width;
-    int height;
-    int depth;
-
-    cairo_bool_t have_clip_rects;
-    xcb_rectangle_t *clip_rects;
-    int num_clip_rects;
-    cairo_region_t *clip_region;
-
-    xcb_render_picture_t src_picture, dst_picture;
-    xcb_render_pictforminfo_t xrender_format;
-
-    cairo_list_t to_be_checked;
-    cairo_freepool_t cookie_pool;
-} cairo_xcb_surface_t;
-
-typedef struct _cairo_xcb_cookie {
-    cairo_list_t link;
-    xcb_void_cookie_t xcb;
-} cairo_xcb_cookie_t;
-
-#define CAIRO_SURFACE_RENDER_AT_LEAST(surface, major, minor)	\
-	(((surface)->render_major > major) ||			\
-	 (((surface)->render_major == major) && ((surface)->render_minor >= minor)))
-
-#define CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
-#define CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT(surface)	CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 0)
+#include "cairo-xcb.h"
+#include "cairo-xcb-private.h"
 
-#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
-#define CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLES(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 1)
+#include <xcb/dri2.h>
 
-#define CAIRO_SURFACE_RENDER_HAS_DISJOINT(surface)			CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
-#define CAIRO_SURFACE_RENDER_HAS_CONJOINT(surface)			CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 2)
+#define AllPlanes ((unsigned) -1)
+#define CAIRO_ASSUME_PIXMAP 20
+#define XLIB_COORD_MAX 32767
 
-#define CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRIANGLES(surface)		CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRISTRIP(surface)			CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
-#define CAIRO_SURFACE_RENDER_HAS_TRIFAN(surface)			CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 4)
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+slim_hidden_proto (cairo_xcb_surface_create);
+slim_hidden_proto (cairo_xcb_surface_create_for_bitmap);
+slim_hidden_proto (cairo_xcb_surface_create_with_xrender_format);
+#endif
 
-#define CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM(surface)	CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
-#define CAIRO_SURFACE_RENDER_HAS_FILTERS(surface)	CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 6)
-#define CAIRO_SURFACE_RENDER_HAS_REPEAT_PAD(surface)	CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
-#define CAIRO_SURFACE_RENDER_HAS_REPEAT_REFLECT(surface)	CAIRO_SURFACE_RENDER_AT_LEAST((surface), 0, 10)
+#if CAIRO_HAS_DRM_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+#include "drm/cairo-drm-private.h"
+#endif
 
 static cairo_status_t
-_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface);
-
-static int
-_CAIRO_FORMAT_DEPTH (cairo_format_t format)
+_cairo_xcb_surface_create_similar_shm (cairo_xcb_surface_t *other,
+				       pixman_format_code_t pixman_format,
+				       int width, int height,
+				       cairo_surface_t **out)
 {
-    switch (format) {
-    case CAIRO_FORMAT_A1:
-	return 1;
-    case CAIRO_FORMAT_A8:
-	return 8;
-    case CAIRO_FORMAT_RGB24:
-	return 24;
-    case CAIRO_FORMAT_ARGB32:
-    default:
-	return 32;
-    }
-}
+    size_t size, stride;
+    cairo_xcb_shm_info_t *shm_info;
+    cairo_status_t status;
+    cairo_surface_t *image;
 
-static cairo_status_t
-_cairo_xcb_add_cookie_to_be_checked (cairo_xcb_surface_t *surface,
-				     xcb_void_cookie_t xcb)
-{
-    cairo_xcb_cookie_t *cookie;
+    stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (pixman_format));
+    size = stride * height;
+    if (size < CAIRO_XCB_SHM_SMALL_IMAGE)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    cookie = _cairo_freepool_alloc (&surface->cookie_pool);
-    if (unlikely (cookie == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    status = _cairo_xcb_connection_allocate_shm_info (other->connection,
+						      size, &shm_info);
+    if (unlikely (status))
+	return status;
+
+    image = _cairo_image_surface_create_with_pixman_format (shm_info->mem,
+							    pixman_format,
+							    width, height,
+							    stride);
+    status = image->status;
+    if (unlikely (status)) {
+	_cairo_xcb_shm_info_destroy (shm_info);
+	return status;
+    }
 
-    cookie->xcb = xcb;
-    cairo_list_add_tail (&cookie->link, &surface->to_be_checked);
+    status = _cairo_user_data_array_set_data (&image->user_data,
+					      (const cairo_user_data_key_t *) other->connection,
+					      shm_info,
+					      (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
+    if (unlikely (status)) {
+	cairo_surface_destroy (image);
+	_cairo_xcb_shm_info_destroy (shm_info);
+	return status;
+    }
 
+    *out = image;
     return CAIRO_STATUS_SUCCESS;
 }
 
-static xcb_render_pictforminfo_t *
-_CAIRO_FORMAT_TO_XRENDER_FORMAT(xcb_connection_t *dpy, cairo_format_t format)
+cairo_surface_t *
+_cairo_xcb_surface_create_similar_image (cairo_xcb_surface_t *other,
+					 cairo_content_t content,
+					 int width, int height)
 {
-    xcb_pict_standard_t	std_format;
-    switch (format) {
-    case CAIRO_FORMAT_A1:
-	std_format = XCB_PICT_STANDARD_A_1; break;
-    case CAIRO_FORMAT_A8:
-	std_format = XCB_PICT_STANDARD_A_8; break;
-    case CAIRO_FORMAT_RGB24:
-	std_format = XCB_PICT_STANDARD_RGB_24; break;
-    case CAIRO_FORMAT_ARGB32:
+    cairo_surface_t *image = NULL;
+    pixman_format_code_t pixman_format;
+
+    /* XXX choose pixman_format from connection->image_formats */
+    switch (content) {
+    case CAIRO_CONTENT_ALPHA:
+	pixman_format = PIXMAN_a8;
+	break;
+    case CAIRO_CONTENT_COLOR:
+	pixman_format = PIXMAN_x8r8g8b8;
+	break;
     default:
-	std_format = XCB_PICT_STANDARD_ARGB_32; break;
+	ASSERT_NOT_REACHED;
+    case CAIRO_CONTENT_COLOR_ALPHA:
+	pixman_format = PIXMAN_a8r8g8b8;
+	break;
     }
-    return xcb_render_util_find_standard_format (xcb_render_util_query_formats (dpy), std_format);
-}
 
-static cairo_content_t
-_xcb_render_format_to_content (xcb_render_pictforminfo_t *xrender_format)
-{
-    cairo_bool_t xrender_format_has_alpha;
-    cairo_bool_t xrender_format_has_color;
-
-    /* This only happens when using a non-Render server. Let's punt
-     * and say there's no alpha here. */
-    if (xrender_format == NULL)
-	return CAIRO_CONTENT_COLOR;
-
-    xrender_format_has_alpha = (xrender_format->direct.alpha_mask != 0);
-    xrender_format_has_color = (xrender_format->direct.red_mask   != 0 ||
-				xrender_format->direct.green_mask != 0 ||
-				xrender_format->direct.blue_mask  != 0);
-
-    if (xrender_format_has_alpha)
-	if (xrender_format_has_color)
-	    return CAIRO_CONTENT_COLOR_ALPHA;
-	else
-	    return CAIRO_CONTENT_ALPHA;
-    else
-	return CAIRO_CONTENT_COLOR;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_set_gc_clip_rects (cairo_xcb_surface_t *surface)
-{
-    if (surface->have_clip_rects) {
-	xcb_void_cookie_t cookie;
+    if (other->flags & CAIRO_XCB_HAS_SHM) {
+	cairo_status_t status;
 
-	cookie = xcb_set_clip_rectangles_checked (surface->dpy,
-					 XCB_CLIP_ORDERING_YX_SORTED, surface->gc,
-					 0, 0,
-					 surface->num_clip_rects,
-					 surface->clip_rects);
+	status = _cairo_xcb_surface_create_similar_shm (other,
+							pixman_format,
+							width, height,
+							&image);
+	if (_cairo_status_is_error (status))
+	    return _cairo_surface_create_in_error (status);
+    }
 
-	return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+    if (image == NULL) {
+	image = _cairo_image_surface_create_with_pixman_format (NULL,
+								pixman_format,
+								width, height,
+								0);
     }
 
-    return CAIRO_STATUS_SUCCESS;
+    return image;
 }
 
-static cairo_status_t
-_cairo_xcb_surface_set_picture_clip_rects (cairo_xcb_surface_t *surface)
+cairo_surface_t *
+_cairo_xcb_surface_create_similar (void			*abstract_other,
+				   cairo_content_t	 content,
+				   int			 width,
+				   int			 height)
 {
-    if (surface->have_clip_rects) {
-	xcb_void_cookie_t cookie;
+    cairo_xcb_surface_t *other = abstract_other;
+    cairo_xcb_surface_t *surface;
+    cairo_xcb_connection_t *connection;
+    xcb_pixmap_t pixmap;
+    cairo_status_t status;
 
-	cookie = xcb_render_set_picture_clip_rectangles_checked (surface->dpy,
-								 surface->dst_picture,
-								 0, 0,
-								 surface->num_clip_rects,
-								 surface->clip_rects);
+    if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
+	return NULL;
 
-	return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
-    }
+    if (width <= 0 || height <= 0)
+	return NULL;
 
-    return CAIRO_STATUS_SUCCESS;
-}
+#if CAIRO_HAS_DRM_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+    if (other->drm != NULL) {
+	cairo_surface_t *drm;
 
-static cairo_status_t
-_cairo_xcb_surface_set_clip_region (void           *abstract_surface,
-				    cairo_region_t *region)
-{
-    cairo_xcb_surface_t *surface = abstract_surface;
+	drm = _cairo_drm_surface_create_similar (other->drm, content, width, height);
+	if (drm != NULL)
+	    return drm;
+    }
+#endif
 
-    if (region == surface->clip_region)
-	return CAIRO_STATUS_SUCCESS;
+    if ((other->flags & CAIRO_XCB_HAS_RENDER) == 0)
+	return _cairo_xcb_surface_create_similar_image (other, content, width, height);
 
-    cairo_region_destroy (surface->clip_region);
-    region = cairo_region_reference (region);
+    connection = other->connection;
+    status = _cairo_xcb_connection_acquire (connection);
+    if (unlikely (status))
+	return _cairo_surface_create_in_error (status);
 
-    if (surface->clip_rects) {
-	free (surface->clip_rects);
-	surface->clip_rects = NULL;
+    status =_cairo_xcb_connection_take_socket (connection);
+    if (unlikely (status)) {
+	_cairo_xcb_connection_release (connection);
+	return _cairo_surface_create_in_error (status);
     }
 
-    surface->have_clip_rects = FALSE;
-    surface->num_clip_rects = 0;
-
-    if (region == NULL) {
-	uint32_t none[] = { XCB_NONE };
-	if (surface->gc)
-	    xcb_change_gc (surface->dpy, surface->gc, XCB_GC_CLIP_MASK, none);
+    if (content == other->base.content) {
+	pixmap = _cairo_xcb_connection_create_pixmap (connection,
+						      other->depth,
+						      other->drawable,
+						      width, height);
 
-	if (surface->xrender_format.id != XCB_NONE && surface->dst_picture)
-	    xcb_render_change_picture (surface->dpy, surface->dst_picture,
-		XCB_RENDER_CP_CLIP_MASK, none);
+	surface = (cairo_xcb_surface_t *)
+	    _cairo_xcb_surface_create_internal (other->screen,
+						pixmap, TRUE,
+						other->pixman_format,
+						other->xrender_format,
+						width, height);
     } else {
-	xcb_rectangle_t *rects = NULL;
-	int n_rects, i;
-
-	n_rects = cairo_region_num_rectangles (region);
-
-	if (n_rects > 0) {
-	    rects = _cairo_malloc_ab (n_rects, sizeof(xcb_rectangle_t));
-	    if (rects == NULL)
-		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	} else {
-	    rects = NULL;
-	}
-
-	for (i = 0; i < n_rects; i++) {
-	    cairo_rectangle_int_t rect;
-
-	    cairo_region_get_rectangle (region, i, &rect);
-
-	    rects[i].x = rect.x;
-	    rects[i].y = rect.y;
-	    rects[i].width = rect.width;
-	    rects[i].height = rect.height;
+	cairo_format_t format;
+	pixman_format_code_t pixman_format;
+
+	/* XXX find a compatible xrender format */
+	switch (content) {
+	case CAIRO_CONTENT_ALPHA:
+	    pixman_format = PIXMAN_a8;
+	    format = CAIRO_FORMAT_A8;
+	    break;
+	case CAIRO_CONTENT_COLOR:
+	    pixman_format = PIXMAN_x8r8g8b8;
+	    format = CAIRO_FORMAT_RGB24;
+	    break;
+	default:
+	    ASSERT_NOT_REACHED;
+	case CAIRO_CONTENT_COLOR_ALPHA:
+	    pixman_format = PIXMAN_a8r8g8b8;
+	    format = CAIRO_FORMAT_ARGB32;
+	    break;
 	}
 
-	surface->have_clip_rects = TRUE;
-	surface->clip_rects = rects;
-	surface->num_clip_rects = n_rects;
-
-	if (surface->gc)
-	    _cairo_xcb_surface_set_gc_clip_rects (surface);
-
-	if (surface->dst_picture)
-	    _cairo_xcb_surface_set_picture_clip_rects (surface);
-    }
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_surface_t *
-_cairo_xcb_surface_create_similar (void		       *abstract_src,
-				   cairo_content_t	content,
-				   int			width,
-				   int			height)
-{
-    cairo_xcb_surface_t *src = abstract_src;
-    xcb_connection_t *dpy = src->dpy;
-    xcb_pixmap_t pixmap;
-    cairo_xcb_surface_t *surface;
-    cairo_format_t format = _cairo_format_from_content (content);
-    xcb_render_pictforminfo_t *xrender_format;
+	pixmap = _cairo_xcb_connection_create_pixmap (connection,
+						      PIXMAN_FORMAT_DEPTH (pixman_format),
+						      other->drawable,
+						      width, height);
 
-    /* As a good first approximation, if the display doesn't have COMPOSITE,
-     * we're better off using image surfaces for all temporary operations
-     */
-    if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (src)) {
-	return cairo_image_surface_create (format, width, height);
+	surface = (cairo_xcb_surface_t *)
+	    _cairo_xcb_surface_create_internal (other->screen,
+						pixmap, TRUE,
+						pixman_format,
+						connection->standard_formats[format],
+						width, height);
     }
 
-    pixmap = xcb_generate_id (dpy);
-    xcb_create_pixmap (dpy, _CAIRO_FORMAT_DEPTH (format),
-		     pixmap, src->drawable,
-		     width <= 0 ? 1 : width,
-		     height <= 0 ? 1 : height);
-
-    xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dpy, format);
-    /* XXX: what to do if xrender_format is null? */
-    surface = (cairo_xcb_surface_t *)
-	cairo_xcb_surface_create_with_xrender_format (dpy, pixmap, src->screen,
-						      xrender_format,
-						      width, height);
-    if (surface->base.status)
-	return &surface->base;
+    if (unlikely (surface->base.status))
+	_cairo_xcb_connection_free_pixmap (connection, pixmap);
 
-    surface->owns_pixmap = TRUE;
+    _cairo_xcb_connection_release (connection);
 
     return &surface->base;
 }
@@ -341,1826 +249,958 @@ static cairo_status_t
 _cairo_xcb_surface_finish (void *abstract_surface)
 {
     cairo_xcb_surface_t *surface = abstract_surface;
+    cairo_status_t status;
 
-    if (surface->dst_picture != XCB_NONE)
-	xcb_render_free_picture (surface->dpy, surface->dst_picture);
-
-    if (surface->src_picture != XCB_NONE)
-	xcb_render_free_picture (surface->dpy, surface->src_picture);
-
-    if (surface->owns_pixmap)
-	xcb_free_pixmap (surface->dpy, surface->drawable);
+    assert (surface->fallback == NULL);
 
-    if (surface->gc != XCB_NONE)
-	xcb_free_gc (surface->dpy, surface->gc);
+    cairo_list_del (&surface->link);
 
-    free (surface->clip_rects);
-    cairo_region_destroy (surface->clip_region);
+    if (surface->drm != NULL) {
+	cairo_surface_finish (surface->drm);
+	cairo_surface_destroy (surface->drm);
 
-    _cairo_freepool_fini (&surface->cookie_pool);
+	xcb_dri2_destroy_drawable (surface->connection->xcb_connection,
+				   surface->drawable);
+    }
 
-    surface->dpy = NULL;
+    status = _cairo_xcb_connection_acquire (surface->connection);
+    if (status == CAIRO_STATUS_SUCCESS) {
+	if (_cairo_xcb_connection_take_socket (surface->connection) == CAIRO_STATUS_SUCCESS) {
+	    if (surface->picture != XCB_NONE) {
+		_cairo_xcb_connection_render_free_picture (surface->connection,
+							   surface->picture);
+	    }
 
-    return CAIRO_STATUS_SUCCESS;
-}
+	    if (surface->owns_pixmap)
+		_cairo_xcb_connection_free_pixmap (surface->connection, surface->drawable);
+	}
+	_cairo_xcb_connection_release (surface->connection);
+    }
 
-static int
-_bits_per_pixel(xcb_connection_t *c, int depth)
-{
-    xcb_format_t *fmt = xcb_setup_pixmap_formats(xcb_get_setup(c));
-    xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length(xcb_get_setup(c));
-
-    for(; fmt != fmtend; ++fmt)
-	if(fmt->depth == depth)
-	    return fmt->bits_per_pixel;
-
-    if(depth <= 4)
-	return 4;
-    if(depth <= 8)
-	return 8;
-    if(depth <= 16)
-	return 16;
-    return 32;
-}
+    _cairo_xcb_connection_destroy (surface->connection);
 
-static int
-_bytes_per_line(xcb_connection_t *c, int width, int bpp)
-{
-    int bitmap_pad = xcb_get_setup(c)->bitmap_format_scanline_pad;
-    return ((bpp * width + bitmap_pad - 1) & -bitmap_pad) >> 3;
+    return status;
 }
 
-static cairo_bool_t
-_CAIRO_MASK_FORMAT (cairo_format_masks_t *masks, cairo_format_t *format)
+static void
+_destroy_image (pixman_image_t *image, void *data)
 {
-    switch (masks->bpp) {
-    case 32:
-	if (masks->alpha_mask == 0xff000000 &&
-	    masks->red_mask == 0x00ff0000 &&
-	    masks->green_mask == 0x0000ff00 &&
-	    masks->blue_mask == 0x000000ff)
-	{
-	    *format = CAIRO_FORMAT_ARGB32;
-	    return TRUE;
-	}
-	if (masks->alpha_mask == 0x00000000 &&
-	    masks->red_mask == 0x00ff0000 &&
-	    masks->green_mask == 0x0000ff00 &&
-	    masks->blue_mask == 0x000000ff)
-	{
-	    *format = CAIRO_FORMAT_RGB24;
-	    return TRUE;
-	}
-	break;
-    case 8:
-	if (masks->alpha_mask == 0xff)
-	{
-	    *format = CAIRO_FORMAT_A8;
-	    return TRUE;
-	}
-	break;
-    case 1:
-	if (masks->alpha_mask == 0x1)
-	{
-	    *format = CAIRO_FORMAT_A1;
-	    return TRUE;
-	}
-	break;
-    }
-    return FALSE;
+    free (data);
 }
 
-static cairo_status_t
-_get_image_surface (cairo_xcb_surface_t     *surface,
-		    cairo_rectangle_int_t   *interest_rect,
-		    cairo_image_surface_t  **image_out,
-		    cairo_rectangle_int_t   *image_rect)
+static cairo_int_status_t
+_cairo_xcb_surface_create_shm_image (cairo_xcb_surface_t *target,
+				     cairo_image_surface_t **image_out,
+				     cairo_xcb_shm_info_t **shm_info_out)
 {
     cairo_image_surface_t *image;
-    xcb_get_image_reply_t *imagerep;
-    int bpp, bytes_per_line;
-    cairo_rectangle_int_t extents;
-    unsigned char *data;
-    cairo_format_masks_t masks;
-    cairo_format_t format;
-
-    extents.x = 0;
-    extents.y = 0;
-    extents.width  = surface->width;
-    extents.height = surface->height;
-
-    if (interest_rect) {
-	if (! _cairo_rectangle_intersect (&extents, interest_rect)) {
-	    *image_out = NULL;
-	    return CAIRO_STATUS_SUCCESS;
-	}
-    }
-
-    if (image_rect)
-	*image_rect = extents;
-
-    /* XXX: This should try to use the XShm extension if available */
-
-    if (surface->use_pixmap == 0)
-    {
-	xcb_generic_error_t *error;
-
-	imagerep = xcb_get_image_reply (surface->dpy,
-					xcb_get_image (surface->dpy,
-						       XCB_IMAGE_FORMAT_Z_PIXMAP,
-						       surface->drawable,
-						       extents.x, extents.y,
-						       extents.width, extents.height,
-						       AllPlanes),
-					&error);
-
-	/* If we get an error, the surface must have been a window,
-	 * so retry with the safe code path.
-	 */
-	if (error)
-	    surface->use_pixmap = CAIRO_ASSUME_PIXMAP;
-    }
-    else
-    {
-	surface->use_pixmap--;
-	imagerep = NULL;
-    }
-
-    if (!imagerep)
-    {
-	/* xcb_get_image_t from a window is dangerous because it can
-	 * produce errors if the window is unmapped or partially
-	 * outside the screen. We could check for errors and
-	 * retry, but to keep things simple, we just create a
-	 * temporary pixmap
-	 */
-	xcb_pixmap_t pixmap;
-	cairo_xcb_cookie_t *cookies[2];
-	cairo_status_t status;
-
-	status = _cairo_xcb_surface_ensure_gc (surface);
-	if (unlikely (status))
-	    return status;
-
-	status = _cairo_freepool_alloc_array (&surface->cookie_pool,
-					      ARRAY_LENGTH (cookies),
-					      (void **) cookies);
-	if (unlikely (status))
-	    return status;
-
-	pixmap = xcb_generate_id (surface->dpy);
-	cookies[0]->xcb = xcb_create_pixmap_checked (surface->dpy,
-						     surface->depth,
-						     pixmap,
-						     surface->drawable,
-						     extents.width, extents.height);
-	cairo_list_add_tail (&cookies[0]->link, &surface->to_be_checked);
-
-	cookies[1]->xcb = xcb_copy_area_checked (surface->dpy,
-						 surface->drawable,
-						 pixmap, surface->gc,
-						 extents.x, extents.y,
-						 0, 0,
-						 extents.width, extents.height);
-	cairo_list_add_tail (&cookies[1]->link, &surface->to_be_checked);
-
-	imagerep = xcb_get_image_reply (surface->dpy,
-					xcb_get_image (surface->dpy,
-						       XCB_IMAGE_FORMAT_Z_PIXMAP,
-						       pixmap,
-						       extents.x, extents.y,
-						       extents.width, extents.height,
-						       AllPlanes),
-					0);
-
-	xcb_free_pixmap (surface->dpy, pixmap);
-
-    }
-    if (unlikely (imagerep == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    cairo_xcb_shm_info_t *shm_info;
+    cairo_status_t status;
+    size_t size, stride;
 
-    bpp = _bits_per_pixel(surface->dpy, imagerep->depth);
-    bytes_per_line = _bytes_per_line(surface->dpy, surface->width, bpp);
+    if ((target->flags & CAIRO_XCB_HAS_SHM) == 0)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    data = _cairo_malloc_ab (surface->height, bytes_per_line);
-    if (data == NULL) {
-	free (imagerep);
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    stride = CAIRO_STRIDE_FOR_WIDTH_BPP (target->width,
+					 PIXMAN_FORMAT_BPP (target->pixman_format));
+    size = stride * target->height;
+    if (size < CAIRO_XCB_SHM_SMALL_IMAGE) {
+	target->flags &= ~CAIRO_XCB_HAS_SHM;
+	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    memcpy (data, xcb_get_image_data (imagerep), bytes_per_line * surface->height);
-    free (imagerep);
+    status = _cairo_xcb_connection_allocate_shm_info (target->screen->connection,
+						      size, &shm_info);
+    if (unlikely (status))
+	return status;
 
-    /*
-     * Compute the pixel format masks from either an xcb_visualtype_t or
-     * a xcb_render_pctforminfo_t, failing we assume the drawable is an
-     * alpha-only pixmap as it could only have been created that way
-     * through the cairo_xlib_surface_create_for_bitmap function.
-     */
-    if (surface->visual) {
-	masks.bpp = bpp;
-	masks.alpha_mask = 0;
-	masks.red_mask = surface->visual->red_mask;
-	masks.green_mask = surface->visual->green_mask;
-	masks.blue_mask = surface->visual->blue_mask;
-    } else if (surface->xrender_format.id != XCB_NONE) {
-	masks.bpp = bpp;
-	masks.red_mask = (unsigned long)surface->xrender_format.direct.red_mask << surface->xrender_format.direct.red_shift;
-	masks.green_mask = (unsigned long)surface->xrender_format.direct.green_mask << surface->xrender_format.direct.green_shift;
-	masks.blue_mask = (unsigned long)surface->xrender_format.direct.blue_mask << surface->xrender_format.direct.blue_shift;
-	masks.alpha_mask = (unsigned long)surface->xrender_format.direct.alpha_mask << surface->xrender_format.direct.alpha_shift;
-    } else {
-	masks.bpp = bpp;
-	masks.red_mask = 0;
-	masks.green_mask = 0;
-	masks.blue_mask = 0;
-	if (surface->depth < 32)
-	    masks.alpha_mask = (1 << surface->depth) - 1;
-	else
-	    masks.alpha_mask = 0xffffffff;
+    image = (cairo_image_surface_t *)
+	_cairo_image_surface_create_with_pixman_format (shm_info->mem,
+							target->pixman_format,
+							target->width,
+							target->height,
+							stride);
+    status = image->base.status;
+    if (unlikely (status)) {
+	_cairo_xcb_shm_info_destroy (shm_info);
+	return status;
     }
 
-    /*
-     * Prefer to use a standard pixman format instead of the
-     * general masks case.
-     */
-    if (_CAIRO_MASK_FORMAT (&masks, &format)) {
-	image = (cairo_image_surface_t *)
-	    cairo_image_surface_create_for_data (data,
-						 format,
-						 extents.width,
-						 extents.height,
-						 bytes_per_line);
-	if (image->base.status)
-	    goto FAIL;
-    } else {
-	/*
-	 * XXX This can't work.  We must convert the data to one of the
-	 * supported pixman formats.  Pixman needs another function
-	 * which takes data in an arbitrary format and converts it
-	 * to something supported by that library.
-	 */
-	ASSERT_NOT_REACHED;
-	goto FAIL;
+    status = _cairo_user_data_array_set_data (&image->base.user_data,
+					      (const cairo_user_data_key_t *) target->connection,
+					      shm_info,
+					      (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy);
+    if (unlikely (status)) {
+	cairo_surface_destroy (&image->base);
+	_cairo_xcb_shm_info_destroy (shm_info);
+	return status;
     }
 
-    /* Let the surface take ownership of the data */
-    _cairo_image_surface_assume_ownership_of_data (image);
-
     *image_out = image;
+    *shm_info_out = shm_info;
     return CAIRO_STATUS_SUCCESS;
-
- FAIL:
-    free (data);
-    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 }
 
 static cairo_status_t
-_cairo_xcb_surface_ensure_src_picture (cairo_xcb_surface_t    *surface)
+_get_shm_image (cairo_xcb_surface_t     *surface,
+		cairo_image_surface_t  **image_out)
 {
-    if (!surface->src_picture) {
-	xcb_void_cookie_t cookie;
+    cairo_image_surface_t *image;
+    cairo_xcb_shm_info_t *shm_info;
+    cairo_status_t status;
 
-	surface->src_picture = xcb_generate_id (surface->dpy);
-	cookie = xcb_render_create_picture_checked (surface->dpy,
-						    surface->src_picture,
-						    surface->drawable,
-						    surface->xrender_format.id,
-						    0, NULL);
+    status = _cairo_xcb_surface_create_shm_image (surface, &image, &shm_info);
+    if (unlikely (status))
+	return status;
 
-	return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+    if (! surface->base.is_clear) {
+	status = _cairo_xcb_connection_shm_get_image (surface->connection,
+						      surface->drawable,
+						      0, 0,
+						      surface->width,
+						      surface->height,
+						      shm_info->shm,
+						      shm_info->offset);
+	if (unlikely (status))
+	    return status;
+    } else {
+	memset (image->data, 0, image->stride * image->height);
     }
 
+    *image_out = image;
     return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
-_cairo_xcb_surface_ensure_dst_picture (cairo_xcb_surface_t    *surface)
+_get_image (cairo_xcb_surface_t		 *surface,
+	    cairo_bool_t		  use_shm,
+	    cairo_image_surface_t	**image_out)
 {
-    if (!surface->dst_picture) {
-	xcb_void_cookie_t cookie;
+    cairo_image_surface_t *image;
+    cairo_xcb_connection_t *connection;
+    xcb_get_image_reply_t *reply;
+    cairo_status_t status;
+
+    connection = surface->connection;
+
+    status = _cairo_xcb_connection_acquire (connection);
+    if (unlikely (status))
+	return status;
 
-	surface->dst_picture = xcb_generate_id (surface->dpy);
-	cookie = xcb_render_create_picture_checked (surface->dpy,
-						    surface->dst_picture,
-						    surface->drawable,
-						    surface->xrender_format.id,
-						    0, NULL);
+    status = _cairo_xcb_connection_take_socket (connection);
+    if (unlikely (status))
+	goto FAIL;
 
-	return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+    if (use_shm) {
+	status = _get_shm_image (surface, image_out);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    goto FAIL;
     }
 
-    return CAIRO_STATUS_SUCCESS;
-}
+    if (surface->base.is_clear) {
+	image = (cairo_image_surface_t *)
+	    _cairo_image_surface_create_with_pixman_format (NULL,
+							    surface->pixman_format,
+							    surface->width,
+							    surface->height,
+							    0);
+	status = image->base.status;
+	*image_out = image;
+	goto FAIL;
+    }
 
-static cairo_status_t
-_cairo_xcb_surface_ensure_gc (cairo_xcb_surface_t *surface)
-{
-    xcb_void_cookie_t cookie;
+    if (surface->use_pixmap == 0) {
+	status = _cairo_xcb_connection_get_image (connection,
+						  surface->drawable,
+						  0, 0,
+						  surface->width,
+						  surface->height,
+						  &reply);
+	if (unlikely (status))
+	    goto FAIL;
+    } else {
+	surface->use_pixmap--;
+	reply = NULL;
+    }
 
-    if (surface->gc)
-	return CAIRO_STATUS_SUCCESS;
+    if (reply == NULL && ! surface->owns_pixmap) {
+	/* xcb_get_image_t from a window is dangerous because it can
+	 * produce errors if the window is unmapped or partially
+	 * outside the screen. We could check for errors and
+	 * retry, but to keep things simple, we just create a
+	 * temporary pixmap
+	 */
+	xcb_pixmap_t pixmap;
+	xcb_gcontext_t gc;
+
+	gc = _cairo_xcb_screen_get_gc (surface->screen,
+				       surface->drawable,
+				       surface->depth);
+	pixmap = _cairo_xcb_connection_create_pixmap (connection,
+						      surface->depth,
+						      surface->drawable,
+						      surface->width,
+						      surface->height);
+
+	/* XXX IncludeInferiors? */
+	_cairo_xcb_connection_copy_area (connection,
+					 surface->drawable,
+					 pixmap, gc,
+					 0, 0,
+					 0, 0,
+					 surface->width,
+					 surface->height);
 
-    surface->gc = xcb_generate_id(surface->dpy);
-    cookie = xcb_create_gc_checked (surface->dpy, surface->gc, surface->drawable, 0, 0);
-    _cairo_xcb_surface_set_gc_clip_rects (surface);
+	_cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);
 
-    return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
-}
+	status = _cairo_xcb_connection_get_image (connection,
+						  pixmap,
+						  0, 0,
+						  surface->width,
+						  surface->height,
+						  &reply);
+	_cairo_xcb_connection_free_pixmap (connection, pixmap);
 
-static cairo_status_t
-_draw_image_surface (cairo_xcb_surface_t    *surface,
-		     cairo_image_surface_t  *image,
-		     int                    src_x,
-		     int                    src_y,
-		     int                    width,
-		     int                    height,
-		     int                    dst_x,
-		     int                    dst_y)
-{
-    int bpp, bpl;
-    uint32_t data_len;
-    uint8_t *data, left_pad=0;
-    xcb_void_cookie_t cookie;
-
-    /* equivalent of XPutImage(..., src_x,src_y, dst_x,dst_y, width,height); */
-    /* XXX: assumes image and surface formats and depths are the same */
-    /* XXX: assumes depth is a multiple of 8 (not bitmap) */
-
-    /* fit src_{x,y,width,height} within image->{0,0,width,height} */
-    if (src_x < 0) {
-	width += src_x;
-	src_x = 0;
+	if (unlikely (status))
+	    goto FAIL;
     }
-    if (src_y < 0) {
-	height += src_y;
-	src_y = 0;
+
+    if (unlikely (reply == NULL)) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto FAIL;
     }
-    if (width + src_x > image->width)
-	width = image->width - src_x;
-    if (height + src_y > image->height)
-	height = image->height - src_y;
-    if (width <= 0 || height <= 0)
-	return CAIRO_STATUS_SUCCESS;
 
-    bpp = _bits_per_pixel(surface->dpy, image->depth);
-    /* XXX: could use bpl = image->stride? */
-    bpl = _bytes_per_line(surface->dpy, image->width, bpp);
+    /* XXX byte swap */
+    /* XXX format conversion */
+    assert (reply->depth == surface->depth);
 
-    if (src_x == 0 && width == image->width) {
-	/* can work in-place */
-	data_len = height * bpl;
-	data = image->data + src_y * bpl;
-    } else {
-	/* must copy {src_x,src_y,width,height} into new data */
-	int line = 0;
-	uint8_t *data_line, *image_line;
-	int data_bpl = _bytes_per_line(surface->dpy, width, bpp);
-	data_len = height * data_bpl;
-	data_line = data = malloc(data_len);
-	if (data == NULL)
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-	image_line = image->data + src_y * bpl + (src_x * bpp / 8);
-	while (line++ < height) {
-	    memcpy(data_line, image_line, data_bpl);
-	    data_line += data_bpl;
-	    image_line += bpl;
-	}
+    image = (cairo_image_surface_t *)
+	_cairo_image_surface_create_with_pixman_format
+	(xcb_get_image_data (reply),
+	 surface->pixman_format,
+	 surface->width,
+	 surface->height,
+	 CAIRO_STRIDE_FOR_WIDTH_BPP (surface->width,
+				     PIXMAN_FORMAT_BPP (surface->pixman_format)));
+    status = image->base.status;
+    if (unlikely (status)) {
+	free (reply);
+	goto FAIL;
     }
-    _cairo_xcb_surface_ensure_gc (surface);
-    cookie = xcb_put_image_checked (surface->dpy, XCB_IMAGE_FORMAT_Z_PIXMAP,
-				    surface->drawable, surface->gc,
-				    width, height,
-				    dst_x, dst_y,
-				    left_pad, image->depth,
-				    data_len, data);
-
-    if (data < image->data || data >= image->data + image->height * bpl)
-	free (data);
-
-    return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
-}
 
-static cairo_status_t
-_cairo_xcb_surface_acquire_source_image (void                    *abstract_surface,
-					 cairo_image_surface_t  **image_out,
-					 void                   **image_extra)
-{
-    cairo_xcb_surface_t *surface = abstract_surface;
-    cairo_image_surface_t *image;
-    cairo_status_t status;
+    assert (xcb_get_image_data_length (reply) == image->height * image->stride);
 
-    status = _get_image_surface (surface, NULL, &image, NULL);
-    if (status)
-	return status;
+    pixman_image_set_destroy_function (image->pixman_image, _destroy_image, reply);
 
-    *image_out = image;
-    *image_extra = NULL;
+    _cairo_xcb_connection_release (connection);
+
+    /* synchronisation point */
+    surface->marked_dirty = FALSE;
 
+    *image_out = image;
     return CAIRO_STATUS_SUCCESS;
+
+FAIL:
+    _cairo_xcb_connection_release (connection);
+    return status;
 }
 
-static cairo_surface_t *
-_cairo_xcb_surface_snapshot (void *abstract_surface)
+static cairo_status_t
+_cairo_xcb_surface_acquire_source_image (void *abstract_surface,
+					 cairo_image_surface_t **image_out,
+					 void **image_extra)
 {
     cairo_xcb_surface_t *surface = abstract_surface;
     cairo_image_surface_t *image;
     cairo_status_t status;
 
-    status = _get_image_surface (surface, NULL, &image, NULL);
-    if (unlikely (status))
-	return _cairo_surface_create_in_error (status);
+    if (surface->drm != NULL && ! surface->marked_dirty) {
+	return _cairo_surface_acquire_source_image (surface->drm,
+						    image_out, image_extra);
+    }
 
-    return &image->base;
-}
+    if (surface->fallback != NULL) {
+	image = (cairo_image_surface_t *) cairo_surface_reference (surface->fallback);
+	goto DONE;
+    }
 
-static void
-_cairo_xcb_surface_release_source_image (void                   *abstract_surface,
-					 cairo_image_surface_t  *image,
-					 void                   *image_extra)
-{
-    cairo_surface_destroy (&image->base);
-}
+    image = (cairo_image_surface_t *)
+	_cairo_surface_has_snapshot (&surface->base,
+				     &_cairo_image_surface_backend);
+    if (image != NULL) {
+	image = (cairo_image_surface_t *) cairo_surface_reference (&image->base);
+	goto DONE;
+    }
 
-static cairo_status_t
-_cairo_xcb_surface_acquire_dest_image (void                    *abstract_surface,
-				       cairo_rectangle_int_t   *interest_rect,
-				       cairo_image_surface_t  **image_out,
-				       cairo_rectangle_int_t   *image_rect_out,
-				       void                   **image_extra)
-{
-    cairo_xcb_surface_t *surface = abstract_surface;
-    cairo_image_surface_t *image;
-    cairo_status_t status;
+    status = _get_image (surface, FALSE, &image);
+    if (unlikely (status))
+	return status;
 
-    status = _get_image_surface (surface, interest_rect, &image, image_rect_out);
-    if (status)
+    status = _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
+    if (unlikely (status)) {
+	cairo_surface_destroy (&image->base);
 	return status;
+    }
 
+DONE:
     *image_out = image;
     *image_extra = NULL;
-
     return CAIRO_STATUS_SUCCESS;
 }
 
 static void
-_cairo_xcb_surface_release_dest_image (void                   *abstract_surface,
-				       cairo_rectangle_int_t  *interest_rect,
-				       cairo_image_surface_t  *image,
-				       cairo_rectangle_int_t  *image_rect,
-				       void                   *image_extra)
+_cairo_xcb_surface_release_source_image (void *abstract_surface,
+					 cairo_image_surface_t *image,
+					 void *image_extra)
 {
     cairo_xcb_surface_t *surface = abstract_surface;
 
-    /* ignore errors */
-    _draw_image_surface (surface, image, 0, 0, image->width, image->height,
-			 image_rect->x, image_rect->y);
+    if (surface->drm != NULL && ! surface->marked_dirty) {
+	return _cairo_surface_release_source_image (surface->drm,
+						    image, image_extra);
+    }
 
     cairo_surface_destroy (&image->base);
 }
 
-/*
- * Return whether two xcb surfaces share the same
- * screen.  Both core and Render drawing require this
- * when using multiple drawables in an operation.
- */
 static cairo_bool_t
-_cairo_xcb_surface_same_screen (cairo_xcb_surface_t *dst,
-				cairo_xcb_surface_t *src)
-{
-    return dst->dpy == src->dpy && dst->screen == src->screen;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_clone_similar (void			*abstract_surface,
-				  cairo_surface_t	*src,
-				  cairo_content_t	 content,
-				  int                    src_x,
-				  int                    src_y,
-				  int                    width,
-				  int                    height,
-				  int                   *clone_offset_x,
-				  int                   *clone_offset_y,
-				  cairo_surface_t     **clone_out)
+_cairo_xcb_surface_get_extents (void *abstract_surface,
+				cairo_rectangle_int_t *extents)
 {
     cairo_xcb_surface_t *surface = abstract_surface;
-    cairo_xcb_surface_t *clone;
-
-    if (src->backend == surface->base.backend ) {
-	cairo_xcb_surface_t *xcb_src = (cairo_xcb_surface_t *)src;
-
-	if (_cairo_xcb_surface_same_screen(surface, xcb_src)) {
-	    *clone_offset_x = 0;
-	    *clone_offset_y = 0;
-	    *clone_out = cairo_surface_reference (src);
-
-	    return CAIRO_STATUS_SUCCESS;
-	}
-    } else if (_cairo_surface_is_image (src)) {
-	cairo_image_surface_t *image_src = (cairo_image_surface_t *)src;
-	cairo_content_t content = _cairo_content_from_format (image_src->format);
-	cairo_status_t status;
-
-	if (surface->base.status)
-	    return surface->base.status;
-
-	clone = (cairo_xcb_surface_t *)
-	    _cairo_xcb_surface_create_similar (surface, content, width, height);
-	if (clone == NULL)
-	    return CAIRO_INT_STATUS_UNSUPPORTED;
-	if (clone->base.status)
-	    return clone->base.status;
-
-	status = _draw_image_surface (clone, image_src,
-		                      src_x, src_y,
-		                      width, height,
-				      0, 0);
-	if (status) {
-	    cairo_surface_destroy (&clone->base);
-	    return status;
-	}
-
-	*clone_offset_x = src_x;
-	*clone_offset_y = src_y;
-	*clone_out = &clone->base;
-
-	return CAIRO_STATUS_SUCCESS;
-    }
 
-    return CAIRO_INT_STATUS_UNSUPPORTED;
+    extents->x = extents->y = 0;
+    extents->width  = surface->width;
+    extents->height = surface->height;
+    return TRUE;
 }
 
-static cairo_status_t
-_cairo_xcb_surface_set_matrix (cairo_xcb_surface_t *surface,
-			       cairo_matrix_t	   *matrix)
+static void
+_cairo_xcb_surface_get_font_options (void *abstract_surface,
+				     cairo_font_options_t *options)
 {
-    xcb_render_transform_t xtransform;
-    xcb_void_cookie_t cookie;
-
-    xtransform.matrix11 = _cairo_fixed_16_16_from_double (matrix->xx);
-    xtransform.matrix12 = _cairo_fixed_16_16_from_double (matrix->xy);
-    xtransform.matrix13 = _cairo_fixed_16_16_from_double (matrix->x0);
-
-    xtransform.matrix21 = _cairo_fixed_16_16_from_double (matrix->yx);
-    xtransform.matrix22 = _cairo_fixed_16_16_from_double (matrix->yy);
-    xtransform.matrix23 = _cairo_fixed_16_16_from_double (matrix->y0);
-
-    xtransform.matrix31 = 0;
-    xtransform.matrix32 = 0;
-    xtransform.matrix33 = 1 << 16;
-
-    if (!CAIRO_SURFACE_RENDER_HAS_PICTURE_TRANSFORM (surface))
-    {
-	static const xcb_render_transform_t identity = {
-	    1 << 16, 0x00000, 0x00000,
-	    0x00000, 1 << 16, 0x00000,
-	    0x00000, 0x00000, 1 << 16
-	};
-
-	if (memcmp (&xtransform, &identity, sizeof (xcb_render_transform_t)) == 0)
-	    return CAIRO_STATUS_SUCCESS;
-
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-    }
-
-    cookie = xcb_render_set_picture_transform_checked (surface->dpy,
-						       surface->src_picture,
-						       xtransform);
-    return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+    /* XXX  copy from xlib */
+    _cairo_font_options_init_default (options);
 }
 
 static cairo_status_t
-_cairo_xcb_surface_set_filter (cairo_xcb_surface_t *surface,
-			       cairo_filter_t	   filter)
+_put_shm_image (cairo_xcb_surface_t    *surface,
+		xcb_gcontext_t		gc,
+		cairo_image_surface_t  *image)
 {
-    const char *render_filter;
-    xcb_void_cookie_t cookie;
-
-    if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
-    {
-	if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST)
-	    return CAIRO_STATUS_SUCCESS;
+    cairo_xcb_shm_info_t *shm_info;
 
+    shm_info = _cairo_user_data_array_get_data (&image->base.user_data,
+						(const cairo_user_data_key_t *) surface->connection);
+    if (shm_info == NULL)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
-    }
-
-    switch (filter) {
-    case CAIRO_FILTER_FAST:
-	render_filter = "fast";
-	break;
-    case CAIRO_FILTER_GOOD:
-	render_filter = "good";
-	break;
-    case CAIRO_FILTER_BEST:
-	render_filter = "best";
-	break;
-    case CAIRO_FILTER_NEAREST:
-	render_filter = "nearest";
-	break;
-    case CAIRO_FILTER_BILINEAR:
-	render_filter = "bilinear";
-	break;
-    case CAIRO_FILTER_GAUSSIAN:
-    default:
-	render_filter = "best";
-	break;
-    }
 
-    cookie = xcb_render_set_picture_filter_checked (surface->dpy, surface->src_picture,
-						    strlen(render_filter), render_filter,
-						    0, NULL);
+    shm_info->seqno =
+	_cairo_xcb_connection_shm_put_image (surface->connection,
+					     surface->drawable,
+					     gc,
+					     surface->width, surface->height,
+					     0, 0,
+					     image->width, image->height,
+					     0, 0,
+					     image->depth,
+					     shm_info->shm,
+					     shm_info->offset);
 
-    return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+    return CAIRO_STATUS_SUCCESS;
 }
 
 static cairo_status_t
-_cairo_xcb_surface_set_repeat (cairo_xcb_surface_t *surface, cairo_extend_t extend)
+_put_image (cairo_xcb_surface_t    *surface,
+	    cairo_image_surface_t  *image)
 {
-    uint32_t mask = XCB_RENDER_CP_REPEAT;
-    uint32_t pa[1];
-    xcb_void_cookie_t cookie;
-
-    switch (extend) {
-    case CAIRO_EXTEND_NONE:
-	pa[0] = XCB_RENDER_REPEAT_NONE;
-	break;
-
-    case CAIRO_EXTEND_REPEAT:
-	pa[0] = XCB_RENDER_REPEAT_NORMAL;
-	break;
-
-    case CAIRO_EXTEND_REFLECT:
-	if (!CAIRO_SURFACE_RENDER_HAS_REPEAT_REFLECT(surface))
-	    return CAIRO_INT_STATUS_UNSUPPORTED;
-
-	pa[0] = XCB_RENDER_REPEAT_REFLECT;
-	break;
-
-    case CAIRO_EXTEND_PAD:
-	if (!CAIRO_SURFACE_RENDER_HAS_REPEAT_PAD(surface))
-	    return CAIRO_INT_STATUS_UNSUPPORTED;
-
-	pa[0] = XCB_RENDER_REPEAT_PAD;
-	break;
-
-    default:
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-    }
-
-    cookie = xcb_render_change_picture_checked (surface->dpy, surface->src_picture,
-						mask, pa);
-    return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
-}
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
-static cairo_int_status_t
-_cairo_xcb_surface_set_attributes (cairo_xcb_surface_t	      *surface,
-				   cairo_surface_attributes_t *attributes)
-{
-    cairo_int_status_t status;
+    /* XXX track damaged region? */
 
-    status = _cairo_xcb_surface_ensure_src_picture (surface);
-    if (status)
+    status = _cairo_xcb_connection_acquire (surface->connection);
+    if (unlikely (status))
 	return status;
 
-    status = _cairo_xcb_surface_set_matrix (surface, &attributes->matrix);
-    if (status)
+    status = _cairo_xcb_connection_take_socket (surface->connection);
+    if (unlikely (status)) {
+	_cairo_xcb_connection_release (surface->connection);
 	return status;
+    }
 
-    status = _cairo_xcb_surface_set_repeat (surface, attributes->extend);
-    if (status)
-	return status;
+    if (image->pixman_format == surface->pixman_format) {
+	xcb_gcontext_t gc;
+
+	assert (image->width == surface->width);
+	assert (image->height == surface->height);
+	assert (image->depth == surface->depth);
+	assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format)));
+
+	gc = _cairo_xcb_screen_get_gc (surface->screen,
+				       surface->drawable,
+				       surface->depth);
+
+	status = _put_shm_image (surface, gc, image);
+	if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+	    _cairo_xcb_connection_put_image (surface->connection,
+					     surface->drawable, gc,
+					     image->width, image->height,
+					     0, 0,
+					     image->depth,
+					     image->stride,
+					     image->data);
+	    status = CAIRO_STATUS_SUCCESS;
+	}
 
-    status = _cairo_xcb_surface_set_filter (surface, attributes->filter);
-    if (status)
-	return status;
+	_cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc);
+    } else {
+	ASSERT_NOT_REACHED;
+    }
 
-    return CAIRO_STATUS_SUCCESS;
+    _cairo_xcb_connection_release (surface->connection);
+    return status;
 }
 
-/* Checks whether we can can directly draw from src to dst with
- * the core protocol: either with CopyArea or using src as a
- * a tile in a GC.
- */
-static cairo_bool_t
-_surfaces_compatible (cairo_xcb_surface_t *dst,
-		      cairo_xcb_surface_t *src)
+static cairo_status_t
+_cairo_xcb_surface_flush (void *abstract_surface)
 {
-    /* same screen */
-    if (!_cairo_xcb_surface_same_screen (dst, src))
-	return FALSE;
-
-    /* same depth (for core) */
-    if (src->depth != dst->depth)
-	return FALSE;
+    cairo_xcb_surface_t *surface = abstract_surface;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
-    /* if Render is supported, match picture formats */
-    if (src->xrender_format.id != dst->xrender_format.id)
-	return FALSE;
-    else if (src->xrender_format.id != XCB_NONE)
-	return TRUE;
+    if (surface->drm != NULL && ! surface->marked_dirty)
+	return surface->drm->backend->flush (surface->drm);
 
-    /* Without Render, match visuals instead */
-    if (src->visual == dst->visual)
-	return TRUE;
+    if (likely (surface->fallback == NULL))
+	return CAIRO_STATUS_SUCCESS;
 
-    return FALSE;
-}
+    if (! surface->base.finished) {
+	status = _put_image (surface,
+			     (cairo_image_surface_t *) surface->fallback);
 
-static cairo_bool_t
-_surface_has_alpha (cairo_xcb_surface_t *surface)
-{
-    if (surface->xrender_format.id != XCB_NONE) {
-	if (surface->xrender_format.type == XCB_RENDER_PICT_TYPE_DIRECT &&
-	    surface->xrender_format.direct.alpha_mask != 0)
-	    return TRUE;
-	else
-	    return FALSE;
-    } else {
+	if (status == CAIRO_STATUS_SUCCESS)
+	    status = cairo_surface_status (surface->fallback);
 
-	/* In the no-render case, we never have alpha */
-	return FALSE;
+	if (status == CAIRO_STATUS_SUCCESS) {
+	    status = _cairo_surface_attach_snapshot (&surface->base,
+						     surface->fallback,
+						     cairo_surface_finish);
+	}
     }
-}
 
-/* Returns true if the given operator and source-alpha combination
- * requires alpha compositing to complete.
- */
-static cairo_bool_t
-_operator_needs_alpha_composite (cairo_operator_t op,
-				 cairo_bool_t     surface_has_alpha)
-{
-    if (op == CAIRO_OPERATOR_SOURCE ||
-	(!surface_has_alpha &&
-	 (op == CAIRO_OPERATOR_OVER ||
-	  op == CAIRO_OPERATOR_ATOP ||
-	  op == CAIRO_OPERATOR_IN)))
-	return FALSE;
+    cairo_surface_destroy (surface->fallback);
+    surface->fallback = NULL;
 
-    return TRUE;
+    return status;
 }
 
-/* There is a bug in most older X servers with compositing using a
- * untransformed repeating source pattern when the source is in off-screen
- * video memory, and another with repeated transformed images using a
- * general transform matrix. When these bugs could be triggered, we need a
- * fallback: in the common case where we have no transformation and the
- * source and destination have the same format/visual, we can do the
- * operation using the core protocol for the first bug, otherwise, we need
- * a software fallback.
- *
- * We can also often optimize a compositing operation by calling XCopyArea
- * for some common cases where there is no alpha compositing to be done.
- * We figure that out here as well.
- */
-typedef enum {
-    DO_RENDER,		/* use render */
-    DO_XCOPYAREA,	/* core protocol XCopyArea optimization/fallback */
-    DO_XTILE,		/* core protocol XSetTile optimization/fallback */
-    DO_UNSUPPORTED	/* software fallback */
-} composite_operation_t;
-
-/* Initial check for the render bugs; we need to recheck for the
- * offscreen-memory bug after we turn patterns into surfaces, since that
- * may introduce a repeating pattern for gradient patterns.  We don't need
- * to check for the repeat+transform bug because gradient surfaces aren't
- * transformed.
- *
- * All we do here is reject cases where we *know* are going to
- * hit the bug and won't be able to use a core protocol fallback.
- */
-static composite_operation_t
-_categorize_composite_operation (cairo_xcb_surface_t	    *dst,
-				 cairo_operator_t	     op,
-				 const cairo_pattern_t	    *src_pattern,
-				 cairo_bool_t		     have_mask)
-
+static cairo_status_t
+_cairo_xcb_surface_mark_dirty (void *abstract_surface,
+			       int x, int y,
+			       int width, int height)
 {
-#if XXX_BUGGY_REPEAT
-    if (!dst->buggy_repeat)
-	return DO_RENDER;
-
-    if (src_pattern->type == CAIRO_PATTERN_TYPE_SURFACE)
-    {
-	cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *)src_pattern;
-
-	if (_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
-	    src_pattern->extend == CAIRO_EXTEND_REPEAT)
-	{
-	    /* This is the case where we have the bug involving
-	     * untransformed repeating source patterns with off-screen
-	     * video memory; reject some cases where a core protocol
-	     * fallback is impossible.
-	     */
-	    if (have_mask ||
-		!(op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER))
-		return DO_UNSUPPORTED;
-
-	    if (_cairo_surface_is_xcb (surface_pattern->surface)) {
-		cairo_xcb_surface_t *src = (cairo_xcb_surface_t *)surface_pattern->surface;
-
-		if (op == CAIRO_OPERATOR_OVER && _surface_has_alpha (src))
-		    return DO_UNSUPPORTED;
-
-		/* If these are on the same screen but otherwise incompatible,
-		 * make a copy as core drawing can't cross depths and doesn't
-		 * work rightacross visuals of the same depth
-		 */
-		if (_cairo_xcb_surface_same_screen (dst, src) &&
-		    !_surfaces_compatible (dst, src))
-		    return DO_UNSUPPORTED;
-	    }
-	}
-
-	/* Check for the other bug involving repeat patterns with general
-	 * transforms. */
-	if (!_cairo_matrix_is_integer_translation (&src_pattern->matrix, NULL, NULL) &&
-	    src_pattern->extend == CAIRO_EXTEND_REPEAT)
-	    return DO_UNSUPPORTED;
-    }
-#endif
-    return DO_RENDER;
+    cairo_xcb_surface_t *surface = abstract_surface;
+    surface->marked_dirty = TRUE;
+    return CAIRO_STATUS_SUCCESS;
 }
 
-/* Recheck for composite-repeat once we've turned patterns into Xlib surfaces
- * If we end up returning DO_UNSUPPORTED here, we're throwing away work we
- * did to turn gradients into a pattern, but most of the time we can handle
- * that case with core protocol fallback.
- *
- * Also check here if we can just use XCopyArea, instead of going through
- * Render.
- */
-static composite_operation_t
-_recategorize_composite_operation (cairo_xcb_surface_t	      *dst,
-				   cairo_operator_t	       op,
-				   cairo_xcb_surface_t	      *src,
-				   cairo_surface_attributes_t *src_attr,
-				   cairo_bool_t		       have_mask)
+static cairo_surface_t *
+_cairo_xcb_surface_map_to_image (cairo_xcb_surface_t *surface)
 {
-    cairo_bool_t is_integer_translation =
-	_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL);
-    cairo_bool_t needs_alpha_composite =
-	_operator_needs_alpha_composite (op, _surface_has_alpha (src));
-
-    if (!have_mask &&
-	is_integer_translation &&
-	src_attr->extend == CAIRO_EXTEND_NONE &&
-	!needs_alpha_composite &&
-	_surfaces_compatible(src, dst))
-    {
-	return DO_XCOPYAREA;
-    }
-#if XXX_BUGGY_REPEAT
-    if (!dst->buggy_repeat)
-	return DO_RENDER;
-
-    if (is_integer_translation &&
-	src_attr->extend == CAIRO_EXTEND_REPEAT &&
-	(src->width != 1 || src->height != 1))
-    {
-	if (!have_mask &&
-	    !needs_alpha_composite &&
-	    _surfaces_compatible (dst, src))
-	{
-	    return DO_XTILE;
-	}
+    cairo_status_t status;
+    cairo_image_surface_t *image;
 
-	return DO_UNSUPPORTED;
-    }
-#endif
-    return DO_RENDER;
-}
+    status = _get_image (surface, TRUE, &image);
+    if (unlikely (status))
+	return _cairo_surface_create_in_error (status);
 
-static int
-_render_operator (cairo_operator_t op)
-{
-    switch (op) {
-    case CAIRO_OPERATOR_CLEAR:
-	return XCB_RENDER_PICT_OP_CLEAR;
-    case CAIRO_OPERATOR_SOURCE:
-	return XCB_RENDER_PICT_OP_SRC;
-    case CAIRO_OPERATOR_DEST:
-	return XCB_RENDER_PICT_OP_DST;
-    case CAIRO_OPERATOR_OVER:
-	return XCB_RENDER_PICT_OP_OVER;
-    case CAIRO_OPERATOR_DEST_OVER:
-	return XCB_RENDER_PICT_OP_OVER_REVERSE;
-    case CAIRO_OPERATOR_IN:
-	return XCB_RENDER_PICT_OP_IN;
-    case CAIRO_OPERATOR_DEST_IN:
-	return XCB_RENDER_PICT_OP_IN_REVERSE;
-    case CAIRO_OPERATOR_OUT:
-	return XCB_RENDER_PICT_OP_OUT;
-    case CAIRO_OPERATOR_DEST_OUT:
-	return XCB_RENDER_PICT_OP_OUT_REVERSE;
-    case CAIRO_OPERATOR_ATOP:
-	return XCB_RENDER_PICT_OP_ATOP;
-    case CAIRO_OPERATOR_DEST_ATOP:
-	return XCB_RENDER_PICT_OP_ATOP_REVERSE;
-    case CAIRO_OPERATOR_XOR:
-	return XCB_RENDER_PICT_OP_XOR;
-    case CAIRO_OPERATOR_ADD:
-	return XCB_RENDER_PICT_OP_ADD;
-    case CAIRO_OPERATOR_SATURATE:
-	return XCB_RENDER_PICT_OP_SATURATE;
-    default:
-	return XCB_RENDER_PICT_OP_OVER;
-    }
+    return &image->base;
 }
 
 static cairo_int_status_t
-_cairo_xcb_surface_composite (cairo_operator_t		op,
-			      const cairo_pattern_t	*src_pattern,
-			      const cairo_pattern_t	*mask_pattern,
-			      void			*abstract_dst,
-			      int			src_x,
-			      int			src_y,
-			      int			mask_x,
-			      int			mask_y,
-			      int			dst_x,
-			      int			dst_y,
-			      unsigned int		width,
-			      unsigned int		height,
-			      cairo_region_t		*clip_region)
+_cairo_xcb_surface_paint (void			*abstract_surface,
+			  cairo_operator_t	 op,
+			  const cairo_pattern_t	*source,
+			  cairo_clip_t		*clip)
 {
-    cairo_surface_attributes_t	src_attr, mask_attr;
-    cairo_xcb_surface_t		*dst = abstract_dst;
-    cairo_xcb_surface_t		*src;
-    cairo_xcb_surface_t		*mask;
-    cairo_int_status_t		status;
-    composite_operation_t       operation;
-    int				itx, ity;
-    cairo_bool_t                is_integer_translation;
-    xcb_void_cookie_t		cookie;
-
-    if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    operation = _categorize_composite_operation (dst, op, src_pattern,
-						 mask_pattern != NULL);
-    if (operation == DO_UNSUPPORTED)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    status = _cairo_pattern_acquire_surfaces (src_pattern, mask_pattern,
-					      &dst->base,
-					      src_x, src_y,
-					      mask_x, mask_y,
-					      width, height,
-					      CAIRO_PATTERN_ACQUIRE_NO_REFLECT,
-					      (cairo_surface_t **) &src,
-					      (cairo_surface_t **) &mask,
-					      &src_attr, &mask_attr);
-    if (status)
-	return status;
-
-    operation = _recategorize_composite_operation (dst, op, src, &src_attr,
-						   mask_pattern != NULL);
-    if (operation == DO_UNSUPPORTED) {
-	status = CAIRO_INT_STATUS_UNSUPPORTED;
-	goto BAIL;
-    }
-
-    status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
-    if (unlikely (status))
-	goto BAIL;
+    cairo_xcb_surface_t *surface = abstract_surface;
+    cairo_status_t status;
 
-    status = _cairo_xcb_surface_set_attributes (src, &src_attr);
-    if (status)
-	goto BAIL;
+    if (surface->drm != NULL && ! surface->marked_dirty)
+	return _cairo_surface_paint (surface->drm, op, source, clip);
 
-    switch (operation)
-    {
-    case DO_RENDER:
-	status = _cairo_xcb_surface_ensure_dst_picture (dst);
-	if (unlikely (status))
-	    goto BAIL;
-
-	if (mask) {
-	    status = _cairo_xcb_surface_set_attributes (mask, &mask_attr);
-	    if (unlikely (status))
-		goto BAIL;
-
-	    cookie = xcb_render_composite_checked (dst->dpy,
-						   _render_operator (op),
-						   src->src_picture,
-						   mask->src_picture,
-						   dst->dst_picture,
-						   src_x + src_attr.x_offset,
-						   src_y + src_attr.y_offset,
-						   mask_x + mask_attr.x_offset,
-						   mask_y + mask_attr.y_offset,
-						   dst_x, dst_y,
-						   width, height);
-	} else {
-	    static xcb_render_picture_t maskpict = { XCB_NONE };
-
-	    cookie = xcb_render_composite_checked (dst->dpy,
-						   _render_operator (op),
-						   src->src_picture,
-						   maskpict,
-						   dst->dst_picture,
-						   src_x + src_attr.x_offset,
-						   src_y + src_attr.y_offset,
-						   0, 0,
-						   dst_x, dst_y,
-						   width, height);
-	}
-	break;
-
-    case DO_XCOPYAREA:
-	status = _cairo_xcb_surface_ensure_gc (dst);
-	if (unlikely (status))
+    if (surface->fallback == NULL) {
+	status = _cairo_xcb_surface_cairo_paint (surface, op, source, clip);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
 
-	cookie = xcb_copy_area_checked (dst->dpy,
-					src->drawable,
-					dst->drawable,
-					dst->gc,
-					src_x + src_attr.x_offset,
-					src_y + src_attr.y_offset,
-					dst_x, dst_y,
-					width, height);
-	break;
-
-    case DO_XTILE:
-	/* This case is only used for bug fallbacks, though it is theoretically
-	 * applicable to the case where we don't have the RENDER extension as
-	 * well.
-	 *
-	 * We've checked that we have a repeating unscaled source in
-	 * _recategorize_composite_operation.
-	 */
-
-	status = _cairo_xcb_surface_ensure_gc (dst);
-	if (unlikely (status))
+	status = _cairo_xcb_surface_render_paint (surface, op, source, clip);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    return status;
 
-	is_integer_translation =
-	    _cairo_matrix_is_integer_translation (&src_attr.matrix, &itx, &ity);
-	assert (is_integer_translation == TRUE);
-	{
-	    uint32_t mask = XCB_GC_FILL_STYLE | XCB_GC_TILE
-	                  | XCB_GC_TILE_STIPPLE_ORIGIN_X
-	                  | XCB_GC_TILE_STIPPLE_ORIGIN_Y;
-	    uint32_t values[] = {
-		XCB_FILL_STYLE_TILED, src->drawable,
-		- (itx + src_attr.x_offset),
-		- (ity + src_attr.y_offset)
-	    };
-	    xcb_rectangle_t rect = { dst_x, dst_y, width, height };
-
-	    xcb_change_gc( dst->dpy, dst->gc, mask, values );
-	    cookie = xcb_poly_fill_rectangle_checked (dst->dpy,
-						      dst->drawable,
-						      dst->gc,
-						      1, &rect);
-	}
-	break;
-
-    case DO_UNSUPPORTED:
-    default:
-	ASSERT_NOT_REACHED;
-    }
-
-    status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
-    if (unlikely (status))
-	goto BAIL;
-
-    if (!_cairo_operator_bounded_by_source (op)) {
-      status = _cairo_surface_composite_fixup_unbounded (&dst->base,
-							 &src_attr, src->width, src->height,
-							 mask ? &mask_attr : NULL,
-							 mask ? mask->width : 0,
-							 mask ? mask->height : 0,
-							 src_x, src_y,
-							 mask_x, mask_y,
-							 dst_x, dst_y, width, height,
-							 clip_region);
+	surface->fallback = _cairo_xcb_surface_map_to_image (surface);
     }
 
- BAIL:
-    if (mask)
-	_cairo_pattern_release_surface (mask_pattern, &mask->base, &mask_attr);
-
-    _cairo_pattern_release_surface (src_pattern, &src->base, &src_attr);
-
-    return status;
+    return _cairo_surface_paint (surface->fallback, op, source, clip);
 }
 
 static cairo_int_status_t
-_cairo_xcb_surface_fill_rectangles (void			     *abstract_surface,
-				     cairo_operator_t	      op,
-				     const cairo_color_t	*     color,
-				     cairo_rectangle_int_t *rects,
-				     int			      num_rects)
+_cairo_xcb_surface_mask (void			*abstract_surface,
+			 cairo_operator_t	 op,
+			 const cairo_pattern_t	*source,
+			 const cairo_pattern_t	*mask,
+			 cairo_clip_t		*clip)
 {
     cairo_xcb_surface_t *surface = abstract_surface;
-    xcb_render_color_t render_color;
-    xcb_rectangle_t static_xrects[16];
-    xcb_rectangle_t *xrects = static_xrects;
     cairo_status_t status;
-    xcb_void_cookie_t cookie;
-    int i;
-
-    if (!CAIRO_SURFACE_RENDER_HAS_FILL_RECTANGLE (surface))
-	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    render_color.red   = color->red_short;
-    render_color.green = color->green_short;
-    render_color.blue  = color->blue_short;
-    render_color.alpha = color->alpha_short;
+    if (surface->drm != NULL && ! surface->marked_dirty)
+	return _cairo_surface_mask (surface->drm, op, source, mask, clip);
 
-    status = _cairo_xcb_surface_set_clip_region (surface, NULL);
-    assert (status == CAIRO_STATUS_SUCCESS);
-
-    if (num_rects > ARRAY_LENGTH(static_xrects)) {
-        xrects = _cairo_malloc_ab (num_rects, sizeof(xcb_rectangle_t));
-	if (xrects == NULL)
-	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
+    if (surface->fallback == NULL) {
+	status =  _cairo_xcb_surface_cairo_mask (surface,
+						 op, source, mask, clip);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
 
-    for (i = 0; i < num_rects; i++) {
-        xrects[i].x = rects[i].x;
-        xrects[i].y = rects[i].y;
-        xrects[i].width = rects[i].width;
-        xrects[i].height = rects[i].height;
-    }
+	status =  _cairo_xcb_surface_render_mask (surface,
+						  op, source, mask, clip);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
 
-    status = _cairo_xcb_surface_ensure_dst_picture (surface);
-    if (unlikely (status)) {
-	if (xrects != static_xrects)
-	    free (xrects);
-	return status;
+	surface->fallback = _cairo_xcb_surface_map_to_image (surface);
     }
 
-    cookie = xcb_render_fill_rectangles_checked (surface->dpy,
-						 _render_operator (op),
-						 surface->dst_picture,
-						 render_color, num_rects, xrects);
-
-    if (xrects != static_xrects)
-        free (xrects);
-
-    return _cairo_xcb_add_cookie_to_be_checked (surface, cookie);
+    return _cairo_surface_mask (surface->fallback,
+				op, source, mask,
+				clip);
 }
 
-/* Creates an A8 picture of size @width x @height, initialized with @color
- */
-static cairo_status_t
-_create_a8_picture (cairo_xcb_surface_t *surface,
-		    xcb_render_color_t   *color,
-		    int                   width,
-		    int                   height,
-		    cairo_bool_t          repeat,
-		    xcb_render_picture_t    *out)
-{
-    uint32_t values[] = { TRUE };
-    uint32_t mask = repeat ? XCB_RENDER_CP_REPEAT : 0;
-
-    xcb_pixmap_t pixmap;
-    xcb_render_picture_t picture;
-    xcb_render_pictforminfo_t *format;
-    xcb_rectangle_t rect = { 0, 0, width, height };
-
-    cairo_xcb_cookie_t *cookie[3];
-    cairo_status_t status;
-
-    status = _cairo_freepool_alloc_array (&surface->cookie_pool,
-					  ARRAY_LENGTH (cookie),
-					  (void **) cookie);
-    if (unlikely (status))
-	return status;
-
-    pixmap = xcb_generate_id (surface->dpy);
-    picture = xcb_generate_id (surface->dpy);
-
-    cookie[0]->xcb = xcb_create_pixmap_checked (surface->dpy, 8, pixmap, surface->drawable,
-						width <= 0 ? 1 : width,
-						height <= 0 ? 1 : height);
-    cairo_list_add_tail (&cookie[0]->link, &surface->to_be_checked);
-
-    format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (surface->dpy, CAIRO_FORMAT_A8);
-    cookie[1]->xcb = xcb_render_create_picture_checked (surface->dpy,
-						picture, pixmap, format->id,
-						mask, values);
-    cairo_list_add_tail (&cookie[1]->link, &surface->to_be_checked);
-
-    cookie[2]->xcb = xcb_render_fill_rectangles_checked (surface->dpy,
-							 XCB_RENDER_PICT_OP_SRC,
-							 picture, *color, 1, &rect);
-    cairo_list_add_tail (&cookie[2]->link, &surface->to_be_checked);
-
-    xcb_free_pixmap (surface->dpy, pixmap);
-
-    *out = picture;
-    return CAIRO_STATUS_SUCCESS;
-}
-
-/* Creates a temporary mask for the trapezoids covering the area
- * [@dst_x, @dst_y, @width, @height] of the destination surface.
- */
-static cairo_status_t
-_create_trapezoid_mask (cairo_xcb_surface_t *dst,
-			cairo_trapezoid_t    *traps,
-			int                   num_traps,
-			int                   dst_x,
-			int                   dst_y,
-			int                   width,
-			int                   height,
-			xcb_render_pictforminfo_t *pict_format,
-			xcb_render_picture_t *mask_picture_out)
+static cairo_int_status_t
+_cairo_xcb_surface_stroke (void				*abstract_surface,
+			   cairo_operator_t		 op,
+			   const cairo_pattern_t	*source,
+			   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_clip_t			*clip)
 {
-    xcb_render_color_t transparent = { 0, 0, 0, 0 };
-    xcb_render_color_t solid = { 0xffff, 0xffff, 0xffff, 0xffff };
-    xcb_render_picture_t mask_picture, solid_picture;
-    xcb_render_trapezoid_t *offset_traps;
-    xcb_void_cookie_t cookie;
+    cairo_xcb_surface_t *surface = abstract_surface;
     cairo_status_t status;
-    int i;
-
-    /* This would be considerably simpler using XRenderAddTraps(), but since
-     * we are only using this in the unbounded-operator case, we stick with
-     * XRenderCompositeTrapezoids, which is available on older versions
-     * of RENDER rather than conditionalizing. We should still hit an
-     * optimization that avoids creating another intermediate surface on
-     * the servers that have XRenderAddTraps().
-     */
-    status = _create_a8_picture (dst, &transparent, width, height, FALSE, &mask_picture);
-    if (unlikely (status))
-	return status;
 
-    status = _create_a8_picture (dst, &solid, 1, 1, TRUE, &solid_picture);
-    if (unlikely (status)) {
-	xcb_render_free_picture (dst->dpy, mask_picture);
-	return status;
+    if (surface->drm != NULL && ! surface->marked_dirty) {
+	return _cairo_surface_stroke (surface->drm,
+				      op, source,
+				      path, style,
+				      ctm, ctm_inverse,
+				      tolerance, antialias,
+				      clip);
     }
 
-    offset_traps = _cairo_malloc_ab (num_traps, sizeof (xcb_render_trapezoid_t));
-    if (offset_traps == NULL) {
-	xcb_render_free_picture (dst->dpy, solid_picture);
-	xcb_render_free_picture (dst->dpy, mask_picture);
-	return	_cairo_error (CAIRO_STATUS_NO_MEMORY);
-    }
+    if (surface->fallback == NULL) {
+	status = _cairo_xcb_surface_cairo_stroke (surface, op, source,
+						  path, style,
+						  ctm, ctm_inverse,
+						  tolerance, antialias,
+						  clip);
 
-    for (i = 0; i < num_traps; i++) {
-	offset_traps[i].top = _cairo_fixed_to_16_16(traps[i].top) - 0x10000 * dst_y;
-	offset_traps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom) - 0x10000 * dst_y;
-	offset_traps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x) - 0x10000 * dst_x;
-	offset_traps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y) - 0x10000 * dst_y;
-	offset_traps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x) - 0x10000 * dst_x;
-	offset_traps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y) - 0x10000 * dst_y;
-	offset_traps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x) - 0x10000 * dst_x;
-	offset_traps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y) - 0x10000 * dst_y;
-	offset_traps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x) - 0x10000 * dst_x;
-        offset_traps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y) - 0x10000 * dst_y;
-    }
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
 
-    cookie = xcb_render_trapezoids_checked (dst->dpy, XCB_RENDER_PICT_OP_ADD,
-					    solid_picture, mask_picture,
-					    pict_format->id,
-					    0, 0,
-					    num_traps, offset_traps);
+	status = _cairo_xcb_surface_render_stroke (surface, op, source,
+						   path, style,
+						   ctm, ctm_inverse,
+						   tolerance, antialias,
+						   clip);
 
-    xcb_render_free_picture (dst->dpy, solid_picture);
-    free (offset_traps);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
 
-    status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
-    if (unlikely (status)) {
-	xcb_render_free_picture (dst->dpy, mask_picture);
-	return status;
+	surface->fallback = _cairo_xcb_surface_map_to_image (surface);
     }
 
-    *mask_picture_out = mask_picture;
-    return CAIRO_STATUS_SUCCESS;
+    return _cairo_surface_stroke (surface->fallback,
+				  op, source,
+				  path, style,
+				  ctm, ctm_inverse,
+				  tolerance, antialias,
+				  clip);
 }
 
 static cairo_int_status_t
-_cairo_xcb_surface_composite_trapezoids (cairo_operator_t	op,
-					 const cairo_pattern_t	*pattern,
-					 void			*abstract_dst,
-					 cairo_antialias_t	antialias,
-					 int			src_x,
-					 int			src_y,
-					 int			dst_x,
-					 int			dst_y,
-					 unsigned int		width,
-					 unsigned int		height,
-					 cairo_trapezoid_t	*traps,
-					 int			num_traps,
-					 cairo_region_t		*clip_region)
+_cairo_xcb_surface_fill (void			*abstract_surface,
+			 cairo_operator_t	 op,
+			 const cairo_pattern_t	*source,
+			 cairo_path_fixed_t	*path,
+			 cairo_fill_rule_t	 fill_rule,
+			 double			 tolerance,
+			 cairo_antialias_t	 antialias,
+			 cairo_clip_t		*clip)
 {
-    cairo_surface_attributes_t	attributes;
-    cairo_xcb_surface_t		*dst = abstract_dst;
-    cairo_xcb_surface_t		*src;
-    cairo_int_status_t		status;
-    composite_operation_t       operation;
-    int				render_reference_x, render_reference_y;
-    int				render_src_x, render_src_y;
-    int				cairo_format;
-    xcb_render_pictforminfo_t	*render_format;
-
-    if (!CAIRO_SURFACE_RENDER_HAS_TRAPEZOIDS (dst))
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    operation = _categorize_composite_operation (dst, op, pattern, TRUE);
-    if (operation == DO_UNSUPPORTED)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    status = _cairo_pattern_acquire_surface (pattern, &dst->base,
-					     src_x, src_y, width, height,
-					     CAIRO_PATTERN_ACQUIRE_NO_REFLECT,
-					     (cairo_surface_t **) &src,
-					     &attributes);
-    if (status)
-	return status;
-
-    operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE);
-    if (operation == DO_UNSUPPORTED) {
-	status = CAIRO_INT_STATUS_UNSUPPORTED;
-	goto BAIL;
-    }
-
-    switch (antialias) {
-    case CAIRO_ANTIALIAS_NONE:
-	cairo_format = CAIRO_FORMAT_A1;
-	break;
-    case CAIRO_ANTIALIAS_GRAY:
-    case CAIRO_ANTIALIAS_SUBPIXEL:
-    case CAIRO_ANTIALIAS_DEFAULT:
-    default:
-	cairo_format = CAIRO_FORMAT_A8;
-	break;
-    }
-    render_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dst->dpy, cairo_format);
-    /* XXX: what to do if render_format is null? */
+    cairo_xcb_surface_t *surface = abstract_surface;
+    cairo_status_t status;
 
-    if (traps[0].left.p1.y < traps[0].left.p2.y) {
-	render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p1.x);
-	render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p1.y);
-    } else {
-	render_reference_x = _cairo_fixed_integer_floor (traps[0].left.p2.x);
-	render_reference_y = _cairo_fixed_integer_floor (traps[0].left.p2.y);
+    if (surface->drm != NULL && ! surface->marked_dirty) {
+	return _cairo_surface_fill (surface->drm,
+				    op, source,
+				    path, fill_rule,
+				    tolerance, antialias,
+				    clip);
     }
 
-    render_src_x = src_x + render_reference_x - dst_x;
-    render_src_y = src_y + render_reference_y - dst_y;
-
-    status = _cairo_xcb_surface_ensure_dst_picture (dst);
-    if (unlikely (status))
-	goto BAIL;
-
-    status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
-    if (unlikely (status))
-	goto BAIL;
-
-    status = _cairo_xcb_surface_set_attributes (src, &attributes);
-    if (status)
-	goto BAIL;
-
-    if (!_cairo_operator_bounded_by_mask (op)) {
-	xcb_void_cookie_t cookie;
-
-	/* xcb_render_composite+trapezoids() creates a mask only large enough for the
-	 * trapezoids themselves, but if the operator is unbounded, then we need
-	 * to actually composite all the way out to the bounds, so we create
-	 * the mask and composite ourselves. There actually would
-	 * be benefit to doing this in all cases, since RENDER implementations
-	 * will frequently create a too temporary big mask, ignoring destination
-	 * bounds and clip. (xcb_render_add_traps() could be used to make creating
-	 * the mask somewhat cheaper.)
-	 */
-	xcb_render_picture_t mask_picture = 0; /* silence compiler */
-
-	status = _create_trapezoid_mask (dst, traps, num_traps,
-		                         dst_x, dst_y, width, height,
-					 render_format,
-					 &mask_picture);
-	if (status)
-	    goto BAIL;
-
-	cookie = xcb_render_composite_checked (dst->dpy,
-					       _render_operator (op),
-					       src->src_picture,
-					       mask_picture,
-					       dst->dst_picture,
-					       src_x + attributes.x_offset,
-					       src_y + attributes.y_offset,
-					       0, 0,
-					       dst_x, dst_y,
-					       width, height);
-	xcb_render_free_picture (dst->dpy, mask_picture);
-
-	status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
-	if (unlikely (status))
-	    goto BAIL;
+    if (surface->fallback == NULL) {
+	status = _cairo_xcb_surface_cairo_fill (surface, op, source,
+						path, fill_rule,
+						tolerance, antialias,
+						clip);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
 
-	status = _cairo_surface_composite_shape_fixup_unbounded (&dst->base,
-								 &attributes, src->width, src->height,
-								 width, height,
-								 src_x, src_y,
-								 0, 0,
-								 dst_x, dst_y, width, height,
-								 clip_region);
+	status = _cairo_xcb_surface_render_fill (surface, op, source,
+						 path, fill_rule,
+						 tolerance, antialias,
+						 clip);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
 
-    } else {
-        xcb_render_trapezoid_t xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (xcb_render_trapezoid_t)];
-        xcb_render_trapezoid_t *xtraps = xtraps_stack;
-	xcb_void_cookie_t cookie;
-        int i;
-
-        if (num_traps > ARRAY_LENGTH(xtraps_stack)) {
-            xtraps = _cairo_malloc_ab (num_traps, sizeof(xcb_render_trapezoid_t));
-            if (xtraps == NULL) {
-                status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-                goto BAIL;
-            }
-        }
-
-        for (i = 0; i < num_traps; i++) {
-            xtraps[i].top = _cairo_fixed_to_16_16(traps[i].top);
-            xtraps[i].bottom = _cairo_fixed_to_16_16(traps[i].bottom);
-            xtraps[i].left.p1.x = _cairo_fixed_to_16_16(traps[i].left.p1.x);
-            xtraps[i].left.p1.y = _cairo_fixed_to_16_16(traps[i].left.p1.y);
-            xtraps[i].left.p2.x = _cairo_fixed_to_16_16(traps[i].left.p2.x);
-            xtraps[i].left.p2.y = _cairo_fixed_to_16_16(traps[i].left.p2.y);
-            xtraps[i].right.p1.x = _cairo_fixed_to_16_16(traps[i].right.p1.x);
-            xtraps[i].right.p1.y = _cairo_fixed_to_16_16(traps[i].right.p1.y);
-            xtraps[i].right.p2.x = _cairo_fixed_to_16_16(traps[i].right.p2.x);
-            xtraps[i].right.p2.y = _cairo_fixed_to_16_16(traps[i].right.p2.y);
-        }
-
-	cookie = xcb_render_trapezoids_checked (dst->dpy,
-						_render_operator (op),
-						src->src_picture, dst->dst_picture,
-						render_format->id,
-						render_src_x + attributes.x_offset,
-						render_src_y + attributes.y_offset,
-						num_traps, xtraps);
-
-        if (xtraps != xtraps_stack)
-            free (xtraps);
-
-	status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
+	surface->fallback = _cairo_xcb_surface_map_to_image (surface);
     }
 
- BAIL:
-    _cairo_pattern_release_surface (pattern, &src->base, &attributes);
-
-    return status;
+    return _cairo_surface_fill (surface->fallback,
+				op, source,
+				path, fill_rule,
+				tolerance, antialias,
+				clip);
 }
 
-static cairo_bool_t
-_cairo_xcb_surface_get_extents (void		        *abstract_surface,
-				cairo_rectangle_int_t   *rectangle)
-{
-    cairo_xcb_surface_t *surface = abstract_surface;
-
-    rectangle->x = 0;
-    rectangle->y = 0;
-
-    rectangle->width  = surface->width;
-    rectangle->height = surface->height;
-
-    return TRUE;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_flush (void		        *abstract_surface)
+static cairo_int_status_t
+_cairo_xcb_surface_glyphs (void				*abstract_surface,
+			   cairo_operator_t		 op,
+			   const cairo_pattern_t	*source,
+			   cairo_glyph_t		*glyphs,
+			   int				 num_glyphs,
+			   cairo_scaled_font_t		*scaled_font,
+			   cairo_clip_t			*clip,
+			   int *num_remaining)
 {
     cairo_xcb_surface_t *surface = abstract_surface;
-    cairo_status_t status = CAIRO_STATUS_SUCCESS;
-
-    while (! cairo_list_is_empty (&surface->to_be_checked)) {
-	cairo_xcb_cookie_t *cookie;
-	xcb_generic_error_t *error;
-
-	cookie = cairo_list_first_entry (&surface->to_be_checked,
-					 cairo_xcb_cookie_t,
-					 link);
+    cairo_status_t status;
 
-	error = xcb_request_check (surface->dpy, cookie->xcb);
-	if (error != NULL) {
-#if 0
-	    /* XXX */
-	    fprintf (stderr, "Delayed error detected: %d, major=%d, minor=%d, seqno=%d\n",
-		     error->error_code,
-		     error->major_code,
-		     error->minor_code,
-		     error->sequence);
-#endif
-	    if (status == CAIRO_STATUS_SUCCESS)
-		status = _cairo_error (CAIRO_STATUS_WRITE_ERROR); /* XXX CAIRO_STATUS_CONNECTION_ERROR */
-	}
+    *num_remaining = 0;
 
-	cairo_list_del (&cookie->link);
-	_cairo_freepool_free (&surface->cookie_pool, cookie);
+    if (surface->drm != NULL && ! surface->marked_dirty) {
+	return _cairo_surface_show_text_glyphs (surface->drm,
+						op, source,
+						NULL, 0,
+						glyphs, num_glyphs,
+						NULL, 0, 0,
+						scaled_font,
+						clip);
     }
 
-    return status;
-}
-
-/* XXX: _cairo_xcb_surface_get_font_options */
-
-static void
-_cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
-
-static void
-_cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
-				       cairo_scaled_font_t  *scaled_font);
-
-static cairo_int_status_t
-_cairo_xcb_surface_show_glyphs (void			*abstract_dst,
-				cairo_operator_t	 op,
-				const cairo_pattern_t	*src_pattern,
-				cairo_glyph_t		*glyphs,
-				int			 num_glyphs,
-				cairo_scaled_font_t	*scaled_font,
-				cairo_clip_t		*clip,
-				int			*remaining_glyphs);
-
-static cairo_bool_t
-_cairo_xcb_surface_is_similar (void *surface_a,
-	                       void *surface_b,
-			       cairo_content_t content)
-{
-    cairo_xcb_surface_t *a = surface_a;
-    cairo_xcb_surface_t *b = surface_b;
-    xcb_render_pictforminfo_t *xrender_format;
-
-    /* XXX: disable caching by the solid pattern cache until we implement
-     * display notification to avoid issuing xcb calls from the wrong thread
-     * or accessing the surface after the Display has been closed.
-     */
-    return FALSE;
+    if (surface->fallback == NULL) {
+	status = _cairo_xcb_surface_cairo_glyphs (surface,
+						  op, source,
+						  scaled_font, glyphs, num_glyphs,
+						  clip);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
 
-    if (! _cairo_xcb_surface_same_screen (a, b))
-	return FALSE;
+	status = _cairo_xcb_surface_render_glyphs (surface,
+						   op, source,
+						   scaled_font, glyphs, num_glyphs,
+						   clip);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
 
-    /* now check that the target is a similar format */
-    xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (b->dpy,
-	    _cairo_format_from_content (content));
+	surface->fallback = _cairo_xcb_surface_map_to_image (surface);
+    }
 
-    return a->xrender_format.id == xrender_format->id;
+    return _cairo_surface_show_text_glyphs (surface->fallback,
+					    op, source,
+					    NULL, 0,
+					    glyphs, num_glyphs,
+					    NULL, 0, 0,
+					    scaled_font,
+					    clip);
 }
 
-/* XXX: move this to the bottom of the file, XCB and Xlib */
-
-static const cairo_surface_backend_t cairo_xcb_surface_backend = {
+const cairo_surface_backend_t _cairo_xcb_surface_backend = {
     CAIRO_SURFACE_TYPE_XCB,
 
     _cairo_xcb_surface_create_similar,
     _cairo_xcb_surface_finish,
     _cairo_xcb_surface_acquire_source_image,
     _cairo_xcb_surface_release_source_image,
+    NULL, NULL, NULL, /* dest acquire/release/clone */
 
-    _cairo_xcb_surface_acquire_dest_image,
-    _cairo_xcb_surface_release_dest_image,
-
-    _cairo_xcb_surface_clone_similar,
-    _cairo_xcb_surface_composite,
-    _cairo_xcb_surface_fill_rectangles,
-    _cairo_xcb_surface_composite_trapezoids,
-    NULL, /* create_span_renderer */
-    NULL, /* check_span_renderer */
+    NULL, /* composite */
+    NULL, /* fill */
+    NULL, /* trapezoids */
+    NULL, /* span */
+    NULL, /* check-span */
 
     NULL, /* copy_page */
     NULL, /* show_page */
-
     _cairo_xcb_surface_get_extents,
-    NULL, /* old_show_glyphs */
-    NULL, /* get_font_options */
+    NULL, /* old-glyphs */
+    _cairo_xcb_surface_get_font_options,
+
     _cairo_xcb_surface_flush,
-    NULL, /* mark_dirty_rectangle */
+    _cairo_xcb_surface_mark_dirty,
     _cairo_xcb_surface_scaled_font_fini,
     _cairo_xcb_surface_scaled_glyph_fini,
 
-    NULL, /* paint */
-    NULL, /* mask */
-    NULL, /* stroke */
-    NULL, /* fill */
-    _cairo_xcb_surface_show_glyphs,
-
-    _cairo_xcb_surface_snapshot,
-
-    _cairo_xcb_surface_is_similar,
+    _cairo_xcb_surface_paint,
+    _cairo_xcb_surface_mask,
+    _cairo_xcb_surface_stroke,
+    _cairo_xcb_surface_fill,
+    _cairo_xcb_surface_glyphs,
 };
 
-/**
- * _cairo_surface_is_xcb:
- * @surface: a #cairo_surface_t
- *
- * Checks if a surface is a #cairo_xcb_surface_t
- *
- * Return value: True if the surface is an xcb surface
- **/
-static cairo_bool_t
-_cairo_surface_is_xcb (cairo_surface_t *surface)
+#if CAIRO_HAS_DRM_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+static cairo_surface_t *
+_xcb_drm_create_surface_for_drawable (cairo_xcb_connection_t *connection,
+				      cairo_xcb_screen_t *screen,
+				      xcb_drawable_t drawable,
+				      pixman_format_code_t pixman_format,
+				      int width, int height)
 {
-    return surface->backend == &cairo_xcb_surface_backend;
+    uint32_t attachments[] = { XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT };
+    xcb_dri2_get_buffers_reply_t *buffers;
+    xcb_dri2_dri2_buffer_t *buffer;
+    cairo_surface_t *surface;
+
+    if (! _cairo_drm_size_is_valid (screen->device, width, height))
+	return NULL;
+
+    xcb_dri2_create_drawable (connection->xcb_connection,
+			      drawable);
+
+    buffers = xcb_dri2_get_buffers_reply (connection->xcb_connection,
+					  xcb_dri2_get_buffers (connection->xcb_connection,
+								drawable, 1,
+								ARRAY_LENGTH (attachments),
+								attachments),
+					  0);
+    if (buffers == NULL) {
+	xcb_dri2_destroy_drawable (connection->xcb_connection,
+				   drawable);
+	return NULL;
+    }
+
+    /* If the drawable is a window, we expect to receive an extra fake front,
+     * which would involve copying on each flush - contrary to the user
+     * expectations. But that is likely to be preferable to mixing drm/xcb
+     * operations.
+     */
+    buffer = xcb_dri2_get_buffers_buffers (buffers);
+    if (buffers->count == 1 && buffer[0].attachment == XCB_DRI2_ATTACHMENT_BUFFER_FRONT_LEFT) {
+	assert (buffer[0].cpp == PIXMAN_FORMAT_BPP (pixman_format) / 8);
+	surface = cairo_drm_surface_create_for_name (screen->device,
+						     buffer[0].name,
+						     _cairo_format_from_pixman_format (pixman_format),
+						     width, height,
+						     buffer[0].pitch);
+    } else {
+	xcb_dri2_destroy_drawable (connection->xcb_connection,
+				   drawable);
+	surface = NULL;
+    }
+    free (buffers);
+
+    return surface;
 }
 
+#else
+
 static cairo_surface_t *
-_cairo_xcb_surface_create_internal (xcb_connection_t	     *dpy,
-				    xcb_drawable_t		      drawable,
-				    xcb_screen_t		     *screen,
-				    xcb_visualtype_t	     *visual,
-				    xcb_render_pictforminfo_t    *xrender_format,
-				    int			      width,
-				    int			      height,
-				    int			      depth)
+_xcb_drm_create_surface_for_drawable (cairo_xcb_connection_t *connection,
+				      cairo_xcb_screen_t *screen,
+				      xcb_drawable_t drawable,
+				      pixman_format_code_t pixman_format,
+				      int width, int height)
+{
+    return NULL;
+}
+
+#endif
+
+cairo_surface_t *
+_cairo_xcb_surface_create_internal (cairo_xcb_screen_t		*screen,
+				    xcb_drawable_t		 drawable,
+				    cairo_bool_t		 owns_pixmap,
+				    pixman_format_code_t	 pixman_format,
+				    xcb_render_pictformat_t	 xrender_format,
+				    int				 width,
+				    int				 height)
 {
     cairo_xcb_surface_t *surface;
-    const xcb_query_extension_reply_t *er;
-    const xcb_render_query_version_reply_t *r = NULL;
 
     surface = malloc (sizeof (cairo_xcb_surface_t));
-    if (surface == NULL)
+    if (unlikely (surface == NULL))
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    if (xrender_format) {
-	depth = xrender_format->depth;
-    } else if (visual) {
-	xcb_depth_iterator_t depths;
-	xcb_visualtype_iterator_t visuals;
-
-	/* This is ugly, but we have to walk over all visuals
-	 * for the screen to find the depth.
-	 */
-	depths = xcb_screen_allowed_depths_iterator(screen);
-	for(; depths.rem; xcb_depth_next(&depths))
-	{
-	    visuals = xcb_depth_visuals_iterator(depths.data);
-	    for(; visuals.rem; xcb_visualtype_next(&visuals))
-	    {
-		if(visuals.data->visual_id == visual->visual_id)
-		{
-		    depth = depths.data->depth;
-		    goto found;
-		}
-	    }
-	}
-    found:
-	;
-    }
-
-    er = xcb_get_extension_data(dpy, &xcb_render_id);
-    if(er && er->present) {
-	r = xcb_render_util_query_version(dpy);
-    }
-    if (r) {
-	surface->render_major = r->major_version;
-	surface->render_minor = r->minor_version;
-    } else {
-	surface->render_major = -1;
-	surface->render_minor = -1;
-    }
-
-    if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
-	if (!xrender_format) {
-	    if (visual) {
-		const xcb_render_query_pict_formats_reply_t *formats;
-		xcb_render_pictvisual_t *pict_visual;
-		formats = xcb_render_util_query_formats (dpy);
-		pict_visual = xcb_render_util_find_visual_format (formats, visual->visual_id);
-		if (pict_visual) {
-		    xcb_render_pictforminfo_t template;
-		    template.id = pict_visual->format;
-		    xrender_format = xcb_render_util_find_format (formats, XCB_PICT_FORMAT_ID, &template, 0);
-		}
-	    } else if (depth == 1) {
-		xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT (dpy, CAIRO_FORMAT_A1);
-	    }
-	}
-    } else {
-	xrender_format = NULL;
-    }
-
     _cairo_surface_init (&surface->base,
-			 &cairo_xcb_surface_backend,
-			 NULL, /* device */
-			 _xcb_render_format_to_content (xrender_format));
+			 &_cairo_xcb_surface_backend,
+			 &screen->connection->device,
+			 _cairo_content_from_pixman_format (pixman_format));
+
+    surface->connection = _cairo_xcb_connection_reference (screen->connection);
+    surface->screen = screen;
+    cairo_list_add (&surface->link, &screen->surfaces);
 
-    surface->dpy = dpy;
+    surface->fallback = NULL;
 
-    surface->gc = XCB_NONE;
     surface->drawable = drawable;
-    surface->screen = screen;
-    surface->owns_pixmap = FALSE;
+    surface->owns_pixmap = owns_pixmap;
     surface->use_pixmap = 0;
-    surface->width = width;
-    surface->height = height;
 
-    /* XXX: set buggy_repeat based on ServerVendor and VendorRelease */
+    surface->width  = width;
+    surface->height = height;
+    surface->depth  = PIXMAN_FORMAT_DEPTH (pixman_format);
 
-    surface->dst_picture = XCB_NONE;
-    surface->src_picture = XCB_NONE;
+    surface->picture = XCB_NONE;
 
-    surface->visual = visual;
-    surface->xrender_format.id = XCB_NONE;
-    if (xrender_format) surface->xrender_format = *xrender_format;
-    surface->depth = depth;
+    surface->pixman_format = pixman_format;
+    surface->xrender_format = xrender_format;
 
-    surface->have_clip_rects = FALSE;
-    surface->clip_rects = NULL;
-    surface->num_clip_rects = 0;
-    surface->clip_region = NULL;
+    surface->flags = screen->connection->flags;
 
-    cairo_list_init (&surface->to_be_checked);
-    _cairo_freepool_init (&surface->cookie_pool,
-			  sizeof (cairo_xcb_cookie_t));
+    surface->marked_dirty = FALSE;
+    surface->drm = NULL;
+    if (screen->device != NULL) {
+	surface->drm = _xcb_drm_create_surface_for_drawable (surface->connection,
+							     surface->screen,
+							     drawable,
+							     pixman_format,
+							     width, height);
+    }
 
     return &surface->base;
 }
 
 static xcb_screen_t *
-_cairo_xcb_screen_from_visual (xcb_connection_t *c, xcb_visualtype_t *visual)
+_cairo_xcb_screen_from_visual (xcb_connection_t *connection,
+			       xcb_visualtype_t *visual,
+			       int *depth)
 {
     xcb_depth_iterator_t d;
-    xcb_screen_iterator_t s = xcb_setup_roots_iterator(xcb_get_setup(c));
-    for (; s.rem; xcb_screen_next(&s))
-    {
-	if (s.data->root_visual == visual->visual_id)
+    xcb_screen_iterator_t s;
+
+    s = xcb_setup_roots_iterator (xcb_get_setup (connection));
+    for (; s.rem; xcb_screen_next (&s)) {
+	if (s.data->root_visual == visual->visual_id) {
+	    *depth = s.data->root_depth;
 	    return s.data;
+	}
 
 	d = xcb_screen_allowed_depths_iterator(s.data);
-	for (; d.rem; xcb_depth_next(&d))
-	{
-	    xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator(d.data);
-	    for (; v.rem; xcb_visualtype_next(&v))
-	    {
-		if (v.data->visual_id == visual->visual_id)
+	for (; d.rem; xcb_depth_next (&d)) {
+	    xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator (d.data);
+
+	    for (; v.rem; xcb_visualtype_next (&v)) {
+		if (v.data->visual_id == visual->visual_id) {
+		    *depth = d.data->depth;
 		    return s.data;
+		}
 	    }
 	}
     }
+
     return NULL;
 }
 
-/**
- * cairo_xcb_surface_create:
- * @c: an XCB connection
- * @drawable: an XCB drawable
- * @visual: the visual to use for drawing to @drawable. The depth
- *          of the visual must match the depth of the drawable.
- *          Currently, only TrueColor visuals are fully supported.
- * @width: the current width of @drawable.
- * @height: the current height of @drawable.
- *
- * Creates an XCB surface that draws to the given drawable.
- * The way that colors are represented in the drawable is specified
- * by the provided visual.
- *
- * Note: If @drawable is a window, then the function
- * cairo_xcb_surface_set_size() must be called whenever the size of the
- * window changes.
- *
- * Return value: the newly created surface
- **/
 cairo_surface_t *
-cairo_xcb_surface_create (xcb_connection_t *c,
-			  xcb_drawable_t	 drawable,
-			  xcb_visualtype_t *visual,
-			  int		 width,
-			  int		 height)
+cairo_xcb_surface_create (xcb_connection_t  *xcb_connection,
+			  xcb_drawable_t     drawable,
+			  xcb_visualtype_t  *visual,
+			  int		     width,
+			  int		     height)
 {
-    xcb_screen_t	*screen = _cairo_xcb_screen_from_visual (c, visual);
+    cairo_xcb_screen_t *screen;
+    xcb_screen_t *xcb_screen;
+    cairo_format_masks_t image_masks;
+    pixman_format_code_t pixman_format;
+    xcb_render_pictformat_t xrender_format;
+    int depth;
 
-    if (screen == NULL)
-	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
+    if (xcb_connection_has_error (xcb_connection))
+	return _cairo_surface_create_in_error (CAIRO_STATUS_WRITE_ERROR);
+
+    if (unlikely (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX))
+	return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
+
+    xcb_screen = _cairo_xcb_screen_from_visual (xcb_connection, visual, &depth);
+    if (unlikely (xcb_screen == NULL))
+	return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_VISUAL);
+
+    image_masks.alpha_mask = 0;
+    image_masks.red_mask   = visual->red_mask;
+    image_masks.green_mask = visual->green_mask;
+    image_masks.blue_mask  = visual->blue_mask;
+    if (depth > 16)
+	image_masks.bpp = 32;
+    else if (depth > 8)
+	image_masks.bpp = 16;
+    else if (depth > 1)
+	image_masks.bpp = 8;
+    else
+	image_masks.bpp = 1;
 
-    return _cairo_xcb_surface_create_internal (c, drawable, screen,
-					       visual, NULL,
-					       width, height, 0);
+    if (! _pixman_format_from_masks (&image_masks, &pixman_format))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+
+    screen = _cairo_xcb_screen_get (xcb_connection, xcb_screen);
+    if (unlikely (screen == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    xrender_format =
+	_cairo_xcb_connection_get_xrender_format_for_visual (screen->connection,
+							     visual->visual_id);
+
+    return _cairo_xcb_surface_create_internal (screen, drawable, FALSE,
+					       pixman_format,
+					       xrender_format,
+					       width, height);
 }
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+slim_hidden_def (cairo_xcb_surface_create);
+#endif
 
-/**
- * cairo_xcb_surface_create_for_bitmap:
- * @c: an XCB connection
- * @bitmap: an XCB Pixmap (a depth-1 pixmap)
- * @screen: an XCB Screen
- * @width: the current width of @bitmap
- * @height: the current height of @bitmap
- *
- * Creates an XCB surface that draws to the given bitmap.
- * This will be drawn to as a %CAIRO_FORMAT_A1 object.
- *
- * Return value: the newly created surface
- **/
 cairo_surface_t *
-cairo_xcb_surface_create_for_bitmap (xcb_connection_t     *c,
-				     xcb_pixmap_t		bitmap,
-				     xcb_screen_t	       *screen,
-				     int		width,
-				     int		height)
+cairo_xcb_surface_create_for_bitmap (xcb_connection_t	*xcb_connection,
+				     xcb_screen_t	*xcb_screen,
+				     xcb_pixmap_t	 bitmap,
+				     int		 width,
+				     int		 height)
 {
-    return _cairo_xcb_surface_create_internal (c, bitmap, screen,
-					       NULL, NULL,
-					       width, height, 1);
+    cairo_xcb_screen_t *screen;
+
+    if (xcb_connection_has_error (xcb_connection))
+	return _cairo_surface_create_in_error (CAIRO_STATUS_WRITE_ERROR);
+
+    if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
+	return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
+
+    screen = _cairo_xcb_screen_get (xcb_connection, xcb_screen);
+    if (unlikely (screen == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    return _cairo_xcb_surface_create_internal (screen, bitmap, FALSE,
+					       PIXMAN_a1,
+					       screen->connection->standard_formats[CAIRO_FORMAT_A1],
+					       width, height);
 }
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+slim_hidden_def (cairo_xcb_surface_create_for_bitmap);
+#endif
 
 /**
  * cairo_xcb_surface_create_with_xrender_format:
- * @c: an XCB connection
+ * @connection: an XCB connection
  * @drawable: an XCB drawable
  * @screen: the XCB screen associated with @drawable
  * @format: the picture format to use for drawing to @drawable. The
@@ -2179,18 +1219,61 @@ cairo_xcb_surface_create_for_bitmap (xcb_connection_t     *c,
  * Return value: the newly created surface.
  **/
 cairo_surface_t *
-cairo_xcb_surface_create_with_xrender_format (xcb_connection_t	    *c,
+cairo_xcb_surface_create_with_xrender_format (xcb_connection_t	    *xcb_connection,
+					      xcb_screen_t	    *xcb_screen,
 					      xcb_drawable_t	     drawable,
-					      xcb_screen_t		    *screen,
 					      xcb_render_pictforminfo_t *format,
 					      int		     width,
 					      int		     height)
 {
-    return _cairo_xcb_surface_create_internal (c, drawable, screen,
-					       NULL, format,
-					       width, height, 0);
+    cairo_xcb_screen_t *screen;
+    cairo_format_masks_t image_masks;
+    pixman_format_code_t pixman_format;
+
+    if (xcb_connection_has_error (xcb_connection))
+	return _cairo_surface_create_in_error (CAIRO_STATUS_WRITE_ERROR);
+
+    if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)
+	return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE);
+
+    image_masks.alpha_mask =
+	(unsigned long) format->direct.alpha_mask << format->direct.alpha_shift;
+    image_masks.red_mask =
+	(unsigned long) format->direct.red_mask << format->direct.red_shift;
+    image_masks.green_mask =
+	(unsigned long) format->direct.green_mask << format->direct.green_shift;
+    image_masks.blue_mask =
+	(unsigned long) format->direct.blue_mask << format->direct.blue_shift;
+#if 0
+    image_masks.bpp = format->depth;
+#else
+    if (format->depth > 16)
+	image_masks.bpp = 32;
+    else if (format->depth > 8)
+	image_masks.bpp = 16;
+    else if (format->depth > 1)
+	image_masks.bpp = 8;
+    else
+	image_masks.bpp = 1;
+#endif
+
+    if (! _pixman_format_from_masks (&image_masks, &pixman_format))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+
+    screen = _cairo_xcb_screen_get (xcb_connection, xcb_screen);
+    if (unlikely (screen == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    return _cairo_xcb_surface_create_internal (screen,
+					       drawable,
+					       FALSE,
+					       pixman_format,
+					       format->id,
+					       width, height);
 }
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
 slim_hidden_def (cairo_xcb_surface_create_with_xrender_format);
+#endif
 
 /**
  * cairo_xcb_surface_set_size:
@@ -2210,613 +1293,28 @@ slim_hidden_def (cairo_xcb_surface_create_with_xrender_format);
  **/
 void
 cairo_xcb_surface_set_size (cairo_surface_t *abstract_surface,
-			     int              width,
-			     int              height)
+			    int              width,
+			    int              height)
 {
-    cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) abstract_surface;
+    cairo_xcb_surface_t *surface;
     cairo_status_t status_ignored;
 
-    if (! _cairo_surface_is_xcb (abstract_surface)) {
+    if (abstract_surface->type != CAIRO_SURFACE_TYPE_XCB) {
 	status_ignored = _cairo_surface_set_error (abstract_surface,
-				  CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+						   CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
 	return;
     }
 
-    surface->width = width;
-    surface->height = height;
-}
-
-/*
- *  Glyph rendering support
- */
-
-typedef struct _cairo_xcb_surface_font_private {
-    xcb_connection_t		*dpy;
-    xcb_render_glyphset_t	glyphset;
-    cairo_format_t		format;
-    xcb_render_pictforminfo_t	*xrender_format;
-} cairo_xcb_surface_font_private_t;
-
-static cairo_status_t
-_cairo_xcb_surface_font_init (xcb_connection_t		    *dpy,
-			       cairo_scaled_font_t  *scaled_font,
-			       cairo_format_t	     format)
-{
-    cairo_xcb_surface_font_private_t	*font_private;
-
-    font_private = malloc (sizeof (cairo_xcb_surface_font_private_t));
-    if (!font_private)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    font_private->dpy = dpy;
-    font_private->format = format;
-    font_private->xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT(dpy, format);
-    font_private->glyphset = xcb_generate_id(dpy);
-
-    /* XXX checking, adding to CloseDisplay */
-    xcb_render_create_glyph_set (dpy,
-				 font_private->glyphset,
-				 font_private->xrender_format->id);
-
-    scaled_font->surface_private = font_private;
-    scaled_font->surface_backend = &cairo_xcb_surface_backend;
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static void
-_cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
-{
-    cairo_xcb_surface_font_private_t	*font_private = scaled_font->surface_private;
-
-    if (font_private) {
-	xcb_render_free_glyph_set (font_private->dpy, font_private->glyphset);
-	free (font_private);
-    }
-}
-
-static void
-_cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
-				       cairo_scaled_font_t  *scaled_font)
-{
-    cairo_xcb_surface_font_private_t	*font_private = scaled_font->surface_private;
-
-    if (font_private != NULL && scaled_glyph->surface_private != NULL) {
-	xcb_render_glyph_t glyph_index = _cairo_scaled_glyph_index(scaled_glyph);
-	xcb_render_free_glyphs (font_private->dpy,
-				font_private->glyphset,
-				1, &glyph_index);
-    }
-}
-
-static cairo_bool_t
-_native_byte_order_lsb (void)
-{
-    int	x = 1;
-
-    return *((char *) &x) == 1;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_add_glyph (cairo_xcb_surface_t *dst,
-			      cairo_scaled_font_t  *scaled_font,
-			      cairo_scaled_glyph_t *scaled_glyph)
-{
-    xcb_render_glyphinfo_t glyph_info;
-    xcb_render_glyph_t glyph_index;
-    unsigned char *data;
-    cairo_status_t status = CAIRO_STATUS_SUCCESS;
-    cairo_xcb_surface_font_private_t *font_private;
-    cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
-    xcb_void_cookie_t cookie;
-
-    if (scaled_font->surface_private == NULL) {
-	status = _cairo_xcb_surface_font_init (dst->dpy, scaled_font,
-					       glyph_surface->format);
-	if (status)
-	    return status;
-    }
-    font_private = scaled_font->surface_private;
-
-    /* If the glyph format does not match the font format, then we
-     * create a temporary surface for the glyph image with the font's
-     * format.
-     */
-    if (glyph_surface->format != font_private->format) {
-	cairo_surface_pattern_t pattern;
-	cairo_surface_t *tmp_surface;
-
-	tmp_surface = cairo_image_surface_create (font_private->format,
-						  glyph_surface->width,
-						  glyph_surface->height);
-	status = tmp_surface->status;
-	if (unlikely (status))
-	    goto BAIL;
-
-	tmp_surface->device_transform = glyph_surface->base.device_transform;
-	tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse;
-
-	_cairo_pattern_init_for_surface (&pattern, &glyph_surface->base);
-	status = _cairo_surface_paint (tmp_surface,
-				       CAIRO_OPERATOR_SOURCE, &pattern.base,
-				       NULL);
-	_cairo_pattern_fini (&pattern.base);
-
-	glyph_surface = (cairo_image_surface_t *) tmp_surface;
-
-	if (unlikely (status))
-	    goto BAIL;
-    }
-
-    /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */
-    glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0);
-    glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0);
-    glyph_info.width = glyph_surface->width;
-    glyph_info.height = glyph_surface->height;
-    glyph_info.x_off = 0;
-    glyph_info.y_off = 0;
-
-    data = glyph_surface->data;
-
-    /* flip formats around */
-    switch (scaled_glyph->surface->format) {
-    case CAIRO_FORMAT_A1:
-	/* local bitmaps are always stored with bit == byte */
-	if (_native_byte_order_lsb() != (xcb_get_setup(dst->dpy)->bitmap_format_bit_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
-	    int		    c = glyph_surface->stride * glyph_surface->height;
-	    unsigned char   *d;
-	    unsigned char   *new, *n;
-
-	    new = malloc (c);
-	    if (!new) {
-		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-		goto BAIL;
-	    }
-	    n = new;
-	    d = data;
-	    while (c--)
-	    {
-		char	b = *d++;
-		b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55);
-		b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33);
-		b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f);
-		*n++ = b;
-	    }
-	    data = new;
-	}
-	break;
-    case CAIRO_FORMAT_A8:
-	break;
-    case CAIRO_FORMAT_ARGB32:
-	if (_native_byte_order_lsb() != (xcb_get_setup(dst->dpy)->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) {
-	    unsigned int    c = glyph_surface->stride * glyph_surface->height;
-	    unsigned char   *d;
-	    unsigned char   *new, *n;
-
-	    new = malloc (c);
-	    if (new == NULL) {
-		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-		goto BAIL;
-	    }
-	    n = new;
-	    d = data;
-	    while (c >= 4)
-	    {
-		n[3] = d[0];
-		n[2] = d[1];
-		n[1] = d[2];
-		n[0] = d[3];
-		d += 4;
-		n += 4;
-		c -= 4;
-	    }
-	    data = new;
-	}
-	break;
-    case CAIRO_FORMAT_RGB24:
-    default:
-	ASSERT_NOT_REACHED;
-	break;
-    }
-    /* XXX assume X server wants pixman padding. Xft assumes this as well */
-
-    glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
-
-    cookie = xcb_render_add_glyphs_checked (dst->dpy, font_private->glyphset,
-					    1, &glyph_index, &glyph_info,
-					    glyph_surface->stride * glyph_surface->height,
-					    data);
-
-    if (data != glyph_surface->data)
-	free (data);
-
-    status = _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
-
- BAIL:
-    if (glyph_surface != scaled_glyph->surface)
-	cairo_surface_destroy (&glyph_surface->base);
-
-    return status;
-}
-
-#define N_STACK_BUF 1024
-
-static cairo_status_t
-_cairo_xcb_surface_show_glyphs_8  (cairo_xcb_surface_t *dst,
-                                   cairo_operator_t op,
-                                   cairo_xcb_surface_t *src,
-                                   int src_x_offset, int src_y_offset,
-                                   const cairo_glyph_t *glyphs,
-                                   int num_glyphs,
-                                   cairo_scaled_font_t *scaled_font)
-{
-    cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
-    xcb_render_util_composite_text_stream_t *stream;
-    xcb_void_cookie_t cookie;
-    int i;
-    int thisX, thisY;
-    int lastX = 0, lastY = 0;
-    uint8_t glyph;
-
-    stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
-
-    for (i = 0; i < num_glyphs; ++i) {
-	thisX = _cairo_lround (glyphs[i].x);
-	thisY = _cairo_lround (glyphs[i].y);
-	glyph = glyphs[i].index;
-	xcb_render_util_glyphs_8 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
-	lastX = thisX;
-	lastY = thisY;
-    }
-
-    cookie = xcb_render_util_composite_text_checked (dst->dpy,
-						     _render_operator (op),
-						     src->src_picture,
-						     dst->dst_picture,
-						     font_private->xrender_format->id,
-						     src_x_offset + _cairo_lround (glyphs[0].x),
-						     src_y_offset + _cairo_lround (glyphs[0].y),
-						     stream);
-
-    xcb_render_util_composite_text_free (stream);
-
-    return _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
-}
-
-static cairo_status_t
-_cairo_xcb_surface_show_glyphs_16 (cairo_xcb_surface_t *dst,
-                                   cairo_operator_t op,
-                                   cairo_xcb_surface_t *src,
-                                   int src_x_offset, int src_y_offset,
-                                   const cairo_glyph_t *glyphs,
-                                   int num_glyphs,
-                                   cairo_scaled_font_t *scaled_font)
-{
-    cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
-    xcb_render_util_composite_text_stream_t *stream;
-    xcb_void_cookie_t cookie;
-    int i;
-    int thisX, thisY;
-    int lastX = 0, lastY = 0;
-    uint16_t glyph;
-
-    stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
-
-    for (i = 0; i < num_glyphs; ++i) {
-	thisX = _cairo_lround (glyphs[i].x);
-	thisY = _cairo_lround (glyphs[i].y);
-	glyph = glyphs[i].index;
-	xcb_render_util_glyphs_16 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
-	lastX = thisX;
-	lastY = thisY;
-    }
-
-    cookie = xcb_render_util_composite_text_checked (dst->dpy,
-						     _render_operator (op),
-						     src->src_picture,
-						     dst->dst_picture,
-						     font_private->xrender_format->id,
-						     src_x_offset + _cairo_lround (glyphs[0].x),
-						     src_y_offset + _cairo_lround (glyphs[0].y),
-						     stream);
-
-    xcb_render_util_composite_text_free (stream);
-
-    return _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
-}
-
-static cairo_status_t
-_cairo_xcb_surface_show_glyphs_32 (cairo_xcb_surface_t *dst,
-                                   cairo_operator_t op,
-                                   cairo_xcb_surface_t *src,
-                                   int src_x_offset, int src_y_offset,
-                                   const cairo_glyph_t *glyphs,
-                                   int num_glyphs,
-                                   cairo_scaled_font_t *scaled_font)
-{
-    cairo_xcb_surface_font_private_t *font_private = scaled_font->surface_private;
-    xcb_render_util_composite_text_stream_t *stream;
-    xcb_void_cookie_t cookie;
-    int i;
-    int thisX, thisY;
-    int lastX = 0, lastY = 0;
-    uint32_t glyph;
-
-    stream = xcb_render_util_composite_text_stream (font_private->glyphset, num_glyphs, 0);
-
-    for (i = 0; i < num_glyphs; ++i) {
-	thisX = _cairo_lround (glyphs[i].x);
-	thisY = _cairo_lround (glyphs[i].y);
-	glyph = glyphs[i].index;
-	xcb_render_util_glyphs_32 (stream, thisX - lastX, thisY - lastY, 1, &glyph);
-	lastX = thisX;
-	lastY = thisY;
-    }
-
-    cookie = xcb_render_util_composite_text_checked (dst->dpy,
-						     _render_operator (op),
-						     src->src_picture,
-						     dst->dst_picture,
-						     font_private->xrender_format->id,
-						     src_x_offset + _cairo_lround (glyphs[0].x),
-						     src_y_offset + _cairo_lround (glyphs[0].y),
-						     stream);
-
-    xcb_render_util_composite_text_free (stream);
-
-    return _cairo_xcb_add_cookie_to_be_checked (dst, cookie);
-}
-
-typedef cairo_status_t (*cairo_xcb_surface_show_glyphs_func_t)
-    (cairo_xcb_surface_t *, cairo_operator_t, cairo_xcb_surface_t *, int, int,
-     const cairo_glyph_t *, int, cairo_scaled_font_t *);
-
-static cairo_bool_t
-_cairo_xcb_surface_owns_font (cairo_xcb_surface_t *dst,
-			      cairo_scaled_font_t *scaled_font)
-{
-    cairo_xcb_surface_font_private_t *font_private;
-
-    font_private = scaled_font->surface_private;
-    if ((scaled_font->surface_backend != NULL &&
-	 scaled_font->surface_backend != &cairo_xcb_surface_backend) ||
-	(font_private != NULL && font_private->dpy != dst->dpy))
-    {
-	return FALSE;
-    }
-
-    return TRUE;
-}
-
-static cairo_status_t
-_cairo_xcb_surface_emit_glyphs (cairo_xcb_surface_t *dst,
-				cairo_glyph_t       *glyphs,
-				int                  num_glyphs,
-				cairo_scaled_font_t *scaled_font,
-				cairo_operator_t     op,
-				cairo_xcb_surface_t *src,
-				cairo_surface_attributes_t *attributes,
-				int                 *remaining_glyphs)
-{
-    cairo_scaled_glyph_t *scaled_glyph;
-    int i, o;
-    unsigned long max_index = 0;
-    cairo_status_t status;
-    cairo_glyph_t *output_glyphs;
-    const cairo_glyph_t *glyphs_chunk;
-    int glyphs_remaining, chunk_size, max_chunk_size;
-    cairo_xcb_surface_show_glyphs_func_t show_glyphs_func;
-
-    /* We make a copy of the glyphs so that we can elide any size-zero
-     * glyphs to workaround an X server bug, (present in at least Xorg
-     * 7.1 without EXA). */
-    output_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
-    if (output_glyphs == NULL)
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
-    for (i = 0, o = 0; i < num_glyphs; i++) {
-	if (glyphs[i].index > max_index)
-	    max_index = glyphs[i].index;
-	status = _cairo_scaled_glyph_lookup (scaled_font,
-					     glyphs[i].index,
-					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
-					     &scaled_glyph);
-	if (status) {
-	    free (output_glyphs);
-	    return status;
-	}
-
-	/* Don't put any size-zero glyphs into output_glyphs to avoid
-	 * an X server bug which stops rendering glyphs after the
-	 * first size-zero glyph. */
-	if (scaled_glyph->surface->width && scaled_glyph->surface->height) {
-	    output_glyphs[o++] = glyphs[i];
-	    if (scaled_glyph->surface_private == NULL) {
-		_cairo_xcb_surface_add_glyph (dst, scaled_font, scaled_glyph);
-		scaled_glyph->surface_private = (void *) 1;
-	    }
-	}
-    }
-    num_glyphs = o;
-
-    status = _cairo_xcb_surface_ensure_dst_picture (dst);
-    if (status) {
-	free (output_glyphs);
-	return status;
-    }
-
-    max_chunk_size = xcb_get_maximum_request_length (dst->dpy);
-    if (max_index < 256) {
-	/* XXX: these are all the same size! (28) */
-	max_chunk_size -= sizeof(xcb_render_composite_glyphs_8_request_t);
-	show_glyphs_func = _cairo_xcb_surface_show_glyphs_8;
-    } else if (max_index < 65536) {
-	max_chunk_size -= sizeof(xcb_render_composite_glyphs_16_request_t);
-	show_glyphs_func = _cairo_xcb_surface_show_glyphs_16;
-    } else {
-	max_chunk_size -= sizeof(xcb_render_composite_glyphs_32_request_t);
-	show_glyphs_func = _cairo_xcb_surface_show_glyphs_32;
-    }
-    /* XXX: I think this is wrong; this is only the header size (2 longs) */
-    /*      but should also include the glyph (1 long) */
-    /* max_chunk_size /= sz_xGlyphElt; */
-    max_chunk_size /= 3*sizeof(uint32_t);
-
-    for (glyphs_remaining = num_glyphs, glyphs_chunk = output_glyphs;
-	 glyphs_remaining;
-	 glyphs_remaining -= chunk_size, glyphs_chunk += chunk_size)
-    {
-	chunk_size = MIN (glyphs_remaining, max_chunk_size);
-
-	status = show_glyphs_func (dst, op, src,
-                                   attributes->x_offset, attributes->y_offset,
-                                   glyphs_chunk, chunk_size, scaled_font);
-	if (status) {
-	    free (output_glyphs);
-	    return status;
-	}
-    }
-
-    /* We wouldn't want to leak memory, would we? */
-    free(output_glyphs);
-
-    return CAIRO_STATUS_SUCCESS;
-}
-
-static cairo_int_status_t
-_cairo_xcb_surface_show_glyphs (void			*abstract_dst,
-				cairo_operator_t	 op,
-				const cairo_pattern_t	*src_pattern,
-				cairo_glyph_t		*glyphs,
-				int			 num_glyphs,
-				cairo_scaled_font_t	*scaled_font,
-				cairo_clip_t		*clip,
-				int			*remaining_glyphs)
-{
-    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;
-    cairo_xcb_surface_t *dst = abstract_dst;
-
-    composite_operation_t operation;
-    cairo_surface_attributes_t attributes;
-    cairo_xcb_surface_t *src = NULL;
-
-    cairo_region_t *clip_region = NULL;
-
-    if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (dst) || dst->xrender_format.id == XCB_NONE)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    /* Just let unbounded operators go through the fallback code
-     * instead of trying to do the fixups here */
-    if (!_cairo_operator_bounded_by_mask (op))
-        return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    /* Render <= 0.10 seems to have a bug with PictOpSrc and glyphs --
-     * the solid source seems to be multiplied by the glyph mask, and
-     * then the entire thing is copied to the destination surface,
-     * including the fully transparent "background" of the rectangular
-     * glyph surface. */
-    if (op == CAIRO_OPERATOR_SOURCE &&
-        !CAIRO_SURFACE_RENDER_AT_LEAST(dst, 0, 11))
-        return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    /* We can only use our code if we either have no clip or
-     * have a real native clip region set.  If we're using
-     * fallback clip masking, we have to go through the full
-     * fallback path.
-     */
-    if (clip != NULL) {
-	status = _cairo_clip_get_region (clip, &clip_region);
-	assert (status != CAIRO_INT_STATUS_NOTHING_TO_DO);
-	if (status)
-	    return status;
-    }
-
-    operation = _categorize_composite_operation (dst, op, src_pattern, TRUE);
-    if (operation == DO_UNSUPPORTED)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    if (! _cairo_xcb_surface_owns_font (dst, scaled_font))
-	return CAIRO_INT_STATUS_UNSUPPORTED;
-
-    /* After passing all those tests, we're now committed to rendering
-     * these glyphs or to fail trying. We first upload any glyphs to
-     * the X server that it doesn't have already, then we draw
-     * them. We tie into the scaled_font's glyph cache and remove
-     * glyphs from the X server when they are ejected from the
-     * scaled_font cache.
-     */
-
-    /* PictOpClear doesn't seem to work with CompositeText; it seems to ignore
-     * the mask (the glyphs).  This code below was executed as a side effect
-     * of going through the _clip_and_composite fallback code for old_show_glyphs,
-     * so PictOpClear was never used with CompositeText before.
-     */
-    if (op == CAIRO_OPERATOR_CLEAR) {
-	src_pattern = &_cairo_pattern_white.base;
-	op = CAIRO_OPERATOR_DEST_OUT;
-    }
-
-    if (src_pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
-        status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
-                                                 0, 0, 1, 1,
-						 CAIRO_PATTERN_ACQUIRE_NONE,
-                                                 (cairo_surface_t **) &src,
-                                                 &attributes);
-    } else {
-        cairo_rectangle_int_t glyph_extents;
-
-        status = _cairo_scaled_font_glyph_device_extents (scaled_font,
-                                                          glyphs,
-                                                          num_glyphs,
-                                                          &glyph_extents,
-							  NULL);
-        if (status)
-	    goto BAIL;
-
-        status = _cairo_pattern_acquire_surface (src_pattern, &dst->base,
-                                                 glyph_extents.x, glyph_extents.y,
-                                                 glyph_extents.width, glyph_extents.height,
-						 CAIRO_PATTERN_ACQUIRE_NO_REFLECT,
-                                                 (cairo_surface_t **) &src,
-                                                 &attributes);
-    }
-
-    if (status)
-        goto BAIL;
-
-    operation = _recategorize_composite_operation (dst, op, src, &attributes, TRUE);
-    if (operation == DO_UNSUPPORTED) {
-	status = CAIRO_INT_STATUS_UNSUPPORTED;
-	goto BAIL;
-    }
-
-    status = _cairo_xcb_surface_set_clip_region (dst, clip_region);
-    if (unlikely (status))
-	goto BAIL;
-
-    status = _cairo_xcb_surface_set_attributes (src, &attributes);
-    if (status)
-        goto BAIL;
-
-    /* Send all unsent glyphs to the server, and count the max of the glyph indices */
-    _cairo_scaled_font_freeze_cache (scaled_font);
-
-    if (_cairo_xcb_surface_owns_font (dst, scaled_font)) {
-	status = _cairo_xcb_surface_emit_glyphs (dst,
-						 glyphs, num_glyphs,
-						 scaled_font,
-						 op,
-						 src,
-						 &attributes,
-						 remaining_glyphs);
-    } else {
-	status = CAIRO_INT_STATUS_UNSUPPORTED;
+    if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) {
+	status_ignored = _cairo_surface_set_error (abstract_surface,
+						   CAIRO_STATUS_INVALID_SIZE);
+	return;
     }
-    _cairo_scaled_font_thaw_cache (scaled_font);
-
-  BAIL:
-    if (src)
-        _cairo_pattern_release_surface (src_pattern, &src->base, &attributes);
 
-    return status;
+    surface = (cairo_xcb_surface_t *) abstract_surface;
+    surface->width  = width;
+    surface->height = height;
 }
+#if CAIRO_HAS_XLIB_XCB_FUNCTIONS
+slim_hidden_def (cairo_xcb_surface_set_size);
+#endif
diff --git a/src/cairo-xcb-xrender.h b/src/cairo-xcb-xrender.h
deleted file mode 100644
index 09c6097..0000000
--- a/src/cairo-xcb-xrender.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* cairo - a vector graphics library with display and print output
- *
- * Copyright © 2002 University of Southern California
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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):
- *	Carl D. Worth <cworth at cworth.org>
- */
-
-#ifndef CAIRO_XCB_XRENDER_H
-#define CAIRO_XCB_XRENDER_H
-
-#include "cairo.h"
-
-#if CAIRO_HAS_XCB_SURFACE
-
-#include <xcb/xcb.h>
-#include <xcb/render.h>
-
-CAIRO_BEGIN_DECLS
-
-cairo_public cairo_surface_t *
-cairo_xcb_surface_create_with_xrender_format (xcb_connection_t	    *c,
-					      xcb_drawable_t	     drawable,
-					      xcb_screen_t		    *screen,
-					      xcb_render_pictforminfo_t *format,
-					      int		     width,
-					      int		     height);
-
-CAIRO_END_DECLS
-
-#else  /* CAIRO_HAS_XCB_SURFACE */
-# error Cairo was not compiled with support for the xcb backend
-#endif /* CAIRO_HAS_XCB_SURFACE */
-
-#endif /* CAIRO_XCB_XRENDER_H */
diff --git a/src/cairo-xcb.h b/src/cairo-xcb.h
index 1b6d2e6..a1e9da1 100644
--- a/src/cairo-xcb.h
+++ b/src/cairo-xcb.h
@@ -1,6 +1,7 @@
 /* cairo - a vector graphics library with display and print output
  *
  * Copyright © 2002 University of Southern California
+ * 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
@@ -32,6 +33,7 @@
  *
  * Contributor(s):
  *	Carl D. Worth <cworth at cworth.org>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
  */
 
 #ifndef CAIRO_XCB_H
@@ -42,28 +44,49 @@
 #if CAIRO_HAS_XCB_SURFACE
 
 #include <xcb/xcb.h>
+#include <xcb/render.h>
 
 CAIRO_BEGIN_DECLS
 
 cairo_public cairo_surface_t *
-cairo_xcb_surface_create (xcb_connection_t *c,
+cairo_xcb_surface_create (xcb_connection_t	*connection,
 			  xcb_drawable_t	 drawable,
-			  xcb_visualtype_t *visual,
-			  int		 width,
-			  int		 height);
+			  xcb_visualtype_t	*visual,
+			  int			 width,
+			  int			 height);
 
 cairo_public cairo_surface_t *
-cairo_xcb_surface_create_for_bitmap (xcb_connection_t *c,
-				     xcb_pixmap_t	    bitmap,
-				     xcb_screen_t	   *screen,
-				     int	    width,
-				     int	    height);
+cairo_xcb_surface_create_for_bitmap (xcb_connection_t	*connection,
+				     xcb_screen_t	*screen,
+				     xcb_pixmap_t	 bitmap,
+				     int		 width,
+				     int		 height);
+
+cairo_public cairo_surface_t *
+cairo_xcb_surface_create_with_xrender_format (xcb_connection_t			*connection,
+					      xcb_screen_t			*screen,
+					      xcb_drawable_t			 drawable,
+					      xcb_render_pictforminfo_t		*format,
+					      int				 width,
+					      int				 height);
 
 cairo_public void
 cairo_xcb_surface_set_size (cairo_surface_t *surface,
 			    int		     width,
 			    int		     height);
 
+/* debug interface */
+
+cairo_public void
+cairo_xcb_device_debug_cap_xshm_version (cairo_device_t *device,
+                                         int major_version,
+                                         int minor_version);
+
+cairo_public void
+cairo_xcb_device_debug_cap_xrender_version (cairo_device_t *device,
+                                            int major_version,
+                                            int minor_version);
+
 CAIRO_END_DECLS
 
 #else  /* CAIRO_HAS_XCB_SURFACE */
diff --git a/src/cairo-xlib-xcb-surface.c b/src/cairo-xlib-xcb-surface.c
new file mode 100644
index 0000000..a8e0cde
--- /dev/null
+++ b/src/cairo-xlib-xcb-surface.c
@@ -0,0 +1,515 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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):
+ *	Carl D. Worth <cworth at cworth.org>
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-xlib.h"
+#include "cairo-xcb.h"
+
+#include "cairo-xcb-private.h"
+#include "cairo-xlib-xrender-private.h"
+
+#include <X11/Xlib-xcb.h>
+
+static cairo_surface_t *
+_cairo_xlib_xcb_surface_create (void *dpy,
+				void *scr,
+				void *visual,
+				void *format,
+				cairo_surface_t *xcb);
+
+static cairo_surface_t *
+_cairo_xlib_xcb_surface_create_similar (void			*abstract_other,
+					cairo_content_t		 content,
+					int			 width,
+					int			 height)
+{
+    cairo_xlib_xcb_surface_t *other = abstract_other;
+    cairo_surface_t *xcb;
+
+    xcb = other->xcb->base.backend->create_similar (other->xcb, content, width, height);
+    if (unlikely (xcb == NULL || xcb->status))
+	return xcb;
+
+    return _cairo_xlib_xcb_surface_create (other->display, other->screen, NULL, NULL, xcb);
+}
+
+static cairo_status_t
+_cairo_xlib_xcb_surface_finish (void *abstract_surface)
+{
+    cairo_xlib_xcb_surface_t *surface = abstract_surface;
+    cairo_status_t status;
+
+    cairo_surface_finish (&surface->xcb->base);
+    status = surface->xcb->base.status;
+    cairo_surface_destroy (&surface->xcb->base);
+
+    return status;
+}
+
+static cairo_status_t
+_cairo_xlib_xcb_surface_acquire_source_image (void *abstract_surface,
+					      cairo_image_surface_t **image_out,
+					      void **image_extra)
+{
+    cairo_xlib_xcb_surface_t *surface = abstract_surface;
+    return _cairo_surface_acquire_source_image (&surface->xcb->base,
+						image_out, image_extra);
+}
+
+static void
+_cairo_xlib_xcb_surface_release_source_image (void *abstract_surface,
+					      cairo_image_surface_t *image_out,
+					      void *image_extra)
+{
+    cairo_xlib_xcb_surface_t *surface = abstract_surface;
+    _cairo_surface_release_source_image (&surface->xcb->base, image_out, image_extra);
+}
+
+static cairo_bool_t
+_cairo_xlib_xcb_surface_get_extents (void *abstract_surface,
+				     cairo_rectangle_int_t *extents)
+{
+    cairo_xlib_xcb_surface_t *surface = abstract_surface;
+    return _cairo_surface_get_extents (&surface->xcb->base, extents);
+}
+
+static void
+_cairo_xlib_xcb_surface_get_font_options (void *abstract_surface,
+					  cairo_font_options_t *options)
+{
+    cairo_xlib_xcb_surface_t *surface = abstract_surface;
+    surface->xcb->base.backend->get_font_options (surface->xcb, options);
+}
+
+static cairo_int_status_t
+_cairo_xlib_xcb_surface_paint (void			*abstract_surface,
+			       cairo_operator_t		 op,
+			       const cairo_pattern_t	*source,
+			       cairo_clip_t		*clip)
+{
+    cairo_xlib_xcb_surface_t *surface = abstract_surface;
+    return surface->xcb->base.backend->paint (surface->xcb, op, source, clip);
+}
+
+static cairo_int_status_t
+_cairo_xlib_xcb_surface_mask (void			*abstract_surface,
+			      cairo_operator_t		 op,
+			      const cairo_pattern_t	*source,
+			      const cairo_pattern_t	*mask,
+			      cairo_clip_t		*clip)
+{
+    cairo_xlib_xcb_surface_t *surface = abstract_surface;
+    return surface->xcb->base.backend->mask (surface->xcb, op, source, mask, clip);
+}
+
+static cairo_int_status_t
+_cairo_xlib_xcb_surface_stroke (void				*abstract_surface,
+				cairo_operator_t		 op,
+				const cairo_pattern_t		*source,
+				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_clip_t			*clip)
+{
+    cairo_xlib_xcb_surface_t *surface = abstract_surface;
+    return surface->xcb->base.backend->stroke (surface->xcb,
+					       op, source, path, style,
+					       ctm, ctm_inverse,
+					       tolerance, antialias, clip);
+}
+
+static cairo_int_status_t
+_cairo_xlib_xcb_surface_fill (void			*abstract_surface,
+			      cairo_operator_t		 op,
+			      const cairo_pattern_t	*source,
+			      cairo_path_fixed_t	*path,
+			      cairo_fill_rule_t		 fill_rule,
+			      double			 tolerance,
+			      cairo_antialias_t		 antialias,
+			      cairo_clip_t		*clip)
+{
+    cairo_xlib_xcb_surface_t *surface = abstract_surface;
+    return surface->xcb->base.backend->fill (surface->xcb,
+					     op, source, path,
+					     fill_rule, tolerance, antialias,
+					     clip);
+}
+
+static cairo_int_status_t
+_cairo_xlib_xcb_surface_glyphs (void			*abstract_surface,
+				cairo_operator_t	 op,
+				const cairo_pattern_t	*source,
+				cairo_glyph_t		*glyphs,
+				int			 num_glyphs,
+				cairo_scaled_font_t	*scaled_font,
+				cairo_clip_t		*clip,
+				int *num_remaining)
+{
+    cairo_xlib_xcb_surface_t *surface = abstract_surface;
+    return surface->xcb->base.backend->show_glyphs (surface->xcb, op, source,
+						    glyphs, num_glyphs, scaled_font,
+						    clip, num_remaining);
+}
+
+static cairo_status_t
+_cairo_xlib_xcb_surface_flush (void *abstract_surface)
+{
+    cairo_xlib_xcb_surface_t *surface = abstract_surface;
+    return surface->xcb->base.backend->flush (surface->xcb);
+}
+
+static cairo_status_t
+_cairo_xlib_xcb_surface_mark_dirty (void *abstract_surface,
+				    int x, int y,
+				    int width, int height)
+{
+    cairo_xlib_xcb_surface_t *surface = abstract_surface;
+    return surface->xcb->base.backend->mark_dirty_rectangle (surface->xcb, x, y, width, height);
+}
+
+static const cairo_surface_backend_t _cairo_xlib_xcb_surface_backend = {
+    CAIRO_SURFACE_TYPE_XLIB,
+    _cairo_xlib_xcb_surface_create_similar,
+    _cairo_xlib_xcb_surface_finish,
+    _cairo_xlib_xcb_surface_acquire_source_image,
+    _cairo_xlib_xcb_surface_release_source_image,
+    NULL, NULL, NULL, /* dest acquire/release/clone */
+
+    NULL, /* composite */
+    NULL, /* fill */
+    NULL, /* trapezoids */
+    NULL, /* span */
+    NULL, /* check-span */
+
+    NULL, /* copy_page */
+    NULL, /* show_page */
+    _cairo_xlib_xcb_surface_get_extents,
+    NULL, /* old-glyphs */
+    _cairo_xlib_xcb_surface_get_font_options,
+
+    _cairo_xlib_xcb_surface_flush,
+    _cairo_xlib_xcb_surface_mark_dirty,
+    NULL, NULL, /* font/glyph fini */
+
+    _cairo_xlib_xcb_surface_paint,
+    _cairo_xlib_xcb_surface_mask,
+    _cairo_xlib_xcb_surface_stroke,
+    _cairo_xlib_xcb_surface_fill,
+    _cairo_xlib_xcb_surface_glyphs,
+};
+
+static cairo_surface_t *
+_cairo_xlib_xcb_surface_create (void *dpy,
+				void *scr,
+				void *visual,
+				void *format,
+				cairo_surface_t *xcb)
+{
+    cairo_xlib_xcb_surface_t *surface;
+
+    if (unlikely (xcb->status))
+	return xcb;
+
+    surface = malloc (sizeof (*surface));
+    if (unlikely (surface == NULL)) {
+	cairo_surface_destroy (xcb);
+	return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    _cairo_surface_init (&surface->base,
+			 &_cairo_xlib_xcb_surface_backend,
+			 xcb->device,
+			 xcb->content);
+
+    surface->display = dpy;
+    surface->screen = scr;
+    surface->visual = visual;
+    surface->format = format;
+    surface->xcb = (cairo_xcb_surface_t *) xcb;
+
+    return &surface->base;
+}
+
+static Screen *
+_cairo_xlib_screen_from_visual (Display *dpy, Visual *visual)
+{
+    int s, d, v;
+
+    for (s = 0; s < ScreenCount (dpy); s++) {
+	Screen *screen;
+
+	screen = ScreenOfDisplay (dpy, s);
+	if (visual == DefaultVisualOfScreen (screen))
+	    return screen;
+
+	for (d = 0; d < screen->ndepths; d++) {
+	    Depth  *depth;
+
+	    depth = &screen->depths[d];
+	    for (v = 0; v < depth->nvisuals; v++)
+		if (visual == &depth->visuals[v])
+		    return screen;
+	}
+    }
+
+    return NULL;
+}
+
+cairo_surface_t *
+cairo_xlib_surface_create (Display     *dpy,
+			   Drawable	drawable,
+			   Visual      *visual,
+			   int		width,
+			   int		height)
+{
+    Screen *scr;
+    xcb_visualtype_t xcb_visual;
+
+    scr = _cairo_xlib_screen_from_visual (dpy, visual);
+    if (scr == NULL)
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL));
+
+    xcb_visual.visual_id = visual->visualid;
+#if defined(__cplusplus) || defined(c_plusplus)
+    xcb_visual._class = visual->c_class;
+#else
+    xcb_visual._class = visual->class;
+#endif
+    xcb_visual.bits_per_rgb_value = visual->bits_per_rgb;
+    xcb_visual.colormap_entries = visual->map_entries;
+    xcb_visual.red_mask = visual->red_mask;
+    xcb_visual.green_mask = visual->green_mask;
+    xcb_visual.blue_mask = visual->blue_mask;
+
+    return _cairo_xlib_xcb_surface_create (dpy, scr, visual, NULL,
+					   cairo_xcb_surface_create (XGetXCBConnection (dpy),
+								     drawable,
+								     &xcb_visual,
+								     width, height));
+}
+
+cairo_surface_t *
+cairo_xlib_surface_create_for_bitmap (Display  *dpy,
+				      Pixmap	bitmap,
+				      Screen   *scr,
+				      int	width,
+				      int	height)
+{
+    return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, NULL,
+					   cairo_xcb_surface_create_for_bitmap (XGetXCBConnection (dpy),
+										(xcb_screen_t *) scr,
+										bitmap,
+										width, height));
+}
+
+#if CAIRO_HAS_XLIB_XRENDER_SURFACE
+cairo_surface_t *
+cairo_xlib_surface_create_with_xrender_format (Display		    *dpy,
+					       Drawable		    drawable,
+					       Screen		    *scr,
+					       XRenderPictFormat    *format,
+					       int		    width,
+					       int		    height)
+{
+    xcb_render_pictforminfo_t xcb_format;
+
+    xcb_format.id = format->id;
+    xcb_format.type = format->type;
+    xcb_format.depth = format->depth;
+    xcb_format.direct.red_shift = format->direct.red;
+    xcb_format.direct.red_mask = format->direct.redMask;
+    xcb_format.direct.green_shift = format->direct.green;
+    xcb_format.direct.green_mask = format->direct.greenMask;
+    xcb_format.direct.blue_shift = format->direct.blue;
+    xcb_format.direct.blue_mask = format->direct.blueMask;
+    xcb_format.direct.alpha_shift = format->direct.alpha;
+    xcb_format.direct.alpha_mask = format->direct.alphaMask;
+    xcb_format.colormap = format->colormap;
+
+    return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, format,
+					   cairo_xcb_surface_create_with_xrender_format (XGetXCBConnection (dpy),
+											 (xcb_screen_t *) scr,
+											 drawable,
+											 &xcb_format,
+											 width, height));
+}
+
+XRenderPictFormat *
+cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface)
+{
+    cairo_xlib_xcb_surface_t *xlib_surface = (cairo_xlib_xcb_surface_t *) surface;
+
+    /* Throw an error for a non-xlib surface */
+    if (surface->type != CAIRO_SURFACE_TYPE_XLIB) {
+	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+	return NULL;
+    }
+
+    return xlib_surface->format;
+}
+#endif
+
+void
+cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface,
+			     int              width,
+			     int              height)
+{
+    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+    cairo_status_t status;
+
+    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+	status = _cairo_surface_set_error (abstract_surface,
+		                           CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+	return;
+    }
+
+    cairo_xcb_surface_set_size (&surface->xcb->base, width, height);
+}
+
+void
+cairo_xlib_surface_set_drawable (cairo_surface_t   *abstract_surface,
+				 Drawable	    drawable,
+				 int		    width,
+				 int		    height)
+{
+    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *)abstract_surface;
+    cairo_status_t status;
+
+    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+	status = _cairo_surface_set_error (abstract_surface,
+		                           CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+	return;
+    }
+
+    ASSERT_NOT_REACHED;
+}
+
+Display *
+cairo_xlib_surface_get_display (cairo_surface_t *abstract_surface)
+{
+    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+	return NULL;
+    }
+
+    return surface->display;
+}
+
+Drawable
+cairo_xlib_surface_get_drawable (cairo_surface_t *abstract_surface)
+{
+    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+	return 0;
+    }
+
+    return surface->xcb->drawable;
+}
+
+Screen *
+cairo_xlib_surface_get_screen (cairo_surface_t *abstract_surface)
+{
+    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+	return NULL;
+    }
+
+    return surface->screen;
+}
+
+Visual *
+cairo_xlib_surface_get_visual (cairo_surface_t *abstract_surface)
+{
+    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+	return NULL;
+    }
+
+    return surface->visual;
+}
+
+int
+cairo_xlib_surface_get_depth (cairo_surface_t *abstract_surface)
+{
+    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+	return 0;
+    }
+
+    return surface->xcb->depth;
+}
+
+int
+cairo_xlib_surface_get_width (cairo_surface_t *abstract_surface)
+{
+    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+	return 0;
+    }
+
+    return surface->xcb->width;
+}
+
+int
+cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface)
+{
+    cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface;
+
+    if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) {
+	_cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+	return 0;
+    }
+
+    return surface->xcb->height;
+}
diff --git a/src/cairoint.h b/src/cairoint.h
index 0892bbb..acc5769 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2555,9 +2555,25 @@ cairo_private unsigned long
 _cairo_pattern_hash (const cairo_pattern_t *pattern);
 
 cairo_private unsigned long
+_cairo_linear_pattern_hash (unsigned long hash,
+			    const cairo_linear_pattern_t *linear);
+
+cairo_private unsigned long
+_cairo_radial_pattern_hash (unsigned long hash,
+			    const cairo_radial_pattern_t *radial);
+
+cairo_private cairo_bool_t
+_cairo_linear_pattern_equal (const cairo_linear_pattern_t *a,
+			     const cairo_linear_pattern_t *b);
+
+cairo_private unsigned long
 _cairo_pattern_size (const cairo_pattern_t *pattern);
 
 cairo_private cairo_bool_t
+_cairo_radial_pattern_equal (const cairo_radial_pattern_t *a,
+			     const cairo_radial_pattern_t *b);
+
+cairo_private cairo_bool_t
 _cairo_pattern_equal (const cairo_pattern_t *a,
 		      const cairo_pattern_t *b);
 
diff --git a/test/xcb-surface-source.c b/test/xcb-surface-source.c
index debe93e..d359cf2 100644
--- a/test/xcb-surface-source.c
+++ b/test/xcb-surface-source.c
@@ -26,7 +26,6 @@
 #include "cairo-test.h"
 #if CAIRO_HAS_XCB_SURFACE
 #include <cairo-xcb.h>
-#include <cairo-xcb-xrender.h>
 #endif
 
 #include "surface-source.c"
commit 77afe8491ed7038a8399c01f10d8f062a7239225
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jan 22 20:48:54 2010 +0000

    drm: Add backends for i915 and i965.
    
    As proof-of-principle add the nearly working demonstrations of using DRM
    to render directly with the GPU bypassing both RENDER and GL for
    performance whilst preserving high quality rendering.
    
    The basis behind developing these chip specific backends is that this is
    the idealised interface that we desire for this chips, and so a target
    for cairo-gl as we continue to develop both it and our GL stack.
    
    Note that this backends do not yet fully pass the test suite, so only
    use if you are brave and willing to help develop them further.

diff --git a/boilerplate/cairo-boilerplate-drm.c b/boilerplate/cairo-boilerplate-drm.c
index 34d67b5..77a052d 100644
--- a/boilerplate/cairo-boilerplate-drm.c
+++ b/boilerplate/cairo-boilerplate-drm.c
@@ -45,7 +45,7 @@ _cairo_boilerplate_drm_create_surface (const char		 *name,
 				       int			  id,
 				       void			**closure)
 {
-    cairo_drm_device_t *device;
+    cairo_device_t *device;
 
     device = cairo_drm_device_default ();
     if (device == NULL)
diff --git a/src/Makefile.sources b/src/Makefile.sources
index 8d68860..f6d4fe3 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -310,12 +310,29 @@ cairo_directfb_sources = cairo-directfb-surface.c
 cairo_drm_headers = cairo-drm.h
 cairo_drm_private = drm/cairo-drm-private.h \
 		    drm/cairo-drm-intel-private.h \
+		    drm/cairo-drm-i915-private.h \
+		    drm/cairo-drm-i965-private.h \
+		    drm/cairo-drm-intel-brw-defines.h \
+		    drm/cairo-drm-intel-brw-structs.h \
+		    drm/cairo-drm-intel-brw-eu.h \
 		    drm/cairo-drm-radeon-private.h
 cairo_drm_sources = drm/cairo-drm.c \
 		    drm/cairo-drm-bo.c \
 		    drm/cairo-drm-surface.c \
 		    drm/cairo-drm-intel.c \
+		    drm/cairo-drm-intel-debug.c \
 		    drm/cairo-drm-intel-surface.c \
+		    drm/cairo-drm-i915-surface.c \
+		    drm/cairo-drm-i915-glyphs.c \
+		    drm/cairo-drm-i915-shader.c \
+		    drm/cairo-drm-i915-spans.c \
+		    drm/cairo-drm-i965-surface.c \
+		    drm/cairo-drm-i965-glyphs.c \
+		    drm/cairo-drm-i965-shader.c \
+		    drm/cairo-drm-i965-spans.c \
+		    drm/cairo-drm-intel-brw-eu.c \
+		    drm/cairo-drm-intel-brw-eu-emit.c \
+		    drm/cairo-drm-intel-brw-eu-util.c \
 		    drm/cairo-drm-radeon.c \
 		    drm/cairo-drm-radeon-surface.c
 cairo_gallium_sources = drm/cairo-drm-gallium-surface.c
diff --git a/src/cairo-drm.h b/src/cairo-drm.h
index 1b50b1b..52b9de2 100644
--- a/src/cairo-drm.h
+++ b/src/cairo-drm.h
@@ -39,56 +39,41 @@
 
 CAIRO_BEGIN_DECLS
 
-typedef struct _cairo_drm_device cairo_drm_device_t;
-
 struct udev_device;
 
-cairo_public cairo_drm_device_t *
+cairo_public cairo_device_t *
 cairo_drm_device_get (struct udev_device *device);
 
-cairo_public cairo_drm_device_t *
+cairo_public cairo_device_t *
 cairo_drm_device_get_for_fd (int fd);
 
-cairo_public cairo_drm_device_t *
+cairo_public cairo_device_t *
 cairo_drm_device_default (void);
 
-cairo_public cairo_drm_device_t *
-cairo_drm_device_reference (cairo_drm_device_t *device);
-
-cairo_public cairo_status_t
-cairo_drm_device_status (cairo_drm_device_t *device);
-
 cairo_public int
-cairo_drm_device_get_fd (cairo_drm_device_t *device);
+cairo_drm_device_get_fd (cairo_device_t *device);
 
 cairo_public void
-cairo_drm_device_throttle (cairo_drm_device_t *device);
-
-cairo_public void
-cairo_drm_device_destroy (cairo_drm_device_t *device);
-
+cairo_drm_device_throttle (cairo_device_t *device);
 
 cairo_public cairo_surface_t *
-cairo_drm_surface_create (cairo_drm_device_t *device,
+cairo_drm_surface_create (cairo_device_t *device,
 			  cairo_content_t content,
 			  int width, int height);
 
 cairo_public cairo_surface_t *
-cairo_drm_surface_create_for_name (cairo_drm_device_t *device,
+cairo_drm_surface_create_for_name (cairo_device_t *device,
 				   unsigned int name,
 	                           cairo_format_t format,
 				   int width, int height, int stride);
 
 cairo_public cairo_surface_t *
-cairo_drm_surface_create_from_cacheable_image (cairo_drm_device_t *device,
+cairo_drm_surface_create_from_cacheable_image (cairo_device_t *device,
 	                                       cairo_surface_t *surface);
 
 cairo_public cairo_status_t
 cairo_drm_surface_enable_scan_out (cairo_surface_t *surface);
 
-cairo_public cairo_drm_device_t *
-cairo_drm_surface_get_device (cairo_surface_t *abstract_surface);
-
 cairo_public unsigned int
 cairo_drm_surface_get_handle (cairo_surface_t *surface);
 
diff --git a/src/cairo-misc.c b/src/cairo-misc.c
index cd1032a..56409af 100644
--- a/src/cairo-misc.c
+++ b/src/cairo-misc.c
@@ -674,6 +674,63 @@ _cairo_lround (double d)
 #undef LSW
 }
 
+/* Convert a 32-bit IEEE single precision floating point number to a
+ * 'half' representation (s10.5)
+ */
+uint16_t
+_cairo_half_from_float (float f)
+{
+    union {
+	uint32_t ui;
+	float f;
+    } u;
+    int s, e, m;
+
+    u.f = f;
+    s =  (u.ui >> 16) & 0x00008000;
+    e = ((u.ui >> 23) & 0x000000ff) - (127 - 15);
+    m =   u.ui        & 0x007fffff;
+    if (e <= 0) {
+	if (e < -10) {
+	    /* underflow */
+	    return 0;
+	}
+
+	m = (m | 0x00800000) >> (1 - e);
+
+	/* round to nearest, round 0.5 up. */
+	if (m &  0x00001000)
+	    m += 0x00002000;
+	return s | (m >> 13);
+    } else if (e == 0xff - (127 - 15)) {
+	if (m == 0) {
+	    /* infinity */
+	    return s | 0x7c00;
+	} else {
+	    /* nan */
+	    m >>= 13;
+	    return s | 0x7c00 | m | (m == 0);
+	}
+    } else {
+	/* round to nearest, round 0.5 up. */
+	if (m &  0x00001000) {
+	    m += 0x00002000;
+
+	    if (m & 0x00800000) {
+		m =  0;
+		e += 1;
+	    }
+	}
+
+	if (e > 30) {
+	    /* overflow -> infinity */
+	    return s | 0x7c00;
+	}
+
+	return s | (e << 10) | (m >> 13);
+    }
+}
+
 
 #ifdef _WIN32
 
diff --git a/src/cairoint.h b/src/cairoint.h
index 6e059c4..0892bbb 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -949,6 +949,8 @@ _cairo_round (double r)
 
 cairo_private int
 _cairo_lround (double d) cairo_const;
+cairo_private uint16_t
+_cairo_half_from_float (float f) cairo_const;
 
 /* cairo-gstate.c */
 cairo_private cairo_status_t
diff --git a/src/drm/cairo-drm-bo.c b/src/drm/cairo-drm-bo.c
index 980484a..cb74bac 100644
--- a/src/drm/cairo-drm-bo.c
+++ b/src/drm/cairo-drm-bo.c
@@ -31,11 +31,14 @@
 
 #include "cairo-drm-private.h"
 #include "cairo-drm-ioctl-private.h"
+
 #include "cairo-error-private.h"
 
 #include <sys/ioctl.h>
 #include <errno.h>
 
+#define ERR_DEBUG(x) x
+
 struct drm_gem_close {
 	/** Handle of the object to be closed. */
 	uint32_t handle;
@@ -79,8 +82,11 @@ _cairo_drm_bo_open_for_name (const cairo_drm_device_t *dev,
     do {
 	ret = ioctl (dev->fd, DRM_IOCTL_GEM_OPEN, &open);
     } while (ret == -1 && errno == EINTR);
-    if (ret == -1)
+    if (ret == -1) {
+	ERR_DEBUG((fprintf (stderr, "Failed to open bo for name %d: %s\n",
+			    name, strerror (errno))));
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
 
     bo->name = name;
     bo->size = open.size;
@@ -99,8 +105,11 @@ _cairo_drm_bo_flink (const cairo_drm_device_t *dev,
     memset (&flink, 0, sizeof (flink));
     flink.handle = bo->handle;
     ret = ioctl (dev->fd, DRM_IOCTL_GEM_FLINK, &flink);
-    if (ret == -1)
+    if (ret == -1) {
+	ERR_DEBUG((fprintf (stderr, "Failed to flink bo: %s\n",
+			    strerror (errno))));
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
 
     bo->name = flink.name;
 
diff --git a/src/drm/cairo-drm-gallium-surface.c b/src/drm/cairo-drm-gallium-surface.c
index c2f331b..73d7547 100644
--- a/src/drm/cairo-drm-gallium-surface.c
+++ b/src/drm/cairo-drm-gallium-surface.c
@@ -444,7 +444,6 @@ gallium_surface_create_internal (gallium_device_t *device,
 
     _cairo_surface_init (&surface->base.base,
 			 &gallium_surface_backend,
-			 NULL, /* device */
 			 content);
     _cairo_drm_surface_init (&surface->base, &device->base);
 
@@ -551,7 +550,6 @@ gallium_surface_create_for_name (cairo_drm_device_t *base_dev,
     content = _cairo_content_from_format (format);
     _cairo_surface_init (&surface->base.base,
 			 &gallium_surface_backend,
-			 NULL, /* device */
 			 content);
     _cairo_drm_surface_init (&surface->base, base_dev);
 
@@ -659,6 +657,7 @@ _cairo_drm_gallium_device_create (int fd, dev_t dev, int vendor_id, int chip_id)
     device->base.surface.enable_scan_out = NULL;
     device->base.surface.flink = gallium_surface_flink;
 
+    device->base.device.flush = NULL;
     device->base.device.throttle = NULL;
     device->base.device.destroy = gallium_device_destroy;
 
diff --git a/src/drm/cairo-drm-i915-glyphs.c b/src/drm/cairo-drm-i915-glyphs.c
new file mode 100644
index 0000000..babd59e
--- /dev/null
+++ b/src/drm/cairo-drm-i915-glyphs.c
@@ -0,0 +1,534 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-drm-i915-private.h"
+#include "cairo-error-private.h"
+#include "cairo-rtree-private.h"
+
+static void
+i915_emit_glyph_rectangle_constant (i915_device_t *device,
+				    i915_shader_t *shader,
+				    int x1, int y1,
+				    int x2, int y2,
+				    intel_glyph_t *glyph)
+{
+    float *v;
+
+    /* Each vertex is:
+     *   2 vertex coordinates
+     *   2 glyph texture coordinates
+     */
+
+    v = i915_add_rectangle (device);
+
+    /* bottom right */
+    *v++ = x2; *v++ = y2;
+    *v++ = glyph->texcoord[0];
+
+    /* bottom left */
+    *v++ = x1; *v++ = y2;
+    *v++ = glyph->texcoord[1];
+
+    /* top left */
+    *v++ = x1; *v++ = y1;
+    *v++ = glyph->texcoord[2];
+}
+
+static void
+i915_emit_glyph_rectangle_general (i915_device_t *device,
+				   i915_shader_t *shader,
+				   int x1, int y1,
+				   int x2, int y2,
+				   intel_glyph_t *glyph)
+{
+    double s, t;
+    float *v;
+
+    /* Each vertex is:
+     *   2 vertex coordinates
+     *   [0-2] source texture coordinates
+     *   2 glyph texture coordinates
+     */
+
+    v = i915_add_rectangle (device);
+
+    /* bottom right */
+    *v++ = x2; *v++ = y2;
+    s = x2, t = y2;
+    switch (shader->source.type.vertex) {
+    case VS_CONSTANT:
+	break;
+    case VS_LINEAR:
+	*v++ = i915_shader_linear_texcoord (&shader->source.linear, s, t);
+	break;
+    case VS_RADIAL:
+	cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+	*v++ = s; *v++ = t;
+	break;
+    case VS_TEXTURE:
+	cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+	*v++ = s; *v++ = t;
+	break;
+    case VS_TEXTURE_16:
+	cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+	*v++ = texcoord_2d_16 (s, t);
+	break;
+    }
+    *v++ = glyph->texcoord[0];
+
+    /* bottom left */
+    *v++ = x1; *v++ = y2;
+    s = x1, t = y2;
+    switch (shader->source.type.vertex) {
+    case VS_CONSTANT:
+	break;
+    case VS_LINEAR:
+	*v++ = i915_shader_linear_texcoord (&shader->source.linear, s, t);
+	break;
+    case VS_RADIAL:
+	cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+	*v++ = s; *v++ = t;
+	break;
+    case VS_TEXTURE:
+	cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+	*v++ = s; *v++ = t;
+	break;
+    case VS_TEXTURE_16:
+	cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+	*v++ = texcoord_2d_16 (s, t);
+	break;
+    }
+    *v++ = glyph->texcoord[1];
+
+    /* top left */
+    *v++ = x1; *v++ = y1;
+    s = x1, t = y2;
+    switch (shader->source.type.vertex) {
+    case VS_CONSTANT:
+	break;
+    case VS_LINEAR:
+	*v++ = i915_shader_linear_texcoord (&shader->source.linear, s, t);
+	break;
+    case VS_RADIAL:
+	cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+	*v++ = s; *v++ = t;
+	break;
+    case VS_TEXTURE:
+	cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+	*v++ = s; *v++ = t;
+	break;
+    case VS_TEXTURE_16:
+	cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+	*v++ = texcoord_2d_16 (s, t);
+	break;
+    }
+    *v++ = glyph->texcoord[2];
+}
+
+typedef void
+(*i915_emit_glyph_rectangle_func_t) (i915_device_t *device,
+				     i915_shader_t *shader,
+				     int x1, int y1,
+				     int x2, int y2,
+				     intel_glyph_t *glyph);
+
+static cairo_status_t
+i915_surface_mask_internal (i915_surface_t *dst,
+			    cairo_operator_t		 op,
+			    const cairo_pattern_t	*source,
+			    i915_surface_t *mask,
+			    cairo_clip_t		*clip,
+			    const cairo_composite_rectangles_t *extents)
+{
+    i915_device_t *device;
+    i915_shader_t shader;
+    cairo_region_t *clip_region = NULL;
+    cairo_status_t status;
+
+    i915_shader_init (&shader, dst, op);
+
+    status = i915_shader_acquire_pattern (&shader, &shader.source,
+					  source, &extents->bounded);
+    if (unlikely (status))
+	return status;
+
+    shader.mask.type.vertex = VS_TEXTURE_16;
+    shader.mask.type.fragment = FS_TEXTURE;
+    shader.mask.base.content = mask->intel.drm.base.content;
+    shader.mask.base.texfmt = TEXCOORDFMT_2D_16;
+    shader.mask.base.n_samplers = 1;
+    shader.mask.base.sampler[0] =
+	(MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
+	i915_texture_filter (CAIRO_FILTER_NEAREST);
+    shader.mask.base.sampler[1] =
+	SS3_NORMALIZED_COORDS |
+	i915_texture_extend (CAIRO_EXTEND_NONE);
+
+    cairo_matrix_init_translate (&shader.mask.base.matrix,
+				 -extents->bounded.x + NEAREST_BIAS,
+				 -extents->bounded.y + NEAREST_BIAS);
+    cairo_matrix_scale (&shader.mask.base.matrix,
+			1. / mask->intel.drm.width,
+			1. / mask->intel.drm.height);
+
+    shader.mask.base.bo = to_intel_bo (mask->intel.drm.bo);
+    shader.mask.base.offset[0] = 0;
+    shader.mask.base.map[0] = mask->map0;
+    shader.mask.base.map[1] = mask->map1;
+
+    if (clip != NULL) {
+	status = _cairo_clip_get_region (clip, &clip_region);
+	assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+	if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+	    clip_region = NULL;
+
+	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+	    i915_shader_set_clip (&shader, clip);
+    }
+
+    status = cairo_device_acquire (dst->intel.drm.base.device);
+    if (unlikely (status))
+	goto CLEANUP_SHADER;
+
+    device = i915_device (dst);
+
+    status = i915_shader_commit (&shader, device);
+    if (unlikely (status))
+	goto CLEANUP_DEVICE;
+
+    if (clip_region != NULL) {
+	unsigned int n, num_rectangles;
+
+	num_rectangles = cairo_region_num_rectangles (clip_region);
+	for (n = 0; n < num_rectangles; n++) {
+	    cairo_rectangle_int_t rect;
+
+	    cairo_region_get_rectangle (clip_region, n, &rect);
+
+	    shader.add_rectangle (&shader,
+				  rect.x, rect.y,
+				  rect.x + rect.width, rect.y + rect.height);
+	}
+    } else {
+	shader.add_rectangle (&shader,
+			      extents->bounded.x, extents->bounded.y,
+			      extents->bounded.x + extents->bounded.width,
+			      extents->bounded.y + extents->bounded.height);
+    }
+
+    if ((extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) == 0)
+	status = i915_fixup_unbounded (dst, extents, clip);
+
+CLEANUP_DEVICE:
+    cairo_device_release (&device->intel.base.base);
+CLEANUP_SHADER:
+    i915_shader_fini (&shader);
+    return status;
+}
+
+cairo_int_status_t
+i915_surface_glyphs (void			*abstract_surface,
+		     cairo_operator_t		 op,
+		     const cairo_pattern_t	*source,
+		     cairo_glyph_t		*glyphs,
+		     int			 num_glyphs,
+		     cairo_scaled_font_t	*scaled_font,
+		     cairo_clip_t		*clip,
+		     int *num_remaining)
+{
+    i915_surface_t *surface = abstract_surface;
+    i915_surface_t *mask = NULL;
+    i915_device_t *device;
+    i915_shader_t shader;
+    cairo_composite_rectangles_t extents;
+    cairo_clip_t local_clip;
+    cairo_bool_t have_clip = FALSE;
+    cairo_bool_t overlap;
+    cairo_region_t *clip_region = NULL;
+    intel_bo_t *last_bo = NULL;
+    i915_emit_glyph_rectangle_func_t emit_func;
+    cairo_scaled_glyph_t *glyph_cache[64];
+    cairo_status_t status;
+    int mask_x = 0, mask_y = 0;
+    int i = 0;
+
+    *num_remaining = 0;
+    status = _cairo_composite_rectangles_init_for_glyphs (&extents,
+							  surface->intel.drm.width,
+							  surface->intel.drm.height,
+							  op, source,
+							  scaled_font,
+							  glyphs, num_glyphs,
+							  clip,
+							  &overlap);
+    if (unlikely (status))
+	return status;
+
+    if (_cairo_clip_contains_rectangle (clip, &extents))
+	clip = NULL;
+
+    if (clip != NULL && extents.is_bounded) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	status = _cairo_clip_rectangle (clip, &extents.bounded);
+	if (unlikely (status))
+	    return status;
+
+	have_clip = TRUE;
+    }
+
+    if (overlap || (extents.is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) == 0) {
+	cairo_content_t content;
+
+	content = CAIRO_CONTENT_ALPHA;
+	if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
+	    content |= CAIRO_CONTENT_COLOR;
+
+	mask = (i915_surface_t *)
+	    i915_surface_create_internal (&i915_device (surface)->intel.base,
+					  CAIRO_CONTENT_ALPHA,
+					  extents.bounded.width,
+					  extents.bounded.height,
+					  I915_TILING_DEFAULT,
+					  TRUE);
+	if (unlikely (mask->intel.drm.base.status))
+	    return mask->intel.drm.base.status;
+
+	status = _cairo_surface_paint (&mask->intel.drm.base,
+				       CAIRO_OPERATOR_CLEAR,
+				       &_cairo_pattern_clear.base,
+				       NULL);
+	if (unlikely (status)) {
+	    cairo_surface_destroy (&mask->intel.drm.base);
+	    return status;
+	}
+
+	i915_shader_init (&shader, mask, CAIRO_OPERATOR_ADD);
+
+	status = i915_shader_acquire_pattern (&shader, &shader.source,
+					      &_cairo_pattern_white.base,
+					      &extents.bounded);
+	if (unlikely (status)) {
+	    cairo_surface_destroy (&mask->intel.drm.base);
+	    return status;
+	}
+
+	mask_x = -extents.bounded.x;
+	mask_y = -extents.bounded.y;
+    } else {
+	i915_shader_init (&shader, surface, op);
+
+	status = i915_shader_acquire_pattern (&shader, &shader.source,
+					      source, &extents.bounded);
+	if (unlikely (status))
+	    return status;
+
+	if (clip != NULL) {
+	    status = _cairo_clip_get_region (clip, &clip_region);
+	    assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+	    if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+		clip_region = NULL;
+
+	    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+		i915_shader_set_clip (&shader, clip);
+	}
+    }
+
+    shader.mask.type.fragment = FS_TEXTURE;
+    shader.mask.base.content = CAIRO_CONTENT_ALPHA; /* XXX */
+    shader.mask.base.texfmt = TEXCOORDFMT_2D_16;
+    shader.mask.base.n_samplers = 1;
+    shader.mask.base.sampler[0] =
+	(MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
+	i915_texture_filter (CAIRO_FILTER_NEAREST);
+    shader.mask.base.sampler[1] =
+	SS3_NORMALIZED_COORDS |
+	i915_texture_extend (CAIRO_EXTEND_NONE);
+
+    switch (shader.source.type.vertex) {
+    case VS_CONSTANT:
+	emit_func = i915_emit_glyph_rectangle_constant;
+	break;
+    default:
+    case VS_LINEAR:
+    case VS_RADIAL:
+    case VS_TEXTURE:
+    case VS_TEXTURE_16:
+	emit_func = i915_emit_glyph_rectangle_general;
+	break;
+    }
+
+    status = cairo_device_acquire (surface->intel.drm.base.device);
+    if (unlikely (status))
+	goto CLEANUP_SHADER;
+
+    device = i915_device (surface);
+
+    _cairo_scaled_font_freeze_cache (scaled_font);
+    if (scaled_font->surface_private == NULL) {
+	/* XXX couple into list to remove on context destruction */
+	scaled_font->surface_private = device;
+	scaled_font->surface_backend = surface->intel.drm.base.backend;
+    }
+
+    memset (glyph_cache, 0, sizeof (glyph_cache));
+
+    for (i = 0; i < num_glyphs; i++) {
+	cairo_scaled_glyph_t *scaled_glyph;
+	int x, y, x1, x2, y1, y2;
+	int cache_index = glyphs[i].index % ARRAY_LENGTH (glyph_cache);
+	intel_glyph_t *glyph;
+
+	scaled_glyph = glyph_cache[cache_index];
+	if (scaled_glyph == NULL ||
+	    _cairo_scaled_glyph_index (scaled_glyph) != glyphs[i].index)
+	{
+	    status = _cairo_scaled_glyph_lookup (scaled_font,
+						 glyphs[i].index,
+						 CAIRO_SCALED_GLYPH_INFO_METRICS,
+						 &scaled_glyph);
+	    if (unlikely (status))
+		goto FINISH;
+
+	    glyph_cache[cache_index] = scaled_glyph;
+	}
+
+	if (unlikely (scaled_glyph->metrics.width  == 0 ||
+		      scaled_glyph->metrics.height == 0))
+	{
+	    continue;
+	}
+
+	/* XXX glyph images are snapped to pixel locations */
+	x = _cairo_lround (glyphs[i].x);
+	y = _cairo_lround (glyphs[i].y);
+
+	x1 = x + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
+	y1 = y + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
+	x2 = x + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x);
+	y2 = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y);
+
+	if (x2 < extents.bounded.x ||
+	    y2 < extents.bounded.y ||
+	    x1 > extents.bounded.x + extents.bounded.width ||
+	    y1 > extents.bounded.y + extents.bounded.height)
+	{
+	    continue;
+	}
+
+	if (scaled_glyph->surface_private == NULL) {
+	    status = intel_get_glyph (&device->intel, scaled_font, scaled_glyph);
+	    if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) {
+		status = CAIRO_STATUS_SUCCESS;
+		continue;
+	    }
+	    if (unlikely (status))
+		goto FINISH;
+	}
+	glyph = intel_glyph_pin (scaled_glyph->surface_private);
+
+	if (glyph->cache->buffer.bo != last_bo) {
+	    intel_buffer_cache_t *cache = glyph->cache;
+
+	    shader.mask.base.bo = cache->buffer.bo;
+	    shader.mask.base.offset[0] = cache->buffer.offset;
+	    shader.mask.base.map[0] = cache->buffer.map0;
+	    shader.mask.base.map[1] = cache->buffer.map1;
+	    shader.mask.base.content = CAIRO_CONTENT_ALPHA; /* XXX */
+
+	    status = i915_shader_commit (&shader, device);
+	    if (unlikely (status))
+		goto FINISH;
+
+	    last_bo = cache->buffer.bo;
+	}
+
+	x1 += mask_x; x2 += mask_x;
+	y1 += mask_y; y2 += mask_y;
+
+	/* XXX clip glyph */
+	emit_func (device, &shader, x1, y1, x2, y2, glyph);
+    }
+
+    status = CAIRO_STATUS_SUCCESS;
+  FINISH:
+    _cairo_scaled_font_thaw_cache (scaled_font);
+    cairo_device_release (surface->intel.drm.base.device);
+  CLEANUP_SHADER:
+    i915_shader_fini (&shader);
+
+    if (unlikely (status == CAIRO_INT_STATUS_UNSUPPORTED)) {
+	cairo_path_fixed_t path;
+
+	_cairo_path_fixed_init (&path);
+	status = _cairo_scaled_font_glyph_path (scaled_font,
+						glyphs + i, num_glyphs - i,
+						&path);
+	if (mask_x | mask_y) {
+	    _cairo_path_fixed_translate (&path,
+					 _cairo_fixed_from_int (mask_x),
+					 _cairo_fixed_from_int (mask_y));
+	}
+	if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	    status = surface->intel.drm.base.backend->fill (shader.target,
+							    shader.op,
+							    mask != NULL ? &_cairo_pattern_white.base : source,
+							    &path,
+							    CAIRO_FILL_RULE_WINDING,
+							    0,
+							    scaled_font->options.antialias,
+							    clip);
+	}
+	_cairo_path_fixed_fini (&path);
+    }
+
+    if (mask != NULL) {
+	if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	    status = i915_surface_mask_internal (surface, op, source, mask,
+					         clip, &extents);
+	}
+	cairo_surface_finish (&mask->intel.drm.base);
+	cairo_surface_destroy (&mask->intel.drm.base);
+    }
+
+    if (have_clip)
+	_cairo_clip_fini (&local_clip);
+
+    return status;
+}
diff --git a/src/drm/cairo-drm-i915-private.h b/src/drm/cairo-drm-i915-private.h
new file mode 100644
index 0000000..060c21c
--- /dev/null
+++ b/src/drm/cairo-drm-i915-private.h
@@ -0,0 +1,1169 @@
+/*
+ * Copyright © 2006, 2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric at anholt.net>
+ *    Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_DRM_I915_PRIVATE_H
+#define CAIRO_DRM_I915_PRIVATE_H
+
+#include "cairo-types-private.h"
+
+#include "cairo-drm-private.h"
+#include "cairo-drm-intel-private.h"
+#include "cairo-drm-intel-command-private.h"
+#include "cairo-drm-intel-ioctl-private.h"
+#include "cairo-freelist-private.h"
+
+#define I915_VERBOSE 1
+
+#define I915_MAX_TEX_INDIRECT 4
+#define I915_MAX_TEX_INSN     32
+#define I915_MAX_ALU_INSN     64
+#define I915_MAX_DECL_INSN    27
+#define I915_MAX_TEMPORARY    16
+
+/* Each instruction is 3 dwords long, though most don't require all
+ * this space.  Maximum of 123 instructions.  Smaller maxes per insn
+ * type.
+ */
+#define _3DSTATE_PIXEL_SHADER_PROGRAM    (CMD_3D|(0x1d<<24)|(0x5<<16))
+
+#define REG_TYPE_R                 0 /* temporary regs, no need to
+				      * dcl, must be written before
+				      * read -- Preserved between
+				      * phases.
+				      */
+#define REG_TYPE_T                 1 /* Interpolated values, must be
+				      * dcl'ed before use.
+				      *
+				      * 0..7: texture coord,
+				      * 8: diffuse spec,
+				      * 9: specular color,
+				      * 10: fog parameter in w.
+				      */
+#define REG_TYPE_CONST             2 /* Restriction: only one const
+				      * can be referenced per
+				      * instruction, though it may be
+				      * selected for multiple inputs.
+				      * Constants not initialized
+				      * default to zero.
+				      */
+#define REG_TYPE_S                 3 /* sampler */
+#define REG_TYPE_OC                4 /* output color (rgba) */
+#define REG_TYPE_OD                5 /* output depth (w), xyz are
+				      * temporaries.  If not written,
+				      * interpolated depth is used?
+				      */
+#define REG_TYPE_U                 6 /* unpreserved temporaries */
+#define REG_TYPE_MASK              0x7
+#define REG_TYPE_SHIFT		   4
+#define REG_NR_MASK                0xf
+
+/* REG_TYPE_T:
+ */
+#define T_TEX0     0
+#define T_TEX1     1
+#define T_TEX2     2
+#define T_TEX3     3
+#define T_TEX4     4
+#define T_TEX5     5
+#define T_TEX6     6
+#define T_TEX7     7
+#define T_DIFFUSE  8
+#define T_SPECULAR 9
+#define T_FOG_W    10		/* interpolated fog is in W coord */
+
+/* Arithmetic instructions */
+
+/* .replicate_swizzle == selection and replication of a particular
+ * scalar channel, ie., .xxxx, .yyyy, .zzzz or .wwww
+ */
+#define A0_NOP    (0x0<<24)		/* no operation */
+#define A0_ADD    (0x1<<24)		/* dst = src0 + src1 */
+#define A0_MOV    (0x2<<24)		/* dst = src0 */
+#define A0_MUL    (0x3<<24)		/* dst = src0 * src1 */
+#define A0_MAD    (0x4<<24)		/* dst = src0 * src1 + src2 */
+#define A0_DP2ADD (0x5<<24)		/* dst.xyzw = src0.xy dot src1.xy + src2.replicate_swizzle */
+#define A0_DP3    (0x6<<24)		/* dst.xyzw = src0.xyz dot src1.xyz */
+#define A0_DP4    (0x7<<24)		/* dst.xyzw = src0.xyzw dot src1.xyzw */
+#define A0_FRC    (0x8<<24)		/* dst = src0 - floor(src0) */
+#define A0_RCP    (0x9<<24)		/* dst.xyzw = 1/(src0.replicate_swizzle) */
+#define A0_RSQ    (0xa<<24)		/* dst.xyzw = 1/(sqrt(abs(src0.replicate_swizzle))) */
+#define A0_EXP    (0xb<<24)		/* dst.xyzw = exp2(src0.replicate_swizzle) */
+#define A0_LOG    (0xc<<24)		/* dst.xyzw = log2(abs(src0.replicate_swizzle)) */
+#define A0_CMP    (0xd<<24)		/* dst = (src0 >= 0.0) ? src1 : src2 */
+#define A0_MIN    (0xe<<24)		/* dst = (src0 < src1) ? src0 : src1 */
+#define A0_MAX    (0xf<<24)		/* dst = (src0 >= src1) ? src0 : src1 */
+#define A0_FLR    (0x10<<24)		/* dst = floor(src0) */
+#define A0_MOD    (0x11<<24)		/* dst = src0 fmod 1.0 */
+#define A0_TRC    (0x12<<24)		/* dst = int(src0) */
+#define A0_SGE    (0x13<<24)		/* dst = src0 >= src1 ? 1.0 : 0.0 */
+#define A0_SLT    (0x14<<24)		/* dst = src0 < src1 ? 1.0 : 0.0 */
+#define A0_DEST_SATURATE                 (1<<22)
+#define A0_DEST_TYPE_SHIFT                19
+/* Allow: R, OC, OD, U */
+#define A0_DEST_NR_SHIFT                 14
+/* Allow R: 0..15, OC,OD: 0..0, U: 0..2 */
+#define A0_DEST_CHANNEL_X                (1<<10)
+#define A0_DEST_CHANNEL_Y                (2<<10)
+#define A0_DEST_CHANNEL_Z                (4<<10)
+#define A0_DEST_CHANNEL_W                (8<<10)
+#define A0_DEST_CHANNEL_ALL              (0xf<<10)
+#define A0_DEST_CHANNEL_SHIFT            10
+#define A0_SRC0_TYPE_SHIFT               7
+#define A0_SRC0_NR_SHIFT                 2
+
+#define A0_DEST_CHANNEL_XY              (A0_DEST_CHANNEL_X|A0_DEST_CHANNEL_Y)
+#define A0_DEST_CHANNEL_XYZ             (A0_DEST_CHANNEL_XY|A0_DEST_CHANNEL_Z)
+
+#define SRC_X        0
+#define SRC_Y        1
+#define SRC_Z        2
+#define SRC_W        3
+#define SRC_ZERO     4
+#define SRC_ONE      5
+
+#define A1_SRC0_CHANNEL_X_NEGATE         (1<<31)
+#define A1_SRC0_CHANNEL_X_SHIFT          28
+#define A1_SRC0_CHANNEL_Y_NEGATE         (1<<27)
+#define A1_SRC0_CHANNEL_Y_SHIFT          24
+#define A1_SRC0_CHANNEL_Z_NEGATE         (1<<23)
+#define A1_SRC0_CHANNEL_Z_SHIFT          20
+#define A1_SRC0_CHANNEL_W_NEGATE         (1<<19)
+#define A1_SRC0_CHANNEL_W_SHIFT          16
+#define A1_SRC1_TYPE_SHIFT               13
+#define A1_SRC1_NR_SHIFT                 8
+#define A1_SRC1_CHANNEL_X_NEGATE         (1<<7)
+#define A1_SRC1_CHANNEL_X_SHIFT          4
+#define A1_SRC1_CHANNEL_Y_NEGATE         (1<<3)
+#define A1_SRC1_CHANNEL_Y_SHIFT          0
+
+#define A2_SRC1_CHANNEL_Z_NEGATE         (1<<31)
+#define A2_SRC1_CHANNEL_Z_SHIFT          28
+#define A2_SRC1_CHANNEL_W_NEGATE         (1<<27)
+#define A2_SRC1_CHANNEL_W_SHIFT          24
+#define A2_SRC2_TYPE_SHIFT               21
+#define A2_SRC2_NR_SHIFT                 16
+#define A2_SRC2_CHANNEL_X_NEGATE         (1<<15)
+#define A2_SRC2_CHANNEL_X_SHIFT          12
+#define A2_SRC2_CHANNEL_Y_NEGATE         (1<<11)
+#define A2_SRC2_CHANNEL_Y_SHIFT          8
+#define A2_SRC2_CHANNEL_Z_NEGATE         (1<<7)
+#define A2_SRC2_CHANNEL_Z_SHIFT          4
+#define A2_SRC2_CHANNEL_W_NEGATE         (1<<3)
+#define A2_SRC2_CHANNEL_W_SHIFT          0
+
+/* Texture instructions */
+#define T0_TEXLD     (0x15<<24)	/* Sample texture using predeclared
+				 * sampler and address, and output
+				 * filtered texel data to destination
+				 * register */
+#define T0_TEXLDP    (0x16<<24)	/* Same as texld but performs a
+				 * perspective divide of the texture
+				 * coordinate .xyz values by .w before
+				 * sampling. */
+#define T0_TEXLDB    (0x17<<24)	/* Same as texld but biases the
+				 * computed LOD by w.  Only S4.6 two's
+				 * comp is used.  This implies that a
+				 * float to fixed conversion is
+				 * done. */
+#define T0_TEXKILL   (0x18<<24)	/* Does not perform a sampling
+				 * operation.  Simply kills the pixel
+				 * if any channel of the address
+				 * register is < 0.0. */
+#define T0_DEST_TYPE_SHIFT                19
+/* Allow: R, OC, OD, U */
+/* Note: U (unpreserved) regs do not retain their values between
+ * phases (cannot be used for feedback)
+ *
+ * Note: oC and OD registers can only be used as the destination of a
+ * texture instruction once per phase (this is an implementation
+ * restriction).
+ */
+#define T0_DEST_NR_SHIFT                 14
+/* Allow R: 0..15, OC,OD: 0..0, U: 0..2 */
+#define T0_SAMPLER_NR_SHIFT              0 /* This field ignored for TEXKILL */
+#define T0_SAMPLER_NR_MASK               (0xf<<0)
+
+#define T1_ADDRESS_REG_TYPE_SHIFT        24 /* Reg to use as texture coord */
+/* Allow R, T, OC, OD -- R, OC, OD are 'dependent' reads, new program phase */
+#define T1_ADDRESS_REG_NR_SHIFT          17
+#define T2_MBZ                           0
+
+/* Declaration instructions */
+#define D0_DCL       (0x19<<24)	/* Declare a t (interpolated attrib)
+				 * register or an s (sampler)
+				 * register. */
+#define D0_SAMPLE_TYPE_SHIFT              22
+#define D0_SAMPLE_TYPE_2D                 (0x0<<22)
+#define D0_SAMPLE_TYPE_CUBE               (0x1<<22)
+#define D0_SAMPLE_TYPE_VOLUME             (0x2<<22)
+#define D0_SAMPLE_TYPE_MASK               (0x3<<22)
+
+#define D0_TYPE_SHIFT                19
+/* Allow: T, S */
+#define D0_NR_SHIFT                  14
+/* Allow T: 0..10, S: 0..15 */
+#define D0_CHANNEL_X                (1<<10)
+#define D0_CHANNEL_Y                (2<<10)
+#define D0_CHANNEL_Z                (4<<10)
+#define D0_CHANNEL_W                (8<<10)
+#define D0_CHANNEL_ALL              (0xf<<10)
+#define D0_CHANNEL_NONE             (0<<10)
+
+#define D0_CHANNEL_XY               (D0_CHANNEL_X|D0_CHANNEL_Y)
+#define D0_CHANNEL_XYZ              (D0_CHANNEL_XY|D0_CHANNEL_Z)
+
+/* I915 Errata: Do not allow (xz), (xw), (xzw) combinations for diffuse
+ * or specular declarations.
+ *
+ * For T dcls, only allow: (x), (xy), (xyz), (w), (xyzw)
+ *
+ * Must be zero for S (sampler) dcls
+ */
+#define D1_MBZ                          0
+#define D2_MBZ                          0
+
+
+/* MASK_* are the unshifted bitmasks of the destination mask in arithmetic
+ * operations
+ */
+#define MASK_X			0x1
+#define MASK_Y			0x2
+#define MASK_Z			0x4
+#define MASK_W			0x8
+#define MASK_XYZ		(MASK_X | MASK_Y | MASK_Z)
+#define MASK_XYZW		(MASK_XYZ | MASK_W)
+#define MASK_SATURATE		0x10
+
+/* Temporary, undeclared regs. Preserved between phases */
+#define FS_R0			((REG_TYPE_R << REG_TYPE_SHIFT) | 0)
+#define FS_R1			((REG_TYPE_R << REG_TYPE_SHIFT) | 1)
+#define FS_R2			((REG_TYPE_R << REG_TYPE_SHIFT) | 2)
+#define FS_R3			((REG_TYPE_R << REG_TYPE_SHIFT) | 3)
+
+/* Texture coordinate regs.  Must be declared. */
+#define FS_T0			((REG_TYPE_T << REG_TYPE_SHIFT) | 0)
+#define FS_T1			((REG_TYPE_T << REG_TYPE_SHIFT) | 1)
+#define FS_T2			((REG_TYPE_T << REG_TYPE_SHIFT) | 2)
+#define FS_T3			((REG_TYPE_T << REG_TYPE_SHIFT) | 3)
+#define FS_T4			((REG_TYPE_T << REG_TYPE_SHIFT) | 4)
+#define FS_T5			((REG_TYPE_T << REG_TYPE_SHIFT) | 5)
+#define FS_T6			((REG_TYPE_T << REG_TYPE_SHIFT) | 6)
+#define FS_T7			((REG_TYPE_T << REG_TYPE_SHIFT) | 7)
+#define FS_T8			((REG_TYPE_T << REG_TYPE_SHIFT) | 8)
+#define FS_T9			((REG_TYPE_T << REG_TYPE_SHIFT) | 9)
+#define FS_T10			((REG_TYPE_T << REG_TYPE_SHIFT) | 10)
+
+/* Constant values */
+#define FS_C0			((REG_TYPE_CONST << REG_TYPE_SHIFT) | 0)
+#define FS_C1			((REG_TYPE_CONST << REG_TYPE_SHIFT) | 1)
+#define FS_C2			((REG_TYPE_CONST << REG_TYPE_SHIFT) | 2)
+#define FS_C3			((REG_TYPE_CONST << REG_TYPE_SHIFT) | 3)
+#define FS_C4			((REG_TYPE_CONST << REG_TYPE_SHIFT) | 4)
+#define FS_C5			((REG_TYPE_CONST << REG_TYPE_SHIFT) | 5)
+#define FS_C6			((REG_TYPE_CONST << REG_TYPE_SHIFT) | 6)
+#define FS_C7			((REG_TYPE_CONST << REG_TYPE_SHIFT) | 7)
+
+/* Sampler regs */
+#define FS_S0			((REG_TYPE_S << REG_TYPE_SHIFT) | 0)
+#define FS_S1			((REG_TYPE_S << REG_TYPE_SHIFT) | 1)
+#define FS_S2			((REG_TYPE_S << REG_TYPE_SHIFT) | 2)
+#define FS_S3			((REG_TYPE_S << REG_TYPE_SHIFT) | 3)
+
+/* Output color */
+#define FS_OC			((REG_TYPE_OC << REG_TYPE_SHIFT) | 0)
+
+/* Output depth */
+#define FS_OD			((REG_TYPE_OD << REG_TYPE_SHIFT) | 0)
+
+/* Unpreserved temporary regs */
+#define FS_U0			((REG_TYPE_U << REG_TYPE_SHIFT) | 0)
+#define FS_U1			((REG_TYPE_U << REG_TYPE_SHIFT) | 1)
+#define FS_U2			((REG_TYPE_U << REG_TYPE_SHIFT) | 2)
+#define FS_U3			((REG_TYPE_U << REG_TYPE_SHIFT) | 3)
+
+#define X_CHANNEL_SHIFT (REG_TYPE_SHIFT + 3)
+#define Y_CHANNEL_SHIFT (X_CHANNEL_SHIFT + 3)
+#define Z_CHANNEL_SHIFT (Y_CHANNEL_SHIFT + 3)
+#define W_CHANNEL_SHIFT (Z_CHANNEL_SHIFT + 3)
+
+#define REG_CHANNEL_MASK 0x7
+
+#define REG_NR(reg)		((reg) & REG_NR_MASK)
+#define REG_TYPE(reg)		(((reg) >> REG_TYPE_SHIFT) & REG_TYPE_MASK)
+#define REG_X(reg)		(((reg) >> X_CHANNEL_SHIFT) & REG_CHANNEL_MASK)
+#define REG_Y(reg)		(((reg) >> Y_CHANNEL_SHIFT) & REG_CHANNEL_MASK)
+#define REG_Z(reg)		(((reg) >> Z_CHANNEL_SHIFT) & REG_CHANNEL_MASK)
+#define REG_W(reg)		(((reg) >> W_CHANNEL_SHIFT) & REG_CHANNEL_MASK)
+
+enum i915_fs_channel {
+    X_CHANNEL_VAL = 1,
+    Y_CHANNEL_VAL,
+    Z_CHANNEL_VAL,
+    W_CHANNEL_VAL,
+    ZERO_CHANNEL_VAL,
+    ONE_CHANNEL_VAL
+};
+
+#define i915_fs_operand(reg, x, y, z, w) \
+    (reg) | \
+    (x##_CHANNEL_VAL << X_CHANNEL_SHIFT) | \
+    (y##_CHANNEL_VAL << Y_CHANNEL_SHIFT) | \
+    (z##_CHANNEL_VAL << Z_CHANNEL_SHIFT) | \
+    (w##_CHANNEL_VAL << W_CHANNEL_SHIFT)
+
+/**
+ * Construct an operand description for using a register with no swizzling
+ */
+#define i915_fs_operand_reg(reg)					\
+    i915_fs_operand(reg, X, Y, Z, W)
+
+#define i915_fs_operand_reg_negate(reg)					\
+    i915_fs_operand(reg, -X, -Y, -Z, -W)
+
+/**
+ * Returns an operand containing (0.0, 0.0, 0.0, 0.0).
+ */
+#define i915_fs_operand_zero() i915_fs_operand(FS_R0, ZERO, ZERO, ZERO, ZERO)
+
+/**
+ * Returns an unused operand
+ */
+#define i915_fs_operand_none() i915_fs_operand_zero()
+
+/**
+ * Returns an operand containing (1.0, 1.0, 1.0, 1.0).
+ */
+#define i915_fs_operand_one() i915_fs_operand(FS_R0, ONE, ONE, ONE, ONE)
+
+#define i915_get_hardware_channel_val(val, shift, negate) \
+    (((int) val < 0) ?  (~val << shift) | negate : (val - 1) << shift)
+
+/**
+ * Outputs a fragment shader command to declare a sampler or texture register.
+ */
+#define i915_fs_dcl(reg)						\
+do {									\
+    OUT_DWORD (D0_DCL | \
+	       (REG_TYPE(reg) << D0_TYPE_SHIFT) | \
+	       (REG_NR(reg) << D0_NR_SHIFT) | \
+               ((REG_TYPE(reg) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0)); \
+    OUT_DWORD (0); \
+    OUT_DWORD (0); \
+} while (0)
+
+#define i915_fs_texld(dest_reg, sampler_reg, address_reg)		\
+do {									\
+    OUT_DWORD (T0_TEXLD | \
+               (REG_TYPE(dest_reg) << T0_DEST_TYPE_SHIFT) | \
+               (REG_NR(dest_reg) << T0_DEST_NR_SHIFT) | \
+               (REG_NR(sampler_reg) << T0_SAMPLER_NR_SHIFT)); \
+    OUT_DWORD((REG_TYPE(address_reg) << T1_ADDRESS_REG_TYPE_SHIFT) | \
+              (REG_NR(address_reg) << T1_ADDRESS_REG_NR_SHIFT)); \
+    OUT_DWORD (0); \
+} while (0)
+
+#define i915_fs_arith_masked(op, dest_reg, dest_mask, operand0, operand1, operand2)	\
+    _i915_fs_arith_masked(A0_##op, dest_reg, dest_mask, operand0, operand1, operand2)
+
+#define i915_fs_arith(op, dest_reg, operand0, operand1, operand2)	\
+    _i915_fs_arith(A0_##op, dest_reg, operand0, operand1, operand2)
+
+#define _i915_fs_arith_masked(cmd, dest_reg, dest_mask, operand0, operand1, operand2) \
+do { \
+    /* Set up destination register and write mask */ \
+    OUT_DWORD (cmd | \
+               (REG_TYPE(dest_reg) << A0_DEST_TYPE_SHIFT) | \
+	       (REG_NR(dest_reg) << A0_DEST_NR_SHIFT) | \
+               (((dest_mask) & ~MASK_SATURATE) << A0_DEST_CHANNEL_SHIFT) | \
+               (((dest_mask) & MASK_SATURATE) ? A0_DEST_SATURATE : 0) | \
+               /* Set up operand 0 */ \
+	       (REG_TYPE(operand0) << A0_SRC0_TYPE_SHIFT) | \
+	       (REG_NR(operand0) << A0_SRC0_NR_SHIFT)); \
+    OUT_DWORD (i915_get_hardware_channel_val(REG_X(operand0), \
+					      A1_SRC0_CHANNEL_X_SHIFT, \
+					      A1_SRC0_CHANNEL_X_NEGATE) | \
+               i915_get_hardware_channel_val(REG_Y(operand0), \
+					      A1_SRC0_CHANNEL_Y_SHIFT, \
+					      A1_SRC0_CHANNEL_Y_NEGATE) | \
+               i915_get_hardware_channel_val(REG_Z(operand0), \
+					      A1_SRC0_CHANNEL_Z_SHIFT, \
+					      A1_SRC0_CHANNEL_Z_NEGATE) | \
+               i915_get_hardware_channel_val(REG_W(operand0), \
+					      A1_SRC0_CHANNEL_W_SHIFT, \
+					      A1_SRC0_CHANNEL_W_NEGATE) | \
+               /* Set up operand 1 */ \
+               (REG_TYPE(operand1) << A1_SRC1_TYPE_SHIFT) | \
+               (REG_NR(operand1) << A1_SRC1_NR_SHIFT) | \
+               i915_get_hardware_channel_val(REG_X(operand1), \
+					      A1_SRC1_CHANNEL_X_SHIFT, \
+					      A1_SRC1_CHANNEL_X_NEGATE) | \
+               i915_get_hardware_channel_val(REG_Y(operand1), \
+					      A1_SRC1_CHANNEL_Y_SHIFT, \
+					      A1_SRC1_CHANNEL_Y_NEGATE)); \
+    OUT_DWORD (i915_get_hardware_channel_val(REG_Z(operand1), \
+					      A2_SRC1_CHANNEL_Z_SHIFT, \
+					      A2_SRC1_CHANNEL_Z_NEGATE) | \
+	       i915_get_hardware_channel_val(REG_W(operand1), \
+		                             A2_SRC1_CHANNEL_W_SHIFT, \
+					     A2_SRC1_CHANNEL_W_NEGATE) | \
+               /* Set up operand 2 */ \
+               (REG_TYPE(operand2) << A2_SRC2_TYPE_SHIFT) | \
+               (REG_NR(operand2) << A2_SRC2_NR_SHIFT) | \
+               i915_get_hardware_channel_val(REG_X(operand2), \
+					      A2_SRC2_CHANNEL_X_SHIFT, \
+					      A2_SRC2_CHANNEL_X_NEGATE) | \
+               i915_get_hardware_channel_val(REG_Y(operand2), \
+					      A2_SRC2_CHANNEL_Y_SHIFT, \
+					      A2_SRC2_CHANNEL_Y_NEGATE) | \
+               i915_get_hardware_channel_val(REG_Z(operand2), \
+					      A2_SRC2_CHANNEL_Z_SHIFT, \
+					      A2_SRC2_CHANNEL_Z_NEGATE) | \
+               i915_get_hardware_channel_val(REG_W(operand2), \
+					       A2_SRC2_CHANNEL_W_SHIFT, \
+					       A2_SRC2_CHANNEL_W_NEGATE)); \
+} while (0)
+
+#define _i915_fs_arith(cmd, dest_reg, operand0, operand1, operand2) do {\
+    /* Set up destination register and write mask */ \
+    OUT_DWORD (cmd | \
+               (REG_TYPE(dest_reg) << A0_DEST_TYPE_SHIFT) | \
+	       (REG_NR(dest_reg) << A0_DEST_NR_SHIFT) | \
+	       (A0_DEST_CHANNEL_ALL) | \
+               /* Set up operand 0 */ \
+	       (REG_TYPE(operand0) << A0_SRC0_TYPE_SHIFT) | \
+	       (REG_NR(operand0) << A0_SRC0_NR_SHIFT)); \
+    OUT_DWORD (i915_get_hardware_channel_val(REG_X(operand0), \
+					      A1_SRC0_CHANNEL_X_SHIFT, \
+					      A1_SRC0_CHANNEL_X_NEGATE) | \
+               i915_get_hardware_channel_val(REG_Y(operand0), \
+					      A1_SRC0_CHANNEL_Y_SHIFT, \
+					      A1_SRC0_CHANNEL_Y_NEGATE) | \
+               i915_get_hardware_channel_val(REG_Z(operand0), \
+					      A1_SRC0_CHANNEL_Z_SHIFT, \
+					      A1_SRC0_CHANNEL_Z_NEGATE) | \
+               i915_get_hardware_channel_val(REG_W(operand0), \
+					      A1_SRC0_CHANNEL_W_SHIFT, \
+					      A1_SRC0_CHANNEL_W_NEGATE) | \
+               /* Set up operand 1 */ \
+               (REG_TYPE(operand1) << A1_SRC1_TYPE_SHIFT) | \
+               (REG_NR(operand1) << A1_SRC1_NR_SHIFT) | \
+               i915_get_hardware_channel_val(REG_X(operand1), \
+					      A1_SRC1_CHANNEL_X_SHIFT, \
+					      A1_SRC1_CHANNEL_X_NEGATE) | \
+               i915_get_hardware_channel_val(REG_Y(operand1), \
+					      A1_SRC1_CHANNEL_Y_SHIFT, \
+					      A1_SRC1_CHANNEL_Y_NEGATE)); \
+    OUT_DWORD (i915_get_hardware_channel_val(REG_Z(operand1), \
+					      A2_SRC1_CHANNEL_Z_SHIFT, \
+					      A2_SRC1_CHANNEL_Z_NEGATE) | \
+	       i915_get_hardware_channel_val(REG_W(operand1), \
+		                             A2_SRC1_CHANNEL_W_SHIFT, \
+					     A2_SRC1_CHANNEL_W_NEGATE) | \
+               /* Set up operand 2 */ \
+               (REG_TYPE(operand2) << A2_SRC2_TYPE_SHIFT) | \
+               (REG_NR(operand2) << A2_SRC2_NR_SHIFT) | \
+               i915_get_hardware_channel_val(REG_X(operand2), \
+					      A2_SRC2_CHANNEL_X_SHIFT, \
+					      A2_SRC2_CHANNEL_X_NEGATE) | \
+               i915_get_hardware_channel_val(REG_Y(operand2), \
+					      A2_SRC2_CHANNEL_Y_SHIFT, \
+					      A2_SRC2_CHANNEL_Y_NEGATE) | \
+               i915_get_hardware_channel_val(REG_Z(operand2), \
+					      A2_SRC2_CHANNEL_Z_SHIFT, \
+					      A2_SRC2_CHANNEL_Z_NEGATE) | \
+               i915_get_hardware_channel_val(REG_W(operand2), \
+					       A2_SRC2_CHANNEL_W_SHIFT, \
+					       A2_SRC2_CHANNEL_W_NEGATE)); \
+} while (0)
+
+#define i915_fs_mov(dest_reg, operand0)					\
+    i915_fs_arith(MOV, dest_reg, \
+	          operand0,			\
+	          i915_fs_operand_none(),			\
+	          i915_fs_operand_none())
+
+#define i915_fs_mov_masked(dest_reg, dest_mask, operand0)		\
+    i915_fs_arith_masked (MOV, dest_reg, dest_mask, \
+	                  operand0, \
+	                  i915_fs_operand_none(), \
+	                  i915_fs_operand_none())
+
+
+#define i915_fs_frc(dest_reg, operand0)					\
+    i915_fs_arith (FRC, dest_reg, \
+	           operand0,			\
+	           i915_fs_operand_none(),			\
+	           i915_fs_operand_none())
+
+/** Add operand0 and operand1 and put the result in dest_reg */
+#define i915_fs_add(dest_reg, operand0, operand1)			\
+    i915_fs_arith (ADD, dest_reg, \
+	           operand0, operand1,	\
+		   i915_fs_operand_none())
+
+/** Multiply operand0 and operand1 and put the result in dest_reg */
+#define i915_fs_mul(dest_reg, operand0, operand1)			\
+    i915_fs_arith (MUL, dest_reg, \
+	           operand0, operand1,	\
+		   i915_fs_operand_none())
+
+/** Computes 1/sqrt(operand0.replicate_swizzle) puts the result in dest_reg */
+#define i915_fs_rsq(dest_reg, dest_mask, operand0)		\
+do {									\
+    if (dest_mask) {							\
+	i915_fs_arith_masked (RSQ, dest_reg, dest_mask, \
+		              operand0,			\
+			      i915_fs_operand_none (),			\
+			      i915_fs_operand_none ());			\
+    } else { \
+	i915_fs_arith (RSQ, dest_reg, \
+		       operand0, \
+		       i915_fs_operand_none (), \
+		       i915_fs_operand_none ()); \
+    } \
+} while (0)
+
+/** Puts the minimum of operand0 and operand1 in dest_reg */
+#define i915_fs_min(dest_reg, operand0, operand1)			\
+    i915_fs_arith (MIN, dest_reg, \
+	           operand0, operand1, \
+		   i915_fs_operand_none())
+
+/** Puts the maximum of operand0 and operand1 in dest_reg */
+#define i915_fs_max(dest_reg, operand0, operand1)			\
+    i915_fs_arith (MAX, dest_reg, \
+	           operand0, operand1, \
+	           i915_fs_operand_none())
+
+#define i915_fs_cmp(dest_reg, operand0, operand1, operand2)		\
+    i915_fs_arith (CMP, dest_reg, operand0, operand1, operand2)
+
+/** Perform operand0 * operand1 + operand2 and put the result in dest_reg */
+#define i915_fs_mad(dest_reg, dest_mask, op0, op1, op2)	\
+do {									\
+    if (dest_mask) {							\
+	i915_fs_arith_masked (MAD, dest_reg, dest_mask, op0, op1, op2); \
+    } else { \
+	i915_fs_arith (MAD, dest_reg, op0, op1, op2); \
+    } \
+} while (0)
+
+#define i915_fs_dp2add(dest_reg, dest_mask, op0, op1, op2)	\
+do {									\
+    if (dest_mask) {							\
+	i915_fs_arith_masked (DP2ADD, dest_reg, dest_mask, op0, op1, op2); \
+    } else { \
+	i915_fs_arith (DP2ADD, dest_reg, op0, op1, op2); \
+    } \
+} while (0)
+
+/**
+ * Perform a 3-component dot-product of operand0 and operand1 and put the
+ * resulting scalar in the channels of dest_reg specified by the dest_mask.
+ */
+#define i915_fs_dp3(dest_reg, dest_mask, op0, op1)	\
+do {									\
+    if (dest_mask) {							\
+	i915_fs_arith_masked (DP3, dest_reg, dest_mask, \
+		              op0, op1,\
+		              i915_fs_operand_none());			\
+    } else { \
+	i915_fs_arith (DP3, dest_reg, op0, op1,\
+		       i915_fs_operand_none());			\
+    } \
+} while (0)
+
+static inline uint32_t cairo_const
+i915_fs_operand_pure_alpha (int pure)
+{
+    if (pure & (1 << 3))
+	return i915_fs_operand_one ();
+    else
+	return i915_fs_operand_zero ();
+}
+
+#define I915_TILING_DEFAULT I915_TILING_Y
+#define I915_BO_CACHE_BUCKETS 13 /* cache surfaces up to 16 MiB */
+
+typedef struct i915_surface i915_surface_t;
+typedef struct i915_device i915_device_t;
+typedef struct i915_shader i915_shader_t;
+
+typedef void (*i915_add_rectangle_func_t) (const i915_shader_t *shader,
+					   int x, int y,
+					   int w, int h);
+
+#define IMAGE_CACHE_WIDTH 1024
+#define IMAGE_CACHE_HEIGHT 1024
+
+typedef struct i915_image_private {
+    cairo_rtree_node_t node;
+    intel_buffer_cache_t *container;
+} i915_image_private_t;
+
+#define I915_BATCH_SIZE (64*1024)
+#define I915_VBO_SIZE (512*1024)
+#define I915_MAX_RELOCS 2048
+
+enum {
+    I915_DEBUG_EXEC = 0x1,
+    I915_DEBUG_SYNC = 0x2,
+    I915_DEBUG_BATCH = 0x4,
+    I915_DEBUG_BUFFER = 0x8,
+    I915_DEBUG_BUFFER_CACHE = 0x10,
+    I915_DEBUG_BUFFER_ALLOC = 0x20,
+    I915_DEBUG_GLYPHS = 0x40,
+    I915_DEBUG_MAP = 0x80,
+    I915_DEBUG_THROTTLE = 0x100,
+};
+
+struct i915_device {
+    intel_device_t intel;
+
+    cairo_bool_t debug;
+
+    struct i915_batch {
+	intel_bo_t *target_bo[I915_MAX_RELOCS];
+	size_t gtt_size;
+
+	struct drm_i915_gem_exec_object2 exec[I915_MAX_RELOCS];
+	int exec_count;
+
+	struct drm_i915_gem_relocation_entry reloc[I915_MAX_RELOCS];
+	uint16_t reloc_count;
+
+	uint16_t used;
+    } batch;
+
+    uint32_t vbo;
+    uint32_t vbo_offset;
+    uint32_t vbo_used;
+    uint32_t vbo_max_index;
+    uint32_t vertex_index;
+    uint32_t vertex_count;
+    uint32_t floats_per_vertex;
+    uint32_t rectangle_size;
+    intel_bo_t *last_vbo;
+    uint32_t last_vbo_offset;
+    uint32_t last_vbo_space;
+
+    i915_shader_t *current_shader;
+
+    i915_surface_t *current_target;
+    uint32_t current_size;
+    uint32_t current_diffuse;
+    uint32_t current_colorbuf;
+    uint32_t *current_source;
+    uint32_t *current_mask;
+    uint32_t *current_clip;
+    uint32_t current_program;
+    uint32_t current_texcoords;
+    uint32_t current_blend;
+    uint32_t current_constants[8*4];
+    uint32_t current_n_constants;
+    uint32_t current_samplers[2*(3+3*4)];
+    uint32_t current_n_samplers;
+    uint32_t last_source_fragment;
+
+    cairo_list_t image_caches[2];
+
+    uint32_t batch_header[18];
+    uint32_t batch_base[I915_BATCH_SIZE / sizeof (uint32_t)];
+    uint8_t vbo_base[I915_VBO_SIZE];
+};
+
+enum {
+    CURRENT_SOURCE = 0x1,
+    CURRENT_MASK = 0x2,
+    CURRENT_CLIP = 0x4
+};
+
+typedef enum {
+    VS_CONSTANT,
+    VS_LINEAR,
+    VS_RADIAL,
+    VS_TEXTURE,
+    VS_TEXTURE_16,
+} i915_vertex_shader_t;
+
+typedef enum {
+    FS_ZERO,
+    FS_ONE,
+    FS_PURE,
+    FS_CONSTANT,
+    FS_DIFFUSE,
+    FS_LINEAR,
+    FS_RADIAL,
+    FS_TEXTURE,
+    FS_YUV,
+    FS_SPANS,
+} i915_fragment_shader_t;
+
+#define FS_DETAILS_SHIFT 4
+
+typedef enum {
+    PATTERN_BASE,
+    PATTERN_CONSTANT,
+    PATTERN_LINEAR,
+    PATTERN_RADIAL,
+    PATTERN_TEXTURE,
+} i915_shader_channel_t;
+
+struct i915_surface {
+    intel_surface_t intel;
+
+    uint32_t map0, map1;
+    uint32_t colorbuf;
+
+    uint32_t offset;
+    uint32_t is_current_texture;
+
+    i915_image_private_t *cache;
+
+    intel_bo_t *stencil;
+    uint32_t stencil_stride;
+    uint32_t stencil_offset;
+};
+
+typedef enum {
+    NONE = 0,
+    YUV_I420,
+    /* XXX */
+    YUV_YV12,
+    YUV_YUY2,
+    YUV_UYVY,
+} i915_packed_pixel_t;
+
+/* read-only container */
+#define I915_PACKED_PIXEL_SURFACE_TYPE 0x1000
+typedef struct i915_packed_pixel_surface {
+    cairo_surface_t base;
+
+    i915_packed_pixel_t pixel;
+
+    i915_device_t *device;
+    intel_bo_t *bo;
+    uint32_t is_current_texture;
+
+    uint32_t offset[4];
+    uint32_t stride[4];
+    uint32_t width[4];
+    uint32_t height[4];
+    uint32_t map0[4], map1[4];
+} i915_packed_pixel_surface_t;
+
+struct i915_shader {
+    i915_device_t *device;
+    i915_surface_t *target;
+
+    cairo_operator_t op;
+    uint32_t blend;
+    cairo_content_t content;
+
+    cairo_bool_t need_combine;
+
+    i915_add_rectangle_func_t add_rectangle;
+
+    union i915_shader_channel {
+	struct {
+	    i915_vertex_shader_t vertex;
+	    i915_fragment_shader_t fragment;
+	    i915_shader_channel_t pattern;
+	} type;
+	struct i915_shader_base {
+	    i915_vertex_shader_t vertex;
+	    i915_fragment_shader_t fragment;
+	    i915_shader_channel_t pattern;
+	    uint32_t texfmt;
+	    cairo_content_t content;
+	    uint32_t mode;
+	    intel_bo_t *bo;
+	    uint32_t n_samplers;
+	    uint32_t offset[4];
+	    uint32_t map[2*4];
+	    uint32_t sampler[2];
+	    cairo_matrix_t matrix;
+	} base;
+	struct i915_shader_solid {
+	    struct i915_shader_base base;
+	    cairo_color_t color;
+	    int pure;
+	} solid;
+	struct i915_shader_linear {
+	    struct i915_shader_base base;
+	    struct {
+		float red, green, blue, alpha;
+	    } color0, color1;
+	    float dx, dy, offset;
+	} linear;
+	struct i915_shader_radial {
+	    struct i915_shader_base base;
+	    float constants[8];
+	} radial;
+	struct i915_shader_surface {
+	    struct i915_shader_base base;
+	    i915_packed_pixel_t pixel;
+	} surface;
+    } source, mask, clip, dst;
+};
+
+enum i915_shader_linear_mode {
+    /* XXX REFLECT */
+    LINEAR_TEXTURE,
+    LINEAR_NONE,
+    LINEAR_REPEAT,
+    LINEAR_PAD,
+};
+
+enum i915_shader_radial_mode {
+    RADIAL_ONE,
+    RADIAL_TWO
+};
+
+typedef cairo_status_t
+(*i915_spans_func_t) (void			*closure,
+		      cairo_span_renderer_t	*renderer,
+		      const cairo_rectangle_int_t	*extents);
+
+cairo_private cairo_status_t
+i915_clip_and_composite_spans (i915_surface_t		*dst,
+			       cairo_operator_t		 op,
+			       const cairo_pattern_t	*pattern,
+			       cairo_antialias_t	 antialias,
+			       i915_spans_func_t	 draw_func,
+			       void			*draw_closure,
+			       const cairo_composite_rectangles_t*extents,
+			       cairo_clip_t		*clip);
+
+cairo_private cairo_surface_t *
+i915_surface_create_internal (cairo_drm_device_t *base_dev,
+		              cairo_content_t content,
+			      int width, int height,
+			      uint32_t tiling,
+			      cairo_bool_t gpu_target);
+
+cairo_private i915_surface_t *
+i915_surface_create_from_cacheable_image_internal (i915_device_t *device,
+						   cairo_image_surface_t *image);
+
+cairo_private void
+i915_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font);
+
+cairo_private cairo_int_status_t
+i915_surface_glyphs (void			*abstract_surface,
+		     cairo_operator_t		 op,
+		     const cairo_pattern_t	*source,
+		     cairo_glyph_t		*glyphs,
+		     int			 num_glyphs,
+		     cairo_scaled_font_t	*scaled_font,
+		     cairo_clip_t		*clip,
+		     int *num_remaining);
+
+static inline int cairo_const
+i915_tiling_height (uint32_t tiling, int height)
+{
+    switch (tiling) {
+    default:
+    case I915_TILING_NONE: return (height + 1) & -2;
+    case I915_TILING_X: return (height + 7) & -8;
+    case I915_TILING_Y: return (height + 31) & -32;
+    }
+}
+
+static inline uint32_t cairo_const
+i915_tiling_stride (int format, uint32_t stride)
+{
+    uint32_t tile_width;
+
+    if (format == I915_TILING_NONE)
+	return (stride + 31) & -32;
+
+    tile_width = 512;
+    /* XXX Currently the kernel enforces a tile_width of 512 for TILING_Y.
+
+       <jbarnes> the docs are a bit confused on that front
+       <jbarnes> once we enable it on 915 we'll find out what the tile width size should be in the fence setup
+       <jbarnes> it could be that 915 has y tiling but that the minimum width is 512 or something
+       <jbarnes> yeah it's probably 128 on 915 also
+       <jbarnes> it's just that we haven't tested
+       <jbarnes> but I wasn't thinking that the tile widths were the same
+       <jbarnes> only that in order to fence y tiles on 915 you needed pitch to be a multiple of 4 y tiles (or something like that)
+
+       tile_width = format == I915_TILING_Y ? 128 : 512;
+    */
+
+    /* needs a pot tile width */
+    while (tile_width < stride)
+	tile_width <<= 1;
+
+    return tile_width;
+}
+
+static inline uint32_t cairo_const
+i915_tiling_size (uint32_t tiling, uint32_t size)
+{
+    uint32_t fence;
+
+    if (tiling == I915_TILING_NONE)
+	return (size + 4095) & -4096;
+
+    fence = 1024 * 1024; /* 1 MiB */
+    while (fence < size)
+	fence <<= 1;
+
+    return fence;
+}
+
+static inline cairo_bool_t cairo_pure
+i915_texture_filter_is_nearest (cairo_filter_t filter)
+{
+    switch (filter) {
+    case CAIRO_FILTER_BEST:
+    case CAIRO_FILTER_GOOD:
+    case CAIRO_FILTER_BILINEAR:
+    case CAIRO_FILTER_GAUSSIAN:
+	return FALSE;
+    default:
+    case CAIRO_FILTER_FAST:
+    case CAIRO_FILTER_NEAREST:
+	return TRUE;
+    }
+}
+
+static inline uint32_t cairo_pure
+i915_texture_filter (cairo_filter_t filter)
+{
+    switch (filter) {
+    case CAIRO_FILTER_BEST:
+    case CAIRO_FILTER_GOOD:
+    case CAIRO_FILTER_BILINEAR:
+    case CAIRO_FILTER_GAUSSIAN:
+        return
+	    (FILTER_LINEAR << SS2_MAG_FILTER_SHIFT) |
+	    (FILTER_LINEAR << SS2_MIN_FILTER_SHIFT);
+    default:
+    case CAIRO_FILTER_FAST:
+    case CAIRO_FILTER_NEAREST:
+	return
+	    (FILTER_NEAREST << SS2_MAG_FILTER_SHIFT) |
+	    (FILTER_NEAREST << SS2_MIN_FILTER_SHIFT);
+    }
+}
+
+static inline uint32_t cairo_pure
+i915_texture_extend (cairo_extend_t extend)
+{
+    switch (extend) {
+    default:
+    case CAIRO_EXTEND_NONE:
+	return
+	    (TEXCOORDMODE_CLAMP_BORDER << SS3_TCX_ADDR_MODE_SHIFT) |
+	    (TEXCOORDMODE_CLAMP_BORDER << SS3_TCY_ADDR_MODE_SHIFT);
+    case CAIRO_EXTEND_REPEAT:
+	return
+	    (TEXCOORDMODE_WRAP << SS3_TCX_ADDR_MODE_SHIFT) |
+	    (TEXCOORDMODE_WRAP << SS3_TCY_ADDR_MODE_SHIFT);
+    case CAIRO_EXTEND_PAD:
+	return
+	    (TEXCOORDMODE_CLAMP_EDGE << SS3_TCX_ADDR_MODE_SHIFT) |
+	    (TEXCOORDMODE_CLAMP_EDGE << SS3_TCY_ADDR_MODE_SHIFT);
+    case CAIRO_EXTEND_REFLECT:
+	return
+	    (TEXCOORDMODE_MIRROR << SS3_TCX_ADDR_MODE_SHIFT) |
+	    (TEXCOORDMODE_MIRROR << SS3_TCY_ADDR_MODE_SHIFT);
+    }
+}
+
+static inline uint32_t cairo_pure
+BUF_tiling (uint32_t tiling)
+{
+    switch (tiling) {
+    default:
+    case I915_TILING_NONE: return 0;
+    case I915_TILING_X: return BUF_3D_TILED_SURFACE | BUF_3D_TILE_WALK_X;
+    case I915_TILING_Y: return BUF_3D_TILED_SURFACE | BUF_3D_TILE_WALK_Y;
+    }
+}
+
+#define OUT_DWORD(dword) i915_batch_emit_dword (device, dword)
+#define OUT_RELOC(surface, read, write) i915_batch_emit_reloc (device, to_intel_bo (surface->intel.drm.bo), surface->offset, read, write)
+
+#define FS_LOCALS							\
+    uint32_t *_shader_start
+
+#define FS_BEGIN()							\
+do {									\
+    _shader_start = BATCH_PTR (device);					\
+    OUT_DWORD (_3DSTATE_PIXEL_SHADER_PROGRAM);				\
+} while (0)
+
+#define FS_END()							\
+do {									\
+    *_shader_start |= BATCH_PTR (device) - _shader_start - 2;		\
+} while (0);
+
+static inline int32_t
+i915_batch_space (i915_device_t *device)
+{
+    /* leave room for RECTLIST(4) + MI_BUFFER_END + MI_NOOP */
+    return sizeof (device->batch_base) - (device->batch.used << 2) - 32;
+}
+
+static inline cairo_bool_t
+i915_check_aperture_size (const i915_device_t *device, int relocs, size_t size)
+{
+    return device->batch.reloc_count + relocs < I915_MAX_RELOCS &&
+	   device->batch.gtt_size + size <= device->intel.gtt_avail_size;
+}
+
+static inline cairo_bool_t
+i915_check_aperture (const i915_device_t *device, intel_bo_t **bo_array, int count)
+{
+    uint32_t relocs = 0, size = 0;
+
+    while (count--) {
+	const intel_bo_t *bo = *bo_array++;
+	if (bo->exec == NULL) {
+	    relocs++;
+	    size += bo->base.size;
+	}
+    }
+
+    return i915_check_aperture_size (device, relocs, size);
+}
+
+#define BATCH_PTR(device) &(device)->batch_base[(device)->batch.used]
+static inline void
+i915_batch_emit_dword (i915_device_t *device, uint32_t dword)
+{
+    device->batch_base[device->batch.used++] = dword;
+}
+
+cairo_private void
+i915_batch_add_reloc (i915_device_t *device, uint32_t pos,
+		      intel_bo_t *bo,
+		      uint32_t offset,
+		      uint32_t read_domains,
+		      uint32_t write_domain);
+
+static inline void
+i915_batch_fill_reloc (i915_device_t *device, uint32_t pos,
+		       intel_bo_t *bo,
+		       uint32_t offset,
+		       uint32_t read_domains,
+		       uint32_t write_domain)
+{
+    i915_batch_add_reloc (device, pos,
+	                  bo, offset,
+			  read_domains, write_domain);
+    device->batch_base[pos] = bo->offset + offset;
+}
+
+static inline void
+i915_batch_emit_reloc (i915_device_t *device,
+		       intel_bo_t *bo,
+		       uint32_t offset,
+		       uint32_t read_domains,
+		       uint32_t write_domain)
+{
+    i915_batch_add_reloc (device, device->batch.used,
+	                  bo, offset,
+			  read_domains, write_domain);
+    i915_batch_emit_dword (device, bo->offset + offset);
+}
+
+cairo_private cairo_status_t
+i915_vbo_flush (i915_device_t *device);
+
+cairo_private void
+i915_vbo_finish (i915_device_t *device);
+
+cairo_private  cairo_status_t
+i915_batch_flush (i915_device_t *device);
+
+static inline float *
+i915_add_rectangle (i915_device_t *device)
+{
+    float *vertices;
+    uint32_t size;
+
+    assert (device->floats_per_vertex);
+
+    size = device->rectangle_size;
+    if (unlikely (device->vbo_offset + size > I915_VBO_SIZE))
+	i915_vbo_finish (device);
+
+    vertices = (float *) (device->vbo_base + device->vbo_offset);
+    device->vbo_used = device->vbo_offset += size;
+    device->vertex_count += 3;
+    return vertices;
+}
+
+static inline i915_device_t *
+i915_device (i915_surface_t *surface)
+{
+    return (i915_device_t *) surface->intel.drm.base.device;
+}
+
+cairo_private void
+i915_shader_init (i915_shader_t *shader,
+		  i915_surface_t *dst,
+		  cairo_operator_t op);
+
+cairo_private cairo_status_t
+i915_shader_acquire_pattern (i915_shader_t *shader,
+			     union i915_shader_channel *src,
+			     const cairo_pattern_t *pattern,
+			     const cairo_rectangle_int_t *extents);
+
+cairo_private void
+i915_shader_set_clip (i915_shader_t *shader,
+		      cairo_clip_t *clip);
+
+cairo_private int
+i915_shader_num_texcoords (const i915_shader_t *shader);
+
+static inline double cairo_const
+i915_shader_linear_texcoord (const struct i915_shader_linear *l,
+			     double src_x, double src_y)
+{
+    return l->dx * src_x + l->dy * src_y + l->offset;
+}
+
+cairo_private cairo_status_t
+i915_shader_commit (i915_shader_t *shader,
+		    i915_device_t *device);
+
+cairo_private void
+i915_shader_fini (i915_shader_t *shader);
+
+cairo_private cairo_status_t
+i915_fixup_unbounded (i915_surface_t *dst,
+		      const cairo_composite_rectangles_t *extents,
+		      cairo_clip_t *clip);
+
+#endif /* CAIRO_DRM_I915_PRIVATE_H */
diff --git a/src/drm/cairo-drm-i915-shader.c b/src/drm/cairo-drm-i915-shader.c
new file mode 100644
index 0000000..afcbd42
--- /dev/null
+++ b/src/drm/cairo-drm-i915-shader.c
@@ -0,0 +1,2674 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-error-private.h"
+#include "cairo-drm-i915-private.h"
+#include "cairo-surface-subsurface-private.h"
+#include "cairo-surface-snapshot-private.h"
+
+#if CAIRO_HAS_XCB_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+/* for DRI2/DRM interoperability */
+#include "cairo-xcb-private.h"
+#endif
+
+#if 0
+static cairo_status_t
+i915_packed_pixel_surface_finish (void *abstract_surface)
+{
+    i915_packed_pixel_surface_t *surface = abstract_surface;
+    i915_device_t *device;
+
+    device = i915_device_acquire (&surface->device->intel.base);
+
+    intel_bo_destroy (&device->intel, surface->bo);
+
+    if (surface->is_current_texture) {
+	if (surface->is_current_texture & CURRENT_SOURCE)
+	    device->current_source = NULL;
+	if (surface->is_current_texture & CURRENT_MASK)
+	    device->current_mask = NULL;
+	device->current_n_samplers = 0;
+    }
+
+    i915_device_release (device);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static const cairo_surface_backend_t i915_packed_pixel_surface_backend = {
+    I915_PACKED_PIXEL_SURFACE_TYPE,
+    i915_packed_pixel_surface_finish,
+};
+
+static cairo_surface_t *
+i915_packed_pixel_surface_create (i915_device_t *device,
+				   i915_packed_pixel_t pixel,
+				   const uint8_t *data,
+				   uint32_t length,
+				   uint32_t width, uint32_t height)
+{
+    i915_packed_pixel_surface_t *surface;
+    cairo_content_t content;
+    uint32_t tiling, size;
+    uint32_t stride, half_stride;
+    uint32_t i;
+
+    if (width > 2048 || height > 2048)
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
+
+    surface = malloc (sizeof (i915_packed_pixel_surface_t));
+    if (unlikely (surface == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    tiling = I915_TILING_NONE; /* XXX */
+    half_stride = stride = i915_tiling_stride (tiling, width/2);
+    if (stride < width)
+	stride *= 2 ;
+    height = i915_tiling_height (tiling, height);
+
+    switch (surface->pixel = pixel) {
+    case YUV_I420:
+	content = CAIRO_CONTENT_COLOR;
+
+	surface->offset[0] = 0;
+	surface->width[0] = width;
+	surface->height[0] = height;
+	surface->stride[0] = stride;
+	surface->map0[0] = MAPSURF_8BIT | MT_8BIT_I8 | MS3_tiling (tiling);
+	surface->map0[0] |= ((height - 1) << MS3_HEIGHT_SHIFT) |
+			    ((width - 1)  << MS3_WIDTH_SHIFT);
+	surface->map1[0] = (stride / 4 - 1) << MS4_PITCH_SHIFT;
+
+	surface->offset[1] = stride * height;
+	surface->width[1] = width / 2;
+	surface->height[1] = height / 2;
+	surface->stride[1] = half_stride;
+	surface->map0[1] = MAPSURF_8BIT | MT_8BIT_I8 | MS3_tiling (tiling);
+	surface->map0[1] |= ((height/2 - 1) << MS3_HEIGHT_SHIFT) |
+			    ((width/2 - 1)  << MS3_WIDTH_SHIFT);
+	surface->map1[1] = (half_stride / 4 - 1) << MS4_PITCH_SHIFT;
+
+	if (width < half_stride) {
+	    surface->offset[2] = stride * height + half_stride / 2;
+	    size = stride * height + half_stride * height / 2;
+	} else {
+	    surface->offset[2] = stride * height + half_stride * height / 2;
+	    size = stride * height + half_stride * height;
+	}
+	surface->width[2] = width / 2;
+	surface->height[2] = height / 2;
+	surface->stride[2] = half_stride;
+	surface->map0[2] = MAPSURF_8BIT | MT_8BIT_I8 | MS3_tiling (tiling);
+	surface->map0[2] |= ((height/2 - 1) << MS3_HEIGHT_SHIFT) |
+			    ((width/2 - 1)  << MS3_WIDTH_SHIFT);
+	surface->map1[2] = (half_stride / 4 - 1) << MS4_PITCH_SHIFT;
+	break;
+
+    case NONE:
+    case YUV_YV12:
+    case YUV_YUY2:
+    case YUV_UYVY:
+	ASSERT_NOT_REACHED;
+	break;
+    }
+
+    _cairo_surface_init (&surface->base,
+	                 &i915_packed_pixel_surface_backend,
+			 content);
+
+    surface->bo = intel_bo_create (&device->intel, size, FALSE);
+    assert (tiling == I915_TILING_NONE);
+    if (unlikely (surface->bo == NULL)) {
+	free (surface);
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+    }
+
+    if (tiling == I915_TILING_NONE) {
+	intel_bo_t *bo = surface->bo;
+	uint32_t dst;
+	int uv;
+
+	dst = surface->offset[0];
+	if (width == stride) {
+	    size = stride * height;
+	    intel_bo_write (&device->intel, bo, dst, size, data);
+	    data += size;
+	} else {
+	    for (i = 0; i < height; i++) {
+		intel_bo_write (&device->intel, bo, dst, width, data);
+		dst += stride;
+		data += width;
+	    }
+	}
+
+	for (uv = 1; uv <= 2; uv++) {
+	    dst = surface->offset[uv];
+	    if (width / 2 == half_stride) {
+		size = half_stride * height / 2;
+		intel_bo_write (&device->intel, bo, dst, size, data);
+		data += size;
+	    } else {
+		size = width / 2;
+		for (i = 0; i < height / 2; i++) {
+		    intel_bo_write (&device->intel, bo, dst, size, data);
+		    dst += half_stride;
+		    data += size;
+		}
+	    }
+	}
+    } else {
+	uint8_t *dst, *base;
+
+	base = intel_bo_map (&device->intel, surface->bo);
+
+	dst = base + surface->offset[0];
+	if (width == stride) {
+	    size = stride * height;
+	    memcpy (dst, data, size);
+	    data += size;
+	} else {
+	    for (i = 0; i < height; i++) {
+		memcpy (dst, data, width);
+		dst += stride;
+		data += width;
+	    }
+	}
+
+	dst = base + surface->offset[1];
+	if (width / 2 == half_stride) {
+	    size = half_stride * height / 2;
+	    memcpy (dst, data, size);
+	    data += size;
+	} else {
+	    size = width / 2;
+	    for (i = 0; i < height / 2; i++) {
+		memcpy (dst, data, size);
+		dst += half_stride;
+		data += size;
+	    }
+	}
+
+	dst = base + surface->offset[2];
+	if (width / 2 == half_stride) {
+	    size = half_stride * height / 2;
+	    memcpy (dst, data, size);
+	    data += size;
+	} else {
+	    size = width / 2;
+	    for (i = 0; i < height / 2; i++) {
+		memcpy (dst, data, size);
+		dst += half_stride;
+		data += size;
+	    }
+	}
+
+	intel_bo_unmap (surface->bo);
+    }
+
+    surface->device = device;
+    surface->is_current_texture = 0;
+
+    return &surface->base;
+}
+
+static cairo_int_status_t
+i915_clone_yuv (i915_surface_t *surface,
+		 cairo_surface_t *source,
+		 int width, int height,
+		 cairo_surface_t **clone_out)
+{
+    const uint8_t *mime_data = NULL;
+    unsigned int mime_data_length;
+    cairo_surface_t *clone;
+
+    cairo_surface_get_mime_data (source, "video/x-raw-yuv/i420",
+				 &mime_data, &mime_data_length);
+    if (mime_data == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    clone =
+	i915_packed_pixel_surface_create ((i915_device_t *) surface->base.device,
+					   YUV_I420,
+					   mime_data, mime_data_length,
+					   width, height);
+    if (clone == NULL)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    if (unlikely (clone->status))
+	return clone->status;
+
+    *clone_out = clone;
+    return CAIRO_STATUS_SUCCESS;
+}
+#endif
+
+/* Max instruction count: 4 */
+static void
+i915_shader_linear_color (i915_device_t *device,
+			  enum i915_shader_linear_mode mode,
+			  int in, int c0, int c1, int out)
+{
+    int tmp = FS_U0;
+
+    switch (mode) {
+    case LINEAR_TEXTURE:
+	ASSERT_NOT_REACHED;
+    case LINEAR_NONE:
+	tmp = in;
+	break;
+
+    case LINEAR_REPEAT:
+	i915_fs_frc (tmp, i915_fs_operand (in, X, X, X, X));
+	break;
+#if 0
+    case LINEAR_REFLECT:
+	/* XXX needs an extra constant: C2 [0.5, 2.0, x, x] */
+	i915_fs_mul (tmp, in, 0.5);
+	i915_fs_frc (tmp, i915_fs_operand_reg (tmp));
+	i915_fs_mul (tmp, tmp, 2.0);
+	i915_fs_add (tmp, i915_fs_operand_one (),
+		     i915_fs_operand_reg_negate (tmp));
+	i915_fs_cmp (tmp,
+		     i915_fs_operand_reg (tmp),
+		     i915_fs_operand_reg (tmp),
+		     i915_fs_operand_reg_negate (tmp));
+	i915_fs_add (tmp, i915_fs_operand_one (),
+		     i915_fs_operand_reg_negate (tmp));
+#endif
+    case LINEAR_PAD:
+	i915_fs_max (tmp,
+		     i915_fs_operand_zero (),
+		     i915_fs_operand (in, X, X, X, X));
+	i915_fs_min (tmp,
+		     i915_fs_operand_one (),
+		     i915_fs_operand_reg (tmp));
+	break;
+    }
+
+    /* interpolate */
+    i915_fs_mad (out, 0,
+		 i915_fs_operand (tmp, -X, -X, -X, -X),
+		 i915_fs_operand_reg (c0),
+		 i915_fs_operand_reg (c0));
+    i915_fs_mad (out, 0,
+		 i915_fs_operand (tmp, X, X, X, X),
+		 i915_fs_operand_reg (c1),
+		 i915_fs_operand_reg (out));
+}
+
+static void
+i915_shader_radial_init (struct i915_shader_radial *r,
+			 const cairo_radial_pattern_t *radial)
+{
+    double dx, dy, dr, r1;
+
+    dx = _cairo_fixed_to_double (radial->c2.x - radial->c1.x);
+    dy = _cairo_fixed_to_double (radial->c2.y - radial->c1.y);
+    dr = _cairo_fixed_to_double (radial->r2 - radial->r1);
+
+    r1 = _cairo_fixed_to_double (radial->r1);
+
+    if (radial->c2.x == radial->c1.x && radial->c2.y == radial->c1.y) {
+	/* XXX dr == 0, meaningless with anything other than PAD */
+	r->constants[0] = _cairo_fixed_to_double (radial->c1.x) / dr;
+	r->constants[1] = _cairo_fixed_to_double (radial->c1.y) / dr;
+	r->constants[2] = 1. / dr;
+	r->constants[3] = -r1 / dr;
+
+	r->constants[4] = 0;
+	r->constants[5] = 0;
+	r->constants[6] = 0;
+	r->constants[7] = 0;
+
+	r->base.mode = RADIAL_ONE;
+    } else {
+	r->constants[0] = -_cairo_fixed_to_double (radial->c1.x);
+	r->constants[1] = -_cairo_fixed_to_double (radial->c1.y);
+	r->constants[2] = r1;
+	r->constants[3] = -4 * (dx*dx + dy*dy - dr*dr);
+
+	r->constants[4] = -2 * dx;
+	r->constants[5] = -2 * dy;
+	r->constants[6] = -2 * r1 * dr;
+	r->constants[7] = 1 / (2 * (dx*dx + dy*dy - dr*dr));
+
+	r->base.mode = RADIAL_TWO;
+    }
+
+    r->base.matrix = radial->base.base.matrix;
+}
+
+/* Max instruction count: 10 */
+static void
+i915_shader_radial_coord (i915_device_t *device,
+			   enum i915_shader_radial_mode mode,
+			   int in, int g0, int g1, int out)
+{
+    switch (mode) {
+    case RADIAL_ONE:
+	/*
+	   pdx = (x - c1x) / dr, pdy = (y - c1y) / dr;
+	   r² = pdx*pdx + pdy*pdy
+	   t = r²/sqrt(r²) - r1/dr;
+	   */
+	i915_fs_mad (FS_U0, MASK_X | MASK_Y,
+		     i915_fs_operand (in, X, Y, ZERO, ZERO),
+		     i915_fs_operand (g0, Z, Z, ZERO, ZERO),
+		     i915_fs_operand (g0, -X, -Y, ZERO, ZERO));
+	i915_fs_dp2add (FS_U0, MASK_X,
+			i915_fs_operand (FS_U0, X, Y, ZERO, ZERO),
+			i915_fs_operand (FS_U0, X, Y, ZERO, ZERO),
+			i915_fs_operand_zero ());
+	i915_fs_rsq (out, MASK_X, i915_fs_operand (FS_U0, X, X, X, X));
+	i915_fs_mad (out, MASK_X,
+		     i915_fs_operand (FS_U0, X, ZERO, ZERO, ZERO),
+		     i915_fs_operand (out, X, ZERO, ZERO, ZERO),
+		     i915_fs_operand (g0, W, ZERO, ZERO, ZERO));
+	break;
+
+    case RADIAL_TWO:
+	/*
+	   pdx = x - c1x, pdy = y - c1y;
+	   A = dx² + dy² - dr²
+	   B = -2*(pdx*dx + pdy*dy + r1*dr);
+	   C = pdx² + pdy² - r1²;
+	   det = B*B - 4*A*C;
+	   t = (-B + sqrt (det)) / (2 * A)
+	   */
+
+	/* u0.x = pdx, u0.y = pdy, u[0].z = r1; */
+	i915_fs_add (FS_U0,
+		     i915_fs_operand (in, X, Y, ZERO, ZERO),
+		     i915_fs_operand (g0, X, Y, Z, ZERO));
+	/* u0.x = pdx, u0.y = pdy, u[0].z = r1, u[0].w = B; */
+	i915_fs_dp3 (FS_U0, MASK_W,
+		     i915_fs_operand (FS_U0, X, Y, ONE, ZERO),
+		     i915_fs_operand (g1, X, Y, Z, ZERO));
+	/* u1.x = pdx² + pdy² - r1²; [C] */
+	i915_fs_dp3 (FS_U1, MASK_X,
+		     i915_fs_operand (FS_U0, X, Y, Z, ZERO),
+		     i915_fs_operand (FS_U0, X, Y, -Z, ZERO));
+	/* u1.x = C, u1.y = B, u1.z=-4*A; */
+	i915_fs_mov_masked (FS_U1, MASK_Y, i915_fs_operand (FS_U0, W, W, W, W));
+	i915_fs_mov_masked (FS_U1, MASK_Z, i915_fs_operand (g0, W, W, W, W));
+	/* u1.x = B² - 4*A*C */
+	i915_fs_dp2add (FS_U1, MASK_X,
+			i915_fs_operand (FS_U1, X, Y, ZERO, ZERO),
+			i915_fs_operand (FS_U1, Z, Y, ZERO, ZERO),
+			i915_fs_operand_zero ());
+	/* out.x = -B + sqrt (B² - 4*A*C),
+	 * out.y = -B - sqrt (B² - 4*A*C),
+	 */
+	i915_fs_rsq (out, MASK_X, i915_fs_operand (FS_U1, X, X, X, X));
+	i915_fs_mad (out, MASK_X | MASK_Y,
+		     i915_fs_operand (out, X, X, ZERO, ZERO),
+		     i915_fs_operand (FS_U1, X, -X, ZERO, ZERO),
+		     i915_fs_operand (FS_U0, -W, -W, ZERO, ZERO));
+	/* out.x = (-B + sqrt (B² - 4*A*C)) / (2 * A),
+	 * out.y = (-B - sqrt (B² - 4*A*C)) / (2 * A)
+	 */
+	i915_fs_mul (out,
+		     i915_fs_operand (out, X, Y, ZERO, ZERO),
+		     i915_fs_operand (g1, W, W, ZERO, ZERO));
+	/* if (A > 0)
+	 *   out = (-B + sqrt (B² - 4*A*C)) / (2 * A),
+	 * else
+	 *   out = (-B - sqrt (B² - 4*A*C)) / (2 * A)
+	 */
+	i915_fs_cmp (out,
+		     i915_fs_operand (g1, W, ZERO, ZERO, ZERO),
+		     i915_fs_operand (out, X, ZERO, ZERO, ZERO),
+		     i915_fs_operand (out, Y, ZERO, ZERO, ZERO));
+	break;
+    }
+}
+
+/* Max instruction count: 7 */
+static inline void
+i915_shader_yuv_color (i915_device_t *device,
+		       int y, int u, int v,
+		       int c0, int c1, int c2,
+		       int out)
+{
+    i915_fs_mov_masked (FS_U0, MASK_X, i915_fs_operand_reg (y));
+    i915_fs_mov_masked (FS_U0, MASK_Y, i915_fs_operand_reg (u));
+    i915_fs_mov_masked (FS_U0, MASK_Z, i915_fs_operand_reg (v));
+
+    i915_fs_add (FS_U0,
+		 i915_fs_operand_reg (FS_U0),
+		 i915_fs_operand_reg (c0));
+    i915_fs_dp3 (out, MASK_X,
+		 i915_fs_operand_reg (FS_U0),
+		 i915_fs_operand (c1, X, ZERO, Y, ZERO));
+    i915_fs_dp3 (out, MASK_Z,
+		 i915_fs_operand_reg (FS_U0),
+		 i915_fs_operand (c1, Z, W, ZERO, ZERO));
+    i915_fs_dp3 (out, MASK_Y,
+		 i915_fs_operand_reg (FS_U0),
+		 i915_fs_operand_reg (c2));
+}
+
+static inline uint32_t
+i915_shader_channel_key (const union i915_shader_channel *channel)
+{
+    return (channel->type.fragment & 0x0f) | (channel->base.mode << FS_DETAILS_SHIFT);
+}
+
+static uint32_t
+i915_shader_channel_get_num_tex_coords (const union i915_shader_channel *channel)
+{
+    switch (channel->type.fragment) {
+    default:
+    case FS_ZERO:
+    case FS_ONE:
+    case FS_CONSTANT:
+    case FS_PURE:
+    case FS_DIFFUSE:
+	return 0;
+
+    case FS_LINEAR:
+    case FS_RADIAL:
+    case FS_TEXTURE:
+    case FS_SPANS:
+    case FS_YUV:
+	return 1;
+    }
+}
+
+static uint32_t
+i915_shader_get_num_tex_coords (const i915_shader_t *shader)
+{
+    uint32_t num_tex_coords;
+
+    num_tex_coords = 0;
+
+    num_tex_coords += i915_shader_channel_get_num_tex_coords (&shader->source);
+    num_tex_coords += i915_shader_channel_get_num_tex_coords (&shader->mask);
+    num_tex_coords += i915_shader_channel_get_num_tex_coords (&shader->clip);
+    num_tex_coords += i915_shader_channel_get_num_tex_coords (&shader->dst);
+
+    return num_tex_coords;
+}
+
+#define i915_fs_operand_impure(reg, channel, pure) \
+    (reg | \
+     (((pure & (1 << 0)) ? channel##_CHANNEL_VAL : ZERO_CHANNEL_VAL) << X_CHANNEL_SHIFT) | \
+     (((pure & (1 << 1)) ? channel##_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Y_CHANNEL_SHIFT) | \
+     (((pure & (1 << 2)) ? channel##_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Z_CHANNEL_SHIFT) | \
+     (((pure & (1 << 3)) ? channel##_CHANNEL_VAL : ZERO_CHANNEL_VAL) << W_CHANNEL_SHIFT))
+
+#define i915_fs_operand_pure(pure) \
+    (FS_R0 | \
+     (((pure & (1 << 0)) ? ONE_CHANNEL_VAL : ZERO_CHANNEL_VAL) << X_CHANNEL_SHIFT) | \
+     (((pure & (1 << 1)) ? ONE_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Y_CHANNEL_SHIFT) | \
+     (((pure & (1 << 2)) ? ONE_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Z_CHANNEL_SHIFT) | \
+     (((pure & (1 << 3)) ? ONE_CHANNEL_VAL : ZERO_CHANNEL_VAL) << W_CHANNEL_SHIFT))
+
+#define i915_fs_operand_reg_pure(reg, pure) \
+    (reg | \
+     (((pure & (1 << 0)) ? X_CHANNEL_VAL : ZERO_CHANNEL_VAL) << X_CHANNEL_SHIFT) | \
+     (((pure & (1 << 1)) ? Y_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Y_CHANNEL_SHIFT) | \
+     (((pure & (1 << 2)) ? Z_CHANNEL_VAL : ZERO_CHANNEL_VAL) << Z_CHANNEL_SHIFT) | \
+     (((pure & (1 << 3)) ? W_CHANNEL_VAL : ZERO_CHANNEL_VAL) << W_CHANNEL_SHIFT))
+
+static void
+i915_set_shader_program (i915_device_t *device,
+			 const i915_shader_t *shader)
+{
+    uint32_t num_tex_coords;
+    uint32_t num_samplers;
+    uint32_t n;
+    uint32_t texture_offset = 0;
+    uint32_t constant_offset = 0;
+    uint32_t sampler_offset = 0;
+    uint32_t source_reg;
+    uint32_t source_pure;
+    uint32_t mask_reg;
+    uint32_t out_reg;
+    uint32_t dest_reg;
+    FS_LOCALS;
+
+    n = (i915_shader_channel_key (&shader->source) <<  0) |
+	(i915_shader_channel_key (&shader->mask)   <<  8) |
+	(i915_shader_channel_key (&shader->clip)   << 16) |
+	(shader->op << 24) |
+	(((shader->content & CAIRO_CONTENT_ALPHA) == CAIRO_CONTENT_ALPHA) << 31);
+    if (n == device->current_program)
+	return;
+    device->current_program = n;
+
+    FS_BEGIN ();
+
+    if (shader->source.type.fragment == FS_ZERO) {
+	if (shader->clip.type.fragment == FS_TEXTURE) {
+	    /* XXX need_combine */
+	    assert (shader->mask.type.fragment == (i915_fragment_shader_t) -1);
+	    i915_fs_dcl (FS_T0);
+	    i915_fs_texld (FS_U0, FS_S0, FS_T0);
+	    if ((shader->content & CAIRO_CONTENT_COLOR) == 0)
+		i915_fs_mov (FS_OC, i915_fs_operand (FS_U0, W, W, W, W));
+	    else
+		i915_fs_mov (FS_OC, i915_fs_operand (FS_U0, ZERO, ZERO, ZERO, W));
+	} else {
+	    i915_fs_mov (FS_OC, i915_fs_operand_zero ());
+	}
+
+	FS_END ();
+	return;
+    }
+
+    num_tex_coords = i915_shader_get_num_tex_coords (shader);
+    for (n = 0; n < num_tex_coords; n++)
+	i915_fs_dcl (FS_T0 + n);
+
+    num_samplers =
+	shader->source.base.n_samplers +
+	shader->mask.base.n_samplers +
+	shader->clip.base.n_samplers +
+	shader->dst.base.n_samplers;
+    for (n = 0; n < num_samplers; n++)
+	i915_fs_dcl (FS_S0 + n);
+
+    source_reg = ~0;
+    source_pure = 0;
+    out_reg = FS_R0;
+    if (! shader->need_combine &&
+	shader->mask.type.fragment == (i915_fragment_shader_t) -1 &&
+	shader->clip.type.fragment != FS_TEXTURE &&
+	shader->content != CAIRO_CONTENT_ALPHA)
+    {
+	out_reg = FS_OC;
+    }
+
+    switch (shader->source.type.fragment) {
+    default:
+    case FS_ZERO:
+    case FS_SPANS:
+	ASSERT_NOT_REACHED;
+
+    case FS_PURE:
+	source_pure = shader->source.solid.pure;
+    case FS_ONE:
+	break;
+
+    case FS_CONSTANT:
+	source_reg = FS_C0;
+	constant_offset += 1;
+	break;
+
+    case FS_DIFFUSE:
+	i915_fs_dcl (FS_T8);
+	source_reg = FS_T8;
+	break;
+
+    case FS_LINEAR:
+	i915_shader_linear_color (device, shader->source.base.mode,
+				  FS_T0, /* input */
+				  FS_C0, FS_C1, /* colour ramp */
+				  FS_U3); /* unpremultiplied output */
+	/* XXX can we defer premultiplication? */
+	i915_fs_mul (out_reg,
+		     i915_fs_operand_reg (FS_U3),
+		     i915_fs_operand (FS_U3, W, W, W, W));
+
+	constant_offset += 2;
+	texture_offset += 1;
+	source_reg = out_reg;
+	break;
+
+    case FS_RADIAL:
+	i915_shader_radial_coord (device, shader->source.base.mode,
+				  FS_T0, /* input */
+				  FS_C0, FS_C1, /* gradient constants */
+				  FS_U3); /* coordinate */
+
+	i915_fs_texld (out_reg, FS_S0, FS_U3);
+	constant_offset += 2;
+	texture_offset += 1;
+	sampler_offset += 1;
+	source_reg = out_reg;
+	break;
+
+    case FS_TEXTURE:
+	i915_fs_texld (out_reg, FS_S0, FS_T0);
+	texture_offset += 1;
+	sampler_offset += 1;
+	source_reg = out_reg;
+	break;
+
+    case FS_YUV:
+	/* Load samplers to temporaries. */
+	i915_fs_texld (FS_R0, FS_S0, FS_T0);
+	i915_fs_texld (FS_R1, FS_S1, FS_T0);
+	i915_fs_texld (FS_R2, FS_S2, FS_T0);
+
+	i915_shader_yuv_color (device,
+			       FS_R0, FS_R1, FS_R2, /* y, u, v */
+			       FS_C0, FS_C1, FS_C2, /* coefficients */
+			       out_reg);
+
+	constant_offset += 3;
+	texture_offset += 1;
+	sampler_offset += 3;
+	source_reg = out_reg;
+	break;
+    }
+
+    mask_reg = ~0;
+    switch (shader->mask.type.fragment) {
+    case FS_PURE:
+    case FS_ZERO:
+    case FS_YUV:
+    case FS_DIFFUSE:
+	ASSERT_NOT_REACHED;
+    case FS_ONE:
+    default:
+	break;
+
+    case FS_SPANS:
+	mask_reg = FS_T0 + texture_offset;
+	texture_offset += 1;
+	break;
+
+    case FS_CONSTANT:
+	mask_reg = FS_C0 + constant_offset;
+	constant_offset += 1;
+	break;
+
+    case FS_LINEAR:
+	i915_shader_linear_color (device, shader->source.base.mode,
+				  FS_T0 + texture_offset, /* input */
+				  FS_C0 + constant_offset,
+				  FS_C0 + constant_offset + 1, /* colour ramp */
+				  FS_U3); /* unpremultiplied output */
+	i915_fs_mul (FS_R1,
+		     i915_fs_operand_reg (FS_U3),
+		     i915_fs_operand (source_reg, W, W, W, W));
+
+	constant_offset += 2;
+	texture_offset += 1;
+	mask_reg = FS_R1;
+	break;
+
+    case FS_RADIAL:
+	i915_shader_radial_coord (device, shader->source.base.mode,
+				  FS_T0 + texture_offset, /* input */
+				  FS_C0 + constant_offset,
+				  FS_C0 + constant_offset + 1, /* gradient constants */
+				  FS_U3); /* coordinate */
+
+	i915_fs_texld (FS_R1, FS_S0 + sampler_offset, FS_U3);
+	constant_offset += 2;
+	texture_offset += 1;
+	sampler_offset += 1;
+	mask_reg = FS_R1;
+	break;
+
+    case FS_TEXTURE:
+	i915_fs_texld (FS_R1, FS_S0 + sampler_offset, FS_T0 + texture_offset);
+	texture_offset += 1;
+	sampler_offset += 1;
+	mask_reg = FS_R1;
+	break;
+    }
+
+    if (mask_reg != ~0U) {
+	if (! shader->need_combine &&
+	    shader->clip.type.fragment != FS_TEXTURE &&
+	    shader->content != CAIRO_CONTENT_ALPHA)
+	{
+	    out_reg = FS_OC;
+	}
+	if (source_reg == ~0U) {
+	    if (source_pure) {
+		if (shader->mask.type.fragment == FS_SPANS) {
+		    i915_fs_mov (out_reg,
+				 i915_fs_operand_impure (mask_reg, X, source_pure));
+		} else {
+		    /* XXX ComponentAlpha
+		       i915_fs_mov (out_reg,
+		       i915_fs_operand_pure (mask_reg,
+		       shader->source.solid.pure));
+		       */
+		    i915_fs_mov (out_reg,
+				 i915_fs_operand_impure (mask_reg, W, source_pure));
+		}
+		source_reg = out_reg;
+	    } else if (shader->mask.type.fragment == FS_SPANS) {
+		i915_fs_mov (out_reg,
+			     i915_fs_operand (mask_reg, X, X, X, X));
+		source_reg = out_reg;
+	    } else {
+		source_reg = mask_reg;
+	    }
+	} else {
+	    if (shader->mask.type.fragment == FS_SPANS) {
+		i915_fs_mul (out_reg,
+			     i915_fs_operand_reg (source_reg),
+			     i915_fs_operand (mask_reg, X, X, X, X));
+	    } else {
+		/* XXX ComponentAlpha
+		i915_fs_mul (FS_R0,
+			     i915_fs_operand_reg (source_reg),
+			     i915_fs_operand_reg (mask_reg));
+		 */
+		i915_fs_mul (out_reg,
+			     i915_fs_operand_reg (source_reg),
+			     i915_fs_operand (mask_reg, W, W, W, W));
+	    }
+
+	    source_reg = out_reg;
+	}
+    }
+
+    /* need to preserve order of src, mask, clip, dst */
+    mask_reg = ~0;
+    if (shader->clip.type.fragment == FS_TEXTURE) {
+	i915_fs_texld (FS_R1, FS_S0 + sampler_offset, FS_T0 + texture_offset);
+	texture_offset += 1;
+	sampler_offset += 1;
+	mask_reg = FS_R1;
+    }
+
+    if (shader->need_combine) {
+	assert (shader->dst.type.fragment == FS_TEXTURE);
+
+	i915_fs_texld (FS_R2, FS_S0 + sampler_offset, FS_T0 + texture_offset);
+	texture_offset += 1;
+	sampler_offset += 1;
+	dest_reg = FS_R2;
+
+	switch (shader->op) {
+	case CAIRO_OPERATOR_CLEAR:
+	case CAIRO_OPERATOR_SOURCE:
+	    ASSERT_NOT_REACHED;
+
+	case CAIRO_OPERATOR_OVER:
+	    if (source_reg == ~0U) {
+		/* XXX shader->source.type.fragment == FS_PURE */
+		dest_reg = FS_OC;
+	    } else {
+		i915_fs_add (FS_U0,
+			     i915_fs_operand (source_reg, -W, -W, -W, -W),
+			     i915_fs_operand_one ());
+		i915_fs_mul (FS_U0,
+			     i915_fs_operand_reg (FS_U0),
+			     dest_reg);
+		i915_fs_add (FS_R3,
+			     i915_fs_operand_reg (source_reg),
+			     i915_fs_operand_reg (FS_U0));
+		source_reg = FS_R3;
+	    }
+	    break;
+
+	case CAIRO_OPERATOR_IN:
+	    if (source_reg == ~0U) {
+		/* XXX shader->source.type.fragment == FS_PURE */
+		source_reg = dest_reg;
+	    } else {
+		i915_fs_mul (FS_R3,
+			     i915_fs_operand_reg (source_reg),
+			     dest_reg);
+		source_reg = FS_R3;
+	    }
+	    break;
+
+	case CAIRO_OPERATOR_OUT:
+	    if (source_reg == ~0U) {
+		/* XXX shader->source.type.fragment == FS_PURE */
+		i915_fs_mov (FS_R3, i915_fs_operand_zero ());
+		source_reg = FS_R3;
+	    } else {
+		i915_fs_add (FS_U0,
+			     i915_fs_operand (source_reg, -W, -W, -W, -W),
+			     i915_fs_operand_one ());
+		i915_fs_mul (FS_R3,
+			     i915_fs_operand_reg (FS_U0),
+			     dest_reg);
+		source_reg = FS_R3;
+	    }
+	    break;
+
+	case CAIRO_OPERATOR_ATOP:
+
+	case CAIRO_OPERATOR_DEST:
+	case CAIRO_OPERATOR_DEST_OVER:
+	case CAIRO_OPERATOR_DEST_IN:
+	case CAIRO_OPERATOR_DEST_OUT:
+	case CAIRO_OPERATOR_DEST_ATOP:
+
+	case CAIRO_OPERATOR_XOR:
+	case CAIRO_OPERATOR_ADD:
+	case CAIRO_OPERATOR_SATURATE:
+
+	case CAIRO_OPERATOR_MULTIPLY:
+	case CAIRO_OPERATOR_SCREEN:
+	case CAIRO_OPERATOR_OVERLAY:
+	case CAIRO_OPERATOR_DARKEN:
+	case CAIRO_OPERATOR_LIGHTEN:
+	case CAIRO_OPERATOR_COLOR_DODGE:
+	case CAIRO_OPERATOR_COLOR_BURN:
+	case CAIRO_OPERATOR_HARD_LIGHT:
+	case CAIRO_OPERATOR_SOFT_LIGHT:
+	case CAIRO_OPERATOR_DIFFERENCE:
+	case CAIRO_OPERATOR_EXCLUSION:
+	case CAIRO_OPERATOR_HSL_HUE:
+	case CAIRO_OPERATOR_HSL_SATURATION:
+	case CAIRO_OPERATOR_HSL_COLOR:
+	case CAIRO_OPERATOR_HSL_LUMINOSITY:
+	    ASSERT_NOT_REACHED;
+	    break;
+	}
+    }
+
+    if (shader->clip.type.fragment == FS_TEXTURE) {
+	assert (mask_reg != ~0U);
+
+	if (! shader->need_combine) {
+	    /* (source IN clip) */
+	    if (source_reg == ~0U) {
+		if (source_pure == 0) {
+		    source_reg = mask_reg;
+		} else {
+		    out_reg = FS_OC;
+		    if (shader->content == CAIRO_CONTENT_ALPHA)
+			out_reg = FS_U0;
+		    i915_fs_mov (out_reg,
+				 i915_fs_operand_reg_pure (mask_reg, source_pure));
+		    source_reg = out_reg;
+		}
+	    } else if (mask_reg) {
+		out_reg = FS_OC;
+		if (shader->content == CAIRO_CONTENT_ALPHA)
+		    out_reg = FS_U0;
+		i915_fs_mul (out_reg,
+			     i915_fs_operand_reg (source_reg),
+			     i915_fs_operand (mask_reg, W, W, W, W));
+
+		source_reg = out_reg;
+	    }
+	} else {
+	    /* (source OP dest)  LERP_clip dest */
+	    if (source_reg == ~0U) {
+		if (source_pure == 0) {
+		    i915_fs_mov (FS_U0,
+				 i915_fs_operand (mask_reg, W, W, W, W));
+		} else {
+		    i915_fs_mov (FS_U0,
+				 i915_fs_operand_impure (mask_reg, W, source_pure));
+		}
+	    } else {
+		i915_fs_mul (FS_U0,
+			     i915_fs_operand_reg (source_reg),
+			     i915_fs_operand (mask_reg, W, W, W, W));
+	    }
+
+	    i915_fs_add (mask_reg,
+			 i915_fs_operand_one (),
+			 i915_fs_operand (mask_reg, -W, -W, -W, -W));
+
+	    if (dest_reg != FS_OC) {
+		if (dest_reg == ~0U) {
+		    assert (shader->dst.type.fragment == FS_TEXTURE);
+
+		    i915_fs_texld (FS_R2, FS_S0 + sampler_offset, FS_T0 + texture_offset);
+		    texture_offset += 1;
+		    sampler_offset += 1;
+		    dest_reg = FS_R2;
+		}
+
+		i915_fs_mul (FS_U1,
+			     i915_fs_operand_reg (dest_reg),
+			     i915_fs_operand_reg (mask_reg));
+		mask_reg = FS_U1;
+	    }
+
+	    source_reg = FS_OC;
+	    if (shader->content != CAIRO_CONTENT_COLOR_ALPHA)
+		source_reg = FS_U0;
+	    i915_fs_add (source_reg,
+			 i915_fs_operand_reg (FS_U0),
+			 i915_fs_operand_reg (mask_reg));
+	}
+    }
+
+    if (source_reg != FS_OC) {
+	if (source_reg == ~0U)
+	    if (source_pure)
+		i915_fs_mov (FS_OC, i915_fs_operand_pure (source_pure));
+	    else
+		i915_fs_mov (FS_OC, i915_fs_operand_one ());
+	else if ((shader->content & CAIRO_CONTENT_COLOR) == 0)
+	    i915_fs_mov (FS_OC, i915_fs_operand (source_reg, W, W, W, W));
+	else
+	    i915_fs_mov (FS_OC, i915_fs_operand_reg (source_reg));
+    } else {
+	if ((shader->content & CAIRO_CONTENT_COLOR) == 0)
+	    i915_fs_mov (FS_OC, i915_fs_operand (FS_OC, W, W, W, W));
+    }
+
+    FS_END ();
+}
+
+static void
+i915_shader_linear_init (struct i915_shader_linear *l,
+			 const cairo_linear_pattern_t *linear)
+{
+    double x0, y0, sf;
+    double dx, dy, offset;
+
+    dx = _cairo_fixed_to_double (linear->p2.x - linear->p1.x);
+    dy = _cairo_fixed_to_double (linear->p2.y - linear->p1.y);
+    sf = 1. / (dx * dx + dy * dy);
+    dx *= sf;
+    dy *= sf;
+
+    x0 = _cairo_fixed_to_double (linear->p1.x);
+    y0 = _cairo_fixed_to_double (linear->p1.y);
+    offset = dx*x0 + dy*y0;
+
+    if (_cairo_matrix_is_identity (&linear->base.base.matrix)) {
+	l->dx = dx;
+	l->dy = dy;
+	l->offset = -offset;
+    } else {
+	cairo_matrix_t m;
+
+	cairo_matrix_init (&m, dx, 0, dy, 0, -offset, 0);
+	cairo_matrix_multiply (&m, &linear->base.base.matrix, &m);
+	l->dx = m.xx;
+	l->dy = m.xy;
+	l->offset = m.x0;
+    }
+}
+
+static cairo_bool_t
+i915_shader_linear_contains_rectangle (struct i915_shader_linear *l,
+				       const cairo_rectangle_int_t *extents)
+{
+    double v;
+
+    v = i915_shader_linear_texcoord (l,
+				     extents->x,
+				     extents->y);
+    if (v < 0.)
+	return FALSE;
+    if (v > 1.)
+	return FALSE;
+
+    v = i915_shader_linear_texcoord (l,
+				     extents->x + extents->width,
+				     extents->y);
+    if (v < 0.)
+	return FALSE;
+    if (v > 1.)
+	return FALSE;
+
+    v = i915_shader_linear_texcoord (l,
+				     extents->x,
+				     extents->y + extents->height);
+    if (v < 0.)
+	return FALSE;
+    if (v > 1.)
+	return FALSE;
+
+    v = i915_shader_linear_texcoord (l,
+				     extents->x + extents->width,
+				     extents->y + extents->height);
+    if (v < 0.)
+	return FALSE;
+    if (v > 1.)
+	return FALSE;
+
+    return TRUE;
+}
+
+#define is_pure(C,mask) (((mask) == 0) || (C) <= 0x00ff || (C) >= 0xff00)
+#define is_one(C,mask) (((mask) != 0) && (C) >= 0xff00)
+#define is_zero(C,mask) (((mask) != 0) && (C) <= 0x00ff)
+
+static cairo_status_t
+i915_shader_acquire_solid (i915_shader_t *shader,
+			   union i915_shader_channel *src,
+			   const cairo_solid_pattern_t *solid,
+			   const cairo_rectangle_int_t *extents)
+{
+    cairo_content_t content;
+
+    content = solid->content;
+    src->solid.color = solid->color;
+    if (content == 0 || solid->color.alpha_short <= 0x00ff)
+    {
+	src->base.content = CAIRO_CONTENT_ALPHA;
+	src->type.fragment = FS_ZERO;
+    }
+    else if ((((content & CAIRO_CONTENT_COLOR) == 0)  ||
+	      (solid->color.red_short >= 0xff00 &&
+	       solid->color.green_short >= 0xff00 &&
+	       solid->color.blue_short >= 0xff00)) &&
+	     ((content & CAIRO_CONTENT_ALPHA) == 0 ||
+	      solid->color.alpha_short >= 0xff00))
+    {
+	src->base.content = CAIRO_CONTENT_ALPHA;
+	src->type.fragment = FS_ONE;
+    }
+    else if (is_pure (solid->color.red_short, content & CAIRO_CONTENT_COLOR) &&
+	     is_pure (solid->color.green_short, content & CAIRO_CONTENT_COLOR) &&
+	     is_pure (solid->color.blue_short, content & CAIRO_CONTENT_COLOR) &&
+	     is_pure (solid->color.alpha_short, content & CAIRO_CONTENT_ALPHA))
+    {
+	src->solid.pure = 0;
+	src->solid.pure |= is_one (solid->color.red_short,   content & CAIRO_CONTENT_COLOR) << 0;
+	src->solid.pure |= is_one (solid->color.green_short, content & CAIRO_CONTENT_COLOR) << 1;
+	src->solid.pure |= is_one (solid->color.blue_short,  content & CAIRO_CONTENT_COLOR) << 2;
+	src->solid.pure |= (! is_zero (solid->color.alpha_short, content & CAIRO_CONTENT_ALPHA)) << 3;
+
+	if (src->solid.pure == 0) {
+	    src->base.content = CAIRO_CONTENT_ALPHA;
+	    src->type.fragment = FS_ZERO;
+	} else if (src->solid.pure == 0x7) {
+	    src->base.content = CAIRO_CONTENT_ALPHA;
+	    src->type.fragment = FS_ONE;
+	} else {
+	    src->base.content = content;
+	    src->type.fragment = FS_PURE;
+	    src->base.mode = src->solid.pure;
+	}
+    }
+    else
+    {
+	src->base.content = content;
+	src->type.fragment = src == &shader->source ? FS_DIFFUSE : FS_CONSTANT;
+    }
+    src->type.vertex = VS_CONSTANT;
+    src->type.pattern = PATTERN_CONSTANT;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_shader_acquire_linear (i915_shader_t *shader,
+			    union i915_shader_channel *src,
+			    const cairo_linear_pattern_t *linear,
+			    const cairo_rectangle_int_t *extents)
+{
+    cairo_bool_t mode = LINEAR_TEXTURE;
+    cairo_status_t status;
+
+    i915_shader_linear_init (&src->linear, linear);
+    if (linear->base.n_stops == 2 &&
+	linear->base.stops[0].offset == 0.0 &&
+	linear->base.stops[1].offset == 1.0)
+    {
+	if (i915_shader_linear_contains_rectangle (&src->linear,
+						   extents))
+	{
+	    /* XXX can also lerp if contained within offset range */
+	    mode = LINEAR_NONE;
+	}
+	else switch (linear->base.base.extend) {
+	case CAIRO_EXTEND_REPEAT:
+	    mode = LINEAR_REPEAT;
+	    break;
+	case CAIRO_EXTEND_PAD:
+	    mode = LINEAR_PAD;
+	    break;
+	case CAIRO_EXTEND_NONE:
+	    break;
+	case CAIRO_EXTEND_REFLECT:
+	    break;
+	default:
+	    ASSERT_NOT_REACHED;
+	    break;
+	}
+    }
+
+    src->type.vertex = VS_LINEAR;
+    src->type.pattern = PATTERN_LINEAR;
+    src->base.texfmt = TEXCOORDFMT_1D;
+    src->base.content = CAIRO_CONTENT_COLOR_ALPHA;
+    src->base.mode = mode;
+    if (mode == LINEAR_TEXTURE) {
+	intel_buffer_t buffer;
+
+	status = intel_gradient_render ((intel_device_t *) shader->target->intel.drm.base.device,
+					&linear->base, &buffer);
+	if (unlikely (status))
+	    return status;
+
+	src->type.fragment = FS_TEXTURE;
+	src->base.bo = intel_bo_reference (buffer.bo);
+	src->base.n_samplers = 1;
+	src->base.offset[0] = buffer.offset;
+	src->base.map[0] = buffer.map0;
+	src->base.map[1] = buffer.map1;
+	src->base.sampler[0] =
+	    (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
+	    i915_texture_filter (CAIRO_FILTER_BILINEAR);
+	src->base.sampler[1] =
+	    SS3_NORMALIZED_COORDS |
+	    i915_texture_extend (linear->base.base.extend);
+    } else {
+	src->type.fragment = FS_LINEAR;
+	src->linear.color0.red   = linear->base.stops[0].color.red;
+	src->linear.color0.green = linear->base.stops[0].color.green;
+	src->linear.color0.blue  = linear->base.stops[0].color.blue;
+	src->linear.color0.alpha = linear->base.stops[0].color.alpha;
+
+	src->linear.color1.red   = linear->base.stops[1].color.red;
+	src->linear.color1.green = linear->base.stops[1].color.green;
+	src->linear.color1.blue  = linear->base.stops[1].color.blue;
+	src->linear.color1.alpha = linear->base.stops[1].color.alpha;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_shader_acquire_radial (i915_shader_t *shader,
+			    union i915_shader_channel *src,
+			    const cairo_radial_pattern_t *radial,
+			    const cairo_rectangle_int_t *extents)
+{
+    intel_buffer_t buffer;
+    cairo_status_t status;
+
+    status = intel_gradient_render ((intel_device_t *) shader->target->intel.drm.base.device,
+				    &radial->base, &buffer);
+    if (unlikely (status))
+	return status;
+
+    i915_shader_radial_init (&src->radial, radial);
+
+    src->type.vertex = VS_RADIAL;
+    src->type.fragment = FS_RADIAL;
+    src->type.pattern = PATTERN_RADIAL;
+    src->base.texfmt = TEXCOORDFMT_2D;
+
+    src->base.content = CAIRO_CONTENT_COLOR_ALPHA;
+    src->base.bo = intel_bo_reference (buffer.bo);
+    src->base.n_samplers = 1;
+    src->base.offset[0] = buffer.offset;
+    src->base.map[0] = buffer.map0;
+    src->base.map[1] = buffer.map1;
+    src->base.sampler[0] =
+	(MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
+	i915_texture_filter (CAIRO_FILTER_BILINEAR);
+    src->base.sampler[1] =
+	SS3_NORMALIZED_COORDS |
+	i915_texture_extend (radial->base.base.extend);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_surface_clone (i915_device_t *device,
+		    cairo_image_surface_t *image,
+		    i915_surface_t **clone_out)
+{
+    i915_surface_t *clone;
+    cairo_status_t status;
+
+    clone =
+	i915_surface_create_from_cacheable_image_internal (device, image);
+    if (unlikely (clone->intel.drm.base.status))
+	return clone->intel.drm.base.status;
+
+    status = _cairo_surface_attach_snapshot (&image->base,
+					     &clone->intel.drm.base,
+					     intel_surface_detach_snapshot);
+    if (likely (status == CAIRO_STATUS_SUCCESS))
+	status = intel_snapshot_cache_insert (&device->intel, &clone->intel);
+
+    if (unlikely (status)) {
+	cairo_surface_destroy (&clone->intel.drm.base);
+	return status;
+    }
+
+    *clone_out = clone;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_surface_clone_subimage (i915_device_t *device,
+			     cairo_image_surface_t *image,
+			     const cairo_rectangle_int_t *extents,
+			     i915_surface_t **clone_out)
+{
+    i915_surface_t *clone;
+    cairo_status_t status;
+
+    clone = (i915_surface_t *)
+	i915_surface_create_internal (&device->intel.base,
+				      image->base.content,
+				      extents->width,
+				      extents->height,
+				      I915_TILING_DEFAULT,
+				      FALSE);
+    if (unlikely (clone->intel.drm.base.status))
+	return clone->intel.drm.base.status;
+
+    status = intel_bo_put_image (to_intel_device (clone->intel.drm.base.device),
+				 to_intel_bo (clone->intel.drm.bo),
+				 clone->intel.drm.stride,
+				 image,
+				 extents->x, extents->y,
+				 extents->width, extents->height,
+				 0, 0);
+
+    if (unlikely (status))
+	return status;
+
+    *clone_out = clone;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_shader_acquire_solid_surface (i915_shader_t *shader,
+				   union i915_shader_channel *src,
+				   cairo_surface_t *surface,
+				   const cairo_rectangle_int_t *extents)
+{
+    cairo_surface_pattern_t pattern;
+    cairo_surface_t *pixel;
+    cairo_image_surface_t *image;
+    void *image_extra;
+    cairo_status_t status;
+    uint32_t argb;
+
+    status = _cairo_surface_acquire_source_image (surface, &image, &image_extra);
+    if (unlikely (status))
+	return status;
+
+    /* extract the pixel as argb32 */
+    pixel = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+    _cairo_pattern_init_for_surface (&pattern, &image->base);
+    cairo_matrix_init_translate (&pattern.base.matrix, extents->x, extents->y);
+    pattern.base.filter = CAIRO_FILTER_NEAREST;
+    status = _cairo_surface_paint (pixel, CAIRO_OPERATOR_SOURCE, &pattern.base, NULL);
+    _cairo_pattern_fini (&pattern.base);
+
+    _cairo_surface_release_source_image (surface, image, image_extra);
+
+    if (unlikely (status)) {
+	cairo_surface_destroy (pixel);
+	return status;
+    }
+
+    image = (cairo_image_surface_t *) pixel;
+    argb = *(uint32_t *) image->data;
+    cairo_surface_destroy (pixel);
+
+    if (argb >> 24 == 0) {
+	_cairo_color_init_rgba (&src->solid.color, 0, 0, 0, 0);
+    } else {
+	uint8_t alpha = argb >> 24;
+
+	_cairo_color_init_rgba (&src->solid.color,
+				((((argb >> 16) & 0xff) * 255 + alpha / 2) / alpha) / 255.,
+				((((argb >>  8) & 0xff) * 255 + alpha / 2) / alpha) / 255.,
+				((((argb >>  0) & 0xff) * 255 + alpha / 2) / alpha) / 255.,
+				alpha / 255.);
+    }
+
+    src->base.content = CAIRO_CONTENT_COLOR_ALPHA;
+    src->type.fragment = FS_CONSTANT;
+    src->type.vertex = VS_CONSTANT;
+    src->type.pattern = PATTERN_CONSTANT;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_shader_acquire_surface (i915_shader_t *shader,
+			     union i915_shader_channel *src,
+			     const cairo_surface_pattern_t *pattern,
+			     const cairo_rectangle_int_t *extents)
+{
+    int surface_width, surface_height;
+    cairo_surface_t *surface, *drm;
+    cairo_extend_t extend;
+    cairo_filter_t filter;
+    cairo_matrix_t m;
+    int src_x = 0, src_y = 0;
+
+    assert (src->type.fragment == (i915_fragment_shader_t) -1);
+    drm = surface = pattern->surface;
+
+#if CAIRO_HAS_XCB_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+    if (surface->type == CAIRO_SURFACE_TYPE_XCB) {
+	cairo_surface_t *xcb = surface;
+
+	if (xcb->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+	    xcb = ((cairo_surface_subsurface_t *) surface)->target;
+	} else if (xcb->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
+	    xcb = ((cairo_surface_snapshot_t *) surface)->target;
+	}
+
+	/* XXX copy windows (IncludeInferiors) to a pixmap/drm surface
+	 * xcb = _cairo_xcb_surface_to_drm (xcb)
+	 */
+	xcb = ((cairo_xcb_surface_t *) xcb)->drm;
+	if (xcb != NULL)
+	    drm = xcb;
+    }
+#endif
+
+    if (surface->type == CAIRO_SURFACE_TYPE_DRM) {
+	if (surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+	    drm = ((cairo_surface_subsurface_t *) surface)->target;
+	} else if (surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
+	    drm = ((cairo_surface_snapshot_t *) surface)->target;
+	}
+    }
+
+    if (drm->type == CAIRO_SURFACE_TYPE_DRM) {
+	i915_surface_t *s = (i915_surface_t *) drm;
+
+	if (surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+	    if (s->intel.drm.base.device == shader->target->intel.drm.base.device &&
+		s != shader->target)
+	    {
+		cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) surface;
+		int x;
+
+		if (to_intel_bo (s->intel.drm.bo)->batch_write_domain) {
+		    /* XXX pipelined flush of RENDER/TEXTURE cache */
+		}
+
+		src->type.fragment = FS_TEXTURE;
+		src->surface.pixel = NONE;
+		surface_width  = sub->extents.width;
+		surface_height = sub->extents.height;
+
+		src->base.bo = intel_bo_reference (to_intel_bo (s->intel.drm.bo));
+		src->base.n_samplers = 1;
+
+		x = sub->extents.x;
+		if (s->intel.drm.format != CAIRO_FORMAT_A8)
+		    x *= 4;
+
+		/* XXX tiling restrictions upon offset? */
+		src->base.offset[0] = s->offset + sub->extents.y * s->intel.drm.stride + x;
+		src->base.map[0] = s->map0;
+		src->base.map[0] &= ~((2047 << MS3_HEIGHT_SHIFT) | (2047 << MS3_WIDTH_SHIFT));
+		src->base.map[0] |=
+		    ((sub->extents.height - 1) << MS3_HEIGHT_SHIFT) |
+		    ((sub->extents.width - 1)  << MS3_WIDTH_SHIFT);
+		src->base.map[1] = (s->intel.drm.stride / 4 - 1) << MS4_PITCH_SHIFT;
+	    }
+	} else {
+	    /* XXX if s == shader->dst allow if FILTER_NEAREST, EXTEND_NONE? */
+	    if (s->intel.drm.base.device == shader->target->intel.drm.base.device &&
+		s != shader->target)
+	    {
+		src->type.fragment = FS_TEXTURE;
+		src->surface.pixel = NONE;
+		surface_width  = s->intel.drm.width;
+		surface_height = s->intel.drm.height;
+
+		src->base.bo = intel_bo_reference (to_intel_bo (s->intel.drm.bo));
+		src->base.n_samplers = 1;
+		src->base.offset[0] = s->offset;
+		src->base.map[0] = s->map0;
+		src->base.map[1] = s->map1;
+	    }
+	}
+    }
+
+    if (src->type.fragment == (i915_fragment_shader_t) -1) {
+	i915_surface_t *s;
+
+	if (extents->width == 1 && extents->height == 1) {
+	    return i915_shader_acquire_solid_surface (shader, src,
+						      surface, extents);
+	}
+
+	s = (i915_surface_t *)
+	    _cairo_surface_has_snapshot (surface,
+					 shader->target->intel.drm.base.backend);
+	if (s == NULL) {
+	    cairo_image_surface_t *image;
+	    void *image_extra;
+	    cairo_status_t status;
+
+#if 0
+	    /* XXX hackity hack hack */
+	    status = i915_clone_yuv (surface, src,
+				     image->width, image->height,
+				     clone_out);
+#endif
+
+	    status = _cairo_surface_acquire_source_image (surface, &image, &image_extra);
+	    if (unlikely (status))
+		return status;
+
+	    if (image->width < 2048 && image->height < 2048) {
+		status = i915_surface_clone ((i915_device_t *) shader->target->intel.drm.base.device,
+					     image, &s);
+	    } else {
+		status = i915_surface_clone_subimage ((i915_device_t *) shader->target->intel.drm.base.device,
+						      image, extents, &s);
+		src_x = -extents->x;
+		src_y = -extents->y;
+	    }
+
+	    surface_width = image->width;
+	    surface_height = image->height;
+
+	    _cairo_surface_release_source_image (surface, image, image_extra);
+
+	    if (unlikely (status))
+		return status;
+	}
+
+	src->type.fragment = FS_TEXTURE;
+	src->surface.pixel = NONE;
+
+	src->base.bo = intel_bo_reference (to_intel_bo (s->intel.drm.bo));
+	src->base.n_samplers = 1;
+	src->base.offset[0] = s->offset;
+	src->base.map[0] = s->map0;
+	src->base.map[1] = s->map1;
+
+	drm = &s->intel.drm.base;
+    }
+
+    /* XXX transform nx1 or 1xn surfaces to 1D */
+
+    src->type.pattern = PATTERN_TEXTURE;
+    extend = pattern->base.extend;
+    if (extend != CAIRO_EXTEND_NONE &&
+	extents->x >= 0 && extents->y >= 0 &&
+	extents->x + extents->width  <= surface_width &&
+	extents->y + extents->height <= surface_height)
+    {
+	extend = CAIRO_EXTEND_NONE;
+    }
+    if (extend == CAIRO_EXTEND_NONE) {
+	src->type.vertex = VS_TEXTURE_16;
+	src->base.texfmt = TEXCOORDFMT_2D_16;
+    } else {
+	src->type.vertex = VS_TEXTURE;
+	src->base.texfmt = TEXCOORDFMT_2D;
+    }
+    src->base.content = drm->content;
+
+    filter = pattern->base.filter;
+    if (_cairo_matrix_is_pixel_exact (&pattern->base.matrix))
+	filter = CAIRO_FILTER_NEAREST;
+
+    src->base.sampler[0] =
+	(MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
+	i915_texture_filter (filter);
+    src->base.sampler[1] =
+	SS3_NORMALIZED_COORDS |
+	i915_texture_extend (extend);
+
+    /* tweak the src matrix to map from dst to texture coordinates */
+    src->base.matrix = pattern->base.matrix;
+    if (src_x | src_y)
+	cairo_matrix_translate (&src->base.matrix, src_x, src_x);
+    if (i915_texture_filter_is_nearest (filter))
+	cairo_matrix_translate (&src->base.matrix, NEAREST_BIAS, NEAREST_BIAS);
+    cairo_matrix_init_scale (&m, 1. / surface_width, 1. / surface_height);
+    cairo_matrix_multiply (&src->base.matrix, &src->base.matrix, &m);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+i915_shader_acquire_pattern (i915_shader_t *shader,
+			     union i915_shader_channel *src,
+			     const cairo_pattern_t *pattern,
+			     const cairo_rectangle_int_t *extents)
+{
+    switch (pattern->type) {
+    case CAIRO_PATTERN_TYPE_SOLID:
+	return i915_shader_acquire_solid (shader, src,
+					  (cairo_solid_pattern_t *) pattern,
+					  extents);
+
+    case CAIRO_PATTERN_TYPE_LINEAR:
+	return i915_shader_acquire_linear (shader, src,
+					   (cairo_linear_pattern_t *) pattern,
+					   extents);
+
+    case CAIRO_PATTERN_TYPE_RADIAL:
+	return i915_shader_acquire_radial (shader, src,
+					   (cairo_radial_pattern_t *) pattern,
+					   extents);
+
+    case CAIRO_PATTERN_TYPE_SURFACE:
+	return i915_shader_acquire_surface (shader, src,
+					    (cairo_surface_pattern_t *) pattern,
+					    extents);
+
+    default:
+	ASSERT_NOT_REACHED;
+	return CAIRO_STATUS_SUCCESS;
+    }
+}
+
+static uint32_t
+i915_get_blend (cairo_operator_t op,
+		i915_surface_t *dst)
+{
+#define SBLEND(X) ((BLENDFACT_##X) << S6_CBUF_SRC_BLEND_FACT_SHIFT)
+#define DBLEND(X) ((BLENDFACT_##X) << S6_CBUF_DST_BLEND_FACT_SHIFT)
+    static const struct blendinfo {
+	cairo_bool_t dst_alpha;
+	uint32_t src_blend;
+	uint32_t dst_blend;
+	enum {
+	    BOUNDED,
+	    SIMPLE,
+	    XRENDER,
+	} kind;
+    } i915_blend_op[] = {
+	{0, SBLEND (ZERO),          DBLEND (ZERO), BOUNDED}, /* Clear */
+	{0, SBLEND (ONE),           DBLEND (ZERO), BOUNDED}, /* Src */
+
+	{0, SBLEND (ONE),           DBLEND (INV_SRC_ALPHA), SIMPLE}, /* Over */
+	{1, SBLEND (DST_ALPHA),     DBLEND (ZERO), XRENDER}, /* In */
+	{1, SBLEND (INV_DST_ALPHA), DBLEND (ZERO), XRENDER}, /* Out */
+	{1, SBLEND (DST_ALPHA),     DBLEND (INV_SRC_ALPHA), SIMPLE}, /* Atop */
+
+	{0, SBLEND (ZERO),          DBLEND (ONE), SIMPLE}, /* Dst */
+	{1, SBLEND (INV_DST_ALPHA), DBLEND (ONE), SIMPLE}, /* OverReverse */
+	{0, SBLEND (ZERO),          DBLEND (SRC_ALPHA), XRENDER}, /* InReverse */
+	{0, SBLEND (ZERO),          DBLEND (INV_SRC_ALPHA), SIMPLE}, /* OutReverse */
+	{1, SBLEND (INV_DST_ALPHA), DBLEND (SRC_ALPHA), XRENDER}, /* AtopReverse */
+
+	{1, SBLEND (INV_DST_ALPHA), DBLEND (INV_SRC_ALPHA), SIMPLE}, /* Xor */
+	{0, SBLEND (ONE),           DBLEND (ONE), SIMPLE}, /* Add */
+	//{0, 0, SBLEND (SRC_ALPHA_SATURATE),	    DBLEND (ONE), SIMPLE}, /* XXX Saturate */
+    };
+    uint32_t sblend, dblend;
+
+    if (op >= ARRAY_LENGTH (i915_blend_op))
+	return 0;
+
+    if (i915_blend_op[op].kind == BOUNDED)
+	return 0;
+
+    sblend = i915_blend_op[op].src_blend;
+    dblend = i915_blend_op[op].dst_blend;
+
+    /* If there's no dst alpha channel, adjust the blend op so that we'll treat
+     * it as always 1.
+     */
+    if ((dst->intel.drm.base.content & CAIRO_CONTENT_ALPHA) == 0 &&
+	i915_blend_op[op].dst_alpha)
+    {
+	if (sblend == SBLEND (DST_ALPHA))
+	    sblend = SBLEND (ONE);
+	else if (sblend == SBLEND (INV_DST_ALPHA))
+	    sblend = SBLEND (ZERO);
+    }
+
+    /* i915 engine reads 8bit color buffer into green channel in cases
+       like color buffer blending etc., and also writes back green channel.
+       So with dst_alpha blend we should use color factor. See spec on
+       "8-bit rendering" */
+    if (dst->intel.drm.format == CAIRO_FORMAT_A8 && i915_blend_op[op].dst_alpha) {
+	if (sblend == SBLEND (DST_ALPHA))
+	    sblend = SBLEND (DST_COLR);
+	else if (sblend == SBLEND (INV_DST_ALPHA))
+	    sblend = SBLEND (INV_DST_COLR);
+    }
+
+    return sblend | dblend;
+#undef SBLEND
+#undef DBLEND
+}
+
+static void
+i915_shader_channel_init (union i915_shader_channel *channel)
+{
+    channel->type.vertex = (i915_vertex_shader_t) -1;
+    channel->type.fragment = (i915_fragment_shader_t) -1;
+    channel->type.pattern = (i915_shader_channel_t) -1;
+    channel->base.texfmt = TEXCOORDFMT_NOT_PRESENT;
+    channel->base.bo = NULL;
+    channel->base.n_samplers = 0;
+    channel->base.mode = 0;
+}
+
+void
+i915_shader_init (i915_shader_t *shader,
+		  i915_surface_t *dst,
+		  cairo_operator_t op)
+{
+    shader->device = i915_device (dst);
+    shader->target = dst;
+    shader->op = op;
+
+    shader->blend = i915_get_blend (op, dst);
+    shader->need_combine = FALSE;
+
+    shader->content = dst->intel.drm.base.content;
+
+    i915_shader_channel_init (&shader->source);
+    i915_shader_channel_init (&shader->mask);
+    i915_shader_channel_init (&shader->clip);
+    i915_shader_channel_init (&shader->dst);
+}
+
+static void
+i915_set_shader_samplers (i915_device_t *device,
+	                  const i915_shader_t *shader)
+{
+    uint32_t n_samplers, n;
+    uint32_t samplers[4 * (1+2+8)];
+    uint32_t mask, tu;
+
+    n_samplers =
+	shader->source.base.n_samplers +
+	shader->mask.base.n_samplers +
+	shader->clip.base.n_samplers +
+	shader->dst.base.n_samplers;
+    assert (n_samplers <= 4);
+
+    if (n_samplers == 0)
+	return;
+
+    mask  = (1 << n_samplers) - 1;
+
+    /* We check for repeated setting of sample state mainly to catch
+     * continuation of text strings across multiple show-glyphs.
+     */
+    tu = 0;
+    if (shader->source.base.bo != NULL) {
+	samplers[tu++] = shader->source.base.bo->base.handle;
+	samplers[tu++] = shader->source.base.sampler[0];
+	samplers[tu++] = shader->source.base.sampler[1];
+	for (n = 0; n < shader->source.base.n_samplers; n++) {
+	    samplers[tu++] = shader->source.base.offset[n];
+	    samplers[tu++] = shader->source.base.map[2*n+0];
+	    samplers[tu++] = shader->source.base.map[2*n+1];
+	}
+    }
+    if (shader->mask.base.bo != NULL) {
+	samplers[tu++] = shader->mask.base.bo->base.handle;
+	samplers[tu++] = shader->mask.base.sampler[0];
+	samplers[tu++] = shader->mask.base.sampler[1];
+	for (n = 0; n < shader->mask.base.n_samplers; n++) {
+	    samplers[tu++] = shader->mask.base.offset[n];
+	    samplers[tu++] = shader->mask.base.map[2*n+0];
+	    samplers[tu++] = shader->mask.base.map[2*n+1];
+	}
+    }
+    if (shader->clip.base.bo != NULL) {
+	samplers[tu++] = shader->clip.base.bo->base.handle;
+	samplers[tu++] = shader->clip.base.sampler[0];
+	samplers[tu++] = shader->clip.base.sampler[1];
+	for (n = 0; n < shader->clip.base.n_samplers; n++) {
+	    samplers[tu++] = shader->clip.base.offset[n];
+	    samplers[tu++] = shader->clip.base.map[2*n+0];
+	    samplers[tu++] = shader->clip.base.map[2*n+1];
+	}
+    }
+    if (shader->dst.base.bo != NULL) {
+	samplers[tu++] = shader->dst.base.bo->base.handle;
+	samplers[tu++] = shader->dst.base.sampler[0];
+	samplers[tu++] = shader->dst.base.sampler[1];
+	for (n = 0; n < shader->dst.base.n_samplers; n++) {
+	    samplers[tu++] = shader->dst.base.offset[n];
+	    samplers[tu++] = shader->dst.base.map[2*n+0];
+	    samplers[tu++] = shader->dst.base.map[2*n+1];
+	}
+    }
+
+    if (tu == device->current_n_samplers &&
+	memcmp (device->current_samplers,
+		samplers,
+		tu * sizeof (uint32_t)) == 0)
+    {
+	return;
+    }
+    device->current_n_samplers = tu;
+    memcpy (device->current_samplers, samplers, tu * sizeof (uint32_t));
+
+    if (device->current_source != NULL)
+	*device->current_source = 0;
+    if (device->current_mask != NULL)
+	*device->current_mask = 0;
+    if (device->current_clip != NULL)
+	*device->current_clip = 0;
+
+#if 0
+    if (shader->source.type.pattern == PATTERN_TEXTURE) {
+	switch ((int) shader->source.surface.surface->type) {
+	case CAIRO_SURFACE_TYPE_DRM:
+	    {
+		i915_surface_t *surface =
+		    (i915_surface_t *) shader->source.surface.surface;
+		device->current_source = &surface->is_current_texture;
+		surface->is_current_texture |= CURRENT_SOURCE;
+		break;
+	    }
+
+	case I915_PACKED_PIXEL_SURFACE_TYPE:
+	    {
+		i915_packed_pixel_surface_t *surface =
+		    (i915_packed_pixel_surface_t *) shader->source.surface.surface;
+		device->current_source = &surface->is_current_texture;
+		surface->is_current_texture |= CURRENT_SOURCE;
+		break;
+	    }
+
+	default:
+	    device->current_source = NULL;
+	    break;
+	}
+    } else
+	device->current_source = NULL;
+
+    if (shader->mask.type.pattern == PATTERN_TEXTURE) {
+	switch ((int) shader->mask.surface.surface->type) {
+	case CAIRO_SURFACE_TYPE_DRM:
+	    {
+		i915_surface_t *surface =
+		    (i915_surface_t *) shader->mask.surface.surface;
+		device->current_mask = &surface->is_current_texture;
+		surface->is_current_texture |= CURRENT_MASK;
+		break;
+	    }
+
+	case I915_PACKED_PIXEL_SURFACE_TYPE:
+	    {
+		i915_packed_pixel_surface_t *surface =
+		    (i915_packed_pixel_surface_t *) shader->mask.surface.surface;
+		device->current_mask = &surface->is_current_texture;
+		surface->is_current_texture |= CURRENT_MASK;
+		break;
+	    }
+
+	default:
+	    device->current_mask = NULL;
+	    break;
+	}
+    } else
+	device->current_mask = NULL;
+#endif
+
+    OUT_DWORD (_3DSTATE_MAP_STATE | (3 * n_samplers));
+    OUT_DWORD (mask);
+    if (shader->source.base.bo != NULL) {
+	for (n = 0; n < shader->source.base.n_samplers; n++) {
+	    i915_batch_emit_reloc (device, shader->source.base.bo,
+				   shader->source.base.offset[n],
+				   I915_GEM_DOMAIN_SAMPLER, 0);
+	    OUT_DWORD (shader->source.base.map[2*n+0]);
+	    OUT_DWORD (shader->source.base.map[2*n+1]);
+	}
+    }
+    if (shader->mask.base.bo != NULL) {
+	for (n = 0; n < shader->mask.base.n_samplers; n++) {
+	    i915_batch_emit_reloc (device, shader->mask.base.bo,
+				   shader->mask.base.offset[n],
+				   I915_GEM_DOMAIN_SAMPLER, 0);
+	    OUT_DWORD (shader->mask.base.map[2*n+0]);
+	    OUT_DWORD (shader->mask.base.map[2*n+1]);
+	}
+    }
+    if (shader->clip.base.bo != NULL) {
+	for (n = 0; n < shader->clip.base.n_samplers; n++) {
+	    i915_batch_emit_reloc (device, shader->clip.base.bo,
+				   shader->clip.base.offset[n],
+				   I915_GEM_DOMAIN_SAMPLER, 0);
+	    OUT_DWORD (shader->clip.base.map[2*n+0]);
+	    OUT_DWORD (shader->clip.base.map[2*n+1]);
+	}
+    }
+    if (shader->dst.base.bo != NULL) {
+	for (n = 0; n < shader->dst.base.n_samplers; n++) {
+	    i915_batch_emit_reloc (device, shader->dst.base.bo,
+				   shader->dst.base.offset[n],
+				   I915_GEM_DOMAIN_SAMPLER, 0);
+	    OUT_DWORD (shader->dst.base.map[2*n+0]);
+	    OUT_DWORD (shader->dst.base.map[2*n+1]);
+	}
+    }
+
+    OUT_DWORD (_3DSTATE_SAMPLER_STATE | (3 * n_samplers));
+    OUT_DWORD (mask);
+    tu = 0;
+    if (shader->source.base.bo != NULL) {
+	for (n = 0; n < shader->source.base.n_samplers; n++) {
+	    OUT_DWORD (shader->source.base.sampler[0]);
+	    OUT_DWORD (shader->source.base.sampler[1] |
+		       (tu << SS3_TEXTUREMAP_INDEX_SHIFT));
+	    OUT_DWORD (0x0);
+	    tu++;
+	}
+    }
+    if (shader->mask.base.bo != NULL) {
+	for (n = 0; n < shader->mask.base.n_samplers; n++) {
+	    OUT_DWORD (shader->mask.base.sampler[0]);
+	    OUT_DWORD (shader->mask.base.sampler[1] |
+		       (tu << SS3_TEXTUREMAP_INDEX_SHIFT));
+	    OUT_DWORD (0x0);
+	    tu++;
+	}
+    }
+    if (shader->clip.base.bo != NULL) {
+	for (n = 0; n < shader->clip.base.n_samplers; n++) {
+	    OUT_DWORD (shader->clip.base.sampler[0]);
+	    OUT_DWORD (shader->clip.base.sampler[1] |
+		       (tu << SS3_TEXTUREMAP_INDEX_SHIFT));
+	    OUT_DWORD (0x0);
+	    tu++;
+	}
+    }
+    if (shader->dst.base.bo != NULL) {
+	for (n = 0; n < shader->dst.base.n_samplers; n++) {
+	    OUT_DWORD (shader->dst.base.sampler[0]);
+	    OUT_DWORD (shader->dst.base.sampler[1] |
+		       (tu << SS3_TEXTUREMAP_INDEX_SHIFT));
+	    OUT_DWORD (0x0);
+	    tu++;
+	}
+    }
+}
+
+static uint32_t
+i915_shader_get_texcoords (const i915_shader_t *shader)
+{
+    uint32_t texcoords;
+    uint32_t tu;
+
+    texcoords = S2_TEXCOORD_NONE;
+    tu = 0;
+    if (shader->source.base.texfmt != TEXCOORDFMT_NOT_PRESENT) {
+	texcoords &= ~S2_TEXCOORD_FMT (tu, S2_TEXCOORD_FMT0_MASK);
+	texcoords |= S2_TEXCOORD_FMT (tu, shader->source.base.texfmt);
+	tu++;
+    }
+    if (shader->mask.base.texfmt != TEXCOORDFMT_NOT_PRESENT) {
+	texcoords &= ~S2_TEXCOORD_FMT (tu, S2_TEXCOORD_FMT0_MASK);
+	texcoords |= S2_TEXCOORD_FMT (tu, shader->mask.base.texfmt);
+	tu++;
+    }
+    if (shader->clip.base.texfmt != TEXCOORDFMT_NOT_PRESENT) {
+	texcoords &= ~S2_TEXCOORD_FMT (tu, S2_TEXCOORD_FMT0_MASK);
+	texcoords |= S2_TEXCOORD_FMT (tu, shader->clip.base.texfmt);
+	tu++;
+    }
+    if (shader->dst.base.texfmt != TEXCOORDFMT_NOT_PRESENT) {
+	texcoords &= ~S2_TEXCOORD_FMT (tu, S2_TEXCOORD_FMT0_MASK);
+	texcoords |= S2_TEXCOORD_FMT (tu, shader->dst.base.texfmt);
+	tu++;
+    }
+
+    return texcoords;
+}
+
+static void
+i915_set_shader_mode (i915_device_t *device,
+	              const i915_shader_t *shader)
+{
+    uint32_t texcoords;
+    uint32_t mask, cnt;
+
+    texcoords = i915_shader_get_texcoords (shader);
+
+    mask = cnt = 0;
+
+    if (device->current_texcoords != texcoords)
+	mask |= I1_LOAD_S (2), cnt++;
+
+    if (device->current_blend != shader->blend)
+	mask |= I1_LOAD_S (6), cnt++;
+
+    if (cnt == 0)
+	return;
+
+    OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | mask | (cnt-1));
+
+    if (device->current_texcoords != texcoords) {
+	OUT_DWORD (texcoords);
+	device->current_texcoords = texcoords;
+    }
+
+    if (device->current_blend != shader->blend) {
+	if (shader->blend) {
+	    OUT_DWORD (S6_CBUF_BLEND_ENABLE | S6_COLOR_WRITE_ENABLE |
+		       (BLENDFUNC_ADD << S6_CBUF_BLEND_FUNC_SHIFT) |
+		       shader->blend);
+	} else {
+	    OUT_DWORD (S6_COLOR_WRITE_ENABLE);
+	}
+
+	device->current_blend = shader->blend;
+    }
+}
+
+static void
+i915_set_constants (i915_device_t *device,
+		    const uint32_t *constants,
+		    uint32_t n_constants)
+{
+    uint32_t n;
+
+    OUT_DWORD (_3DSTATE_PIXEL_SHADER_CONSTANTS | n_constants);
+    OUT_DWORD ((1 << (n_constants >> 2)) - 1);
+
+    for (n = 0; n < n_constants; n++)
+	OUT_DWORD (constants[n]);
+
+    device->current_n_constants = n_constants;
+    memcpy (device->current_constants, constants, n_constants*4);
+}
+
+static inline uint32_t
+pack_float (float f)
+{
+    union {
+	float f;
+	uint32_t ui;
+    } t;
+    t.f = f;
+    return t.ui;
+}
+
+static uint32_t
+pack_constants (const union i915_shader_channel *channel,
+		uint32_t *constants)
+{
+    uint32_t count = 0, n;
+
+    switch (channel->type.fragment) {
+    case FS_ZERO:
+    case FS_ONE:
+    case FS_PURE:
+    case FS_DIFFUSE:
+	break;
+
+    case FS_CONSTANT:
+	constants[count++] = pack_float (channel->solid.color.red);
+	constants[count++] = pack_float (channel->solid.color.green);
+	constants[count++] = pack_float (channel->solid.color.blue);
+	constants[count++] = pack_float (channel->solid.color.alpha);
+	break;
+
+    case FS_LINEAR:
+	constants[count++] = pack_float (channel->linear.color0.red);
+	constants[count++] = pack_float (channel->linear.color0.green);
+	constants[count++] = pack_float (channel->linear.color0.blue);
+	constants[count++] = pack_float (channel->linear.color0.alpha);
+
+	constants[count++] = pack_float (channel->linear.color1.red);
+	constants[count++] = pack_float (channel->linear.color1.green);
+	constants[count++] = pack_float (channel->linear.color1.blue);
+	constants[count++] = pack_float (channel->linear.color1.alpha);
+	break;
+
+    case FS_RADIAL:
+	for (n = 0; n < ARRAY_LENGTH (channel->radial.constants); n++)
+	    constants[count++] = pack_float (channel->radial.constants[n]);
+	break;
+
+    case FS_TEXTURE:
+    case FS_YUV:
+    case FS_SPANS:
+	break;
+    }
+
+    return count;
+}
+
+static void
+i915_set_shader_constants (i915_device_t *device,
+	                   const i915_shader_t *shader)
+{
+    uint32_t constants[4*4*3];
+    unsigned n_constants;
+
+    n_constants = 0;
+    if (shader->source.type.fragment == FS_DIFFUSE) {
+	uint32_t diffuse;
+
+	diffuse =
+	    ((shader->source.solid.color.alpha_short >> 8) << 24) |
+	    ((shader->source.solid.color.red_short   >> 8) << 16) |
+	    ((shader->source.solid.color.green_short >> 8) << 8) |
+	    ((shader->source.solid.color.blue_short  >> 8) << 0);
+
+	if (diffuse != device->current_diffuse) {
+	    OUT_DWORD (_3DSTATE_DFLT_DIFFUSE_CMD);
+	    OUT_DWORD (diffuse);
+	    device->current_diffuse = diffuse;
+	}
+    } else {
+	n_constants += pack_constants (&shader->source, constants + n_constants);
+    }
+    n_constants += pack_constants (&shader->mask, constants + n_constants);
+
+    if (n_constants != 0 &&
+	(device->current_n_constants != n_constants ||
+	 memcmp (device->current_constants, constants, n_constants*4)))
+    {
+	i915_set_constants (device, constants, n_constants);
+    }
+}
+
+static cairo_bool_t
+i915_shader_needs_update (const i915_shader_t *shader,
+			  const i915_device_t *device)
+{
+    uint32_t count, n;
+    uint32_t buf[64];
+
+    if (device->current_target != shader->target)
+	return TRUE;
+
+    count =
+	shader->source.base.n_samplers +
+	shader->mask.base.n_samplers +
+	shader->clip.base.n_samplers +
+	shader->dst.base.n_samplers;
+    if (count > 4)
+	return TRUE;
+
+    if (count != 0) {
+	count *= 3;
+	if (shader->source.base.bo != NULL)
+	    count += 3;
+	if (shader->mask.base.bo != NULL)
+	    count += 3;
+	if (shader->clip.base.bo != NULL)
+	    count += 3;
+	if (shader->dst.base.bo != NULL)
+	    count += 3;
+
+	if (count != device->current_n_samplers)
+	    return TRUE;
+
+	if (count != 0) {
+	    count = 0;
+	    if (shader->source.base.bo != NULL) {
+		buf[count++] = shader->source.base.bo->base.handle;
+		buf[count++] = shader->source.base.sampler[0];
+		buf[count++] = shader->source.base.sampler[1];
+		for (n = 0; n < shader->source.base.n_samplers; n++) {
+		    buf[count++] = shader->source.base.offset[n];
+		    buf[count++] = shader->source.base.map[2*n+0];
+		    buf[count++] = shader->source.base.map[2*n+1];
+		}
+	    }
+	    if (shader->mask.base.bo != NULL) {
+		buf[count++] = shader->mask.base.bo->base.handle;
+		buf[count++] = shader->mask.base.sampler[0];
+		buf[count++] = shader->mask.base.sampler[1];
+		for (n = 0; n < shader->mask.base.n_samplers; n++) {
+		    buf[count++] = shader->mask.base.offset[n];
+		    buf[count++] = shader->mask.base.map[2*n+0];
+		    buf[count++] = shader->mask.base.map[2*n+1];
+		}
+	    }
+	    if (shader->clip.base.bo != NULL) {
+		buf[count++] = shader->clip.base.bo->base.handle;
+		buf[count++] = shader->clip.base.sampler[0];
+		buf[count++] = shader->clip.base.sampler[1];
+		for (n = 0; n < shader->clip.base.n_samplers; n++) {
+		    buf[count++] = shader->clip.base.offset[n];
+		    buf[count++] = shader->clip.base.map[2*n+0];
+		    buf[count++] = shader->clip.base.map[2*n+1];
+		}
+	    }
+	    if (shader->dst.base.bo != NULL) {
+		buf[count++] = shader->dst.base.bo->base.handle;
+		buf[count++] = shader->dst.base.sampler[0];
+		buf[count++] = shader->dst.base.sampler[1];
+		for (n = 0; n < shader->dst.base.n_samplers; n++) {
+		    buf[count++] = shader->dst.base.offset[n];
+		    buf[count++] = shader->dst.base.map[2*n+0];
+		    buf[count++] = shader->dst.base.map[2*n+1];
+		}
+	    }
+
+	    assert (count == device->current_n_samplers);
+	    if (memcmp (device->current_samplers, buf, count * sizeof (uint32_t)))
+		return TRUE;
+	}
+    }
+
+    if (i915_shader_get_texcoords (shader) != device->current_texcoords)
+	return TRUE;
+    if (device->current_blend != shader->blend)
+	return TRUE;
+
+    count = 0;
+    if (shader->source.type.fragment == FS_DIFFUSE) {
+	uint32_t diffuse;
+
+	diffuse =
+	    ((shader->source.solid.color.alpha_short >> 8) << 24) |
+	    ((shader->source.solid.color.red_short   >> 8) << 16) |
+	    ((shader->source.solid.color.green_short >> 8) << 8) |
+	    ((shader->source.solid.color.blue_short  >> 8) << 0);
+
+	if (diffuse != device->current_diffuse)
+	    return TRUE;
+    } else {
+	count += pack_constants (&shader->source, buf + count);
+    }
+    count += pack_constants (&shader->mask, buf + count);
+
+    if (count &&
+	(device->current_n_constants != count ||
+	 memcmp (device->current_constants, buf, count*4)))
+    {
+	return TRUE;
+    }
+
+    n = (i915_shader_channel_key (&shader->source) <<  0) |
+	(i915_shader_channel_key (&shader->mask)   <<  8) |
+	(i915_shader_channel_key (&shader->clip)   << 16) |
+	(shader->op << 24) |
+	(((shader->content & CAIRO_CONTENT_ALPHA) == CAIRO_CONTENT_ALPHA) << 31);
+    return n != device->current_program;
+}
+
+static void
+i915_set_shader_target (i915_device_t *device,
+		        const i915_shader_t *shader)
+{
+    i915_surface_t *dst;
+    intel_bo_t *bo;
+    uint32_t size;
+
+    dst = shader->target;
+    if (device->current_target == dst)
+	return;
+
+    bo = to_intel_bo (dst->intel.drm.bo);
+    assert (bo != NULL);
+
+    OUT_DWORD (_3DSTATE_BUF_INFO_CMD);
+    OUT_DWORD (BUF_3D_ID_COLOR_BACK |
+	       BUF_tiling (bo->tiling) |
+	       BUF_3D_PITCH (dst->intel.drm.stride));
+    OUT_RELOC (dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+
+    if (dst->colorbuf != device->current_colorbuf) {
+	OUT_DWORD (_3DSTATE_DST_BUF_VARS_CMD);
+	OUT_DWORD (dst->colorbuf);
+	device->current_colorbuf = dst->colorbuf;
+    }
+
+    size = DRAW_YMAX (dst->intel.drm.height) | DRAW_XMAX (dst->intel.drm.width);
+    if (size != device->current_size) {
+	OUT_DWORD (_3DSTATE_DRAW_RECT_CMD);
+	OUT_DWORD (0); /* dither */
+	OUT_DWORD (0); /* top-left */
+	OUT_DWORD (size);
+	OUT_DWORD (0);  /* origin */
+	device->current_size = size;
+    }
+
+    device->current_target = dst;
+}
+
+int
+i915_shader_num_texcoords (const i915_shader_t *shader)
+{
+    int cnt = 0;
+
+    switch (shader->source.base.texfmt) {
+    default:
+	ASSERT_NOT_REACHED;
+    case TEXCOORDFMT_NOT_PRESENT: break;
+    case TEXCOORDFMT_2D: cnt += 2; break;
+    case TEXCOORDFMT_3D: cnt += 3; break;
+    case TEXCOORDFMT_4D: cnt += 4; break;
+    case TEXCOORDFMT_1D: cnt += 1; break;
+    case TEXCOORDFMT_2D_16: cnt += 1; break;
+    }
+
+    switch (shader->mask.base.texfmt) {
+    default:
+	ASSERT_NOT_REACHED;
+    case TEXCOORDFMT_NOT_PRESENT: break;
+    case TEXCOORDFMT_2D: cnt += 2; break;
+    case TEXCOORDFMT_3D: cnt += 3; break;
+    case TEXCOORDFMT_4D: cnt += 4; break;
+    case TEXCOORDFMT_1D: cnt += 1; break;
+    case TEXCOORDFMT_2D_16: cnt += 1; break;
+    }
+
+    switch (shader->clip.base.texfmt) {
+    default:
+	ASSERT_NOT_REACHED;
+    case TEXCOORDFMT_NOT_PRESENT: break;
+    case TEXCOORDFMT_2D: cnt += 2; break;
+    case TEXCOORDFMT_3D: cnt += 3; break;
+    case TEXCOORDFMT_4D: cnt += 4; break;
+    case TEXCOORDFMT_1D: cnt += 1; break;
+    case TEXCOORDFMT_2D_16: cnt += 1; break;
+    }
+
+    switch (shader->dst.base.texfmt) {
+    default:
+	ASSERT_NOT_REACHED;
+    case TEXCOORDFMT_NOT_PRESENT: break;
+    case TEXCOORDFMT_2D: cnt += 2; break;
+    case TEXCOORDFMT_3D: cnt += 3; break;
+    case TEXCOORDFMT_4D: cnt += 4; break;
+    case TEXCOORDFMT_1D: cnt += 1; break;
+    case TEXCOORDFMT_2D_16: cnt += 1; break;
+    }
+
+    return cnt;
+}
+
+void
+i915_shader_fini (i915_shader_t *shader)
+{
+    i915_device_t *device = i915_device (shader->target);
+
+    switch (shader->source.type.pattern) {
+    case PATTERN_TEXTURE:
+    case PATTERN_BASE:
+    case PATTERN_LINEAR:
+    case PATTERN_RADIAL:
+	if (shader->source.base.bo != NULL)
+	    cairo_drm_bo_destroy (&device->intel.base.base, &shader->source.base.bo->base);
+	break;
+
+    default:
+    case PATTERN_CONSTANT:
+	break;
+    }
+
+    switch (shader->mask.type.pattern) {
+    case PATTERN_TEXTURE:
+    case PATTERN_BASE:
+    case PATTERN_LINEAR:
+    case PATTERN_RADIAL:
+	if (shader->mask.base.bo != NULL)
+	    cairo_drm_bo_destroy (&device->intel.base.base, &shader->mask.base.bo->base);
+	break;
+
+    default:
+    case PATTERN_CONSTANT:
+	break;
+    }
+
+    switch (shader->clip.type.pattern) {
+    case PATTERN_TEXTURE:
+    case PATTERN_BASE:
+    case PATTERN_LINEAR:
+    case PATTERN_RADIAL:
+	if (shader->clip.base.bo != NULL)
+	    cairo_drm_bo_destroy (&device->intel.base.base, &shader->clip.base.bo->base);
+	break;
+
+    default:
+    case PATTERN_CONSTANT:
+	break;
+    }
+}
+
+void
+i915_shader_set_clip (i915_shader_t *shader,
+		      cairo_clip_t *clip)
+{
+    cairo_surface_t *clip_surface;
+    const cairo_rectangle_int_t *clip_extents;
+    union i915_shader_channel *channel;
+    i915_surface_t *s;
+
+    clip_surface = _cairo_clip_get_surface (clip, &shader->target->intel.drm.base);
+    assert (clip_surface->status == CAIRO_STATUS_SUCCESS);
+    assert (clip_surface->type == CAIRO_SURFACE_TYPE_DRM);
+
+    channel = &shader->clip;
+    channel->type.pattern = PATTERN_TEXTURE;
+    channel->type.vertex = VS_TEXTURE_16;
+    channel->base.texfmt = TEXCOORDFMT_2D_16;
+    channel->base.content = CAIRO_CONTENT_ALPHA;
+
+    channel->type.fragment = FS_TEXTURE;
+    channel->surface.pixel = NONE;
+
+    s = (i915_surface_t *) clip_surface;
+    channel->base.bo = intel_bo_reference (to_intel_bo (s->intel.drm.bo));
+    channel->base.n_samplers = 1;
+    channel->base.offset[0] = s->offset;
+    channel->base.map[0] = s->map0;
+    channel->base.map[1] = s->map1;
+
+    channel->base.sampler[0] =
+	(MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
+	i915_texture_filter (CAIRO_FILTER_NEAREST);
+    channel->base.sampler[1] =
+	SS3_NORMALIZED_COORDS |
+	i915_texture_extend (CAIRO_EXTEND_NONE);
+
+    cairo_matrix_init_scale (&shader->clip.base.matrix,
+			     1. / s->intel.drm.width,
+			     1. / s->intel.drm.height);
+
+    clip_extents = _cairo_clip_get_extents (clip);
+    cairo_matrix_translate (&shader->clip.base.matrix,
+			    NEAREST_BIAS + clip_extents->x,
+			    NEAREST_BIAS + clip_extents->y);
+}
+
+static cairo_status_t
+i915_shader_check_aperture (i915_shader_t *shader,
+			    i915_device_t *device)
+{
+    cairo_status_t status;
+    intel_bo_t *bo_array[4];
+    uint32_t n = 0;
+
+    if (shader->target != device->current_target)
+	bo_array[n++] = to_intel_bo (shader->target->intel.drm.bo);
+
+    if (shader->source.base.bo != NULL)
+	bo_array[n++] = shader->source.base.bo;
+
+    if (shader->mask.base.bo != NULL)
+	bo_array[n++] = shader->mask.base.bo;
+
+    if (shader->clip.base.bo != NULL)
+	bo_array[n++] = shader->clip.base.bo;
+
+    if (n == 0 || i915_check_aperture (device, bo_array, n))
+	return CAIRO_STATUS_SUCCESS;
+
+    status = i915_batch_flush (device);
+    if (unlikely (status))
+	return status;
+
+    assert (i915_check_aperture (device, bo_array, n));
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+i915_shader_combine_mask (i915_shader_t *shader)
+{
+    if (shader->mask.type.fragment == (i915_fragment_shader_t) -1 ||
+	shader->mask.type.fragment == FS_CONSTANT)
+    {
+	return;
+    }
+
+    if (shader->mask.type.fragment == FS_PURE) {
+	if (shader->mask.solid.pure & (1<<3)) {
+	    shader->mask.type.fragment = FS_ONE;
+	} else {
+	    shader->mask.type.fragment = FS_ZERO;
+	}
+    }
+
+    if (shader->mask.type.fragment == FS_ONE ||
+	(shader->mask.base.content & CAIRO_CONTENT_ALPHA) == 0)
+    {
+	shader->mask.type.vertex = (i915_vertex_shader_t) -1;
+	shader->mask.type.fragment = (i915_fragment_shader_t) -1;
+	shader->mask.base.texfmt = TEXCOORDFMT_NOT_PRESENT;
+	shader->mask.base.mode = 0;
+    }
+
+    if (shader->mask.type.fragment == FS_ZERO) {
+	shader->source.type.fragment = FS_ZERO;
+	shader->source.type.vertex = VS_CONSTANT;
+	shader->source.base.texfmt = TEXCOORDFMT_NOT_PRESENT;
+	shader->source.base.mode = 0;
+    }
+
+    if (shader->source.type.fragment == FS_ZERO) {
+	shader->mask.type.vertex = (i915_vertex_shader_t) -1;
+	shader->mask.type.fragment = (i915_fragment_shader_t) -1;
+	shader->mask.base.texfmt = TEXCOORDFMT_NOT_PRESENT;
+	shader->mask.base.mode = 0;
+    }
+}
+
+static void
+i915_shader_setup_dst (i915_shader_t *shader)
+{
+    union i915_shader_channel *channel;
+    i915_surface_t *s;
+
+    /* We need to manual blending if we have a clip surface and an unbounded op,
+     * or an extended blend mode.
+     */
+    if (shader->need_combine ||
+	(shader->op < CAIRO_OPERATOR_SATURATE &&
+	 (shader->clip.type.fragment == (i915_fragment_shader_t) -1 ||
+	  _cairo_operator_bounded_by_mask (shader->op))))
+    {
+	return;
+    }
+
+    shader->need_combine = TRUE;
+
+    channel = &shader->dst;
+    channel->type.pattern = PATTERN_TEXTURE;
+    channel->type.vertex = VS_TEXTURE_16;
+    channel->base.texfmt = TEXCOORDFMT_2D_16;
+    channel->base.content = shader->content;
+
+    channel->type.fragment = FS_TEXTURE;
+    channel->surface.pixel = NONE;
+
+    s = shader->target;
+    channel->base.bo = to_intel_bo (s->intel.drm.bo);
+    channel->base.n_samplers = 1;
+    channel->base.offset[0] = s->offset;
+    channel->base.map[0] = s->map0;
+    channel->base.map[1] = s->map1;
+
+    channel->base.sampler[0] =
+	(MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) |
+	i915_texture_filter (CAIRO_FILTER_NEAREST);
+    channel->base.sampler[1] =
+	SS3_NORMALIZED_COORDS |
+	i915_texture_extend (CAIRO_EXTEND_NONE);
+
+    cairo_matrix_init_scale (&shader->dst.base.matrix,
+			     1. / s->intel.drm.width,
+			     1. / s->intel.drm.height);
+
+    cairo_matrix_translate (&shader->dst.base.matrix,
+			    NEAREST_BIAS,
+			    NEAREST_BIAS);
+}
+
+static void
+i915_shader_combine_source (i915_shader_t *shader,
+			    i915_device_t *device)
+{
+    if (device->last_source_fragment == shader->source.type.fragment)
+	return;
+
+    if (device->last_source_fragment == FS_DIFFUSE) {
+	switch (shader->source.type.fragment) {
+	case FS_ONE:
+	case FS_PURE:
+	case FS_CONSTANT:
+	case FS_DIFFUSE:
+	    shader->source.type.fragment = FS_DIFFUSE;
+	    shader->source.base.mode = 0;
+	    break;
+	case FS_ZERO:
+	case FS_LINEAR:
+	case FS_RADIAL:
+	case FS_TEXTURE:
+	case FS_YUV:
+	case FS_SPANS:
+	default:
+	    break;
+	}
+    }
+
+    device->last_source_fragment = shader->source.type.fragment;
+}
+
+static inline float *
+i915_composite_vertex (float *v,
+		       const i915_shader_t *shader,
+		       double x, double y)
+{
+    double s, t;
+
+    /* Each vertex is:
+     *   2 vertex coordinates
+     *   [0-2] source texture coordinates
+     *   [0-2] mask texture coordinates
+     */
+
+    *v++ = x; *v++ = y;
+    switch (shader->source.type.vertex) {
+    case VS_CONSTANT:
+	break;
+    case VS_LINEAR:
+	*v++ = i915_shader_linear_texcoord (&shader->source.linear, x, y);
+	break;
+    case VS_RADIAL:
+    case VS_TEXTURE:
+	s = x, t = y;
+	cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+	*v++ = s; *v++ = t;
+	break;
+    case VS_TEXTURE_16:
+	s = x, t = y;
+	cairo_matrix_transform_point (&shader->source.base.matrix, &s, &t);
+	*v++ = texcoord_2d_16 (s, t);
+	break;
+    }
+    switch (shader->mask.type.vertex) {
+    case VS_CONSTANT:
+	break;
+    case VS_LINEAR:
+	*v++ = i915_shader_linear_texcoord (&shader->mask.linear, x, y);
+	break;
+    case VS_RADIAL:
+	s = x, t = y;
+	cairo_matrix_transform_point (&shader->mask.base.matrix, &s, &t);
+	*v++ = s; *v++ = t;
+	break;
+    case VS_TEXTURE:
+	s = x, t = y;
+	cairo_matrix_transform_point (&shader->mask.base.matrix, &s, &t);
+	*v++ = s; *v++ = t;
+	break;
+    case VS_TEXTURE_16:
+	s = x, t = y;
+	cairo_matrix_transform_point (&shader->mask.base.matrix, &s, &t);
+	*v++ = texcoord_2d_16 (s, t);
+	break;
+    }
+
+    return v;
+}
+
+static inline void
+i915_shader_add_rectangle_general (const i915_shader_t *shader,
+				   int x, int y,
+				   int w, int h)
+{
+    float *vertices;
+
+    vertices = i915_add_rectangle (shader->device);
+    vertices = i915_composite_vertex (vertices, shader, x + w, y + h);
+    vertices = i915_composite_vertex (vertices, shader, x, y + h);
+    vertices = i915_composite_vertex (vertices, shader, x, y);
+    /* XXX overflow! */
+}
+
+cairo_status_t
+i915_shader_commit (i915_shader_t *shader,
+		    i915_device_t *device)
+{
+    unsigned floats_per_vertex;
+    cairo_status_t status;
+
+    i915_shader_combine_source (shader, device);
+    i915_shader_combine_mask (shader);
+    i915_shader_setup_dst (shader);
+
+    if (i915_shader_needs_update (shader, device)) {
+	if (device->vertex_count) {
+	    status = i915_vbo_flush (device);
+	    if (unlikely (status))
+		return status;
+	}
+
+	status = i915_shader_check_aperture (shader, device);
+	if (unlikely (status))
+	    return status;
+
+	i915_set_shader_target (device, shader);
+	i915_set_shader_mode (device, shader);
+	i915_set_shader_samplers (device, shader);
+	i915_set_shader_constants (device, shader);
+	i915_set_shader_program (device, shader);
+    }
+
+    device->current_shader = shader;
+    shader->add_rectangle = i915_shader_add_rectangle_general;
+
+    floats_per_vertex = 2 + i915_shader_num_texcoords (shader);
+    if (device->floats_per_vertex == floats_per_vertex)
+	return CAIRO_STATUS_SUCCESS;
+
+    if (device->vertex_count) {
+	status = i915_vbo_flush (device);
+	if (unlikely (status))
+	    return status;
+    }
+
+    if (device->vbo) {
+	device->batch_base[device->vbo_max_index] |= device->vertex_index;
+	OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S (1) | 0);
+	device->vbo_max_index = device->batch.used;
+	OUT_DWORD ((floats_per_vertex << S1_VERTEX_WIDTH_SHIFT) |
+		   (floats_per_vertex << S1_VERTEX_PITCH_SHIFT));
+    }
+
+    device->floats_per_vertex = floats_per_vertex;
+    device->rectangle_size = floats_per_vertex * 3 * sizeof (float);
+    device->vertex_index =
+	(device->vbo_used + 4*floats_per_vertex - 1) / (4 * floats_per_vertex);
+    device->vbo_offset = 4 * device->vertex_index * floats_per_vertex;
+
+    return CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/drm/cairo-drm-i915-spans.c b/src/drm/cairo-drm-i915-spans.c
new file mode 100644
index 0000000..0f1617d
--- /dev/null
+++ b/src/drm/cairo-drm-i915-spans.c
@@ -0,0 +1,708 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-boxes-private.h"
+#include "cairo-error-private.h"
+#include "cairo-drm-i915-private.h"
+
+/* Operates in either immediate or retained mode.
+ * When given a clip region we record the sequence of vbo and then
+ * replay them for each clip rectangle, otherwise we simply emit
+ * the vbo straight into the command stream.
+ */
+
+typedef struct _i915_spans i915_spans_t;
+
+typedef float *
+(*i915_get_rectangle_func_t) (i915_spans_t *spans);
+
+typedef void
+(*i915_span_func_t) (i915_spans_t *spans,
+		     int x0, int x1, int y0, int y1,
+		     int alpha);
+
+struct _i915_spans {
+    cairo_span_renderer_t renderer;
+
+    i915_device_t *device;
+
+    int xmin, xmax;
+    cairo_bool_t is_bounded;
+    const cairo_rectangle_int_t *extents;
+
+    i915_get_rectangle_func_t get_rectangle;
+    i915_span_func_t span;
+    i915_shader_t shader;
+
+    cairo_region_t *clip_region;
+    cairo_bool_t need_clip_surface;
+
+    struct vbo {
+	struct vbo *next;
+	intel_bo_t *bo;
+	unsigned int count;
+    } head, *tail;
+
+    int rectangle_size;
+
+    unsigned int vbo_offset;
+    float *vbo_base;
+};
+
+static float *
+i915_emit_rectangle (i915_spans_t *spans)
+{
+    return i915_add_rectangle (spans->device);
+}
+
+static float *
+i915_accumulate_rectangle (i915_spans_t *spans)
+{
+    float *vertices;
+    uint32_t size;
+
+    size = spans->rectangle_size;
+    if (unlikely (spans->vbo_offset + size > I915_VBO_SIZE)) {
+	struct vbo *vbo;
+
+	intel_bo_unmap (spans->tail->bo);
+
+	vbo = malloc (sizeof (struct vbo));
+	if (unlikely (vbo == NULL)) {
+	    /* throw error! */
+	}
+
+	spans->tail->next = vbo;
+	spans->tail = vbo;
+
+	vbo->next = NULL;
+	vbo->bo = intel_bo_create (&spans->device->intel, I915_VBO_SIZE, FALSE);
+	vbo->count = 0;
+
+	spans->vbo_offset = 0;
+	spans->vbo_base = intel_bo_map (&spans->device->intel, vbo->bo);
+    }
+
+    vertices = spans->vbo_base + spans->vbo_offset;
+    spans->vbo_offset += size;
+    spans->tail->count += 3;
+
+    return vertices;
+}
+
+static void
+i915_span_constant (i915_spans_t *spans,
+		    int x0, int x1, int y0, int y1,
+		    int alpha)
+{
+    float *vertices;
+    float a = alpha / 255.;
+
+    vertices = spans->get_rectangle (spans);
+
+    *vertices++ = x1;
+    *vertices++ = y1;
+    *vertices++ = a;
+
+    *vertices++ = x0;
+    *vertices++ = y1;
+    *vertices++ = a;
+
+    *vertices++ = x0;
+    *vertices++ = y0;
+    *vertices++ = a;
+}
+
+static void
+i915_span_linear (i915_spans_t *spans,
+		  int x0, int x1, int y0, int y1,
+		  int alpha)
+{
+    float *vertices;
+    float a = alpha / 255.;
+    double s, t;
+
+    vertices = spans->get_rectangle (spans);
+
+    *vertices++ = x1;
+    *vertices++ = y1;
+    s = x0, t = y0;
+    *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
+    *vertices++ = a;
+
+    *vertices++ = x0;
+    *vertices++ = y1;
+    s = x1, t = y0;
+    *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
+    *vertices++ = a;
+
+    *vertices++ = x0;
+    *vertices++ = y0;
+    s = x1, t = y1;
+    *vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
+    *vertices++ = a;
+}
+
+static void
+i915_span_radial (i915_spans_t *spans,
+		  int x0, int x1, int y0, int y1,
+		  int alpha)
+{
+    float *vertices;
+    float a = alpha / 255.;
+    double s, t;
+
+    vertices = spans->get_rectangle (spans);
+
+    *vertices++ = x1;
+    *vertices++ = y1;
+    s = x0, t = y0;
+    cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+    *vertices++ = s; *vertices++ = t;
+    *vertices++ = a;
+
+    *vertices++ = x0;
+    *vertices++ = y1;
+    s = x1, t = y0;
+    cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+    *vertices++ = s; *vertices++ = t;
+    *vertices++ = a;
+
+    *vertices++ = x0;
+    *vertices++ = y0;
+    s = x1, t = y1;
+    cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+    *vertices++ = s; *vertices++ = t;
+    *vertices++ = a;
+}
+
+static void
+i915_span_texture (i915_spans_t *spans,
+		   int x0, int x1, int y0, int y1, int alpha)
+{
+    float *vertices;
+    float a = alpha / 255.;
+    double s, t;
+
+    vertices = spans->get_rectangle (spans);
+
+    *vertices++ = x1;
+    *vertices++ = y1;
+    s = x0, t = y0;
+    cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+    *vertices++ = s; *vertices++ = t;
+    *vertices++ = a;
+
+    *vertices++ = x0;
+    *vertices++ = y1;
+    s = x1, t = y0;
+    cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+    *vertices++ = s; *vertices++ = t;
+    *vertices++ = a;
+
+    *vertices++ = x0;
+    *vertices++ = y0;
+    s = x1, t = y1;
+    cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+    *vertices++ = s; *vertices++ = t;
+    *vertices++ = a;
+}
+
+static void
+i915_span_texture16 (i915_spans_t *spans,
+		     int x0, int x1, int y0, int y1, int alpha)
+{
+    float *vertices;
+    float a = alpha / 255.;
+    double s, t;
+
+    vertices = spans->get_rectangle (spans);
+
+    *vertices++ = x1;
+    *vertices++ = y1;
+    s = x0, t = y0;
+    cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+    *vertices++ = texcoord_2d_16 (s, t);
+    *vertices++ = a;
+
+    *vertices++ = x0;
+    *vertices++ = y1;
+    s = x1, t = y0;
+    cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+    *vertices++ = texcoord_2d_16 (s, t);
+    *vertices++ = a;
+
+    *vertices++ = x0;
+    *vertices++ = y0;
+    s = x1, t = y1;
+    cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+    *vertices++ = texcoord_2d_16 (s, t);
+    *vertices++ = a;
+}
+
+static void
+i915_span_generic (i915_spans_t *spans,
+		   int x0, int x1, int y0, int y1, int alpha)
+{
+    double s, t;
+    float *vertices;
+
+    /* Each vertex is:
+     *   2 vertex coordinates
+     *   [0-2] source texture coordinates
+     *   1 alpha value.
+     *   [0,2] clip mask coordinates
+     */
+
+    vertices = spans->get_rectangle (spans);
+
+    /* bottom right */
+    *vertices++ = x1; *vertices++ = y1;
+    s = x1, t = y1;
+    switch (spans->shader.source.type.vertex) {
+    case VS_CONSTANT:
+	break;
+    case VS_LINEAR:
+	*vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
+	break;
+    case VS_RADIAL:
+    case VS_TEXTURE:
+	cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+	*vertices++ = s; *vertices++ = t;
+	break;
+    case VS_TEXTURE_16:
+	cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+	*vertices++ = texcoord_2d_16 (s, t);
+	break;
+    }
+    *vertices++ = alpha;
+    if (spans->need_clip_surface) {
+	s = x1, t = y1;
+	cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+	*vertices++ = s; *vertices++ = t;
+    }
+
+    /* bottom left */
+    *vertices++ = x0; *vertices++ = y1;
+    s = x0, t = y1;
+    switch (spans->shader.source.type.vertex) {
+    case VS_CONSTANT:
+	break;
+    case VS_LINEAR:
+	*vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
+	break;
+    case VS_RADIAL:
+    case VS_TEXTURE:
+	cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+	*vertices++ = s; *vertices++ = t;
+	break;
+    case VS_TEXTURE_16:
+	cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+	*vertices++ = texcoord_2d_16 (s, t);
+	break;
+    }
+    *vertices++ = alpha;
+    if (spans->need_clip_surface) {
+	s = x0, t = y1;
+	cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+	*vertices++ = s; *vertices++ = t;
+    }
+
+    /* top left */
+    *vertices++ = x0; *vertices++ = y0;
+    s = x0, t = y0;
+    switch (spans->shader.source.type.vertex) {
+    case VS_CONSTANT:
+	break;
+    case VS_LINEAR:
+	*vertices++ = i915_shader_linear_texcoord (&spans->shader.source.linear, s, t);
+	break;
+    case VS_RADIAL:
+    case VS_TEXTURE:
+	cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+	*vertices++ = s; *vertices++ = t;
+	break;
+    case VS_TEXTURE_16:
+	cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+	*vertices++ = texcoord_2d_16 (s, t);
+	break;
+    }
+    *vertices++ = alpha;
+    if (spans->need_clip_surface) {
+	s = x0, t = y0;
+	cairo_matrix_transform_point (&spans->shader.source.base.matrix, &s, &t);
+	*vertices++ = s; *vertices++ = t;
+    }
+}
+
+static cairo_status_t
+i915_bounded_spans_mono (void *abstract_renderer,
+			 int y, int height,
+			 const cairo_half_open_span_t *half,
+			 unsigned num_spans)
+{
+    i915_spans_t *spans = abstract_renderer;
+
+    if (num_spans == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    do {
+	if (half[0].coverage >= 128) {
+	    spans->span (spans,
+			 half[0].x, half[1].x,
+			 y, y + height,
+			 255);
+	}
+	half++;
+    } while (--num_spans > 1);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_bounded_spans (void *abstract_renderer,
+		    int y, int height,
+		    const cairo_half_open_span_t *half,
+		    unsigned num_spans)
+{
+    i915_spans_t *spans = abstract_renderer;
+
+    if (num_spans == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    do {
+	if (half[0].coverage) {
+	    spans->span (spans,
+			 half[0].x, half[1].x,
+			 y, y + height,
+			 half[0].coverage);
+	}
+	half++;
+    } while (--num_spans > 1);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_unbounded_spans (void *abstract_renderer,
+		      int y, int height,
+		      const cairo_half_open_span_t *half,
+		      unsigned num_spans)
+{
+    i915_spans_t *spans = abstract_renderer;
+
+    if (num_spans == 0) {
+	spans->span (spans,
+		     spans->xmin, spans->xmax,
+		     y, y + height,
+		     0);
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    if (half[0].x != spans->xmin) {
+	spans->span (spans,
+		     spans->xmin, half[0].x,
+		     y, y + height,
+		     0);
+    }
+
+    do {
+	spans->span (spans,
+		     half[0].x, half[1].x,
+		     y, y + height,
+		     half[0].coverage);
+	half++;
+    } while (--num_spans > 1);
+
+    if (half[0].x != spans->xmax) {
+	spans->span (spans,
+		     half[0].x, spans->xmax,
+		     y, y + height,
+		     0);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_unbounded_spans_mono (void *abstract_renderer,
+			   int y, int height,
+			   const cairo_half_open_span_t *half,
+			   unsigned num_spans)
+{
+    i915_spans_t *spans = abstract_renderer;
+
+    if (num_spans == 0) {
+	spans->span (spans,
+		     spans->xmin, spans->xmax,
+		     y, y + height,
+		     0);
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    if (half[0].x != spans->xmin) {
+	spans->span (spans,
+		     spans->xmin, half[0].x,
+		     y, y + height,
+		     0);
+    }
+
+    do {
+	int alpha = 0;
+	if (half[0].coverage >= 128)
+	    alpha = 255;
+	spans->span (spans,
+		     half[0].x, half[1].x,
+		     y, y + height,
+		     alpha);
+	half++;
+    } while (--num_spans > 1);
+
+    if (half[0].x != spans->xmax) {
+	spans->span (spans,
+		     half[0].x, spans->xmax,
+		     y, y + height,
+		     0);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_spans_init (i915_spans_t *spans,
+		 i915_surface_t *dst,
+		 cairo_operator_t op,
+		 const cairo_pattern_t *pattern,
+		 cairo_antialias_t antialias,
+		 cairo_clip_t *clip,
+		 const cairo_composite_rectangles_t *extents)
+{
+    cairo_status_t status;
+
+    spans->device = (i915_device_t *) dst->intel.drm.base.device;
+
+    spans->is_bounded = extents->is_bounded;
+    if (extents->is_bounded) {
+	if (antialias == CAIRO_ANTIALIAS_NONE)
+	    spans->renderer.render_rows = i915_bounded_spans_mono;
+	else
+	    spans->renderer.render_rows = i915_bounded_spans;
+
+	spans->extents = &extents->bounded;
+    } else {
+	if (antialias == CAIRO_ANTIALIAS_NONE)
+	    spans->renderer.render_rows = i915_unbounded_spans_mono;
+	else
+	    spans->renderer.render_rows = i915_unbounded_spans;
+
+	spans->extents = &extents->unbounded;
+    }
+    spans->xmin = spans->extents->x;
+    spans->xmax = spans->extents->x + spans->extents->width;
+
+    spans->clip_region = NULL;
+    spans->need_clip_surface = FALSE;
+    if (clip != NULL) {
+	cairo_region_t *clip_region = NULL;
+
+	status = _cairo_clip_get_region (clip, &clip_region);
+	assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+	if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+	    clip_region = NULL;
+
+	spans->clip_region = clip_region;
+	spans->need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    spans->head.next = NULL;
+    spans->head.bo = NULL;
+    spans->head.count = 0;
+    spans->tail = &spans->head;
+
+    if (spans->clip_region == NULL) {
+	spans->get_rectangle = i915_emit_rectangle;
+    } else {
+	assert (! extents->is_bounded);
+	spans->get_rectangle = i915_accumulate_rectangle;
+	spans->head.bo = intel_bo_create (&spans->device->intel,
+					  I915_VBO_SIZE, FALSE);
+	if (unlikely (spans->head.bo == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+	spans->vbo_base = intel_bo_map (&spans->device->intel, spans->head.bo);
+    }
+    spans->vbo_offset = 0;
+
+    i915_shader_init (&spans->shader, dst, op);
+    if (spans->need_clip_surface)
+	i915_shader_set_clip (&spans->shader, clip);
+
+    status = i915_shader_acquire_pattern (&spans->shader, &spans->shader.source,
+					  pattern, &extents->bounded);
+    if (unlikely (status))
+	return status;
+
+    if (! spans->need_clip_surface) {
+	switch (spans->shader.source.type.vertex) {
+	case VS_CONSTANT:
+	    spans->span = i915_span_constant;
+	    break;
+	case VS_LINEAR:
+	    spans->span = i915_span_linear;
+	    break;
+	case VS_RADIAL:
+	    spans->span = i915_span_radial;
+	    break;
+	case VS_TEXTURE:
+	    spans->span = i915_span_texture;
+	    break;
+	case VS_TEXTURE_16:
+	    spans->span = i915_span_texture16;
+	    break;
+	default:
+	    spans->span = i915_span_generic;
+	    break;
+	}
+    } else {
+	spans->span = i915_span_generic;
+    }
+
+    spans->rectangle_size = 3 * (2 + i915_shader_num_texcoords (&spans->shader));
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static void
+i915_spans_fini (i915_spans_t *spans)
+{
+    i915_shader_fini (&spans->shader);
+
+    if (spans->head.bo != NULL) {
+	struct vbo *vbo, *next;
+
+	intel_bo_destroy (&spans->device->intel, spans->head.bo);
+	for (vbo = spans->head.next; vbo != NULL; vbo = next) {
+	    next = vbo->next;
+	    intel_bo_destroy (&spans->device->intel, vbo->bo);
+	    free (vbo);
+	}
+    }
+}
+
+cairo_status_t
+i915_clip_and_composite_spans (i915_surface_t		*dst,
+			       cairo_operator_t		 op,
+			       const cairo_pattern_t	*pattern,
+			       cairo_antialias_t	 antialias,
+			       i915_spans_func_t	 draw_func,
+			       void			*draw_closure,
+			       const cairo_composite_rectangles_t*extents,
+			       cairo_clip_t		*clip)
+{
+    i915_spans_t spans;
+    i915_device_t *device;
+    cairo_status_t status;
+    struct vbo *vbo;
+
+    if (op == CAIRO_OPERATOR_CLEAR) {
+	pattern = &_cairo_pattern_white.base;
+	op = CAIRO_OPERATOR_DEST_OUT;
+    }
+
+    status = i915_spans_init (&spans, dst, op, pattern, antialias, clip, extents);
+    if (unlikely (status))
+	return status;
+
+    spans.shader.mask.base.texfmt = TEXCOORDFMT_1D;
+    spans.shader.mask.base.content = CAIRO_CONTENT_ALPHA;
+    spans.shader.mask.type.fragment = FS_SPANS;
+
+    status = cairo_device_acquire (dst->intel.drm.base.device);
+    if (unlikely (status))
+	goto CLEANUP_SPANS;
+
+    device = i915_device (dst);
+    status = i915_shader_commit (&spans.shader, device);
+    if (unlikely (status))
+	goto CLEANUP_DEVICE;
+
+    status = draw_func (draw_closure, &spans.renderer, spans.extents);
+    if (spans.clip_region != NULL && status == CAIRO_STATUS_SUCCESS) {
+	intel_bo_unmap (spans.tail->bo);
+
+	i915_vbo_finish (device);
+
+	OUT_DWORD (_3DSTATE_SCISSOR_ENABLE_CMD | ENABLE_SCISSOR_RECT);
+	for (vbo = &spans.head; vbo != NULL; vbo = vbo->next) {
+	    int i, num_rectangles;
+
+	    /* XXX require_space & batch_flush */
+
+	    OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S (0) | I1_LOAD_S (1) | 1);
+	    i915_batch_emit_reloc (device, vbo->bo, 0,
+				   I915_GEM_DOMAIN_VERTEX, 0);
+	    OUT_DWORD ((device->floats_per_vertex << S1_VERTEX_WIDTH_SHIFT) |
+		       (device->floats_per_vertex << S1_VERTEX_PITCH_SHIFT) |
+		       vbo->count);
+
+	    num_rectangles = cairo_region_num_rectangles (spans.clip_region);
+	    for (i = 0; i < num_rectangles; i++) {
+		cairo_rectangle_int_t rect;
+
+		cairo_region_get_rectangle (spans.clip_region, i, &rect);
+
+		OUT_DWORD (_3DSTATE_SCISSOR_RECT_0_CMD);
+		OUT_DWORD (SCISSOR_RECT_0_XMIN (rect.x) |
+			   SCISSOR_RECT_0_YMIN (rect.y));
+		OUT_DWORD (SCISSOR_RECT_0_XMAX (rect.x + rect.width) |
+			   SCISSOR_RECT_0_YMAX (rect.y + rect.height));
+
+		OUT_DWORD (PRIM3D_RECTLIST | PRIM3D_INDIRECT_SEQUENTIAL | vbo->count);
+		OUT_DWORD (0);
+	    }
+	}
+	OUT_DWORD (_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT);
+    }
+
+CLEANUP_DEVICE:
+    cairo_device_release (dst->intel.drm.base.device);
+CLEANUP_SPANS:
+    i915_spans_fini (&spans);
+
+    return status;
+}
diff --git a/src/drm/cairo-drm-i915-surface.c b/src/drm/cairo-drm-i915-surface.c
new file mode 100644
index 0000000..2079ac9
--- /dev/null
+++ b/src/drm/cairo-drm-i915-surface.c
@@ -0,0 +1,1996 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Chris Wilson
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+ *
+ * **************************************************************************
+ * This work was initially based upon xf86-video-intel/src/i915_render.c:
+ * Copyright © 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Wang Zhenyu <zhenyu.z.wang at intel.com>
+ *    Eric Anholt <eric at anholt.net>
+ *
+ * **************************************************************************
+ * and also upon libdrm/intel/intel_bufmgr_gem.c:
+ * Copyright © 2007 Red Hat Inc.
+ * Copyright © 2007 Intel Corporation
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ *          Keith Whitwell <keithw-at-tungstengraphics-dot-com>
+ *          Eric Anholt <eric at anholt.net>
+ *          Dave Airlie <airlied at linux.ie>
+ */
+
+/* XXX
+ *
+ * - Per thread context? Would it actually avoid many locks?
+ *
+ */
+
+#include "cairoint.h"
+
+#include "cairo-drm-private.h"
+#include "cairo-drm-ioctl-private.h"
+#include "cairo-drm-intel-private.h"
+#include "cairo-drm-intel-command-private.h"
+#include "cairo-drm-intel-ioctl-private.h"
+#include "cairo-drm-i915-private.h"
+
+#include "cairo-boxes-private.h"
+#include "cairo-cache-private.h"
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-error-private.h"
+#include "cairo-freelist-private.h"
+#include "cairo-list-private.h"
+#include "cairo-path-fixed-private.h"
+#include "cairo-region-private.h"
+#include "cairo-surface-offset-private.h"
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+static cairo_int_status_t
+i915_surface_fill (void			*abstract_dst,
+		   cairo_operator_t	 op,
+		   const cairo_pattern_t*source,
+		   cairo_path_fixed_t	*path,
+		   cairo_fill_rule_t	 fill_rule,
+		   double		 tolerance,
+		   cairo_antialias_t	 antialias,
+		   cairo_clip_t		*clip);
+
+static const uint32_t i915_batch_setup[] = {
+    /* Disable line anti-aliasing */
+    _3DSTATE_AA_CMD,
+
+    /* Disable independent alpha blend */
+    _3DSTATE_INDEPENDENT_ALPHA_BLEND_CMD |
+	IAB_MODIFY_ENABLE |
+	IAB_MODIFY_FUNC | (BLENDFUNC_ADD << IAB_FUNC_SHIFT) |
+	IAB_MODIFY_SRC_FACTOR | (BLENDFACT_ONE << IAB_SRC_FACTOR_SHIFT) |
+	IAB_MODIFY_DST_FACTOR | (BLENDFACT_ZERO << IAB_DST_FACTOR_SHIFT),
+
+    /* Disable texture crossbar */
+    _3DSTATE_COORD_SET_BINDINGS |
+	CSB_TCB (0, 0) |
+	CSB_TCB (1, 1) |
+	CSB_TCB (2, 2) |
+	CSB_TCB (3, 3) |
+	CSB_TCB (4, 4) |
+	CSB_TCB (5, 5) |
+	CSB_TCB (6, 6) |
+	CSB_TCB (7, 7),
+
+    _3DSTATE_RASTER_RULES_CMD |
+	ENABLE_POINT_RASTER_RULE | OGL_POINT_RASTER_RULE |
+	ENABLE_LINE_STRIP_PROVOKE_VRTX | LINE_STRIP_PROVOKE_VRTX (1) |
+	ENABLE_TRI_FAN_PROVOKE_VRTX | TRI_FAN_PROVOKE_VRTX (2) |
+	ENABLE_TEXKILL_3D_4D | TEXKILL_4D,
+
+    _3DSTATE_MODES_4_CMD | ENABLE_LOGIC_OP_FUNC | LOGIC_OP_FUNC (LOGICOP_COPY),
+
+    _3DSTATE_LOAD_STATE_IMMEDIATE_1 |
+	I1_LOAD_S (2) |
+	I1_LOAD_S (3) |
+	I1_LOAD_S (4) |
+	I1_LOAD_S (5) |
+	I1_LOAD_S (6) |
+	4,
+    S2_TEXCOORD_NONE,
+    0, /* Disable texture coordinate wrap-shortest */
+    (1 << S4_POINT_WIDTH_SHIFT) |
+	S4_LINE_WIDTH_ONE |
+	S4_FLATSHADE_ALPHA |
+	S4_FLATSHADE_FOG |
+	S4_FLATSHADE_SPECULAR |
+	S4_FLATSHADE_COLOR |
+	S4_CULLMODE_NONE |
+	S4_VFMT_XY,
+    0, /* Disable stencil buffer */
+    S6_COLOR_WRITE_ENABLE,
+
+    _3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT,
+    _3DSTATE_DEPTH_SUBRECT_DISABLE,
+
+    /* disable indirect state */
+    _3DSTATE_LOAD_INDIRECT,
+    0,
+
+    _3DSTATE_STIPPLE,
+    0,
+
+    _3DSTATE_BACKFACE_STENCIL_OPS | BFO_ENABLE_STENCIL_TWO_SIDE,
+};
+
+static const cairo_surface_backend_t i915_surface_backend;
+
+#define NEAREST_BIAS (-.375)
+
+static cairo_surface_t *
+i915_surface_create_from_cacheable_image (cairo_drm_device_t *base_dev,
+	                                   cairo_surface_t *source);
+
+static cairo_status_t
+i915_bo_exec (i915_device_t *device, intel_bo_t *bo, uint32_t offset)
+{
+    struct drm_i915_gem_execbuffer2 execbuf;
+    int ret, cnt, i;
+
+    /* Add the batch buffer to the validation list.  */
+    cnt = device->batch.exec_count;
+    if (cnt > 0 && bo->base.handle == device->batch.exec[cnt-1].handle)
+	i = cnt - 1;
+    else
+	i = device->batch.exec_count++;
+    device->batch.exec[i].handle = bo->base.handle;
+    device->batch.exec[i].relocation_count = device->batch.reloc_count;
+    device->batch.exec[i].relocs_ptr = (uintptr_t) device->batch.reloc;
+    device->batch.exec[i].alignment = 0;
+    device->batch.exec[i].offset = 0;
+    device->batch.exec[i].flags = 0;
+    device->batch.exec[i].rsvd1 = 0;
+    device->batch.exec[i].rsvd2 = 0;
+
+    execbuf.buffers_ptr = (uintptr_t) device->batch.exec;
+    execbuf.buffer_count = device->batch.exec_count;
+    execbuf.batch_start_offset = offset;
+    execbuf.batch_len = (device->batch.used << 2) + sizeof (device->batch_header);
+    execbuf.DR1 = 0;
+    execbuf.DR4 = 0;
+    execbuf.num_cliprects = 0;
+    execbuf.cliprects_ptr = 0;
+    execbuf.flags = 0;
+    execbuf.rsvd1 = 0;
+    execbuf.rsvd2 = 0;
+
+    if (I915_VERBOSE && device->debug & I915_DEBUG_EXEC) {
+	int n;
+	fprintf (stderr,
+		"Executing batch: %d+%d bytes, %d buffers, %d relocations\n",
+		execbuf.batch_start_offset,
+		execbuf.batch_len,
+		device->batch.exec_count,
+		device->batch.reloc_count);
+	for (n = 0; n < device->batch.exec_count; n++) {
+	    fprintf (stderr, "    exec[%d] = %d\n", n,
+		     device->batch.exec[n].handle);
+	}
+	for (n = 0; n < device->batch.reloc_count; n++) {
+	    fprintf (stderr, "    reloc[%d] = %d @ %qx\n", n,
+		     device->batch.reloc[n].target_handle,
+		     (unsigned long long) device->batch.reloc[n].offset);
+	}
+    }
+
+    do {
+	ret = ioctl (device->intel.base.fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
+    } while (ret != 0 && errno == EINTR);
+
+    if (I915_VERBOSE && ret) {
+	int n;
+
+	fprintf (stderr, "Batch submission failed: %d\n", errno);
+	fprintf (stderr, "   relocation entries: %d/%d\n",
+		 device->batch.reloc_count, I915_MAX_RELOCS);
+	fprintf (stderr, "   gtt size: %zd/%zd\n",
+		 device->batch.gtt_size, device->intel.gtt_avail_size);
+
+	fprintf (stderr, "   buffers:\n");
+	for (n = 0; n < cnt; n++) {
+	    fprintf (stderr, "     exec[%d] = %d\n",
+		     n, device->batch.target_bo[n]->base.size);
+	}
+
+	intel_dump_batchbuffer (device->batch_header,
+				device->batch.used,
+				device->intel.base.chip_id);
+    }
+
+    VG (VALGRIND_MAKE_MEM_DEFINED (device->batch.exec, sizeof (device->batch.exec[0]) * i));
+
+    bo->offset = device->batch.exec[i].offset;
+    while (cnt--) {
+	device->batch.target_bo[cnt]->offset = device->batch.exec[cnt].offset;
+	device->batch.target_bo[cnt]->exec = NULL;
+	device->batch.target_bo[cnt]->batch_read_domains = 0;
+	device->batch.target_bo[cnt]->batch_write_domain = 0;
+	intel_bo_destroy (&device->intel, device->batch.target_bo[cnt]);
+    }
+
+    device->batch.exec_count = 0;
+    device->batch.reloc_count = 0;
+
+    device->batch.gtt_size = I915_BATCH_SIZE;
+
+    return ret == 0 ? CAIRO_STATUS_SUCCESS : _cairo_error (CAIRO_STATUS_NO_MEMORY);
+}
+
+void
+i915_batch_add_reloc (i915_device_t *device,
+		      uint32_t pos,
+		      intel_bo_t *bo,
+		      uint32_t offset,
+		      uint32_t read_domains,
+		      uint32_t write_domain)
+{
+    int index;
+
+    if (bo->exec == NULL) {
+	device->batch.gtt_size += bo->base.size;
+
+	index = device->batch.exec_count++;
+	device->batch.exec[index].handle = bo->base.handle;
+	device->batch.exec[index].relocation_count = 0;
+	device->batch.exec[index].relocs_ptr = 0;
+	device->batch.exec[index].alignment = 0;
+	device->batch.exec[index].offset = 0;
+	device->batch.exec[index].flags = 0;
+	device->batch.exec[index].rsvd1 = 0;
+	device->batch.exec[index].rsvd2 = 0;
+
+	device->batch.target_bo[index] = intel_bo_reference (bo);
+
+	bo->exec = &device->batch.exec[index];
+    }
+
+    index = device->batch.reloc_count++;
+    device->batch.reloc[index].offset = (pos << 2) + sizeof (device->batch_header);
+    device->batch.reloc[index].delta = offset;
+    device->batch.reloc[index].target_handle = bo->base.handle;
+    device->batch.reloc[index].read_domains = read_domains;
+    device->batch.reloc[index].write_domain = write_domain;
+    device->batch.reloc[index].presumed_offset = bo->offset;
+
+    assert (write_domain == 0 || bo->batch_write_domain == 0 || bo->batch_write_domain == write_domain);
+    bo->batch_read_domains |= read_domains;
+    bo->batch_write_domain |= write_domain;
+}
+
+void
+i915_vbo_finish (i915_device_t *device)
+{
+    if (device->vbo_used == 0)
+	return;
+
+    if (device->vbo || i915_batch_space (device) < (int32_t) device->vbo_used) {
+	intel_bo_t *vbo;
+
+	if (device->vertex_count) {
+	    if (device->vbo == 0) {
+		/* XXX unchecked, must fit! */
+		/* XXX batch_flush and i915_shader_commit (device, device->shader)); */
+		assert (i915_check_aperture_size (device, 1,
+			                          (device->vbo_used + 4095) & -4096));
+		OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
+			   I1_LOAD_S (0) |
+			   I1_LOAD_S (1) |
+			   1);
+		device->vbo = device->batch.used++;
+		device->vbo_max_index = device->batch.used;
+		OUT_DWORD ((device->floats_per_vertex << S1_VERTEX_WIDTH_SHIFT) |
+			   (device->floats_per_vertex << S1_VERTEX_PITCH_SHIFT));
+	    }
+
+	    OUT_DWORD (PRIM3D_RECTLIST |
+		       PRIM3D_INDIRECT_SEQUENTIAL |
+		       device->vertex_count);
+	    OUT_DWORD (device->vertex_index);
+	}
+
+	if (I915_VERBOSE && device->debug & I915_DEBUG_BUFFER) {
+	    fprintf (stderr, "Creating vertex buffer: %d bytes\n",
+		     device->vbo_used);
+	}
+
+	if (device->last_vbo != NULL)
+	    intel_bo_destroy (&device->intel, device->last_vbo);
+
+	device->batch_base[device->vbo_max_index] |= device->vertex_index + device->vertex_count;
+
+	/* will include a few bytes of inter-array padding */
+	vbo = intel_bo_create (&device->intel, device->vbo_used, FALSE);
+	i915_batch_fill_reloc (device, device->vbo,
+			       vbo, 0,
+			       I915_GEM_DOMAIN_VERTEX, 0);
+	intel_bo_write (&device->intel, vbo, 0, device->vbo_used, device->vbo_base);
+	device->last_vbo = vbo;
+	device->last_vbo_offset = (device->vbo_used+7)&-8;
+	device->last_vbo_space = vbo->base.size - device->last_vbo_offset;
+
+	device->vbo = 0;
+    }
+    else
+    {
+	/* Only a single rectlist in this batch, and no active vertex buffer. */
+	OUT_DWORD (PRIM3D_RECTLIST | (device->vbo_used / 4 - 1));
+
+	memcpy (BATCH_PTR (device), device->vbo_base, device->vbo_used);
+	device->batch.used += device->vbo_used >> 2;
+    }
+
+    device->vbo_used = device->vbo_offset = 0;
+    device->vertex_index = device->vertex_count = 0;
+}
+
+/* XXX improve state tracker/difference and flush state on vertex emission */
+static void
+i915_device_reset (i915_device_t *device)
+{
+    if (device->current_source != NULL)
+	*device->current_source = 0;
+    if (device->current_mask != NULL)
+	*device->current_mask = 0;
+    if (device->current_clip != NULL)
+	*device->current_clip = 0;
+
+    device->current_target = NULL;
+    device->current_size = 0;
+    device->current_source = NULL;
+    device->current_mask = NULL;
+    device->current_clip = NULL;
+    device->current_shader = 0;
+    device->current_texcoords = ~0;
+    device->current_blend = 0;
+    device->current_n_constants = 0;
+    device->current_n_samplers = 0;
+    device->current_colorbuf = 0;
+    device->current_diffuse = 0;
+    device->current_program = ~0;
+
+    device->last_source_fragment = ~0;
+
+    device->floats_per_vertex = 0;
+}
+
+static void
+i915_batch_cleanup (i915_device_t *device)
+{
+    int i;
+
+    for (i = 0; i < device->batch.exec_count; i++)
+	intel_bo_destroy (&device->intel, device->batch.target_bo[i]);
+
+    device->batch.exec_count = 0;
+    device->batch.reloc_count = 0;
+}
+
+cairo_status_t
+i915_batch_flush (i915_device_t *device)
+{
+    intel_bo_t *batch;
+    cairo_status_t status;
+    uint32_t length, offset;
+    int n;
+
+    i915_vbo_finish (device);
+
+    if (device->batch.used == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    i915_batch_emit_dword (device, MI_BATCH_BUFFER_END);
+    if ((device->batch.used & 1) != (sizeof (device->batch_header) & 4))
+	i915_batch_emit_dword (device, MI_NOOP);
+
+    length = (device->batch.used << 2) + sizeof (device->batch_header);
+
+    if (I915_VERBOSE && device->debug & I915_DEBUG_BATCH)
+	intel_dump_batchbuffer (device->batch_header, length, device->intel.base.chip_id);
+
+    intel_glyph_cache_unmap(&device->intel);
+
+    /* NB: it is faster to copy the data then map/unmap the batch,
+     * presumably because we frequently only use a small part of the buffer.
+     */
+    batch = NULL;
+    if (device->last_vbo) {
+	if (length <= device->last_vbo_space) {
+	    if (I915_VERBOSE && device->debug & I915_DEBUG_BATCH) {
+		fprintf (stderr, "Packing batch buffer into last vbo: %d+%d bytes\n", length, device->last_vbo_offset);
+	    }
+	    batch = device->last_vbo;
+	    offset = device->last_vbo_offset;
+
+	    /* fixup the relocations */
+	    for (n = 0; n < device->batch.reloc_count; n++)
+		device->batch.reloc[n].offset += offset;
+	} else
+	    intel_bo_destroy (&device->intel, device->last_vbo);
+	device->last_vbo = NULL;
+    }
+    if (batch == NULL) {
+	if (I915_VERBOSE && device->debug & I915_DEBUG_BUFFER) {
+	    fprintf (stderr, "Creating batch buffer: %d bytes\n", length);
+	}
+	batch = intel_bo_create (&device->intel, length, FALSE);
+	if (unlikely (batch == NULL)) {
+	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    i915_batch_cleanup (device);
+	    goto BAIL;
+	}
+
+	offset = 0;
+    }
+    intel_bo_write (&device->intel, batch, offset, length, device->batch_header);
+    status = i915_bo_exec (device, batch, offset);
+
+    if (device->debug & I915_DEBUG_SYNC && status == CAIRO_STATUS_SUCCESS)
+	intel_bo_wait (&device->intel, batch);
+
+    intel_bo_destroy (&device->intel, batch);
+
+BAIL:
+    device->batch.used = 0;
+
+    intel_glyph_cache_unpin (&device->intel);
+    intel_snapshot_cache_thaw (&device->intel);
+
+    i915_device_reset (device);
+
+    return status;
+}
+
+cairo_status_t
+i915_vbo_flush (i915_device_t *device)
+{
+    assert (device->vertex_count);
+
+    if (device->vbo == 0) {
+	assert (device->floats_per_vertex);
+
+	if (i915_batch_space (device) < 9 ||
+	    ! i915_check_aperture_size (device, 1, I915_VBO_SIZE))
+	{
+	    return i915_batch_flush (device);
+	}
+
+	OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
+		   I1_LOAD_S (0) |
+		   I1_LOAD_S (1) |
+		   1);
+	device->vbo = device->batch.used++;
+	device->vbo_max_index = device->batch.used;
+	OUT_DWORD ((device->floats_per_vertex << S1_VERTEX_WIDTH_SHIFT) |
+		   (device->floats_per_vertex << S1_VERTEX_PITCH_SHIFT));
+    }
+
+    OUT_DWORD (PRIM3D_RECTLIST |
+	       PRIM3D_INDIRECT_SEQUENTIAL |
+	       device->vertex_count);
+    OUT_DWORD (device->vertex_index);
+
+    device->vertex_index += device->vertex_count;
+    device->vertex_count = 0;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+#if 0
+static float *
+i915_add_rectangles (i915_device_t *device, int num_rects, int *count)
+{
+    float *vertices;
+    uint32_t size;
+    int cnt;
+
+    assert (device->floats_per_vertex);
+
+    size = device->rectangle_size;
+    if (unlikely (device->vbo_offset + size > I915_VBO_SIZE))
+	i915_vbo_finish (device);
+
+    vertices = (float *) (device->vbo_base + device->vbo_offset);
+    cnt = (I915_VBO_SIZE - device->vbo_offset) / size;
+    if (cnt > num_rects)
+	cnt = num_rects;
+    device->vbo_used = device->vbo_offset += size * cnt;
+    device->vertex_count += 3 * cnt;
+    *count = cnt;
+    return vertices;
+}
+#endif
+
+static cairo_status_t
+i915_surface_finish (void *abstract_surface)
+{
+    i915_surface_t *surface = abstract_surface;
+    i915_device_t *device = i915_device (surface);
+
+    if (surface->stencil != NULL)
+	intel_bo_destroy (&device->intel, surface->stencil);
+
+    if (surface->is_current_texture) {
+	if (surface->is_current_texture & CURRENT_SOURCE)
+	    device->current_source = NULL;
+	if (surface->is_current_texture & CURRENT_MASK)
+	    device->current_mask = NULL;
+	if (surface->is_current_texture & CURRENT_CLIP)
+	    device->current_clip = NULL;
+	device->current_n_samplers = 0;
+    }
+
+    if (surface == device->current_target)
+	device->current_target = NULL;
+
+    if (surface->cache != NULL) {
+	i915_image_private_t *node = surface->cache;
+	intel_buffer_cache_t *cache = node->container;
+
+	if (--cache->ref_count == 0) {
+	    intel_bo_destroy (&device->intel, cache->buffer.bo);
+	    _cairo_rtree_fini (&cache->rtree);
+	    cairo_list_del (&cache->link);
+	    free (cache);
+	} else {
+	    node->node.state = CAIRO_RTREE_NODE_AVAILABLE;
+	    cairo_list_move (&node->node.link, &cache->rtree.available);
+	    _cairo_rtree_node_collapse (&cache->rtree, node->node.parent);
+	}
+    }
+
+    return _cairo_drm_surface_finish (&surface->intel.drm);
+}
+
+static cairo_status_t
+i915_surface_batch_flush (i915_surface_t *surface)
+{
+    cairo_status_t status;
+    intel_bo_t *bo;
+
+    assert (surface->intel.drm.fallback == NULL);
+
+    bo = to_intel_bo (surface->intel.drm.bo);
+    if (bo == NULL || bo->batch_write_domain == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    status = cairo_device_acquire (surface->intel.drm.base.device);
+    if (unlikely (status))
+	return status;
+
+    status = i915_batch_flush (i915_device (surface));
+    cairo_device_release (surface->intel.drm.base.device);
+
+    return status;
+}
+
+static cairo_status_t
+i915_surface_flush (void *abstract_surface)
+{
+    i915_surface_t *surface = abstract_surface;
+
+    if (surface->intel.drm.fallback == NULL) {
+	if (surface->intel.drm.base.finished) {
+	    /* Forgo flushing on finish as the user cannot access the surface directly. */
+	    return CAIRO_STATUS_SUCCESS;
+	}
+
+	return i915_surface_batch_flush (surface);
+    }
+
+    return intel_surface_flush (abstract_surface);
+}
+
+/* rasterisation */
+
+static cairo_status_t
+_composite_boxes_spans (void			*closure,
+			cairo_span_renderer_t	*renderer,
+			const cairo_rectangle_int_t	*extents)
+{
+    cairo_boxes_t *boxes = closure;
+    cairo_rectangular_scan_converter_t converter;
+    struct _cairo_boxes_chunk *chunk;
+    cairo_status_t status;
+    int i;
+
+    _cairo_rectangular_scan_converter_init (&converter, extents);
+    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	cairo_box_t *box = chunk->base;
+	for (i = 0; i < chunk->count; i++) {
+	    status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
+	    if (unlikely (status))
+		goto CLEANUP;
+	}
+    }
+
+    status = converter.base.generate (&converter.base, renderer);
+
+  CLEANUP:
+    converter.base.destroy (&converter.base);
+    return status;
+}
+
+cairo_status_t
+i915_fixup_unbounded (i915_surface_t *dst,
+		      const cairo_composite_rectangles_t *extents,
+		      cairo_clip_t *clip)
+{
+    i915_shader_t shader;
+    cairo_status_t status;
+
+    i915_shader_init (&shader, dst, CAIRO_OPERATOR_CLEAR);
+
+    if (clip != NULL) {
+	cairo_region_t *clip_region = NULL;
+
+	status = _cairo_clip_get_region (clip, &clip_region);
+	assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+	assert (clip_region == NULL);
+
+	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+	    i915_shader_set_clip (&shader, clip);
+    } else {
+	if (extents->bounded.width == extents->unbounded.width &&
+	    extents->bounded.height == extents->unbounded.height)
+	{
+	    return CAIRO_STATUS_SUCCESS;
+	}
+    }
+
+    status = i915_shader_commit (&shader,
+				 (i915_device_t *) dst->intel.drm.base.device);
+    if (unlikely (status))
+	return status;
+
+    /* top */
+    if (extents->bounded.y != extents->unbounded.y) {
+	shader.add_rectangle (&shader,
+			      extents->unbounded.x,
+			      extents->unbounded.y,
+			      extents->unbounded.width,
+			      extents->bounded.y - extents->unbounded.y);
+    }
+
+    /* left */
+    if (extents->bounded.x != extents->unbounded.x) {
+	shader.add_rectangle (&shader,
+			      extents->unbounded.x,
+			      extents->bounded.y,
+			      extents->bounded.x - extents->unbounded.x,
+			      extents->bounded.height);
+    }
+
+    /* right */
+    if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
+	shader.add_rectangle (&shader,
+			      extents->bounded.x + extents->bounded.width,
+			      extents->bounded.y,
+			      extents->unbounded.x + extents->unbounded.width - (extents->bounded.x + extents->bounded.width),
+			      extents->bounded.height);
+    }
+
+    /* bottom */
+    if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
+	shader.add_rectangle (&shader,
+			      extents->unbounded.x,
+			      extents->bounded.y + extents->bounded.height,
+			      extents->unbounded.width,
+			      extents->unbounded.y + extents->unbounded.height - (extents->bounded.y + extents->bounded.height));
+    }
+
+    i915_shader_fini (&shader);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_fixup_unbounded_boxes (i915_surface_t *dst,
+			    const cairo_composite_rectangles_t *extents,
+			    cairo_clip_t *clip,
+			    cairo_boxes_t *boxes)
+{
+    cairo_boxes_t clear;
+    cairo_box_t box;
+    cairo_region_t *clip_region = NULL;
+    cairo_status_t status;
+    struct _cairo_boxes_chunk *chunk;
+    i915_shader_t shader;
+    int i;
+
+    if (boxes->num_boxes <= 1)
+	return i915_fixup_unbounded (dst, extents, clip);
+
+    i915_shader_init (&shader, dst, CAIRO_OPERATOR_CLEAR);
+    _cairo_boxes_init (&clear);
+
+    box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
+    box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
+    box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
+    box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
+
+    if (clip != NULL) {
+	status = _cairo_clip_get_region (clip, &clip_region);
+	assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+	    i915_shader_set_clip (&shader, clip);
+    }
+
+    if (clip_region == NULL) {
+	cairo_boxes_t tmp;
+
+	_cairo_boxes_init (&tmp);
+
+	status = _cairo_boxes_add (&tmp, &box);
+	assert (status == CAIRO_STATUS_SUCCESS);
+
+	tmp.chunks.next = &boxes->chunks;
+	tmp.num_boxes += boxes->num_boxes;
+
+	status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
+							  CAIRO_FILL_RULE_WINDING,
+							  &clear);
+
+	tmp.chunks.next = NULL;
+    } else {
+	pixman_box32_t *pbox;
+
+	pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
+	_cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
+
+	status = _cairo_boxes_add (&clear, &box);
+	assert (status == CAIRO_STATUS_SUCCESS);
+
+	for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	    for (i = 0; i < chunk->count; i++) {
+		status = _cairo_boxes_add (&clear, &chunk->base[i]);
+		if (unlikely (status)) {
+		    _cairo_boxes_fini (&clear);
+		    return status;
+		}
+	    }
+	}
+
+	status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
+							  CAIRO_FILL_RULE_WINDING,
+							  &clear);
+    }
+
+    if (likely (status == CAIRO_STATUS_SUCCESS && clear.num_boxes)) {
+	status = i915_shader_commit (&shader,
+				     (i915_device_t *) dst->intel.drm.base.device);
+	if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	    for (chunk = &clear.chunks; chunk != NULL; 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);
+
+		    shader.add_rectangle (&shader, x1, y1, x2 - x1, y2 - y1);
+		}
+	    }
+	}
+	i915_shader_fini (&shader);
+    }
+
+    _cairo_boxes_fini (&clear);
+
+    return status;
+}
+
+static cairo_status_t
+_composite_boxes (i915_surface_t *dst,
+		  cairo_operator_t op,
+		  const cairo_pattern_t *pattern,
+		  cairo_boxes_t *boxes,
+		  cairo_antialias_t antialias,
+		  cairo_clip_t *clip,
+		  const cairo_composite_rectangles_t *extents)
+{
+    cairo_bool_t need_clip_surface = FALSE;
+    cairo_region_t *clip_region = NULL;
+    const struct _cairo_boxes_chunk *chunk;
+    cairo_status_t status;
+    i915_shader_t shader;
+    int i;
+
+    /* If the boxes are not pixel-aligned, we will need to compute a real mask */
+    if (antialias != CAIRO_ANTIALIAS_NONE) {
+	if (! boxes->is_pixel_aligned)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    i915_shader_init (&shader, dst, op);
+
+    status = i915_shader_acquire_pattern (&shader,
+					  &shader.source,
+					  pattern,
+					  &extents->bounded);
+    if (unlikely (status))
+	return status;
+
+    if (clip != NULL) {
+	status = _cairo_clip_get_region (clip, &clip_region);
+	assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+	need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+	if (need_clip_surface)
+	    i915_shader_set_clip (&shader, clip);
+    }
+
+    status = i915_shader_commit (&shader,
+				 (i915_device_t *) dst->intel.drm.base.device);
+    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	    cairo_box_t *box = chunk->base;
+	    for (i = 0; i < chunk->count; i++) {
+		int x1 = _cairo_fixed_integer_round (box[i].p1.x);
+		int y1 = _cairo_fixed_integer_round (box[i].p1.y);
+		int x2 = _cairo_fixed_integer_round (box[i].p2.x);
+		int y2 = _cairo_fixed_integer_round (box[i].p2.y);
+
+		if (x2 > x1 && y2 > y1)
+		    shader.add_rectangle (&shader, x1, y1, x2 - x1, y2 - y1);
+	    }
+	}
+
+	if (! extents->is_bounded)
+	    status = i915_fixup_unbounded_boxes (dst, extents, clip, boxes);
+    }
+    i915_shader_fini (&shader);
+
+    return status;
+}
+
+static cairo_status_t
+_clip_and_composite_boxes (i915_surface_t *dst,
+			   cairo_operator_t op,
+			   const cairo_pattern_t *src,
+			   cairo_boxes_t *boxes,
+			   cairo_antialias_t antialias,
+			   const cairo_composite_rectangles_t *extents,
+			   cairo_clip_t *clip)
+{
+    cairo_status_t status;
+
+    if (boxes->num_boxes == 0) {
+	if (extents->is_bounded)
+	    return CAIRO_STATUS_SUCCESS;
+
+	return i915_fixup_unbounded (dst, extents, clip);
+    }
+
+    /* Use a fast path if the boxes are pixel aligned */
+    status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents);
+    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	return status;
+
+    /* Otherwise render the boxes via an implicit mask and composite in the usual
+     * fashion.
+     */
+    return i915_clip_and_composite_spans (dst, op, src, antialias,
+					  _composite_boxes_spans, boxes,
+					  extents, clip);
+}
+
+static cairo_bool_t
+box_is_aligned (const cairo_box_t *box)
+{
+    return
+	_cairo_fixed_is_integer (box->p1.x) &&
+	_cairo_fixed_is_integer (box->p1.y) &&
+	_cairo_fixed_is_integer (box->p2.x) &&
+	_cairo_fixed_is_integer (box->p2.y);
+}
+
+static inline cairo_status_t
+_clip_to_boxes (cairo_clip_t **clip,
+		const cairo_composite_rectangles_t *extents,
+		cairo_box_t **boxes,
+		int *num_boxes)
+{
+    cairo_status_t status;
+    const cairo_rectangle_int_t *rect;
+
+    rect = extents->is_bounded ? &extents->bounded: &extents->unbounded;
+
+    if (*clip == NULL)
+	goto EXTENTS;
+
+    status = _cairo_clip_rectangle (*clip, rect);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_clip_get_boxes (*clip, boxes, num_boxes);
+    if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
+	if (extents->is_bounded || (*num_boxes == 1 && box_is_aligned (*boxes)))
+	    *clip = NULL;
+	return status;
+    }
+
+  EXTENTS:
+    _cairo_box_from_rectangle (&(*boxes)[0], rect);
+    *num_boxes = 1;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_clip_path_t *
+_clip_get_solitary_path (cairo_clip_t *clip)
+{
+    cairo_clip_path_t *iter = clip->path;
+    cairo_clip_path_t *path = NULL;
+
+    do {
+	if ((iter->flags & CAIRO_CLIP_PATH_IS_BOX) == 0) {
+	    if (path != NULL)
+		return FALSE;
+
+	    path = iter;
+	}
+	iter = iter->prev;
+    } while (iter != NULL);
+
+    return path;
+}
+
+static cairo_int_status_t
+i915_surface_paint (void			*abstract_dst,
+		    cairo_operator_t		 op,
+		    const cairo_pattern_t	*source,
+		    cairo_clip_t		*clip)
+{
+    i915_surface_t *dst = abstract_dst;
+    cairo_composite_rectangles_t extents;
+    cairo_clip_t local_clip;
+    cairo_bool_t have_clip = FALSE;
+    cairo_clip_path_t *clip_path;
+    cairo_boxes_t boxes;
+    int num_boxes = ARRAY_LENGTH (boxes.boxes_embedded);
+    cairo_box_t *clip_boxes = boxes.boxes_embedded;
+    cairo_status_t status;
+
+    /* XXX unsupported operators? use pixel shader blending, eventually */
+
+    status = _cairo_composite_rectangles_init_for_paint (&extents,
+							 dst->intel.drm.width,
+							 dst->intel.drm.height,
+							 op, source,
+							 clip);
+    if (unlikely (status))
+	return status;
+
+    if (_cairo_clip_contains_rectangle (clip, &extents))
+	clip = NULL;
+
+    if (clip != NULL) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	have_clip = TRUE;
+    }
+
+    status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+    if (unlikely (status)) {
+	if (have_clip)
+	    _cairo_clip_fini (&local_clip);
+
+	return status;
+    }
+
+    /* If the clip cannot be reduced to a set of boxes, we will need to
+     * use a clipmask. Paint is special as it is the only operation that
+     * does not implicitly use a mask, so we may be able to reduce this
+     * operation to a fill...
+     */
+    if (clip != NULL &&
+	extents.is_bounded &&
+	(clip_path = _clip_get_solitary_path (clip)) != NULL)
+    {
+	status = i915_surface_fill (dst, op, source,
+				    &clip_path->path,
+				    clip_path->fill_rule,
+				    clip_path->tolerance,
+				    clip_path->antialias,
+				    NULL);
+    }
+    else
+    {
+	_cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
+	status = _clip_and_composite_boxes (dst, op, source,
+					    &boxes, CAIRO_ANTIALIAS_DEFAULT,
+					    &extents, clip);
+    }
+    if (clip_boxes != boxes.boxes_embedded)
+	free (clip_boxes);
+
+    if (have_clip)
+	_cairo_clip_fini (&local_clip);
+
+    return status;
+}
+
+static cairo_int_status_t
+i915_surface_mask (void				*abstract_dst,
+		   cairo_operator_t		 op,
+		   const cairo_pattern_t	*source,
+		   const cairo_pattern_t	*mask,
+		   cairo_clip_t			*clip)
+{
+    i915_surface_t *dst = abstract_dst;
+    cairo_composite_rectangles_t extents;
+    i915_shader_t shader;
+    cairo_clip_t local_clip;
+    cairo_region_t *clip_region = NULL;
+    cairo_bool_t need_clip_surface = FALSE;
+    cairo_bool_t have_clip = FALSE;
+    cairo_status_t status;
+
+    status = _cairo_composite_rectangles_init_for_mask (&extents,
+							dst->intel.drm.width,
+							dst->intel.drm.height,
+							op, source, mask, clip);
+    if (unlikely (status))
+	return status;
+
+    if (_cairo_clip_contains_rectangle (clip, &extents))
+	clip = NULL;
+
+    if (clip != NULL && extents.is_bounded) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	status = _cairo_clip_rectangle (clip, &extents.bounded);
+	if (unlikely (status)) {
+	    _cairo_clip_fini (&local_clip);
+	    return status;
+	}
+
+	have_clip = TRUE;
+    }
+
+    i915_shader_init (&shader, dst, op);
+
+    status = i915_shader_acquire_pattern (&shader,
+					  &shader.source,
+					  source,
+					  &extents.bounded);
+    if (unlikely (status))
+	goto BAIL;
+
+    status = i915_shader_acquire_pattern (&shader,
+					  &shader.mask,
+					  mask,
+					  &extents.bounded);
+    if (unlikely (status))
+	goto BAIL;
+
+    if (clip != NULL) {
+	status = _cairo_clip_get_region (clip, &clip_region);
+	assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+	need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+	if (need_clip_surface)
+	    i915_shader_set_clip (&shader, clip);
+    }
+
+    status = i915_shader_commit (&shader,
+				 (i915_device_t *) dst->intel.drm.base.device);
+    if (unlikely (status))
+	goto BAIL;
+
+    if (clip_region != NULL) {
+	unsigned int n, num_rectangles;
+
+	num_rectangles = cairo_region_num_rectangles (clip_region);
+	for (n = 0; n < num_rectangles; n++) {
+	    cairo_rectangle_int_t rect;
+
+	    cairo_region_get_rectangle (clip_region, n, &rect);
+
+	    shader.add_rectangle (&shader,
+				  rect.x, rect.y,
+				  rect.x + rect.width, rect.y + rect.height);
+	}
+    } else {
+	shader.add_rectangle (&shader,
+			      extents.bounded.x, extents.bounded.y,
+			      extents.bounded.x + extents.bounded.width,
+			      extents.bounded.y + extents.bounded.height);
+    }
+
+    if (! extents.is_bounded)
+	status = i915_fixup_unbounded (dst, &extents, clip);
+
+  BAIL:
+    i915_shader_fini (&shader);
+    if (have_clip)
+	_cairo_clip_fini (&local_clip);
+
+    return status;
+}
+
+typedef struct {
+    cairo_polygon_t		polygon;
+    cairo_fill_rule_t		 fill_rule;
+    cairo_antialias_t		 antialias;
+} composite_polygon_info_t;
+
+static cairo_status_t
+_composite_polygon_spans (void                          *closure,
+			  cairo_span_renderer_t		*renderer,
+			  const cairo_rectangle_int_t   *extents)
+{
+    composite_polygon_info_t *info = closure;
+    cairo_botor_scan_converter_t converter;
+    cairo_status_t status;
+    cairo_box_t box;
+
+    box.p1.x = _cairo_fixed_from_int (extents->x);
+    box.p1.y = _cairo_fixed_from_int (extents->y);
+    box.p2.x = _cairo_fixed_from_int (extents->x + extents->width);
+    box.p2.y = _cairo_fixed_from_int (extents->y + extents->height);
+
+    _cairo_botor_scan_converter_init (&converter, &box, info->fill_rule);
+
+    status = converter.base.add_polygon (&converter.base, &info->polygon);
+    if (likely (status == CAIRO_STATUS_SUCCESS))
+	status = converter.base.generate (&converter.base, renderer);
+
+    converter.base.destroy (&converter.base);
+
+    return status;
+}
+
+static cairo_int_status_t
+i915_surface_stroke (void			*abstract_dst,
+		     cairo_operator_t		 op,
+		     const cairo_pattern_t	*source,
+		     cairo_path_fixed_t		*path,
+		     const cairo_stroke_style_t	*stroke_style,
+		     const cairo_matrix_t	*ctm,
+		     const cairo_matrix_t	*ctm_inverse,
+		     double			 tolerance,
+		     cairo_antialias_t		 antialias,
+		     cairo_clip_t		*clip)
+{
+    i915_surface_t *dst = abstract_dst;
+    cairo_composite_rectangles_t extents;
+    composite_polygon_info_t info;
+    cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+    int num_boxes = ARRAY_LENGTH (boxes_stack);
+    cairo_clip_t local_clip;
+    cairo_bool_t have_clip = FALSE;
+    cairo_status_t status;
+
+    status = _cairo_composite_rectangles_init_for_stroke (&extents,
+							  dst->intel.drm.width,
+							  dst->intel.drm.height,
+							  op, source,
+							  path, stroke_style, ctm,
+							  clip);
+    if (unlikely (status))
+	return status;
+
+    if (_cairo_clip_contains_rectangle (clip, &extents))
+	clip = NULL;
+
+    if (clip != NULL) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	have_clip = TRUE;
+    }
+
+    status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+    if (unlikely (status)) {
+	if (have_clip)
+	    _cairo_clip_fini (&local_clip);
+
+	return status;
+    }
+
+    if (path->is_rectilinear) {
+	cairo_boxes_t boxes;
+
+	_cairo_boxes_init (&boxes);
+	_cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
+	status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
+								stroke_style,
+								ctm,
+								&boxes);
+	if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	    status = _clip_and_composite_boxes (dst, op, source,
+						&boxes, antialias,
+						&extents, clip);
+	}
+
+	_cairo_boxes_fini (&boxes);
+
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    goto CLEANUP_BOXES;
+    }
+
+    _cairo_polygon_init (&info.polygon);
+    _cairo_polygon_limit (&info.polygon, clip_boxes, num_boxes);
+
+    status = _cairo_path_fixed_stroke_to_polygon (path,
+						  stroke_style,
+						  ctm, ctm_inverse,
+						  tolerance,
+						  &info.polygon);
+    if (unlikely (status))
+	goto CLEANUP_POLYGON;
+
+    if (extents.is_bounded) {
+	cairo_rectangle_int_t rect;
+
+	_cairo_box_round_to_rectangle (&info.polygon.extents, &rect);
+	if (! _cairo_rectangle_intersect (&extents.bounded, &rect))
+	    goto CLEANUP_POLYGON;
+    }
+
+    if (info.polygon.num_edges == 0) {
+	if (! extents.is_bounded)
+	    status =  i915_fixup_unbounded (dst, &extents, clip);
+
+	goto CLEANUP_POLYGON;
+    }
+
+    info.fill_rule = CAIRO_FILL_RULE_WINDING;
+    info.antialias = antialias;
+    status = i915_clip_and_composite_spans (dst, op, source, antialias,
+					    _composite_polygon_spans, &info,
+					    &extents, clip);
+
+CLEANUP_POLYGON:
+    _cairo_polygon_fini (&info.polygon);
+
+CLEANUP_BOXES:
+    if (clip_boxes != boxes_stack)
+	free (clip_boxes);
+
+    if (have_clip)
+	_cairo_clip_fini (&local_clip);
+
+    return status;
+}
+
+static cairo_int_status_t
+i915_surface_fill (void			*abstract_dst,
+		   cairo_operator_t	 op,
+		   const cairo_pattern_t*source,
+		   cairo_path_fixed_t	*path,
+		   cairo_fill_rule_t	 fill_rule,
+		   double		 tolerance,
+		   cairo_antialias_t	 antialias,
+		   cairo_clip_t		*clip)
+{
+    i915_surface_t *dst = abstract_dst;
+    cairo_composite_rectangles_t extents;
+    composite_polygon_info_t info;
+    cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+    cairo_clip_t local_clip;
+    cairo_bool_t have_clip = FALSE;
+    int num_boxes = ARRAY_LENGTH (boxes_stack);
+    cairo_status_t status;
+
+    status = _cairo_composite_rectangles_init_for_fill (&extents,
+							dst->intel.drm.width,
+							dst->intel.drm.height,
+							op, source, path,
+							clip);
+    if (unlikely (status))
+	return status;
+
+    if (_cairo_clip_contains_rectangle (clip, &extents))
+	clip = NULL;
+
+    if (clip != NULL) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	have_clip = TRUE;
+    }
+
+    status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+    if (unlikely (status)) {
+	if (have_clip)
+	    _cairo_clip_fini (&local_clip);
+
+	return status;
+    }
+
+    assert (! path->is_empty_fill);
+
+    if (_cairo_path_fixed_is_rectilinear_fill (path)) {
+	cairo_boxes_t boxes;
+
+	_cairo_boxes_init (&boxes);
+	_cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
+	status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
+							      fill_rule,
+							      &boxes);
+	if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	    status = _clip_and_composite_boxes (dst, op, source,
+						&boxes, antialias,
+						&extents, clip);
+	}
+
+	_cairo_boxes_fini (&boxes);
+
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    goto CLEANUP_BOXES;
+    }
+
+    _cairo_polygon_init (&info.polygon);
+    _cairo_polygon_limit (&info.polygon, clip_boxes, num_boxes);
+
+    status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &info.polygon);
+    if (unlikely (status))
+	goto CLEANUP_POLYGON;
+
+    if (extents.is_bounded) {
+	cairo_rectangle_int_t rect;
+
+	_cairo_box_round_to_rectangle (&info.polygon.extents, &rect);
+	if (! _cairo_rectangle_intersect (&extents.bounded, &rect))
+	    goto CLEANUP_POLYGON;
+    }
+
+    if (info.polygon.num_edges == 0) {
+	if (! extents.is_bounded)
+	    status =  i915_fixup_unbounded (dst, &extents, clip);
+
+	goto CLEANUP_POLYGON;
+    }
+
+    info.fill_rule = fill_rule;
+    info.antialias = antialias;
+    status = i915_clip_and_composite_spans (dst, op, source, antialias,
+					    _composite_polygon_spans, &info,
+					    &extents, clip);
+
+CLEANUP_POLYGON:
+    _cairo_polygon_fini (&info.polygon);
+
+CLEANUP_BOXES:
+    if (clip_boxes != boxes_stack)
+	free (clip_boxes);
+
+    if (have_clip)
+	_cairo_clip_fini (&local_clip);
+
+    return status;
+}
+
+static const cairo_surface_backend_t i915_surface_backend = {
+    CAIRO_SURFACE_TYPE_DRM,
+
+    _cairo_drm_surface_create_similar,
+    i915_surface_finish,
+    intel_surface_acquire_source_image,
+    intel_surface_release_source_image,
+
+    NULL, NULL, NULL,
+    NULL, /* composite */
+    NULL, /* fill */
+    NULL, /* trapezoids */
+    NULL, /* span */
+    NULL, /* check-span */
+
+    NULL, /* copy_page */
+    NULL, /* show_page */
+    _cairo_drm_surface_get_extents,
+    NULL, /* old-glyphs */
+    _cairo_drm_surface_get_font_options,
+
+    i915_surface_flush,
+    NULL, /* mark_dirty */
+    intel_scaled_font_fini,
+    intel_scaled_glyph_fini,
+
+    i915_surface_paint,
+    i915_surface_mask,
+    i915_surface_stroke,
+    i915_surface_fill,
+    i915_surface_glyphs,
+};
+
+static void
+i915_surface_init (i915_surface_t *surface,
+	           cairo_content_t content,
+		   cairo_drm_device_t *device)
+{
+    intel_surface_init (&surface->intel, &i915_surface_backend, device, content);
+
+    switch (content) {
+    default:
+	ASSERT_NOT_REACHED;
+    case CAIRO_CONTENT_COLOR_ALPHA:
+	surface->map0 = MAPSURF_32BIT | MT_32BIT_ARGB8888;
+	surface->colorbuf = COLR_BUF_ARGB8888 | DEPTH_FRMT_24_FIXED_8_OTHER;
+	break;
+    case CAIRO_CONTENT_COLOR:
+	surface->map0 = MAPSURF_32BIT | MT_32BIT_XRGB8888;
+	surface->colorbuf = COLR_BUF_ARGB8888 | DEPTH_FRMT_24_FIXED_8_OTHER;
+	break;
+    case CAIRO_CONTENT_ALPHA:
+	surface->map0 = MAPSURF_8BIT | MT_8BIT_A8;
+	surface->colorbuf = COLR_BUF_8BIT | DEPTH_FRMT_24_FIXED_8_OTHER;
+	break;
+    }
+    surface->colorbuf |= DSTORG_HORT_BIAS (0x8) | DSTORG_VERT_BIAS (0x8);
+
+    surface->map1 = 0;
+
+    surface->is_current_texture = 0;
+
+    surface->offset = 0;
+
+    surface->stencil  = NULL;
+    surface->cache = NULL;
+}
+
+cairo_surface_t *
+i915_surface_create_internal (cairo_drm_device_t *base_dev,
+		              cairo_content_t content,
+			      int width, int height,
+			      uint32_t tiling,
+			      cairo_bool_t gpu_target)
+{
+    i915_surface_t *surface;
+    cairo_status_t status_ignored;
+
+    surface = malloc (sizeof (i915_surface_t));
+    if (unlikely (surface == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    i915_surface_init (surface, content, base_dev);
+
+    if (width && height) {
+	uint32_t size;
+
+	surface->intel.drm.width  = width;
+	surface->intel.drm.height = height;
+	surface->map0 |= ((height - 1) << MS3_HEIGHT_SHIFT) |
+		         ((width  - 1) << MS3_WIDTH_SHIFT);
+
+	width = (width + 3) & -4;
+	surface->intel.drm.stride = cairo_format_stride_for_width (surface->intel.drm.format,
+							      width);
+	/* check for tiny surfaces for which tiling is irrelevant */
+	if (height * surface->intel.drm.stride < 4096)
+	    tiling = I915_TILING_NONE;
+
+	surface->intel.drm.stride = i915_tiling_stride (tiling,
+		                                   surface->intel.drm.stride);
+	assert (surface->intel.drm.stride <= 8192);
+	assert (surface->intel.drm.stride >= cairo_format_stride_for_width (surface->intel.drm.format, width));
+	height = i915_tiling_height (tiling, height);
+	assert (height <= 2048);
+
+	size = i915_tiling_size (tiling, surface->intel.drm.stride * height);
+
+	surface->intel.drm.bo = &intel_bo_create (to_intel_device (&base_dev->base),
+					     size, gpu_target)->base;
+	if (surface->intel.drm.bo == NULL) {
+	    status_ignored = _cairo_drm_surface_finish (&surface->intel.drm);
+	    free (surface);
+	    return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+	}
+
+	intel_bo_set_tiling (to_intel_device (&base_dev->base),
+			     to_intel_bo (surface->intel.drm.bo),
+			     tiling, surface->intel.drm.stride);
+
+	assert (surface->intel.drm.bo->size >= (size_t) surface->intel.drm.stride*height);
+
+	surface->map0 |= MS3_tiling (to_intel_bo (surface->intel.drm.bo)->tiling);
+	surface->map1 = (surface->intel.drm.stride/4 - 1) << MS4_PITCH_SHIFT;
+    }
+
+    return &surface->intel.drm.base;
+}
+
+static cairo_surface_t *
+i915_surface_create (cairo_drm_device_t *base_dev,
+		      cairo_content_t content,
+		      int width, int height)
+{
+    return i915_surface_create_internal (base_dev, content, width, height,
+	                                 I915_TILING_DEFAULT, TRUE);
+}
+
+static cairo_surface_t *
+i915_surface_create_for_name (cairo_drm_device_t *base_dev,
+			       unsigned int name,
+			       cairo_format_t format,
+			       int width, int height, int stride)
+{
+    i915_surface_t *surface;
+    cairo_content_t content;
+
+    /* Vol I, p134: size restrictions for textures */
+    /* Vol I, p129: destination surface stride must be a multiple of 32 bytes */
+    if (stride < cairo_format_stride_for_width (format, (width + 3) & -4) ||
+	stride & 31)
+    {
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
+    }
+
+    switch (format) {
+    default:
+    case CAIRO_FORMAT_A1:
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+    case CAIRO_FORMAT_ARGB32:
+	content = CAIRO_CONTENT_COLOR_ALPHA;
+	break;
+    case CAIRO_FORMAT_RGB24:
+	content = CAIRO_CONTENT_COLOR;
+	break;
+    case CAIRO_FORMAT_A8:
+	content = CAIRO_CONTENT_ALPHA;
+	break;
+    }
+
+    surface = malloc (sizeof (i915_surface_t));
+    if (unlikely (surface == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    i915_surface_init (surface, content, base_dev);
+
+    if (width && height) {
+	surface->intel.drm.width  = width;
+	surface->intel.drm.height = height;
+	surface->intel.drm.stride = stride;
+
+	surface->map0 |= ((height - 1) << MS3_HEIGHT_SHIFT) |
+		         ((width  - 1) << MS3_WIDTH_SHIFT);
+	surface->map1 = (surface->intel.drm.stride/4 - 1) << MS4_PITCH_SHIFT;
+
+	surface->intel.drm.bo =
+	    &intel_bo_create_for_name (to_intel_device (&base_dev->base),
+				       name)->base;
+	if (unlikely (surface->intel.drm.bo == NULL)) {
+	    free (surface);
+	    return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+	}
+	to_intel_bo (surface->intel.drm.bo)->stride = stride;
+
+	surface->map0 |= MS3_tiling (to_intel_bo (surface->intel.drm.bo)->tiling);
+    }
+
+    return &surface->intel.drm.base;
+}
+
+static cairo_status_t
+i915_buffer_cache_init (intel_buffer_cache_t *cache,
+		        i915_device_t *device,
+			cairo_format_t format,
+			int width, int height)
+{
+    const uint32_t tiling = I915_TILING_Y;
+
+    assert ((width & 3) == 0);
+    assert ((height & 1) == 0);
+    cache->buffer.width = width;
+    cache->buffer.height = height;
+
+    switch (format) {
+    case CAIRO_FORMAT_A1:
+    case CAIRO_FORMAT_RGB24:
+	ASSERT_NOT_REACHED;
+    case CAIRO_FORMAT_ARGB32:
+	cache->buffer.map0 = MAPSURF_32BIT | MT_32BIT_ARGB8888;
+	cache->buffer.stride = width * 4;
+	break;
+    case CAIRO_FORMAT_A8:
+	cache->buffer.map0 = MAPSURF_8BIT | MT_8BIT_I8;
+	cache->buffer.stride = width;
+	break;
+    }
+    cache->buffer.map0 |= ((height - 1) << MS3_HEIGHT_SHIFT) |
+			  ((width  - 1) << MS3_WIDTH_SHIFT);
+    cache->buffer.map1 = ((cache->buffer.stride / 4) - 1) << MS4_PITCH_SHIFT;
+
+    assert ((cache->buffer.stride & 7) == 0);
+    assert (i915_tiling_stride (tiling, cache->buffer.stride) == cache->buffer.stride);
+    assert (i915_tiling_height (tiling, height) == height);
+
+    cache->buffer.bo = intel_bo_create (&device->intel,
+					height * cache->buffer.stride,
+					FALSE);
+    if (unlikely (cache->buffer.bo == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+    intel_bo_set_tiling (&device->intel, cache->buffer.bo, tiling, cache->buffer.stride);
+    cache->buffer.map0 |= MS3_tiling (cache->buffer.bo->tiling);
+
+    cache->ref_count = 0;
+    cairo_list_init (&cache->link);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+i915_surface_t *
+i915_surface_create_from_cacheable_image_internal (i915_device_t *device,
+						   cairo_image_surface_t *image)
+{
+    i915_surface_t *surface;
+    cairo_status_t status;
+    cairo_list_t *caches;
+    intel_buffer_cache_t *cache;
+    cairo_rtree_node_t *node;
+    cairo_format_t format;
+    int width, height, bpp;
+
+    width = image->width;
+    height = image->height;
+    if (width > IMAGE_CACHE_WIDTH/2 || height > IMAGE_CACHE_HEIGHT/2) {
+	surface = (i915_surface_t *)
+	    i915_surface_create_internal (&device->intel.base,
+					  image->base.content,
+					  width, height,
+					  I915_TILING_NONE, FALSE);
+	if (unlikely (surface->intel.drm.base.status))
+	    return surface;
+
+	status = intel_bo_put_image (&device->intel,
+				     to_intel_bo (surface->intel.drm.bo),
+				     surface->intel.drm.stride,
+				     image,
+				     0, 0,
+				     width, height,
+				     0, 0);
+
+	if (unlikely (status)) {
+	    cairo_surface_destroy (&surface->intel.drm.base);
+	    return (i915_surface_t *) _cairo_surface_create_in_error (status);
+	}
+
+	return surface;
+    }
+
+    status = cairo_device_acquire (&device->intel.base.base);
+    if (unlikely (status))
+	return (i915_surface_t *) _cairo_surface_create_in_error (status);
+
+    switch (image->format) {
+    case CAIRO_FORMAT_ARGB32:
+    case CAIRO_FORMAT_RGB24:
+	caches = &device->image_caches[0];
+	format = CAIRO_FORMAT_ARGB32;
+	bpp = 4;
+	break;
+    case CAIRO_FORMAT_A8:
+    case CAIRO_FORMAT_A1:
+	caches = &device->image_caches[1];
+	format = CAIRO_FORMAT_A8;
+	bpp = 1;
+	break;
+    default:
+	ASSERT_NOT_REACHED;
+	status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
+	goto CLEANUP_DEVICE;
+    }
+
+    node = NULL;
+    cairo_list_foreach_entry (cache, intel_buffer_cache_t, caches, link) {
+	if (! intel_bo_is_inactive (&device->intel, cache->buffer.bo))
+	    continue;
+
+	status = _cairo_rtree_insert (&cache->rtree, width, height, &node);
+	if (unlikely (_cairo_status_is_error (status)))
+	    goto CLEANUP_DEVICE;
+	if (status == CAIRO_STATUS_SUCCESS)
+	    break;
+    }
+    if (node == NULL) {
+	cache = malloc (sizeof (intel_buffer_cache_t));
+	if (unlikely (cache == NULL)) {
+	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	    goto CLEANUP_DEVICE;
+	}
+
+	status = i915_buffer_cache_init (cache, device, format,
+					 IMAGE_CACHE_WIDTH,
+					 IMAGE_CACHE_HEIGHT);
+	if (unlikely (status)) {
+	    free (cache);
+	    goto CLEANUP_DEVICE;
+	}
+
+	_cairo_rtree_init (&cache->rtree,
+			   IMAGE_CACHE_WIDTH,
+			   IMAGE_CACHE_HEIGHT,
+			   4,
+			   sizeof (i915_image_private_t),
+			   NULL);
+
+	status = _cairo_rtree_insert (&cache->rtree, width, height, &node);
+	assert (status == CAIRO_STATUS_SUCCESS);
+
+	cairo_list_init (&cache->link);
+    }
+    cairo_list_move (&cache->link, caches);
+    ((i915_image_private_t *) node)->container = cache;
+
+    status = intel_bo_put_image (&device->intel,
+				 cache->buffer.bo, cache->buffer.stride,
+				 image,
+				 0, 0,
+				 width, height,
+				 node->x, node->y);
+    if (unlikely (status))
+	goto CLEANUP_CACHE;
+
+    surface = malloc (sizeof (i915_surface_t));
+    if (unlikely (surface == NULL)) {
+	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	goto CLEANUP_CACHE;
+    }
+
+    i915_surface_init (surface, image->base.content, &device->intel.base);
+
+    surface->intel.drm.width  = width;
+    surface->intel.drm.height = height;
+    surface->intel.drm.stride = cache->buffer.stride;
+
+    surface->map0 |= MS3_tiling (cache->buffer.bo->tiling) |
+	             ((height - 1) << MS3_HEIGHT_SHIFT) |
+		     ((width  - 1) << MS3_WIDTH_SHIFT);
+    surface->map1 = (surface->intel.drm.stride/4 - 1) << MS4_PITCH_SHIFT;
+
+    surface->intel.drm.bo = &intel_bo_reference (cache->buffer.bo)->base;
+    surface->offset = node->y * cache->buffer.stride + bpp * node->x;
+
+    surface->cache = (i915_image_private_t *) node;
+    cache->ref_count++;
+
+    cairo_device_release (&device->intel.base.base);
+
+    return surface;
+
+CLEANUP_CACHE:
+    _cairo_rtree_node_destroy (&cache->rtree, node);
+    if (cache->ref_count == 0) {
+	intel_bo_destroy (&device->intel, cache->buffer.bo);
+	_cairo_rtree_fini (&cache->rtree);
+	cairo_list_del (&cache->link);
+	free (cache);
+    }
+CLEANUP_DEVICE:
+    cairo_device_release (&device->intel.base.base);
+    return (i915_surface_t *) _cairo_surface_create_in_error (status);
+}
+
+static cairo_surface_t *
+i915_surface_create_from_cacheable_image (cairo_drm_device_t *device,
+					  cairo_surface_t *source)
+{
+    i915_surface_t *surface;
+    cairo_image_surface_t *image;
+    void *image_extra;
+    cairo_status_t status;
+
+    status = _cairo_surface_acquire_source_image (source, &image, &image_extra);
+    if (unlikely (status))
+	return _cairo_surface_create_in_error (status);
+
+    surface = i915_surface_create_from_cacheable_image_internal ((i915_device_t *) device, image);
+
+    _cairo_surface_release_source_image (source, image, image_extra);
+
+    return &surface->intel.drm.base;
+}
+
+static cairo_status_t
+i915_surface_enable_scan_out (void *abstract_surface)
+{
+    i915_surface_t *surface = abstract_surface;
+    intel_bo_t *bo;
+    cairo_status_t status;
+
+    if (unlikely (surface->intel.drm.bo == NULL))
+	return _cairo_error (CAIRO_STATUS_INVALID_SIZE);
+
+    bo = to_intel_bo (surface->intel.drm.bo);
+    if (bo->tiling == I915_TILING_Y) {
+	status = i915_surface_batch_flush (surface);
+	if (unlikely (status))
+	    return status;
+
+	intel_bo_set_tiling (to_intel_device (surface->intel.drm.base.device),
+			     bo, I915_TILING_X, surface->intel.drm.stride);
+	if (bo->tiling == I915_TILING_X) {
+	    surface->map0 &= ~MS3_tiling (I915_TILING_Y);
+	    surface->map0 |= MS3_tiling (I915_TILING_X);
+	}
+    }
+
+    if (unlikely (bo->tiling == I915_TILING_Y))
+	return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+i915_device_flush (cairo_drm_device_t *device)
+{
+    cairo_status_t status;
+
+    if (unlikely (device->base.finished))
+	return CAIRO_STATUS_SUCCESS;
+
+    status = cairo_device_acquire (&device->base);
+    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	status = i915_batch_flush ((i915_device_t *) device);
+	cairo_device_release (&device->base);
+    }
+
+    return status;
+}
+
+static cairo_int_status_t
+i915_device_throttle (cairo_drm_device_t *device)
+{
+    cairo_status_t status;
+
+    status = cairo_device_acquire (&device->base);
+    if (unlikely (status))
+	return status;
+
+    status = i915_batch_flush ((i915_device_t *) device);
+    intel_throttle ((intel_device_t *) device);
+
+    cairo_device_release (&device->base);
+
+    return status;
+}
+
+static void
+i915_device_destroy (void *data)
+{
+    i915_device_t *device = data;
+
+    if (device->last_vbo)
+	intel_bo_destroy (&device->intel, device->last_vbo);
+
+    i915_batch_cleanup (device);
+
+    intel_device_fini (&device->intel);
+    free (device);
+}
+
+COMPILE_TIME_ASSERT (sizeof (i915_batch_setup) == sizeof (((i915_device_t *)0)->batch_header));
+COMPILE_TIME_ASSERT (offsetof (i915_device_t, batch_base) == offsetof (i915_device_t, batch_header) + sizeof (i915_batch_setup));
+
+cairo_drm_device_t *
+_cairo_drm_i915_device_create (int fd, dev_t dev_id, int vendor_id, int chip_id)
+{
+    i915_device_t *device;
+    cairo_status_t status;
+    uint64_t gtt_size;
+    int n;
+
+    if (! intel_info (fd, &gtt_size))
+	return NULL;
+
+    device = malloc (sizeof (i915_device_t));
+    if (device == NULL)
+	return (cairo_drm_device_t *) _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+    status = intel_device_init (&device->intel, fd);
+    if (unlikely (status)) {
+	free (device);
+	return (cairo_drm_device_t *) _cairo_device_create_in_error (status);
+    }
+
+    device->debug = 0;
+    if (getenv ("CAIRO_DEBUG_DRM") != NULL)
+	device->debug = I915_DEBUG_BATCH;
+
+    device->batch.gtt_size = I915_BATCH_SIZE;
+    device->batch.exec_count = 0;
+    device->batch.reloc_count = 0;
+    device->batch.used = 0;
+
+    memcpy (device->batch_header, i915_batch_setup, sizeof (i915_batch_setup));
+    device->vbo = 0;
+    device->vbo_offset = 0;
+    device->vbo_used = 0;
+    device->vertex_index = 0;
+    device->vertex_count = 0;
+    device->last_vbo = NULL;
+
+    device->current_n_samplers = 0;
+    device->current_target = NULL;
+    device->current_source = NULL;
+    device->current_mask = NULL;
+    device->current_clip = NULL;
+    device->current_colorbuf = 0;
+
+    for (n = 0; n < ARRAY_LENGTH (device->image_caches); n++)
+	cairo_list_init (&device->image_caches[n]);
+
+    device->intel.base.surface.create = i915_surface_create;
+    device->intel.base.surface.create_for_name = i915_surface_create_for_name;
+    device->intel.base.surface.create_from_cacheable_image = i915_surface_create_from_cacheable_image;
+
+    device->intel.base.surface.flink = _cairo_drm_surface_flink;
+    device->intel.base.surface.enable_scan_out = i915_surface_enable_scan_out;
+    device->intel.base.surface.map_to_image = intel_surface_map_to_image;
+
+    device->intel.base.device.flush = i915_device_flush;
+    device->intel.base.device.throttle = i915_device_throttle;
+    device->intel.base.device.destroy = i915_device_destroy;
+
+    i915_device_reset (device);
+
+    return _cairo_drm_device_init (&device->intel.base,
+				   fd, dev_id, vendor_id, chip_id,
+				   2048);
+}
diff --git a/src/drm/cairo-drm-i965-glyphs.c b/src/drm/cairo-drm-i965-glyphs.c
new file mode 100644
index 0000000..fa86e34
--- /dev/null
+++ b/src/drm/cairo-drm-i965-glyphs.c
@@ -0,0 +1,500 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-drm-i965-private.h"
+#include "cairo-error-private.h"
+#include "cairo-rtree-private.h"
+
+typedef struct _i965_glyphs i965_glyphs_t;
+
+typedef float *
+(*i965_get_rectangle_func_t) (i965_glyphs_t *glyphs);
+
+struct _i965_glyphs {
+    i965_get_rectangle_func_t get_rectangle;
+    i965_shader_t shader;
+
+    struct i965_vbo head, *tail;
+
+    unsigned int vbo_offset;
+    float *vbo_base;
+};
+
+static float *
+i965_glyphs_emit_rectangle (i965_glyphs_t *glyphs)
+{
+    return i965_add_rectangle (glyphs->shader.device);
+}
+
+static float *
+i965_glyphs_accumulate_rectangle (i965_glyphs_t *glyphs)
+{
+    float *vertices;
+    uint32_t size;
+
+    size = glyphs->shader.device->rectangle_size;
+    if (unlikely (glyphs->vbo_offset + size > I965_VERTEX_SIZE)) {
+	struct i965_vbo *vbo;
+
+	intel_bo_unmap (glyphs->tail->bo);
+
+	vbo = malloc (sizeof (struct i965_vbo));
+	if (unlikely (vbo == NULL)) {
+	    /* throw error! */
+	}
+
+	glyphs->tail->next = vbo;
+	glyphs->tail = vbo;
+
+	vbo->next = NULL;
+	vbo->bo = intel_bo_create (&glyphs->shader.device->intel,
+				   I965_VERTEX_SIZE, FALSE);
+	vbo->count = 0;
+
+	glyphs->vbo_offset = 0;
+	glyphs->vbo_base = intel_bo_map (&glyphs->shader.device->intel, vbo->bo);
+    }
+
+    vertices = glyphs->vbo_base + glyphs->vbo_offset;
+    glyphs->vbo_offset += size;
+    glyphs->tail->count += 3;
+
+    return vertices;
+}
+
+static void
+i965_add_glyph_rectangle (i965_glyphs_t *glyphs,
+			  int x1, int y1,
+			  int x2, int y2,
+			  intel_glyph_t *glyph)
+{
+    float *v;
+
+    /* Each vertex is:
+     *   2 vertex coordinates
+     *   1 glyph texture coordinate
+     */
+
+    v = glyphs->get_rectangle (glyphs);
+
+    /* bottom right */
+    *v++ = x2; *v++ = y2;
+    *v++ = glyph->texcoord[0];
+
+    /* bottom left */
+    *v++ = x1; *v++ = y2;
+    *v++ = glyph->texcoord[1];
+
+    /* top left */
+    *v++ = x1; *v++ = y1;
+    *v++ = glyph->texcoord[2];
+}
+
+static cairo_status_t
+i965_surface_mask_internal (i965_surface_t *dst,
+			    cairo_operator_t		 op,
+			    const cairo_pattern_t	*source,
+			    i965_surface_t *mask,
+			    cairo_clip_t		*clip,
+			    const cairo_composite_rectangles_t *extents)
+{
+    i965_device_t *device;
+    i965_shader_t shader;
+    cairo_region_t *clip_region = NULL;
+    cairo_status_t status;
+
+    i965_shader_init (&shader, dst, op);
+
+    status = i965_shader_acquire_pattern (&shader, &shader.source,
+					  source, &extents->bounded);
+    if (unlikely (status))
+	return status;
+
+    shader.mask.type.vertex = VS_NONE;
+    shader.mask.type.fragment = FS_SURFACE;
+    shader.mask.base.content = mask->intel.drm.base.content;
+    shader.mask.base.filter = i965_filter (CAIRO_FILTER_NEAREST);
+    shader.mask.base.extend = i965_extend (CAIRO_EXTEND_NONE);
+
+    cairo_matrix_init_translate (&shader.mask.base.matrix,
+				 -extents->bounded.x + NEAREST_BIAS,
+				 -extents->bounded.y + NEAREST_BIAS);
+    cairo_matrix_scale (&shader.mask.base.matrix,
+			1. / mask->intel.drm.width,
+			1. / mask->intel.drm.height);
+
+    shader.mask.base.bo = to_intel_bo (mask->intel.drm.bo);
+    shader.mask.base.format = mask->intel.drm.format;
+    shader.mask.base.width = mask->intel.drm.width;
+    shader.mask.base.height = mask->intel.drm.height;
+    shader.mask.base.stride = mask->intel.drm.stride;
+
+    if (clip != NULL) {
+	status = _cairo_clip_get_region (clip, &clip_region);
+	assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+	if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+	    clip_region = NULL;
+
+	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+	    i965_shader_set_clip (&shader, clip);
+    }
+
+    status = cairo_device_acquire (dst->intel.drm.base.device);
+    if (unlikely (status))
+	goto CLEANUP_SHADER;
+
+    device = i965_device (dst);
+
+    status = i965_shader_commit (&shader, device);
+    if (unlikely (status))
+	goto CLEANUP_DEVICE;
+
+    if (clip_region != NULL) {
+	unsigned int n, num_rectangles;
+
+	num_rectangles = cairo_region_num_rectangles (clip_region);
+	for (n = 0; n < num_rectangles; n++) {
+	    cairo_rectangle_int_t rect;
+
+	    cairo_region_get_rectangle (clip_region, n, &rect);
+
+	    i965_shader_add_rectangle (&shader,
+				       rect.x, rect.y,
+				       rect.width, rect.height);
+	}
+    } else {
+	i965_shader_add_rectangle (&shader,
+				   extents->bounded.x,
+				   extents->bounded.y,
+				   extents->bounded.width,
+				   extents->bounded.height);
+    }
+
+    if (! extents->is_bounded)
+	status = i965_fixup_unbounded (dst, extents, clip);
+
+  CLEANUP_DEVICE:
+    cairo_device_release (&device->intel.base.base);
+  CLEANUP_SHADER:
+    i965_shader_fini (&shader);
+    return status;
+}
+
+cairo_int_status_t
+i965_surface_glyphs (void			*abstract_surface,
+		     cairo_operator_t		 op,
+		     const cairo_pattern_t	*source,
+		     cairo_glyph_t		*g,
+		     int			 num_glyphs,
+		     cairo_scaled_font_t	*scaled_font,
+		     cairo_clip_t		*clip,
+		     int *num_remaining)
+{
+    i965_surface_t *surface = abstract_surface;
+    i965_surface_t *mask = NULL;
+    i965_device_t *device;
+    i965_glyphs_t glyphs;
+    cairo_composite_rectangles_t extents;
+    cairo_clip_t local_clip;
+    cairo_bool_t have_clip = FALSE;
+    cairo_bool_t overlap;
+    cairo_region_t *clip_region = NULL;
+    intel_bo_t *last_bo = NULL;
+    cairo_scaled_glyph_t *glyph_cache[64];
+    cairo_status_t status;
+    int mask_x = 0, mask_y = 0;
+    int i = 0;
+
+    *num_remaining = 0;
+    status = _cairo_composite_rectangles_init_for_glyphs (&extents,
+							  surface->intel.drm.width,
+							  surface->intel.drm.height,
+							  op, source,
+							  scaled_font,
+							  g, num_glyphs,
+							  clip,
+							  &overlap);
+    if (unlikely (status))
+	return status;
+
+    if (clip != NULL && _cairo_clip_contains_rectangle (clip, &extents))
+	clip = NULL;
+
+    if (clip != NULL && extents.is_bounded) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	status = _cairo_clip_rectangle (clip, &extents.bounded);
+	if (unlikely (status))
+	    return status;
+
+	have_clip = TRUE;
+    }
+
+    if (overlap || ! extents.is_bounded) {
+	cairo_content_t content;
+
+	content = CAIRO_CONTENT_ALPHA;
+	if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
+	    content |= CAIRO_CONTENT_COLOR;
+
+	mask = (i965_surface_t *)
+	    i965_surface_create_internal (&i965_device (surface)->intel.base,
+					  content,
+					  extents.bounded.width,
+					  extents.bounded.height,
+					  I965_TILING_DEFAULT,
+					  TRUE);
+	if (unlikely (mask->intel.drm.base.status))
+	    return mask->intel.drm.base.status;
+
+	status = _cairo_surface_paint (&mask->intel.drm.base,
+				       CAIRO_OPERATOR_CLEAR,
+				       &_cairo_pattern_clear.base,
+				       NULL);
+	if (unlikely (status)) {
+	    cairo_surface_destroy (&mask->intel.drm.base);
+	    return status;
+	}
+
+	i965_shader_init (&glyphs.shader, mask, CAIRO_OPERATOR_ADD);
+
+	status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source,
+					      &_cairo_pattern_white.base,
+					      &extents.bounded);
+	if (unlikely (status)) {
+	    cairo_surface_destroy (&mask->intel.drm.base);
+	    return status;
+	}
+
+	mask_x = -extents.bounded.x;
+	mask_y = -extents.bounded.y;
+    } else {
+	i965_shader_init (&glyphs.shader, surface, op);
+
+	status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source,
+					      source, &extents.bounded);
+	if (unlikely (status))
+	    return status;
+
+	if (clip != NULL) {
+	    status = _cairo_clip_get_region (clip, &clip_region);
+	    assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+	    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+		i965_shader_set_clip (&glyphs.shader, clip);
+	}
+    }
+
+    glyphs.head.next = NULL;
+    glyphs.head.bo = NULL;
+    glyphs.head.count = 0;
+    glyphs.tail = &glyphs.head;
+
+    device = i965_device (surface);
+    if (mask != NULL || clip_region == NULL) {
+	glyphs.get_rectangle = i965_glyphs_emit_rectangle;
+    } else {
+	glyphs.get_rectangle = i965_glyphs_accumulate_rectangle;
+	glyphs.head.bo = intel_bo_create (&device->intel,
+					  I965_VERTEX_SIZE, FALSE);
+	if (unlikely (glyphs.head.bo == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+	glyphs.vbo_base = intel_bo_map (&device->intel, glyphs.head.bo);
+    }
+    glyphs.vbo_offset = 0;
+
+    status = cairo_device_acquire (&device->intel.base.base);
+    if (unlikely (status))
+	goto CLEANUP_GLYPHS;
+
+    _cairo_scaled_font_freeze_cache (scaled_font);
+    //private = _cairo_scaled_font_get_device (scaled_font, device);
+    if (scaled_font->surface_private == NULL) {
+	/* XXX couple into list to remove on context destruction */
+	scaled_font->surface_private = device;
+	scaled_font->surface_backend = surface->intel.drm.base.backend;
+    }
+
+    memset (glyph_cache, 0, sizeof (glyph_cache));
+
+    for (i = 0; i < num_glyphs; i++) {
+	cairo_scaled_glyph_t *scaled_glyph;
+	int x, y, x1, x2, y1, y2;
+	int cache_index = g[i].index % ARRAY_LENGTH (glyph_cache);
+	intel_glyph_t *glyph;
+
+	scaled_glyph = glyph_cache[cache_index];
+	if (scaled_glyph == NULL ||
+	    _cairo_scaled_glyph_index (scaled_glyph) != g[i].index)
+	{
+	    status = _cairo_scaled_glyph_lookup (scaled_font,
+						 g[i].index,
+						 CAIRO_SCALED_GLYPH_INFO_METRICS,
+						 &scaled_glyph);
+	    if (unlikely (status))
+		goto FINISH;
+
+	    glyph_cache[cache_index] = scaled_glyph;
+	}
+
+	if (unlikely (scaled_glyph->metrics.width  == 0 ||
+		      scaled_glyph->metrics.height == 0))
+	{
+	    continue;
+	}
+
+	/* XXX glyph images are snapped to pixel locations */
+	x = _cairo_lround (g[i].x);
+	y = _cairo_lround (g[i].y);
+
+	x1 = x + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
+	y1 = y + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
+	x2 = x + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x);
+	y2 = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y);
+
+	if (x2 < extents.bounded.x ||
+	    y2 < extents.bounded.y ||
+	    x1 > extents.bounded.x + extents.bounded.width ||
+	    y1 > extents.bounded.y + extents.bounded.height)
+	{
+	    continue;
+	}
+
+	if (scaled_glyph->surface_private == NULL) {
+	    status = intel_get_glyph (&device->intel, scaled_font, scaled_glyph);
+	    if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) {
+		status = CAIRO_STATUS_SUCCESS;
+		continue;
+	    }
+	    if (unlikely (status))
+		goto FINISH;
+	}
+	glyph = intel_glyph_pin (scaled_glyph->surface_private);
+
+	if (glyph->cache->buffer.bo != last_bo) {
+	    intel_buffer_cache_t *cache = glyph->cache;
+
+	    glyphs.shader.mask.type.vertex   = VS_GLYPHS;
+	    glyphs.shader.mask.type.fragment = FS_GLYPHS;
+	    glyphs.shader.mask.type.pattern  = PATTERN_BASE;
+
+	    glyphs.shader.mask.base.bo = cache->buffer.bo;
+	    glyphs.shader.mask.base.format = cache->buffer.format;
+	    glyphs.shader.mask.base.width  = cache->buffer.width;
+	    glyphs.shader.mask.base.height = cache->buffer.height;
+	    glyphs.shader.mask.base.stride = cache->buffer.stride;
+	    glyphs.shader.mask.base.filter = i965_filter (CAIRO_FILTER_NEAREST);
+	    glyphs.shader.mask.base.extend = i965_extend (CAIRO_EXTEND_NONE);
+	    glyphs.shader.mask.base.content = CAIRO_CONTENT_ALPHA; /* XXX */
+
+	    glyphs.shader.committed = FALSE;
+	    status = i965_shader_commit (&glyphs.shader, device);
+	    if (unlikely (status))
+		goto FINISH;
+
+	    last_bo = cache->buffer.bo;
+	}
+
+	x1 += mask_x; x2 += mask_x;
+	y1 += mask_y; y2 += mask_y;
+
+	i965_add_glyph_rectangle (&glyphs, x1, y1, x2, y2, glyph);
+    }
+
+    if (mask != NULL && clip_region != NULL) {
+	intel_bo_unmap (glyphs.tail->bo);
+	i965_clipped_vertices (device, &glyphs.head, clip_region);
+    }
+
+    status = CAIRO_STATUS_SUCCESS;
+  FINISH:
+    _cairo_scaled_font_thaw_cache (scaled_font);
+    cairo_device_release (surface->intel.drm.base.device);
+  CLEANUP_GLYPHS:
+    i965_shader_fini (&glyphs.shader);
+    if (glyphs.head.bo != NULL) {
+	struct i965_vbo *vbo, *next;
+
+	intel_bo_destroy (&device->intel, glyphs.head.bo);
+	for (vbo = glyphs.head.next; vbo != NULL; vbo = next) {
+	    next = vbo->next;
+	    intel_bo_destroy (&device->intel, vbo->bo);
+	    free (vbo);
+	}
+    }
+
+    if (unlikely (status == CAIRO_INT_STATUS_UNSUPPORTED)) {
+	cairo_path_fixed_t path;
+
+	_cairo_path_fixed_init (&path);
+	status = _cairo_scaled_font_glyph_path (scaled_font,
+						g + i, num_glyphs - i,
+						&path);
+	if (mask_x | mask_y) {
+	    _cairo_path_fixed_translate (&path,
+					 _cairo_fixed_from_int (mask_x),
+					 _cairo_fixed_from_int (mask_y));
+	}
+	if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	    status = surface->intel.drm.base.backend->fill (glyphs.shader.target,
+							    glyphs.shader.op,
+							    mask != NULL ? &_cairo_pattern_white.base : source,
+							    &path,
+							    CAIRO_FILL_RULE_WINDING,
+							    0,
+							    scaled_font->options.antialias,
+							    clip);
+	}
+	_cairo_path_fixed_fini (&path);
+    }
+
+    if (mask != NULL) {
+	if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	    status = i965_surface_mask_internal (surface, op, source, mask,
+					         clip, &extents);
+	}
+	cairo_surface_finish (&mask->intel.drm.base);
+	cairo_surface_destroy (&mask->intel.drm.base);
+    }
+
+    if (have_clip)
+	_cairo_clip_fini (&local_clip);
+
+    return status;
+}
diff --git a/src/drm/cairo-drm-i965-private.h b/src/drm/cairo-drm-i965-private.h
new file mode 100644
index 0000000..14fabe9
--- /dev/null
+++ b/src/drm/cairo-drm-i965-private.h
@@ -0,0 +1,742 @@
+#ifndef CAIRO_DRM_I965_PRIVATE_H
+#define CAIRO_DRM_I965_PRIVATE_H
+
+#include "cairo-drm-intel-private.h"
+
+#include "cairo-hash-private.h"
+#include "cairo-freelist-private.h"
+
+#include "cairo-drm-intel-brw-defines.h"
+
+#include <setjmp.h>
+
+#define BRW_MI_GLOBAL_SNAPSHOT_RESET   (1 << 3)
+
+/*
+ * New regs for broadwater -- we need to split this file up sensibly somehow.
+ */
+#define BRW_3D(Pipeline,Opcode,Subopcode) ((3 << 29) | \
+					   ((Pipeline) << 27) | \
+					   ((Opcode) << 24) | \
+					   ((Subopcode) << 16))
+
+#define BRW_URB_FENCE				BRW_3D(0, 0, 0)
+#define BRW_CS_URB_STATE			BRW_3D(0, 0, 1)
+#define BRW_CONSTANT_BUFFER			BRW_3D(0, 0, 2)
+#define BRW_STATE_PREFETCH			BRW_3D(0, 0, 3)
+
+#define BRW_STATE_BASE_ADDRESS			BRW_3D(0, 1, 1)
+#define BRW_STATE_SIP				BRW_3D(0, 1, 2)
+#define BRW_PIPELINE_SELECT			BRW_3D(0, 1, 4)
+
+#define NEW_PIPELINE_SELECT			BRW_3D(1, 1, 4)
+
+#define BRW_MEDIA_STATE_POINTERS		BRW_3D(2, 0, 0)
+#define BRW_MEDIA_OBJECT			BRW_3D(2, 1, 0)
+
+#define BRW_3DSTATE_PIPELINED_POINTERS		BRW_3D(3, 0, 0)
+#define BRW_3DSTATE_BINDING_TABLE_POINTERS	BRW_3D(3, 0, 1)
+#define BRW_3DSTATE_VERTEX_BUFFERS		BRW_3D(3, 0, 8)
+#define BRW_3DSTATE_VERTEX_ELEMENTS		BRW_3D(3, 0, 9)
+#define BRW_3DSTATE_INDEX_BUFFER		BRW_3D(3, 0, 0xa)
+#define BRW_3DSTATE_VF_STATISTICS		BRW_3D(3, 0, 0xb)
+
+#define BRW_3DSTATE_DRAWING_RECTANGLE		BRW_3D(3, 1, 0)
+#define BRW_3DSTATE_CONSTANT_COLOR		BRW_3D(3, 1, 1)
+#define BRW_3DSTATE_SAMPLER_PALETTE_LOAD	BRW_3D(3, 1, 2)
+#define BRW_3DSTATE_CHROMA_KEY			BRW_3D(3, 1, 4)
+#define BRW_3DSTATE_DEPTH_BUFFER		BRW_3D(3, 1, 5)
+#define BRW_3DSTATE_POLY_STIPPLE_OFFSET		BRW_3D(3, 1, 6)
+#define BRW_3DSTATE_POLY_STIPPLE_PATTERN	BRW_3D(3, 1, 7)
+#define BRW_3DSTATE_LINE_STIPPLE		BRW_3D(3, 1, 8)
+#define BRW_3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP	BRW_3D(3, 1, 9)
+/* These two are BLC and CTG only, not BW or CL */
+#define BRW_3DSTATE_AA_LINE_PARAMS		BRW_3D(3, 1, 0xa)
+#define BRW_3DSTATE_GS_SVB_INDEX		BRW_3D(3, 1, 0xb)
+
+#define BRW_PIPE_CONTROL			BRW_3D(3, 2, 0)
+
+#define BRW_3DPRIMITIVE				BRW_3D(3, 3, 0)
+
+#define PIPELINE_SELECT_3D		0
+#define PIPELINE_SELECT_MEDIA		1
+
+#define UF0_CS_REALLOC			(1 << 13)
+#define UF0_VFE_REALLOC			(1 << 12)
+#define UF0_SF_REALLOC			(1 << 11)
+#define UF0_CLIP_REALLOC		(1 << 10)
+#define UF0_GS_REALLOC			(1 << 9)
+#define UF0_VS_REALLOC			(1 << 8)
+#define UF1_CLIP_FENCE_SHIFT		20
+#define UF1_GS_FENCE_SHIFT		10
+#define UF1_VS_FENCE_SHIFT		0
+#define UF2_CS_FENCE_SHIFT		20
+#define UF2_VFE_FENCE_SHIFT		10
+#define UF2_SF_FENCE_SHIFT		0
+
+/* for BRW_STATE_BASE_ADDRESS */
+#define BASE_ADDRESS_MODIFY		(1 << 0)
+
+/* for BRW_3DSTATE_PIPELINED_POINTERS */
+#define BRW_GS_DISABLE		       0
+#define BRW_GS_ENABLE		       1
+#define BRW_CLIP_DISABLE	       0
+#define BRW_CLIP_ENABLE		       1
+
+/* for BRW_PIPE_CONTROL */
+#define BRW_PIPE_CONTROL_NOWRITE       (0 << 14)
+#define BRW_PIPE_CONTROL_WRITE_QWORD   (1 << 14)
+#define BRW_PIPE_CONTROL_WRITE_DEPTH   (2 << 14)
+#define BRW_PIPE_CONTROL_WRITE_TIME    (3 << 14)
+#define BRW_PIPE_CONTROL_DEPTH_STALL   (1 << 13)
+#define BRW_PIPE_CONTROL_WC_FLUSH      (1 << 12)
+#define BRW_PIPE_CONTROL_IS_FLUSH      (1 << 11)
+#define BRW_PIPE_CONTROL_NOTIFY_ENABLE (1 << 8)
+#define BRW_PIPE_CONTROL_GLOBAL_GTT    (1 << 2)
+#define BRW_PIPE_CONTROL_LOCAL_PGTT    (0 << 2)
+
+/* VERTEX_BUFFER_STATE Structure */
+#define VB0_BUFFER_INDEX_SHIFT		27
+#define VB0_VERTEXDATA			(0 << 26)
+#define VB0_INSTANCEDATA		(1 << 26)
+#define VB0_BUFFER_PITCH_SHIFT		0
+
+/* VERTEX_ELEMENT_STATE Structure */
+#define VE0_VERTEX_BUFFER_INDEX_SHIFT	27
+#define VE0_VALID			(1 << 26)
+#define VE0_FORMAT_SHIFT		16
+#define VE0_OFFSET_SHIFT		0
+#define VE1_VFCOMPONENT_0_SHIFT		28
+#define VE1_VFCOMPONENT_1_SHIFT		24
+#define VE1_VFCOMPONENT_2_SHIFT		20
+#define VE1_VFCOMPONENT_3_SHIFT		16
+#define VE1_DESTINATION_ELEMENT_OFFSET_SHIFT	0
+
+/* 3DPRIMITIVE bits */
+#define BRW_3DPRIMITIVE_VERTEX_SEQUENTIAL (0 << 15)
+#define BRW_3DPRIMITIVE_VERTEX_RANDOM	  (1 << 15)
+/* Primitive types are in brw_defines.h */
+#define BRW_3DPRIMITIVE_TOPOLOGY_SHIFT	  10
+
+#define BRW_SVG_CTL		       0x7400
+
+#define BRW_SVG_CTL_GS_BA	       (0 << 8)
+#define BRW_SVG_CTL_SS_BA	       (1 << 8)
+#define BRW_SVG_CTL_IO_BA	       (2 << 8)
+#define BRW_SVG_CTL_GS_AUB	       (3 << 8)
+#define BRW_SVG_CTL_IO_AUB	       (4 << 8)
+#define BRW_SVG_CTL_SIP		       (5 << 8)
+
+#define BRW_SVG_RDATA		       0x7404
+#define BRW_SVG_WORK_CTL	       0x7408
+
+#define BRW_VF_CTL		       0x7500
+
+#define BRW_VF_CTL_SNAPSHOT_COMPLETE		   (1 << 31)
+#define BRW_VF_CTL_SNAPSHOT_MUX_SELECT_THREADID	   (0 << 8)
+#define BRW_VF_CTL_SNAPSHOT_MUX_SELECT_VF_DEBUG	   (1 << 8)
+#define BRW_VF_CTL_SNAPSHOT_TYPE_VERTEX_SEQUENCE   (0 << 4)
+#define BRW_VF_CTL_SNAPSHOT_TYPE_VERTEX_INDEX	   (1 << 4)
+#define BRW_VF_CTL_SKIP_INITIAL_PRIMITIVES	   (1 << 3)
+#define BRW_VF_CTL_MAX_PRIMITIVES_LIMIT_ENABLE	   (1 << 2)
+#define BRW_VF_CTL_VERTEX_RANGE_LIMIT_ENABLE	   (1 << 1)
+#define BRW_VF_CTL_SNAPSHOT_ENABLE	     	   (1 << 0)
+
+#define BRW_VF_STRG_VAL		       0x7504
+#define BRW_VF_STR_VL_OVR	       0x7508
+#define BRW_VF_VC_OVR		       0x750c
+#define BRW_VF_STR_PSKIP	       0x7510
+#define BRW_VF_MAX_PRIM		       0x7514
+#define BRW_VF_RDATA		       0x7518
+
+#define BRW_VS_CTL		       0x7600
+#define BRW_VS_CTL_SNAPSHOT_COMPLETE		   (1 << 31)
+#define BRW_VS_CTL_SNAPSHOT_MUX_VERTEX_0	   (0 << 8)
+#define BRW_VS_CTL_SNAPSHOT_MUX_VERTEX_1	   (1 << 8)
+#define BRW_VS_CTL_SNAPSHOT_MUX_VALID_COUNT	   (2 << 8)
+#define BRW_VS_CTL_SNAPSHOT_MUX_VS_KERNEL_POINTER  (3 << 8)
+#define BRW_VS_CTL_SNAPSHOT_ALL_THREADS		   (1 << 2)
+#define BRW_VS_CTL_THREAD_SNAPSHOT_ENABLE	   (1 << 1)
+#define BRW_VS_CTL_SNAPSHOT_ENABLE		   (1 << 0)
+
+#define BRW_VS_STRG_VAL		       0x7604
+#define BRW_VS_RDATA		       0x7608
+
+#define BRW_SF_CTL		       0x7b00
+#define BRW_SF_CTL_SNAPSHOT_COMPLETE		   (1 << 31)
+#define BRW_SF_CTL_SNAPSHOT_MUX_VERTEX_0_FF_ID	   (0 << 8)
+#define BRW_SF_CTL_SNAPSHOT_MUX_VERTEX_0_REL_COUNT (1 << 8)
+#define BRW_SF_CTL_SNAPSHOT_MUX_VERTEX_1_FF_ID	   (2 << 8)
+#define BRW_SF_CTL_SNAPSHOT_MUX_VERTEX_1_REL_COUNT (3 << 8)
+#define BRW_SF_CTL_SNAPSHOT_MUX_VERTEX_2_FF_ID	   (4 << 8)
+#define BRW_SF_CTL_SNAPSHOT_MUX_VERTEX_2_REL_COUNT (5 << 8)
+#define BRW_SF_CTL_SNAPSHOT_MUX_VERTEX_COUNT	   (6 << 8)
+#define BRW_SF_CTL_SNAPSHOT_MUX_SF_KERNEL_POINTER  (7 << 8)
+#define BRW_SF_CTL_MIN_MAX_PRIMITIVE_RANGE_ENABLE  (1 << 4)
+#define BRW_SF_CTL_DEBUG_CLIP_RECTANGLE_ENABLE	   (1 << 3)
+#define BRW_SF_CTL_SNAPSHOT_ALL_THREADS		   (1 << 2)
+#define BRW_SF_CTL_THREAD_SNAPSHOT_ENABLE	   (1 << 1)
+#define BRW_SF_CTL_SNAPSHOT_ENABLE		   (1 << 0)
+
+#define BRW_SF_STRG_VAL		       0x7b04
+#define BRW_SF_RDATA		       0x7b18
+
+#define BRW_WIZ_CTL		       0x7c00
+#define BRW_WIZ_CTL_SNAPSHOT_COMPLETE		   (1 << 31)
+#define BRW_WIZ_CTL_SUBSPAN_INSTANCE_SHIFT	   16
+#define BRW_WIZ_CTL_SNAPSHOT_MUX_WIZ_KERNEL_POINTER   (0 << 8)
+#define BRW_WIZ_CTL_SNAPSHOT_MUX_SUBSPAN_INSTANCE     (1 << 8)
+#define BRW_WIZ_CTL_SNAPSHOT_MUX_PRIMITIVE_SEQUENCE   (2 << 8)
+#define BRW_WIZ_CTL_SINGLE_SUBSPAN_DISPATCH	      (1 << 6)
+#define BRW_WIZ_CTL_IGNORE_COLOR_SCOREBOARD_STALLS    (1 << 5)
+#define BRW_WIZ_CTL_ENABLE_SUBSPAN_INSTANCE_COMPARE   (1 << 4)
+#define BRW_WIZ_CTL_USE_UPSTREAM_SNAPSHOT_FLAG	      (1 << 3)
+#define BRW_WIZ_CTL_SNAPSHOT_ALL_THREADS	      (1 << 2)
+#define BRW_WIZ_CTL_THREAD_SNAPSHOT_ENABLE	      (1 << 1)
+#define BRW_WIZ_CTL_SNAPSHOT_ENABLE		      (1 << 0)
+
+#define BRW_WIZ_STRG_VAL			      0x7c04
+#define BRW_WIZ_RDATA				      0x7c18
+
+#define BRW_TS_CTL		       0x7e00
+#define BRW_TS_CTL_SNAPSHOT_COMPLETE		   (1 << 31)
+#define BRW_TS_CTL_SNAPSHOT_MESSAGE_ERROR	   (0 << 8)
+#define BRW_TS_CTL_SNAPSHOT_INTERFACE_DESCRIPTOR   (3 << 8)
+#define BRW_TS_CTL_SNAPSHOT_ALL_CHILD_THREADS	   (1 << 2)
+#define BRW_TS_CTL_SNAPSHOT_ALL_ROOT_THREADS  	   (1 << 1)
+#define BRW_TS_CTL_SNAPSHOT_ENABLE		   (1 << 0)
+
+#define BRW_TS_STRG_VAL		       0x7e04
+#define BRW_TS_RDATA		       0x7e08
+
+#define BRW_TD_CTL		       0x8000
+#define BRW_TD_CTL_MUX_SHIFT	       8
+#define BRW_TD_CTL_EXTERNAL_HALT_R0_DEBUG_MATCH	   (1 << 7)
+#define BRW_TD_CTL_FORCE_EXTERNAL_HALT		   (1 << 6)
+#define BRW_TD_CTL_EXCEPTION_MASK_OVERRIDE	   (1 << 5)
+#define BRW_TD_CTL_FORCE_THREAD_BREAKPOINT_ENABLE  (1 << 4)
+#define BRW_TD_CTL_BREAKPOINT_ENABLE		   (1 << 2)
+#define BRW_TD_CTL2		       0x8004
+#define BRW_TD_CTL2_ILLEGAL_OPCODE_EXCEPTION_OVERRIDE (1 << 28)
+#define BRW_TD_CTL2_MASKSTACK_EXCEPTION_OVERRIDE      (1 << 26)
+#define BRW_TD_CTL2_SOFTWARE_EXCEPTION_OVERRIDE	      (1 << 25)
+#define BRW_TD_CTL2_ACTIVE_THREAD_LIMIT_SHIFT	      16
+#define BRW_TD_CTL2_ACTIVE_THREAD_LIMIT_ENABLE	      (1 << 8)
+#define BRW_TD_CTL2_THREAD_SPAWNER_EXECUTION_MASK_ENABLE (1 << 7)
+#define BRW_TD_CTL2_WIZ_EXECUTION_MASK_ENABLE	      (1 << 6)
+#define BRW_TD_CTL2_SF_EXECUTION_MASK_ENABLE	      (1 << 5)
+#define BRW_TD_CTL2_CLIPPER_EXECUTION_MASK_ENABLE     (1 << 4)
+#define BRW_TD_CTL2_GS_EXECUTION_MASK_ENABLE	      (1 << 3)
+#define BRW_TD_CTL2_VS_EXECUTION_MASK_ENABLE	      (1 << 0)
+#define BRW_TD_VF_VS_EMSK	       0x8008
+#define BRW_TD_GS_EMSK		       0x800c
+#define BRW_TD_CLIP_EMSK	       0x8010
+#define BRW_TD_SF_EMSK		       0x8014
+#define BRW_TD_WIZ_EMSK		       0x8018
+#define BRW_TD_0_6_EHTRG_VAL	       0x801c
+#define BRW_TD_0_7_EHTRG_VAL	       0x8020
+#define BRW_TD_0_6_EHTRG_MSK           0x8024
+#define BRW_TD_0_7_EHTRG_MSK	       0x8028
+#define BRW_TD_RDATA		       0x802c
+#define BRW_TD_TS_EMSK		       0x8030
+
+#define BRW_EU_CTL		       0x8800
+#define BRW_EU_CTL_SELECT_SHIFT	       16
+#define BRW_EU_CTL_DATA_MUX_SHIFT      8
+#define BRW_EU_ATT_0		       0x8810
+#define BRW_EU_ATT_1		       0x8814
+#define BRW_EU_ATT_DATA_0	       0x8820
+#define BRW_EU_ATT_DATA_1	       0x8824
+#define BRW_EU_ATT_CLR_0	       0x8830
+#define BRW_EU_ATT_CLR_1	       0x8834
+#define BRW_EU_RDATA		       0x8840
+
+typedef struct i965_device i965_device_t;
+typedef struct i965_surface i965_surface_t;
+typedef struct i965_shader i965_shader_t;
+typedef struct i965_stream i965_stream_t;
+
+struct i965_sf_state {
+    cairo_hash_entry_t entry;
+    uint32_t offset;
+};
+
+cairo_private cairo_bool_t
+i965_sf_state_equal (const void *, const void *);
+
+struct i965_cc_state {
+    cairo_hash_entry_t entry;
+    uint32_t offset;
+};
+
+cairo_private cairo_bool_t
+i965_cc_state_equal (const void *, const void *);
+
+struct i965_wm_kernel {
+    cairo_hash_entry_t entry;
+    uint32_t offset;
+};
+
+struct i965_wm_state {
+    cairo_hash_entry_t entry;
+    uint32_t kernel;
+    uint32_t sampler;
+    uint32_t offset;
+};
+
+cairo_private cairo_bool_t
+i965_wm_state_equal (const void *, const void *);
+
+struct i965_wm_binding {
+    cairo_hash_entry_t entry;
+    uint32_t table[4];
+    int size;
+    uint32_t offset;
+};
+
+cairo_private cairo_bool_t
+i965_wm_binding_equal (const void *, const void *);
+
+struct i965_sampler {
+    cairo_hash_entry_t entry;
+    uint32_t offset;
+};
+
+struct i965_vbo {
+    struct i965_vbo *next;
+    intel_bo_t *bo;
+    unsigned int count;
+};
+
+struct i965_surface {
+    intel_surface_t intel;
+
+    uint32_t stream;
+    uint32_t offset;
+};
+
+struct i965_pending_relocation {
+    uint32_t offset;
+    uint32_t read_domains;
+    uint32_t write_domain;
+    uint32_t delta;
+};
+
+struct i965_stream {
+    uint32_t used;
+    uint32_t committed;
+    uint32_t size;
+    uint8_t *data;
+    uint32_t serial;
+
+    int num_pending_relocations;
+    int max_pending_relocations;
+    struct i965_pending_relocation *pending_relocations;
+
+    int num_relocations;
+    int max_relocations;
+    struct drm_i915_gem_relocation_entry *relocations;
+};
+
+#define I965_BATCH_SIZE (16 * 4096)
+#define I965_SURFACE_SIZE (16 * 4096)
+#define I965_GENERAL_SIZE (16 * 4096)
+#define I965_CONSTANT_SIZE (16 * 4096)
+#define I965_VERTEX_SIZE (128 * 4096)
+
+#define I965_TILING_DEFAULT I915_TILING_Y
+
+
+struct i965_device {
+    intel_device_t intel;
+
+    cairo_bool_t is_g4x;
+
+    i965_shader_t *shader; /* note: only valid during geometry emission */
+
+    /* track state changes */
+    struct i965_sf_state sf_state;
+    struct i965_cc_state cc_state;
+    struct i965_wm_state wm_state;
+    struct i965_wm_binding wm_binding;
+
+    i965_surface_t *target;
+    uint32_t target_offset;
+
+    intel_bo_t *source;
+    uint32_t source_offset;
+
+    intel_bo_t *mask;
+    uint32_t mask_offset;
+
+    intel_bo_t *clip;
+    uint32_t clip_offset;
+
+    uint32_t draw_rectangle;
+
+    uint32_t vs_offset;
+    uint32_t border_color_offset;
+    cairo_hash_table_t *sf_states;
+    cairo_hash_table_t *cc_states;
+    cairo_hash_table_t *wm_kernels;
+    cairo_hash_table_t *wm_states;
+    cairo_hash_table_t *wm_bindings;
+    cairo_hash_table_t *samplers;
+    intel_bo_t *general_state;
+
+    cairo_freelist_t sf_freelist;
+    cairo_freelist_t cc_freelist;
+    cairo_freelist_t wm_kernel_freelist;
+    cairo_freelist_t wm_state_freelist;
+    cairo_freelist_t wm_binding_freelist;
+    cairo_freelist_t sampler_freelist;
+
+    uint32_t vertex_type;
+    uint32_t vertex_size;
+    uint32_t rectangle_size;
+    uint32_t last_vertex_size;
+
+    float *constants; /* 4 x matrix + 2 x source */
+    unsigned constants_size;
+    cairo_bool_t have_urb_fences;
+
+    i965_stream_t batch;
+    uint8_t batch_base[I965_BATCH_SIZE];
+    struct drm_i915_gem_relocation_entry batch_relocations[1024];
+
+    i965_stream_t surface;
+    uint8_t surface_base[I965_SURFACE_SIZE];
+    struct i965_pending_relocation surface_pending_relocations[1];
+    struct drm_i915_gem_relocation_entry surface_relocations[512];
+
+    i965_stream_t general;
+    uint8_t general_base[I965_GENERAL_SIZE];
+    struct i965_pending_relocation general_pending_relocations[1];
+
+    i965_stream_t vertex;
+    uint8_t vertex_base[I965_VERTEX_SIZE];
+    struct i965_pending_relocation vertex_pending_relocations[512];
+
+    i965_stream_t constant;
+    uint8_t constant_base[I965_CONSTANT_SIZE];
+    struct i965_pending_relocation constant_pending_relocations[512];
+
+    struct {
+	size_t gtt_size;
+
+	intel_bo_t *bo[1024];
+	int count;
+
+	struct drm_i915_gem_exec_object2 exec[1024];
+    } exec;
+    cairo_list_t flush;
+};
+
+typedef enum {
+    VS_NONE = 0,
+    VS_GLYPHS,
+    VS_SPANS,
+} i965_vertex_shader_t;
+
+typedef enum {
+    FS_NONE = 0,
+    FS_CONSTANT,
+    FS_LINEAR,
+    FS_RADIAL,
+    FS_SURFACE,
+    FS_GLYPHS,
+    FS_SPANS,
+} i965_fragment_shader_t;
+
+typedef enum {
+    PATTERN_BASE,
+    PATTERN_SOLID,
+    PATTERN_LINEAR,
+    PATTERN_RADIAL,
+    PATTERN_SURFACE,
+} i965_shader_channel_t;
+#define PATTERN_NONE (i965_shader_channel_t)-1
+
+struct i965_shader {
+    i965_device_t *device;
+    i965_surface_t *target;
+
+    cairo_operator_t op;
+
+    cairo_bool_t committed;
+    cairo_bool_t need_combine;
+
+    float constants[4*8 + 2*8]; /* 4 x matrix + 2 x source */
+    unsigned constants_size;
+
+    union i965_shader_channel {
+	struct {
+	    i965_vertex_shader_t vertex;
+	    i965_fragment_shader_t fragment;
+	    i965_shader_channel_t pattern;
+	} type;
+	struct i965_shader_base {
+	    i965_vertex_shader_t vertex;
+	    i965_fragment_shader_t fragment;
+	    i965_shader_channel_t pattern;
+
+	    uint32_t mode;
+
+	    float constants[8];
+	    unsigned constants_size;
+
+	    intel_bo_t *bo;
+	    cairo_format_t format;
+	    cairo_content_t content;
+	    int width, height, stride;
+	    int filter, extend;
+	    cairo_matrix_t matrix;
+	    cairo_bool_t has_component_alpha;
+	} base;
+	struct i965_shader_solid {
+	    struct i965_shader_base base;
+	} solid;
+	struct i965_shader_linear {
+	    struct i965_shader_base base;
+	} linear;
+	struct i965_shader_radial {
+	    struct i965_shader_base base;
+	} radial;
+	struct i965_shader_surface {
+	    struct i965_shader_base base;
+	    cairo_surface_t *surface;
+	} surface;
+    } source, mask, clip, dst;
+
+    jmp_buf unwind;
+};
+
+enum i965_shader_linear_mode {
+    /* XXX REFLECT */
+    LINEAR_TEXTURE,
+    LINEAR_NONE,
+    LINEAR_REPEAT,
+    LINEAR_PAD,
+};
+
+enum i965_shader_radial_mode {
+    RADIAL_ONE,
+    RADIAL_TWO
+};
+
+typedef cairo_status_t
+(*i965_spans_func_t) (void			*closure,
+		      cairo_span_renderer_t	*renderer,
+		      const cairo_rectangle_int_t	*extents);
+
+static inline i965_device_t *
+i965_device (i965_surface_t *surface)
+{
+    return (i965_device_t *) surface->intel.drm.base.device;
+}
+
+cairo_private void
+i965_emit_relocation (i965_device_t *device,
+		      i965_stream_t *stream,
+		      intel_bo_t *target,
+		      uint32_t target_offset,
+		      uint32_t read_domains,
+		      uint32_t write_domain,
+		      uint32_t offset);
+
+static always_inline uint32_t
+i965_stream_emit (i965_stream_t *stream, const void *data, size_t size)
+{
+    uint32_t offset;
+
+    offset = stream->used;
+    assert (offset + size <= stream->size);
+    memcpy (stream->data + offset, data, size);
+    stream->used += size;
+
+    return offset;
+}
+
+static always_inline void
+i965_stream_align (i965_stream_t *stream, uint32_t size)
+{
+    stream->used = (stream->used + size - 1) & -size;
+}
+
+static always_inline void *
+i965_stream_alloc (i965_stream_t *stream, uint32_t align, uint32_t size)
+{
+    void *ptr;
+
+    if (align)
+	i965_stream_align (stream, align);
+
+    assert (stream->used + size <= stream->size);
+    ptr = stream->data + stream->used;
+    stream->used += size;
+
+    return ptr;
+}
+
+static always_inline uint32_t
+i965_stream_offsetof (i965_stream_t *stream, const void *ptr)
+{
+    return (char *) ptr - (char *) stream->data;
+}
+
+cairo_private void
+i965_stream_commit (i965_device_t *device,
+		    i965_stream_t *stream);
+
+cairo_private void
+i965_general_state_reset (i965_device_t *device);
+
+static inline void
+i965_batch_emit_dword (i965_device_t *device, uint32_t dword)
+{
+    *(uint32_t *) (device->batch.data + device->batch.used) = dword;
+    device->batch.used += 4;
+}
+
+#define OUT_BATCH(dword) i965_batch_emit_dword(device, dword)
+
+cairo_private void
+i965_clipped_vertices (i965_device_t *device,
+		       struct i965_vbo *vbo,
+		       cairo_region_t *clip_region);
+
+cairo_private void
+i965_flush_vertices (i965_device_t *device);
+
+cairo_private void
+i965_finish_vertices (i965_device_t *device);
+
+static inline float *
+i965_add_rectangle (i965_device_t *device)
+{
+    float *vertices;
+    uint32_t size;
+
+    size = device->rectangle_size;
+    if (unlikely (device->vertex.used + size > device->vertex.size))
+	i965_finish_vertices (device);
+
+    vertices = (float *) (device->vertex.data + device->vertex.used);
+    device->vertex.used += size;
+
+    return vertices;
+}
+
+static inline void
+i965_shader_add_rectangle (const i965_shader_t *shader,
+			   int x, int y,
+			   int w, int h)
+{
+    float *v;
+
+    v= i965_add_rectangle (shader->device);
+
+    /* bottom-right */
+    *v++ = x + w;
+    *v++ = y + h;
+
+    /* bottom-left */
+    *v++ = x;
+    *v++ = y + h;
+
+    /* top-left */
+    *v++ = x;
+    *v++ = y;
+}
+
+cairo_private cairo_surface_t *
+i965_surface_create_internal (cairo_drm_device_t *base_dev,
+		              cairo_content_t content,
+			      int width, int height,
+			      uint32_t tiling,
+			      cairo_bool_t gpu_target);
+
+cairo_private cairo_status_t
+i965_clip_and_composite_spans (i965_surface_t		*dst,
+			       cairo_operator_t		 op,
+			       const cairo_pattern_t	*pattern,
+			       cairo_antialias_t	 antialias,
+			       i965_spans_func_t	 draw_func,
+			       void			*draw_closure,
+			       const cairo_composite_rectangles_t*extents,
+			       cairo_clip_t		*clip);
+
+cairo_private cairo_int_status_t
+i965_surface_glyphs (void			*abstract_surface,
+		     cairo_operator_t		 op,
+		     const cairo_pattern_t	*source,
+		     cairo_glyph_t		*glyphs,
+		     int			 num_glyphs,
+		     cairo_scaled_font_t	*scaled_font,
+		     cairo_clip_t		*clip,
+		     int *num_remaining);
+
+cairo_private void
+i965_shader_init (i965_shader_t *shader,
+		  i965_surface_t *dst,
+		  cairo_operator_t op);
+
+cairo_private cairo_status_t
+i965_shader_acquire_pattern (i965_shader_t *shader,
+			     union i965_shader_channel *src,
+			     const cairo_pattern_t *pattern,
+			     const cairo_rectangle_int_t *extents);
+
+cairo_private void
+i965_shader_set_clip (i965_shader_t *shader,
+		      cairo_clip_t *clip);
+
+cairo_private cairo_status_t
+i965_shader_commit (i965_shader_t *shader,
+		    i965_device_t *device);
+
+cairo_private void
+i965_shader_fini (i965_shader_t *shader);
+
+cairo_private cairo_status_t
+i965_device_flush (i965_device_t *device);
+
+cairo_private cairo_status_t
+i965_fixup_unbounded (i965_surface_t *dst,
+		      const cairo_composite_rectangles_t *extents,
+		      cairo_clip_t *clip);
+
+static inline int
+i965_filter (cairo_filter_t filter)
+{
+    switch (filter) {
+    default:
+    case CAIRO_FILTER_FAST:
+    case CAIRO_FILTER_NEAREST:
+	return BRW_MAPFILTER_NEAREST;
+
+    case CAIRO_FILTER_GOOD:
+    case CAIRO_FILTER_BEST:
+    case CAIRO_FILTER_BILINEAR:
+    case CAIRO_FILTER_GAUSSIAN:
+	return BRW_MAPFILTER_LINEAR;
+    }
+}
+
+static inline int
+i965_extend (cairo_extend_t extend)
+{
+    switch (extend) {
+    default:
+    case CAIRO_EXTEND_NONE:
+	return BRW_TEXCOORDMODE_CLAMP_BORDER;
+    case CAIRO_EXTEND_REPEAT:
+	return BRW_TEXCOORDMODE_WRAP;
+    case CAIRO_EXTEND_PAD:
+	return BRW_TEXCOORDMODE_CLAMP;
+    case CAIRO_EXTEND_REFLECT:
+	return BRW_TEXCOORDMODE_MIRROR;
+    }
+}
+
+#endif /* CAIRO_DRM_I965_PRIVATE_H */
diff --git a/src/drm/cairo-drm-i965-shader.c b/src/drm/cairo-drm-i965-shader.c
new file mode 100644
index 0000000..fc9ae57
--- /dev/null
+++ b/src/drm/cairo-drm-i965-shader.c
@@ -0,0 +1,2852 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Kristian Høgsberg
+ * Copyright © 2009 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ *      Kristian Høgsberg <krh at bitplanet.net>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-error-private.h"
+#include "cairo-drm-i965-private.h"
+#include "cairo-surface-subsurface-private.h"
+#include "cairo-surface-snapshot-private.h"
+
+#include "cairo-drm-intel-brw-eu.h"
+
+#if CAIRO_HAS_XCB_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+/* for DRI2/DRM interoperability */
+#include "cairo-xcb-private.h"
+#endif
+
+/* Theory of shaders:
+ *
+ * 3 types of rectangular inputs:
+ *  (a) standard composite: x,y, use source, mask matrices to compute texcoords
+ *  (b) spans: x,y, alpha, use source matrix
+ *  (c) glyphs: x,y, s,t, use source matrix
+ *
+ * 5 types of pixel shaders:
+ *  (a) Solid colour
+ *  (b) Linear gradient (via 1D texture, with precomputed tex)
+ *  (c) Radial gradient (per-pixel s computation, 1D texture)
+ *  (d) Spans (mask only): apply opacity
+ *  (e) Texture (includes glyphs).
+ *
+ *  Clip masks are limited to 2D textures only.
+ */
+
+/* XXX dual source blending for LERP + ComponentAlpha!!! */
+
+#define BRW_GRF_BLOCKS(nreg)    ((nreg + 15) / 16 - 1)
+
+#define SF_KERNEL_NUM_GRF  1
+#define SF_MAX_THREADS	   24
+
+#define PS_MAX_THREADS_CTG 50
+#define PS_MAX_THREADS_BRW 32
+
+#define URB_CS_ENTRY_SIZE     3 /* We need 4 matrices + 2 sources */
+#define URB_CS_ENTRIES	      4 /* 4x sets of CONSTANT_BUFFER */
+
+#define URB_VS_ENTRY_SIZE     1
+#define URB_VS_ENTRIES	      8
+
+#define URB_GS_ENTRY_SIZE     0
+#define URB_GS_ENTRIES	      0
+
+#define URB_CLIP_ENTRY_SIZE   0
+#define URB_CLIP_ENTRIES      0
+
+#define URB_SF_ENTRY_SIZE     1
+#define URB_SF_ENTRIES	      (SF_MAX_THREADS + 1)
+
+static void
+i965_pipelined_flush (i965_device_t *device)
+{
+    intel_bo_t *bo, *next;
+
+    if (device->batch.used == 0)
+	return;
+
+    OUT_BATCH (BRW_PIPE_CONTROL |
+	       BRW_PIPE_CONTROL_NOWRITE |
+	       BRW_PIPE_CONTROL_WC_FLUSH |
+	       2);
+    OUT_BATCH(0);   /* Destination address */ 
+    OUT_BATCH(0);   /* Immediate data low DW */ 
+    OUT_BATCH(0);   /* Immediate data high DW */ 
+
+    cairo_list_foreach_entry_safe (bo, next, intel_bo_t, &device->flush, link) {
+	bo->batch_write_domain = 0;
+	cairo_list_init (&bo->link);
+    }
+    cairo_list_init (&device->flush);
+}
+
+static cairo_status_t
+i965_shader_acquire_solid (i965_shader_t *shader,
+			   union i965_shader_channel *src,
+			   const cairo_solid_pattern_t *solid,
+			   const cairo_rectangle_int_t *extents)
+{
+    src->type.fragment = FS_CONSTANT;
+    src->type.vertex = VS_NONE;
+    src->type.pattern = PATTERN_SOLID;
+
+    src->base.content = solid->content;
+    if (CAIRO_COLOR_IS_OPAQUE(&solid->color))
+	src->base.content &= ~CAIRO_CONTENT_ALPHA;
+
+    src->base.constants[0] = solid->color.red   * solid->color.alpha;
+    src->base.constants[1] = solid->color.green * solid->color.alpha;
+    src->base.constants[2] = solid->color.blue  * solid->color.alpha;
+    src->base.constants[3] = solid->color.alpha;
+    src->base.constants_size = 4;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_shader_acquire_linear (i965_shader_t *shader,
+			    union i965_shader_channel *src,
+			    const cairo_linear_pattern_t *linear,
+			    const cairo_rectangle_int_t *extents)
+{
+    intel_buffer_t buffer;
+    cairo_status_t status;
+    double x0, y0, sf;
+    double dx, dy, offset;
+
+    status = intel_gradient_render (&i965_device (shader->target)->intel,
+				    &linear->base, &buffer);
+    if (unlikely (status))
+	return status;
+
+    src->type.vertex = VS_NONE;
+    src->type.pattern = PATTERN_LINEAR;
+    src->type.fragment = FS_LINEAR;
+    src->base.bo = buffer.bo;
+    src->base.content = CAIRO_CONTENT_COLOR_ALPHA;
+    src->base.format = buffer.format;
+    src->base.width  = buffer.width;
+    src->base.height = buffer.height;
+    src->base.stride = buffer.stride;
+    src->base.filter = i965_filter (CAIRO_FILTER_BILINEAR);
+    src->base.extend = i965_extend (linear->base.base.extend);
+
+    dx = _cairo_fixed_to_double (linear->p2.x - linear->p1.x);
+    dy = _cairo_fixed_to_double (linear->p2.y - linear->p1.y);
+    sf = 1. / (dx * dx + dy * dy);
+    dx *= sf;
+    dy *= sf;
+
+    x0 = _cairo_fixed_to_double (linear->p1.x);
+    y0 = _cairo_fixed_to_double (linear->p1.y);
+    offset = dx*x0 + dy*y0;
+
+    if (_cairo_matrix_is_identity (&linear->base.base.matrix)) {
+	src->base.matrix.xx = dx;
+	src->base.matrix.xy = dy;
+	src->base.matrix.x0 = -offset;
+    } else {
+	cairo_matrix_t m;
+
+	cairo_matrix_init (&m, dx, 0, dy, 0, -offset, 0);
+	cairo_matrix_multiply (&src->base.matrix, &linear->base.base.matrix, &m);
+    }
+    src->base.matrix.yx = 0.;
+    src->base.matrix.yy = 1.;
+    src->base.matrix.y0 = 0.;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_shader_acquire_radial (i965_shader_t *shader,
+			    union i965_shader_channel *src,
+			    const cairo_radial_pattern_t *radial,
+			    const cairo_rectangle_int_t *extents)
+{
+    intel_buffer_t buffer;
+    cairo_status_t status;
+    double dx, dy, dr, r1;
+
+    status = intel_gradient_render (&i965_device (shader->target)->intel,
+				    &radial->base, &buffer);
+    if (unlikely (status))
+	return status;
+
+    src->type.vertex = VS_NONE;
+    src->type.pattern = PATTERN_RADIAL;
+    src->type.fragment = FS_RADIAL;
+    src->base.bo = buffer.bo;
+    src->base.content = CAIRO_CONTENT_COLOR_ALPHA;
+    src->base.format = buffer.format;
+    src->base.width  = buffer.width;
+    src->base.height = buffer.height;
+    src->base.stride = buffer.stride;
+    src->base.filter = i965_filter (CAIRO_FILTER_BILINEAR);
+    src->base.extend = i965_extend (radial->base.base.extend);
+
+    dx = _cairo_fixed_to_double (radial->c2.x - radial->c1.x);
+    dy = _cairo_fixed_to_double (radial->c2.y - radial->c1.y);
+    dr = _cairo_fixed_to_double (radial->r2 - radial->r1);
+
+    r1 = _cairo_fixed_to_double (radial->r1);
+
+    if (FALSE && radial->c2.x == radial->c1.x && radial->c2.y == radial->c1.y) {
+	/* XXX dr == 0, meaningless with anything other than PAD */
+	src->base.constants[0] = _cairo_fixed_to_double (radial->c1.x) / dr;
+	src->base.constants[1] = _cairo_fixed_to_double (radial->c1.y) / dr;
+	src->base.constants[2] = 1. / dr;
+	src->base.constants[3] = -r1 / dr;
+
+	src->base.constants_size = 4;
+	src->base.mode = RADIAL_ONE;
+    } else {
+	src->base.constants[0] = -_cairo_fixed_to_double (radial->c1.x);
+	src->base.constants[1] = -_cairo_fixed_to_double (radial->c1.y);
+	src->base.constants[2] = r1;
+	src->base.constants[3] = -4 * (dx*dx + dy*dy - dr*dr);
+
+	src->base.constants[4] = -2 * dx;
+	src->base.constants[5] = -2 * dy;
+	src->base.constants[6] = -2 * r1 * dr;
+	src->base.constants[7] = 1 / (2 * (dx*dx + dy*dy - dr*dr));
+
+	src->base.constants_size = 8;
+	src->base.mode = RADIAL_TWO;
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_surface_clone (i965_device_t *device,
+		    cairo_image_surface_t *image,
+		    i965_surface_t **clone_out)
+{
+    i965_surface_t *clone;
+    cairo_status_t status;
+
+    clone = (i965_surface_t *)
+	i965_surface_create_internal (&device->intel.base,
+				      image->base.content,
+				      image->width,
+				      image->height,
+				      I965_TILING_DEFAULT,
+				      FALSE);
+    if (unlikely (clone->intel.drm.base.status))
+	return clone->intel.drm.base.status;
+
+    status = intel_bo_put_image (&device->intel,
+				 to_intel_bo (clone->intel.drm.bo),
+				 clone->intel.drm.stride,
+				 image,
+				 0, 0,
+				 image->width, image->height,
+				 0, 0);
+
+    if (unlikely (status)) {
+	cairo_surface_destroy (&clone->intel.drm.base);
+	return status;
+    }
+
+    status = _cairo_surface_attach_snapshot (&image->base,
+					     &clone->intel.drm.base,
+					     intel_surface_detach_snapshot);
+    if (likely (status == CAIRO_STATUS_SUCCESS))
+	status = intel_snapshot_cache_insert (&device->intel, &clone->intel);
+
+    if (unlikely (status)) {
+	cairo_surface_destroy (&clone->intel.drm.base);
+	return status;
+    }
+
+    *clone_out = clone;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_surface_clone_subimage (i965_device_t *device,
+			     cairo_image_surface_t *image,
+			     const cairo_rectangle_int_t *extents,
+			     i965_surface_t **clone_out)
+{
+    i965_surface_t *clone;
+    cairo_status_t status;
+
+    clone = (i965_surface_t *)
+	i965_surface_create_internal (&device->intel.base,
+				      image->base.content,
+				      extents->width,
+				      extents->height,
+				      I965_TILING_DEFAULT,
+				      FALSE);
+    if (unlikely (clone->intel.drm.base.status))
+	return clone->intel.drm.base.status;
+
+    status = intel_bo_put_image (to_intel_device (clone->intel.drm.base.device),
+				 to_intel_bo (clone->intel.drm.bo),
+				 clone->intel.drm.stride,
+				 image,
+				 extents->x, extents->y,
+				 extents->width, extents->height,
+				 0, 0);
+    if (unlikely (status))
+	return status;
+
+    *clone_out = clone;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_shader_acquire_solid_surface (i965_shader_t *shader,
+				   union i965_shader_channel *src,
+				   cairo_surface_t *surface,
+				   const cairo_rectangle_int_t *extents)
+{
+    cairo_image_surface_t *image;
+    void *image_extra;
+    cairo_status_t status;
+    uint32_t argb;
+
+    status = _cairo_surface_acquire_source_image (surface, &image, &image_extra);
+    if (unlikely (status))
+	return status;
+
+    if (image->format != CAIRO_FORMAT_ARGB32) {
+	cairo_surface_t *pixel;
+	cairo_surface_pattern_t pattern;
+
+	/* extract the pixel as argb32 */
+	pixel = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
+	_cairo_pattern_init_for_surface (&pattern, &image->base);
+	cairo_matrix_init_translate (&pattern.base.matrix, extents->x, extents->y);
+	pattern.base.filter = CAIRO_FILTER_NEAREST;
+	status = _cairo_surface_paint (pixel, CAIRO_OPERATOR_SOURCE, &pattern.base, NULL);
+	_cairo_pattern_fini (&pattern.base);
+
+	if (unlikely (status)) {
+	    _cairo_surface_release_source_image (surface, image, image_extra);
+	    cairo_surface_destroy (pixel);
+	    return status;
+	}
+
+	argb = *(uint32_t *) ((cairo_image_surface_t *) pixel)->data;
+	cairo_surface_destroy (pixel);
+    } else {
+	argb = ((uint32_t *) (image->data + extents->y * image->stride))[extents->x];
+    }
+
+    _cairo_surface_release_source_image (surface, image, image_extra);
+
+    if (argb >> 24 == 0)
+	argb = 0;
+
+    src->base.constants[0] = ((argb >> 16) & 0xff) / 255.;
+    src->base.constants[1] = ((argb >>  8) & 0xff) / 255.;
+    src->base.constants[2] = ((argb >>  0) & 0xff) / 255.;
+    src->base.constants[3] = ((argb >> 24) & 0xff) / 255.;
+    src->base.constants_size = 4;
+
+    src->base.content  = CAIRO_CONTENT_COLOR_ALPHA;
+    if (CAIRO_ALPHA_IS_OPAQUE(src->base.constants[3]))
+	src->base.content &= ~CAIRO_CONTENT_ALPHA;
+    src->type.fragment = FS_CONSTANT;
+    src->type.vertex   = VS_NONE;
+    src->type.pattern  = PATTERN_SOLID;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_shader_acquire_surface (i965_shader_t *shader,
+			     union i965_shader_channel *src,
+			     const cairo_surface_pattern_t *pattern,
+			     const cairo_rectangle_int_t *extents)
+{
+    cairo_surface_t *surface, *drm;
+    cairo_matrix_t m;
+    cairo_status_t status;
+    int src_x = 0, src_y = 0;
+
+    assert (src->type.fragment == FS_NONE);
+    drm = surface = pattern->surface;
+
+#if CAIRO_HAS_XCB_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
+    if (surface->type == CAIRO_SURFACE_TYPE_XCB) {
+	cairo_surface_t *xcb = surface;
+
+	if (xcb->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+	    xcb = ((cairo_surface_subsurface_t *) surface)->target;
+	} else if (xcb->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
+	    xcb = ((cairo_surface_snapshot_t *) surface)->target;
+	}
+
+	/* XXX copy windows (IncludeInferiors) to a pixmap/drm surface
+	 * xcb = _cairo_xcb_surface_to_drm (xcb)
+	 */
+	xcb = ((cairo_xcb_surface_t *) xcb)->drm;
+	if (xcb != NULL)
+	    drm = xcb;
+    }
+#endif
+
+    if (surface->type == CAIRO_SURFACE_TYPE_DRM) {
+	if (surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+	    drm = ((cairo_surface_subsurface_t *) surface)->target;
+	} else if (surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT) {
+	    drm = ((cairo_surface_snapshot_t *) surface)->target;
+	}
+    }
+
+    src->type.pattern = PATTERN_SURFACE;
+    src->surface.surface = NULL;
+    if (drm->type == CAIRO_SURFACE_TYPE_DRM) {
+	i965_surface_t *s = (i965_surface_t *) drm;
+
+	if (surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
+	    if (s->intel.drm.base.device == shader->target->intel.drm.base.device) {
+		cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) surface;
+		if (s != shader->target) {
+		    int x;
+
+		    if (to_intel_bo (s->intel.drm.bo)->batch_write_domain)
+			i965_pipelined_flush (i965_device (s));
+
+		    src->type.fragment = FS_SURFACE;
+
+		    src->base.bo = to_intel_bo (s->intel.drm.bo);
+		    src->base.format = s->intel.drm.format;
+		    src->base.content = s->intel.drm.base.content;
+		    src->base.width = sub->extents.width;
+		    src->base.height = sub->extents.height;
+		    src->base.stride = s->intel.drm.stride;
+
+		    x = sub->extents.x;
+		    if (s->intel.drm.format != CAIRO_FORMAT_A8)
+			x *= 4;
+
+		    /* XXX tiling restrictions upon offset? */
+		    //src->base.offset[0] = s->offset + sub->extents.y * s->intel.drm.stride + x;
+		} else {
+		    i965_surface_t *clone;
+		    cairo_surface_pattern_t pattern;
+
+		    clone = (i965_surface_t *)
+			i965_surface_create_internal ((cairo_drm_device_t *) s->intel.drm.base.device,
+						      s->intel.drm.base.content,
+						      sub->extents.width,
+						      sub->extents.height,
+						      I965_TILING_DEFAULT,
+						      TRUE);
+		    if (unlikely (clone->intel.drm.base.status))
+			return clone->intel.drm.base.status;
+
+		    _cairo_pattern_init_for_surface (&pattern, &s->intel.drm.base);
+		    pattern.base.filter = CAIRO_FILTER_NEAREST;
+		    cairo_matrix_init_translate (&pattern.base.matrix,
+						 sub->extents.x, sub->extents.y);
+
+		    status = _cairo_surface_paint (&clone->intel.drm.base,
+						   CAIRO_OPERATOR_SOURCE,
+						   &pattern.base,
+						   NULL);
+
+		    _cairo_pattern_fini (&pattern.base);
+
+		    if (unlikely (status)) {
+			cairo_surface_destroy (&clone->intel.drm.base);
+			return status;
+		    }
+
+		    i965_pipelined_flush (i965_device (s));
+		    src->type.fragment = FS_SURFACE;
+
+		    src->base.bo = to_intel_bo (clone->intel.drm.bo);
+		    src->base.format = clone->intel.drm.format;
+		    src->base.content = clone->intel.drm.base.content;
+		    src->base.width = clone->intel.drm.width;
+		    src->base.height = clone->intel.drm.height;
+		    src->base.stride = clone->intel.drm.stride;
+
+		    src->surface.surface = &clone->intel.drm.base;
+		}
+
+		src_x = sub->extents.x;
+		src_y = sub->extents.y;
+	    }
+	} else {
+	    if (s->intel.drm.base.device == shader->target->intel.drm.base.device) {
+		if (s != shader->target) {
+		    if (to_intel_bo (s->intel.drm.bo)->batch_write_domain)
+			i965_pipelined_flush (i965_device (s));
+
+		    src->type.fragment = FS_SURFACE;
+
+		    src->base.bo = to_intel_bo (s->intel.drm.bo);
+		    src->base.format = s->intel.drm.format;
+		    src->base.content = s->intel.drm.base.content;
+		    src->base.width = s->intel.drm.width;
+		    src->base.height = s->intel.drm.height;
+		    src->base.stride = s->intel.drm.stride;
+		} else {
+		    i965_surface_t *clone;
+		    cairo_surface_pattern_t pattern;
+
+		    clone = (i965_surface_t *)
+			i965_surface_create_internal ((cairo_drm_device_t *) s->intel.drm.base.device,
+						      s->intel.drm.base.content,
+						      s->intel.drm.width,
+						      s->intel.drm.height,
+						      I965_TILING_DEFAULT,
+						      TRUE);
+		    if (unlikely (clone->intel.drm.base.status))
+			return clone->intel.drm.base.status;
+
+		    _cairo_pattern_init_for_surface (&pattern, &s->intel.drm.base);
+		    pattern.base.filter = CAIRO_FILTER_NEAREST;
+		    status = _cairo_surface_paint (&clone->intel.drm.base,
+						   CAIRO_OPERATOR_SOURCE,
+						   &pattern.base,
+						   NULL);
+
+		    _cairo_pattern_fini (&pattern.base);
+
+		    if (unlikely (status)) {
+			cairo_surface_destroy (&clone->intel.drm.base);
+			return status;
+		    }
+
+		    i965_pipelined_flush (i965_device (s));
+		    src->type.fragment = FS_SURFACE;
+
+		    src->base.bo = to_intel_bo (clone->intel.drm.bo);
+		    src->base.format = clone->intel.drm.format;
+		    src->base.content = clone->intel.drm.base.content;
+		    src->base.width = clone->intel.drm.width;
+		    src->base.height = clone->intel.drm.height;
+		    src->base.stride = clone->intel.drm.stride;
+
+		    src->surface.surface = &clone->intel.drm.base;
+		}
+	    }
+	}
+    }
+
+    if (src->type.fragment == FS_NONE) {
+	i965_surface_t *s;
+
+	if (extents->width == 1 && extents->height == 1) {
+	    return i965_shader_acquire_solid_surface (shader, src,
+						      surface, extents);
+	}
+
+	s = (i965_surface_t *)
+	    _cairo_surface_has_snapshot (surface,
+					 shader->target->intel.drm.base.backend);
+	if (s != NULL) {
+	    i965_device_t *device = i965_device (shader->target);
+	    intel_bo_t *bo = to_intel_bo (s->intel.drm.bo);
+
+	    if (bo->purgeable &&
+		! intel_bo_madvise (&device->intel, bo, I915_MADV_WILLNEED))
+	    {
+		_cairo_surface_detach_snapshot (&s->intel.drm.base);
+		s = NULL;
+	    }
+
+	    if (s != NULL)
+		cairo_surface_reference (&s->intel.drm.base);
+	}
+
+	if (s == NULL) {
+	    cairo_image_surface_t *image;
+	    void *image_extra;
+	    cairo_status_t status;
+
+	    status = _cairo_surface_acquire_source_image (surface, &image, &image_extra);
+	    if (unlikely (status))
+		return status;
+
+	    if (image->width < 8192 && image->height < 8192) {
+		status = i965_surface_clone (i965_device (shader->target), image, &s);
+	    } else {
+		status = i965_surface_clone_subimage (i965_device (shader->target),
+						      image, extents, &s);
+		src_x = -extents->x;
+		src_y = -extents->y;
+	    }
+
+	    _cairo_surface_release_source_image (surface, image, image_extra);
+
+	    if (unlikely (status))
+		return status;
+
+	    /* XXX? */
+	    //intel_bo_mark_purgeable (to_intel_bo (s->intel.drm.bo), TRUE);
+	}
+
+	src->type.fragment = FS_SURFACE;
+
+	src->base.bo = to_intel_bo (s->intel.drm.bo);
+	src->base.content = s->intel.drm.base.content;
+	src->base.format = s->intel.drm.format;
+	src->base.width  = s->intel.drm.width;
+	src->base.height = s->intel.drm.height;
+	src->base.stride = s->intel.drm.stride;
+
+	src->surface.surface = &s->intel.drm.base;
+
+	drm = &s->intel.drm.base;
+    }
+
+    /* XXX transform nx1 or 1xn surfaces to 1D? */
+
+    src->type.vertex = VS_NONE;
+
+    src->base.extend = i965_extend (pattern->base.extend);
+    if (pattern->base.extend == CAIRO_EXTEND_NONE &&
+	extents->x >= 0 && extents->y >= 0 &&
+	extents->x + extents->width  <= src->base.width &&
+	extents->y + extents->height <= src->base.height)
+    {
+	/* Convert a wholly contained NONE to a REFLECT as the contiguous sampler
+	 * cannot not handle CLAMP_BORDER textures.
+	 */
+	src->base.extend = i965_extend (CAIRO_EXTEND_REFLECT);
+	/* XXX also need to check |u,v| < 3 */
+    }
+
+    src->base.filter = i965_filter (pattern->base.filter);
+    if (_cairo_matrix_is_pixel_exact (&pattern->base.matrix))
+	src->base.filter = i965_filter (CAIRO_FILTER_NEAREST);
+
+    /* tweak the src matrix to map from dst to texture coordinates */
+    src->base.matrix = pattern->base.matrix;
+    if (src_x | src_y)
+	cairo_matrix_translate (&src->base.matrix, src_x, src_x);
+    if (src->base.filter == BRW_MAPFILTER_NEAREST)
+	cairo_matrix_translate (&src->base.matrix, NEAREST_BIAS, NEAREST_BIAS);
+    cairo_matrix_init_scale (&m, 1. / src->base.width, 1. / src->base.height);
+    cairo_matrix_multiply (&src->base.matrix, &src->base.matrix, &m);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+i965_shader_acquire_pattern (i965_shader_t *shader,
+			     union i965_shader_channel *src,
+			     const cairo_pattern_t *pattern,
+			     const cairo_rectangle_int_t *extents)
+{
+    switch (pattern->type) {
+    case CAIRO_PATTERN_TYPE_SOLID:
+	return i965_shader_acquire_solid (shader, src,
+					  (cairo_solid_pattern_t *) pattern,
+					  extents);
+
+    case CAIRO_PATTERN_TYPE_LINEAR:
+	return i965_shader_acquire_linear (shader, src,
+					   (cairo_linear_pattern_t *) pattern,
+					   extents);
+
+    case CAIRO_PATTERN_TYPE_RADIAL:
+	return i965_shader_acquire_radial (shader, src,
+					   (cairo_radial_pattern_t *) pattern,
+					   extents);
+
+    case CAIRO_PATTERN_TYPE_SURFACE:
+	return i965_shader_acquire_surface (shader, src,
+					    (cairo_surface_pattern_t *) pattern,
+					    extents);
+
+    default:
+	ASSERT_NOT_REACHED;
+	return CAIRO_STATUS_SUCCESS;
+    }
+}
+
+static void
+i965_shader_channel_init (union i965_shader_channel *channel)
+{
+    channel->type.vertex = VS_NONE;
+    channel->type.fragment = FS_NONE;
+    channel->type.pattern = PATTERN_NONE;
+
+    channel->base.mode = 0;
+    channel->base.bo = NULL;
+    channel->base.filter = i965_extend (CAIRO_FILTER_NEAREST);
+    channel->base.extend = i965_extend (CAIRO_EXTEND_NONE);
+    channel->base.has_component_alpha = 0;
+    channel->base.constants_size = 0;
+}
+
+void
+i965_shader_init (i965_shader_t *shader,
+		  i965_surface_t *dst,
+		  cairo_operator_t op)
+{
+    shader->committed = FALSE;
+    shader->device = i965_device (dst);
+    shader->target = dst;
+    shader->op = op;
+    shader->constants_size = 0;
+
+    shader->need_combine = FALSE;
+
+    i965_shader_channel_init (&shader->source);
+    i965_shader_channel_init (&shader->mask);
+    i965_shader_channel_init (&shader->clip);
+    i965_shader_channel_init (&shader->dst);
+}
+
+void
+i965_shader_fini (i965_shader_t *shader)
+{
+    if (shader->source.type.pattern == PATTERN_SURFACE)
+	cairo_surface_destroy (shader->source.surface.surface);
+    if (shader->mask.type.pattern == PATTERN_SURFACE)
+	cairo_surface_destroy (shader->mask.surface.surface);
+    if (shader->clip.type.pattern == PATTERN_SURFACE)
+	cairo_surface_destroy (shader->clip.surface.surface);
+    if (shader->dst.type.pattern == PATTERN_SURFACE)
+	cairo_surface_destroy (shader->dst.surface.surface);
+}
+
+void
+i965_shader_set_clip (i965_shader_t *shader,
+		      cairo_clip_t *clip)
+{
+    cairo_surface_t *clip_surface;
+    union i965_shader_channel *channel;
+    i965_surface_t *s;
+
+    clip_surface = _cairo_clip_get_surface (clip, &shader->target->intel.drm.base);
+    assert (clip_surface->status == CAIRO_STATUS_SUCCESS);
+    assert (clip_surface->type == CAIRO_SURFACE_TYPE_DRM);
+    s = (i965_surface_t *) clip_surface;
+
+    if (to_intel_bo (s->intel.drm.bo)->batch_write_domain)
+	i965_pipelined_flush (i965_device (s));
+
+    channel = &shader->clip;
+    channel->type.pattern = PATTERN_BASE;
+    channel->type.vertex  = VS_NONE;
+    channel->type.fragment = FS_SURFACE;
+
+    channel->base.bo = to_intel_bo (s->intel.drm.bo);
+    channel->base.content = CAIRO_CONTENT_ALPHA;
+    channel->base.format = CAIRO_FORMAT_A8;
+    channel->base.width  = s->intel.drm.width;
+    channel->base.height = s->intel.drm.height;
+    channel->base.stride = s->intel.drm.stride;
+
+    channel->base.extend = i965_extend (CAIRO_EXTEND_NONE);
+    channel->base.filter = i965_filter (CAIRO_FILTER_NEAREST);
+
+    cairo_matrix_init_scale (&shader->clip.base.matrix,
+			     1. / s->intel.drm.width,
+			     1. / s->intel.drm.height);
+
+    cairo_matrix_translate (&shader->clip.base.matrix,
+			    NEAREST_BIAS + clip->path->extents.x,
+			    NEAREST_BIAS + clip->path->extents.y);
+}
+
+static cairo_bool_t
+i965_shader_check_aperture (i965_shader_t *shader,
+			    i965_device_t *device)
+{
+    uint32_t size = device->exec.gtt_size;
+
+    if (shader->target != device->target) {
+	const intel_bo_t *bo = to_intel_bo (shader->target->intel.drm.bo);
+	if (bo->exec == NULL)
+	    size += bo->base.size;
+    }
+
+    if (shader->source.base.bo != NULL && shader->source.base.bo != device->source) {
+	const intel_bo_t *bo = to_intel_bo (shader->target->intel.drm.bo);
+	if (bo->exec == NULL)
+	    size += bo->base.size;
+    }
+
+    if (shader->mask.base.bo != NULL && shader->mask.base.bo != device->mask) {
+	const intel_bo_t *bo = to_intel_bo (shader->target->intel.drm.bo);
+	if (bo->exec == NULL)
+	    size += bo->base.size;
+    }
+
+    if (shader->clip.base.bo != NULL && shader->clip.base.bo != device->clip) {
+	const intel_bo_t *bo = to_intel_bo (shader->target->intel.drm.bo);
+	if (bo->exec == NULL)
+	    size += bo->base.size;
+    }
+
+    return size <= device->intel.gtt_avail_size;
+}
+
+static cairo_status_t
+i965_shader_setup_dst (i965_shader_t *shader)
+{
+    union i965_shader_channel *channel;
+    i965_surface_t *s, *clone;
+
+    /* We need to manual blending if we have a clip surface and an unbounded op,
+     * or an extended blend mode.
+     */
+    if (shader->need_combine ||
+	(shader->op < CAIRO_OPERATOR_SATURATE &&
+	 (shader->clip.type.fragment == FS_NONE ||
+	  _cairo_operator_bounded_by_mask (shader->op))))
+    {
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    shader->need_combine = TRUE;
+
+    s = shader->target;
+
+    /* we need to allocate a new render target and use the original as a source */
+    clone = (i965_surface_t *)
+	i965_surface_create_internal ((cairo_drm_device_t *) s->intel.drm.base.device,
+				      s->intel.drm.base.content,
+				      s->intel.drm.width,
+				      s->intel.drm.height,
+				      I965_TILING_DEFAULT,
+				      TRUE);
+    if (unlikely (clone->intel.drm.base.status))
+	return clone->intel.drm.base.status;
+
+    if (to_intel_bo (s->intel.drm.bo)->batch_write_domain)
+	i965_pipelined_flush (i965_device (s));
+
+    channel = &shader->dst;
+
+    channel->type.vertex = VS_NONE;
+    channel->type.fragment = FS_SURFACE;
+    channel->type.pattern = PATTERN_SURFACE;
+
+    /* swap buffer objects */
+    channel->base.bo = to_intel_bo (s->intel.drm.bo);
+    s->intel.drm.bo = ((cairo_drm_surface_t *) clone)->bo;
+    ((cairo_drm_surface_t *) clone)->bo = &channel->base.bo->base;
+
+    channel->base.content = s->intel.drm.base.content;
+    channel->base.format  = s->intel.drm.format;
+    channel->base.width   = s->intel.drm.width;
+    channel->base.height  = s->intel.drm.height;
+    channel->base.stride  = s->intel.drm.stride;
+
+    channel->base.filter = i965_filter (CAIRO_FILTER_NEAREST);
+    channel->base.extend = i965_extend (CAIRO_EXTEND_NONE);
+
+    cairo_matrix_init_scale (&channel->base.matrix,
+			     1. / s->intel.drm.width,
+			     1. / s->intel.drm.height);
+    cairo_matrix_translate (&channel->base.matrix,
+			    NEAREST_BIAS,
+			    NEAREST_BIAS);
+
+    channel->surface.surface = &clone->intel.drm.base;
+
+    s->intel.drm.base.content = clone->intel.drm.base.content;
+    s->intel.drm.format = clone->intel.drm.format;
+    assert (s->intel.drm.width == clone->intel.drm.width);
+    assert (s->intel.drm.height == clone->intel.drm.height);
+    s->intel.drm.stride = clone->intel.drm.stride;
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static inline void
+constant_add_float (i965_shader_t *shader, float v)
+{
+    shader->constants[shader->constants_size++] = v;
+}
+
+static inline void
+i965_shader_copy_channel_constants (i965_shader_t *shader,
+				    const union i965_shader_channel *channel)
+{
+    if (channel->base.constants_size) {
+	assert (shader->constants_size + channel->base.constants_size < ARRAY_LENGTH (shader->constants));
+
+	memcpy (shader->constants + shader->constants_size,
+		channel->base.constants,
+		sizeof (float) * channel->base.constants_size);
+	shader->constants_size += channel->base.constants_size;
+    }
+}
+
+static void
+i965_shader_setup_channel_constants (i965_shader_t *shader,
+				     const union i965_shader_channel *channel)
+{
+    switch (channel->type.fragment) {
+    case FS_NONE:
+    case FS_CONSTANT:
+	/* no plane equations */
+	break;
+
+    case FS_LINEAR:
+	constant_add_float (shader, channel->base.matrix.xx);
+	constant_add_float (shader, channel->base.matrix.xy);
+	constant_add_float (shader, 0);
+	constant_add_float (shader, channel->base.matrix.x0);
+	break;
+
+    case FS_RADIAL:
+    case FS_SURFACE:
+	constant_add_float (shader, channel->base.matrix.xx);
+	constant_add_float (shader, channel->base.matrix.xy);
+	constant_add_float (shader, 0);
+	constant_add_float (shader, channel->base.matrix.x0);
+
+	constant_add_float (shader, channel->base.matrix.yx);
+	constant_add_float (shader, channel->base.matrix.yy);
+	constant_add_float (shader, 0);
+	constant_add_float (shader, channel->base.matrix.y0);
+	break;
+
+    case FS_SPANS:
+    case FS_GLYPHS:
+	/* use pue from SF */
+	break;
+    }
+
+    i965_shader_copy_channel_constants (shader, channel);
+}
+
+static void
+i965_shader_setup_constants (i965_shader_t *shader)
+{
+    i965_shader_setup_channel_constants (shader, &shader->source);
+    i965_shader_setup_channel_constants (shader, &shader->mask);
+    i965_shader_setup_channel_constants (shader, &shader->clip);
+    i965_shader_setup_channel_constants (shader, &shader->dst);
+    assert (shader->constants_size < ARRAY_LENGTH (shader->constants));
+}
+
+/**
+ * Highest-valued BLENDFACTOR used in i965_blend_op.
+ *
+ * This leaves out BRW_BLENDFACTOR_INV_DST_COLOR,
+ * BRW_BLENDFACTOR_INV_CONST_{COLOR,ALPHA},
+ * BRW_BLENDFACTOR_INV_SRC1_{COLOR,ALPHA}
+ */
+#define BRW_BLENDFACTOR_COUNT (BRW_BLENDFACTOR_INV_DST_ALPHA + 1)
+
+static void
+i965_shader_get_blend_cntl (const i965_shader_t *shader,
+			    uint32_t *sblend, uint32_t *dblend)
+{
+    static const struct blendinfo {
+	cairo_bool_t dst_alpha;
+	cairo_bool_t src_alpha;
+	uint32_t src_blend;
+	uint32_t dst_blend;
+    } i965_blend_op[] = {
+	/* CAIRO_OPERATOR_CLEAR treat as SOURCE with transparent */
+	{0, 0, BRW_BLENDFACTOR_ONE,          BRW_BLENDFACTOR_ZERO},
+	/* CAIRO_OPERATOR_SOURCE */
+	{0, 0, BRW_BLENDFACTOR_ONE,           BRW_BLENDFACTOR_ZERO},
+	/* CAIRO_OPERATOR_OVER */
+	{0, 1, BRW_BLENDFACTOR_ONE,           BRW_BLENDFACTOR_INV_SRC_ALPHA},
+	/* CAIRO_OPERATOR_IN */
+	{1, 0, BRW_BLENDFACTOR_DST_ALPHA,     BRW_BLENDFACTOR_ZERO},
+	/* CAIRO_OPERATOR_OUT */
+	{1, 0, BRW_BLENDFACTOR_INV_DST_ALPHA, BRW_BLENDFACTOR_ZERO},
+	/* CAIRO_OPERATOR_ATOP */
+	{1, 1, BRW_BLENDFACTOR_DST_ALPHA,     BRW_BLENDFACTOR_INV_SRC_ALPHA},
+
+	/* CAIRO_OPERATOR_DEST */
+	{0, 0, BRW_BLENDFACTOR_ZERO,          BRW_BLENDFACTOR_ONE},
+	/* CAIRO_OPERATOR_DEST_OVER */
+	{1, 0, BRW_BLENDFACTOR_INV_DST_ALPHA, BRW_BLENDFACTOR_ONE},
+	/* CAIRO_OPERATOR_DEST_IN */
+	{0, 1, BRW_BLENDFACTOR_ZERO,          BRW_BLENDFACTOR_SRC_ALPHA},
+	/* CAIRO_OPERATOR_DEST_OUT */
+	{0, 1, BRW_BLENDFACTOR_ZERO,          BRW_BLENDFACTOR_INV_SRC_ALPHA},
+	/* CAIRO_OPERATOR_DEST_ATOP */
+	{1, 1, BRW_BLENDFACTOR_INV_DST_ALPHA, BRW_BLENDFACTOR_SRC_ALPHA},
+	/* CAIRO_OPERATOR_XOR */
+	{1, 1, BRW_BLENDFACTOR_INV_DST_ALPHA, BRW_BLENDFACTOR_INV_SRC_ALPHA},
+	/* CAIRO_OPERATOR_ADD */
+	{0, 0, BRW_BLENDFACTOR_ONE,           BRW_BLENDFACTOR_ONE},
+    };
+    const struct blendinfo *op = &i965_blend_op[shader->op];
+
+    *sblend = op->src_blend;
+    *dblend = op->dst_blend;
+
+    /* If there's no dst alpha channel, adjust the blend op so that we'll treat
+     * it as always 1.
+     */
+    if (shader->target->intel.drm.base.content == CAIRO_CONTENT_COLOR &&
+	op->dst_alpha)
+    {
+	if (*sblend == BRW_BLENDFACTOR_DST_ALPHA)
+	    *sblend = BRW_BLENDFACTOR_ONE;
+	else if (*sblend == BRW_BLENDFACTOR_INV_DST_ALPHA)
+	    *sblend = BRW_BLENDFACTOR_ZERO;
+    }
+}
+
+static void
+emit_wm_subpans_to_pixels (struct brw_compile *compile,
+			   int tmp)
+{
+    /* Inputs:
+     * R1.5 x/y of upper-left pixel of subspan 3
+     * R1.4 x/y of upper-left pixel of subspan 2
+     * R1.3 x/y of upper-left pixel of subspan 1
+     * R1.2 x/y of upper-left pixel of subspan 0
+     *
+     * Outputs:
+     * M1,2: u
+     * M3,4: v
+     *
+     * upper left, upper right, lower left, lower right.
+     */
+
+    /* compute pixel locations for each subspan */
+    brw_set_compression_control (compile, BRW_COMPRESSION_NONE);
+    brw_ADD (compile,
+	     brw_vec8_grf (tmp),
+	     brw_reg (BRW_GENERAL_REGISTER_FILE, 1, 4,
+		      BRW_REGISTER_TYPE_UW,
+		      BRW_VERTICAL_STRIDE_2,
+		      BRW_WIDTH_4,
+		      BRW_HORIZONTAL_STRIDE_0,
+		      BRW_SWIZZLE_NOOP,
+		      WRITEMASK_XYZW),
+	     brw_imm_vf4 (VF_ZERO, VF_ONE, VF_ZERO, VF_ONE));
+    brw_ADD (compile,
+	     brw_vec8_grf (tmp+1),
+	     brw_reg (BRW_GENERAL_REGISTER_FILE, 1, 8,
+		      BRW_REGISTER_TYPE_UW,
+		      BRW_VERTICAL_STRIDE_2,
+		      BRW_WIDTH_4,
+		      BRW_HORIZONTAL_STRIDE_0,
+		      BRW_SWIZZLE_NOOP,
+		      WRITEMASK_XYZW),
+	     brw_imm_vf4 (VF_ZERO, VF_ONE, VF_ZERO, VF_ONE));
+    brw_ADD (compile,
+	     brw_vec8_grf (tmp+2),
+	     brw_reg (BRW_GENERAL_REGISTER_FILE, 1, 5,
+		      BRW_REGISTER_TYPE_UW,
+		      BRW_VERTICAL_STRIDE_2,
+		      BRW_WIDTH_4,
+		      BRW_HORIZONTAL_STRIDE_0,
+		      BRW_SWIZZLE_NOOP,
+		      WRITEMASK_XYZW),
+	     brw_imm_vf4 (VF_ZERO, VF_ZERO, VF_ONE, VF_ONE));
+    brw_ADD (compile,
+	     brw_vec8_grf (tmp+3),
+	     brw_reg (BRW_GENERAL_REGISTER_FILE, 1, 9,
+		      BRW_REGISTER_TYPE_UW,
+		      BRW_VERTICAL_STRIDE_2,
+		      BRW_WIDTH_4,
+		      BRW_HORIZONTAL_STRIDE_0,
+		      BRW_SWIZZLE_NOOP,
+		      WRITEMASK_XYZW),
+	     brw_imm_vf4 (VF_ZERO, VF_ZERO, VF_ONE, VF_ONE));
+    brw_set_compression_control (compile, BRW_COMPRESSION_COMPRESSED);
+}
+
+static void
+emit_wm_affine (struct brw_compile *compile,
+		int tmp, int reg, int msg)
+{
+    emit_wm_subpans_to_pixels (compile, tmp);
+
+    brw_LINE (compile,
+	      brw_null_reg (),
+	      brw_vec1_grf (reg, 0),
+	      brw_vec8_grf (tmp));
+    brw_MAC (compile,
+	     brw_message_reg (msg + 1),
+	     brw_vec1_grf (reg, 1),
+	     brw_vec8_grf (tmp+2));
+
+    brw_LINE (compile,
+	      brw_null_reg (),
+	      brw_vec1_grf (reg, 4),
+	      brw_vec8_grf (tmp));
+    brw_MAC (compile,
+	     brw_message_reg (msg + 3),
+	     brw_vec1_grf (reg, 5),
+	     brw_vec8_grf (tmp+2));
+}
+
+static void
+emit_wm_glyph (struct brw_compile *compile,
+	       int tmp, int vue, int msg)
+{
+    emit_wm_subpans_to_pixels (compile, tmp);
+
+    brw_MUL (compile,
+	     brw_null_reg (),
+	     brw_vec8_grf (tmp),
+	     brw_imm_f (1./1024));
+    brw_ADD (compile,
+	     brw_message_reg (msg + 1),
+	     brw_acc_reg (),
+	     brw_vec1_grf (vue, 0));
+
+    brw_MUL (compile,
+	     brw_null_reg (),
+	     brw_vec8_grf (tmp + 2),
+	     brw_imm_f (1./1024));
+    brw_ADD (compile,
+	     brw_message_reg (msg + 3),
+	     brw_acc_reg (),
+	     brw_vec1_grf (vue, 1));
+}
+
+static void
+emit_wm_load_constant (struct brw_compile *compile,
+		       int reg,
+		       struct brw_reg *result)
+{
+    int n;
+
+    for (n = 0; n < 4; n++) {
+	result[n] = result[n+4] = brw_reg (BRW_GENERAL_REGISTER_FILE, reg, n,
+					   BRW_REGISTER_TYPE_F,
+					   BRW_VERTICAL_STRIDE_0,
+					   BRW_WIDTH_1,
+					   BRW_HORIZONTAL_STRIDE_0,
+					   BRW_SWIZZLE_XXXX,
+					   WRITEMASK_XYZW);
+    }
+}
+
+static void
+emit_wm_load_opacity (struct brw_compile *compile,
+		      int reg,
+		      struct brw_reg *result)
+{
+    result[0] = result[1] = result[2] = result[3] =
+	result[4] = result[5] = result[6] = result[7] =
+	brw_reg (BRW_GENERAL_REGISTER_FILE, reg, 0,
+		 BRW_REGISTER_TYPE_F,
+		 BRW_VERTICAL_STRIDE_0,
+		 BRW_WIDTH_1,
+		 BRW_HORIZONTAL_STRIDE_1,
+		 BRW_SWIZZLE_XXXX,
+		 WRITEMASK_XYZW);
+}
+
+static void
+emit_wm_load_linear (struct brw_compile *compile,
+		     int tmp, int reg, int msg)
+{
+    emit_wm_subpans_to_pixels (compile, tmp);
+
+    brw_LINE (compile,
+	      brw_null_reg(),
+	      brw_vec1_grf (reg, 0),
+	      brw_vec8_grf (tmp));
+    brw_MAC (compile,
+	     brw_message_reg(msg + 1),
+	     brw_vec1_grf (reg, 1),
+	     brw_vec8_grf (tmp + 2));
+}
+
+static void
+emit_wm_load_radial (struct brw_compile *compile,
+		     int reg, int msg)
+
+{
+    struct brw_reg c1x = brw_vec1_grf (reg, 0);
+    struct brw_reg c1y = brw_vec1_grf (reg, 1);
+    struct brw_reg minus_r_sq = brw_vec1_grf (reg, 3);
+    struct brw_reg cdx = brw_vec1_grf (reg, 4);
+    struct brw_reg cdy = brw_vec1_grf (reg, 5);
+    struct brw_reg neg_4a = brw_vec1_grf (reg + 1, 0);
+    struct brw_reg inv_2a = brw_vec1_grf (reg + 1, 1);
+
+    struct brw_reg tmp_x = brw_uw16_grf (30, 0);
+    struct brw_reg tmp_y = brw_uw16_grf (28, 0);
+    struct brw_reg det = brw_vec8_grf (22);
+    struct brw_reg b = brw_vec8_grf (20);
+    struct brw_reg c = brw_vec8_grf (18);
+    struct brw_reg pdx = brw_vec8_grf (16);
+    struct brw_reg pdy = brw_vec8_grf (14);
+    struct brw_reg t = brw_message_reg (msg + 1);
+
+    /* cdx = (c₂x - c₁x)
+     * cdy = (c₂y - c₁y)
+     *  dr =  r₂-r₁
+     * pdx =  px - c₁x
+     * pdy =  py - c₁y
+     *
+     * A = cdx² + cdy² - dr²
+     * B = -2·(pdx·cdx + pdy·cdy + r₁·dr)
+     * C = pdx² + pdy² - r₁²
+     *
+     * t = (-2·B ± ⎷(B² - 4·A·C)) / 2·A
+     */
+
+    brw_ADD (compile, pdx, vec8 (tmp_x), negate (c1x));
+    brw_ADD (compile, pdy, vec8 (tmp_y), negate (c1y));
+
+    brw_LINE (compile, brw_null_reg (), cdx, pdx);
+    brw_MAC (compile, b, cdy, pdy);
+
+    brw_MUL (compile, brw_null_reg (), pdx, pdx);
+    brw_MAC (compile, c, pdy, pdy);
+    brw_ADD (compile, c, c, minus_r_sq);
+
+    brw_MUL (compile, brw_null_reg (), b, b);
+    brw_MAC (compile, det, neg_4a, c);
+
+    /* XXX use rsqrt like i915?, it's faster and we need to mac anyway */
+    brw_math (compile,
+	      det,
+	      BRW_MATH_FUNCTION_SQRT,
+	      BRW_MATH_SATURATE_NONE,
+	      2,
+	      det,
+	      BRW_MATH_DATA_VECTOR,
+	      BRW_MATH_PRECISION_FULL);
+
+    /* XXX cmp, +- */
+
+    brw_ADD (compile, det, negate (det), negate (b));
+    brw_ADD (compile, det, det, negate (b));
+    brw_MUL (compile, t, det, inv_2a);
+}
+
+static int
+emit_wm_sample (struct brw_compile *compile,
+		union i965_shader_channel *channel,
+		int sampler,
+		int msg_base, int msg_len,
+		int dst,
+		struct brw_reg *result)
+{
+    int response_len, mask;
+
+    if (channel->base.content == CAIRO_CONTENT_ALPHA) {
+	mask = 0x7000;
+	response_len = 2;
+	result[0] = result[1] = result[2] = result[3] = brw_vec8_grf (dst);
+	result[4] = result[5] = result[6] = result[7] = brw_vec8_grf (dst + 1);
+    } else {
+	mask = 0;
+	response_len = 8;
+	result[0] = brw_vec8_grf (dst + 0);
+	result[1] = brw_vec8_grf (dst + 2);
+	result[2] = brw_vec8_grf (dst + 4);
+	result[3] = brw_vec8_grf (dst + 6);
+	result[4] = brw_vec8_grf (dst + 1);
+	result[5] = brw_vec8_grf (dst + 3);
+	result[6] = brw_vec8_grf (dst + 5);
+	result[7] = brw_vec8_grf (dst + 7);
+    }
+
+    brw_set_compression_control (compile, BRW_COMPRESSION_NONE);
+
+    brw_set_mask_control (compile, BRW_MASK_DISABLE);
+    brw_MOV (compile,
+	     get_element_ud (brw_vec8_grf (0), 2),
+	     brw_imm_ud (mask));
+    brw_set_mask_control (compile, BRW_MASK_ENABLE);
+
+    brw_SAMPLE (compile,
+		brw_uw16_grf (dst, 0),
+		msg_base,
+		brw_uw8_grf (0, 0),
+		sampler + 1, /* binding table */
+		sampler,
+		WRITEMASK_XYZW,
+		BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE,
+		response_len,
+		msg_len,
+		0 /* eot */);
+
+    brw_set_compression_control (compile, BRW_COMPRESSION_COMPRESSED);
+
+    return response_len;
+}
+
+#define MAX_MSG_REGISTER 16
+
+static void
+emit_wm_load_channel (struct brw_compile *compile,
+		      union i965_shader_channel *channel,
+		      int *vue,
+		      int *cue,
+		      int *msg,
+		      int *sampler,
+		      int *grf,
+		      struct brw_reg *result)
+{
+    switch (channel->type.fragment) {
+    case FS_NONE:
+	break;
+
+    case FS_CONSTANT:
+	emit_wm_load_constant (compile, *cue, result);
+	*cue += 1;
+	break;
+
+    case FS_RADIAL:
+	emit_wm_load_radial (compile, *cue, *msg);
+	*cue += 2;
+
+	if (*msg + 3 > MAX_MSG_REGISTER)
+	    *msg = 1;
+
+	*grf += emit_wm_sample (compile, channel, *sampler, *msg, 3, *grf, result);
+	*sampler += 1;
+	*msg += 3;
+	break;
+
+    case FS_LINEAR:
+	emit_wm_load_linear (compile, *grf, *cue, *msg);
+	*cue += 1;
+
+	if (*msg + 3 > MAX_MSG_REGISTER)
+	    *msg = 1;
+
+	*grf += emit_wm_sample (compile, channel, *sampler, *msg, 3, *grf, result);
+	*sampler += 1;
+	*msg += 3;
+	break;
+
+    case FS_SURFACE:
+	emit_wm_affine (compile, *grf, *cue, *msg);
+	*cue += 2;
+
+	if (*msg + 5 > MAX_MSG_REGISTER)
+	    *msg = 1;
+
+	*grf += emit_wm_sample (compile, channel, *sampler, *msg, 5, *grf, result);
+	*sampler += 1;
+	*msg += 5;
+	break;
+
+    case FS_SPANS:
+	emit_wm_load_opacity (compile, *vue, result);
+	*vue += 1;
+	break;
+
+    case FS_GLYPHS:
+	emit_wm_glyph (compile, *grf, *vue, *msg);
+	*vue += 1;
+
+	if (*msg + 5 > MAX_MSG_REGISTER)
+	    *msg = 1;
+
+	*grf += emit_wm_sample (compile, channel, *sampler, *msg, 5, *grf, result);
+	*sampler += 1;
+	*msg += 5;
+	break;
+    }
+}
+
+static unsigned long
+i965_wm_kernel_hash (const i965_shader_t *shader)
+{
+    unsigned long hash;
+
+    hash =
+	(shader->source.type.fragment & 0xff) |
+	(shader->mask.type.fragment & 0xff) << 8 |
+	(shader->clip.type.fragment & 0xff) << 16;
+    if (shader->need_combine)
+	hash |= (1 + shader->op) << 24;
+
+    return hash;
+}
+
+static void
+i965_wm_kernel_init (struct i965_wm_kernel *key,
+		     const i965_shader_t *shader)
+{
+    key->entry.hash = i965_wm_kernel_hash (shader);
+}
+
+static uint32_t
+i965_shader_const_urb_length (i965_shader_t *shader)
+{
+    const int lengths[] = { 0, 1, 1, 4, 2, 0, 0 };
+    int count = 0; /* 128-bit/16-byte increments */
+
+    count += lengths[shader->source.type.fragment];
+    count += lengths[shader->mask.type.fragment];
+    count += lengths[shader->clip.type.fragment];
+    count += lengths[shader->dst.type.fragment];
+
+    return (count + 1) / 2; /* 256-bit/32-byte increments */
+}
+
+static uint32_t
+i965_shader_pue_length (i965_shader_t *shader)
+{
+    return 1 + (shader->mask.type.vertex != VS_NONE);
+}
+
+static uint32_t
+create_wm_kernel (i965_device_t *device,
+		  i965_shader_t *shader,
+		  int *num_reg)
+{
+    struct brw_compile compile;
+    struct brw_reg source[8], mask[8], clip[8], dst[8];
+    const uint32_t *program;
+    uint32_t size;
+    int msg, cue, vue, grf, sampler;
+    int i;
+
+    struct i965_wm_kernel key, *cache;
+    cairo_status_t status;
+    uint32_t offset;
+
+    i965_wm_kernel_init (&key, shader);
+    cache = _cairo_hash_table_lookup (device->wm_kernels, &key.entry);
+    if (cache != NULL)
+	return cache->offset;
+
+    brw_compile_init (&compile, device->is_g4x);
+
+    if (key.entry.hash == FS_CONSTANT &&
+	to_intel_bo (shader->target->intel.drm.bo)->tiling)
+    {
+	struct brw_instruction *insn;
+
+	assert (i965_shader_const_urb_length (shader) == 1);
+	brw_MOV (&compile, brw_message4_reg (2), brw_vec4_grf (2, 0));
+	grf = 3;
+
+	brw_push_insn_state (&compile);
+	brw_set_mask_control (&compile, BRW_MASK_DISABLE); /* ? */
+	brw_MOV (&compile,
+		 retype (brw_message_reg (1), BRW_REGISTER_TYPE_UD),
+		 retype (brw_vec8_grf (1), BRW_REGISTER_TYPE_UD));
+	brw_pop_insn_state (&compile);
+
+	insn = brw_next_instruction (&compile, BRW_OPCODE_SEND);
+	insn->header.predicate_control = 0;
+	insn->header.compression_control = BRW_COMPRESSION_NONE;
+	insn->header.destreg__conditonalmod = 0;
+
+	brw_instruction_set_destination (insn,
+					 retype (vec16 (brw_acc_reg ()),
+						 BRW_REGISTER_TYPE_UW));
+
+	brw_instruction_set_source0 (insn,
+				     retype (brw_vec8_grf (0),
+					     BRW_REGISTER_TYPE_UW));
+
+	brw_instruction_set_dp_write_message (insn,
+					      0,
+					      BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE_REPLICATED, /* msg_control */
+					      BRW_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE, /* msg_type */
+					      3,
+					      1,	/* pixel scoreboard */
+					      0,
+					      TRUE);
+    }
+    else
+    {
+	msg = 1;
+	cue = 2;
+	vue = cue + i965_shader_const_urb_length (shader);
+	grf = vue + i965_shader_pue_length (shader);
+	sampler = 0;
+
+	brw_set_compression_control (&compile, BRW_COMPRESSION_COMPRESSED);
+	emit_wm_load_channel (&compile, &shader->source,
+			      &vue, &cue, &msg, &sampler, &grf,
+			      source);
+	emit_wm_load_channel (&compile, &shader->mask,
+			      &vue, &cue, &msg, &sampler, &grf,
+			      mask);
+	emit_wm_load_channel (&compile, &shader->clip,
+			      &vue, &cue, &msg, &sampler, &grf,
+			      clip);
+	emit_wm_load_channel (&compile, &shader->dst,
+			      &vue, &cue, &msg, &sampler, &grf,
+			      dst);
+	brw_set_compression_control (&compile, BRW_COMPRESSION_NONE);
+
+	if (shader->need_combine) {
+	    if (shader->mask.type.fragment != FS_NONE &&
+		shader->clip.type.fragment != FS_NONE)
+	    {
+		for (i = 0; i < 8; i++)
+		    brw_MUL (&compile, mask[i], mask[i], clip[i]);
+	    }
+
+	    /* XXX LERP ! */
+	    for (i = 0; i < 8; i++)
+		brw_MOV (&compile, brw_message_reg (2 + i), source[i]);
+	} else {
+	    if (shader->mask.type.fragment != FS_NONE) {
+		if (shader->clip.type.fragment != FS_NONE) {
+		    for (i = 0; i < 8; i++)
+			brw_MUL (&compile, mask[i], mask[i], clip[i]);
+		}
+
+		for (i = 0; i < 8; i++)
+		    brw_MUL (&compile, brw_message_reg (2 + i), source[i], mask[i]);
+	    } else {
+		if (shader->clip.type.fragment != FS_NONE) {
+		    for (i = 0; i < 8; i++)
+			brw_MUL (&compile, brw_message_reg (2 + i), source[i], clip[i]);
+		} else {
+		    for (i = 0; i < 8; i++)
+			brw_MOV (&compile, brw_message_reg (2 + i), source[i]);
+		}
+	    }
+	}
+
+	brw_push_insn_state (&compile);
+	brw_set_mask_control (&compile, BRW_MASK_DISABLE); /* ? */
+	brw_MOV (&compile,
+		 retype (brw_message_reg (1), BRW_REGISTER_TYPE_UD),
+		 retype (brw_vec8_grf (1), BRW_REGISTER_TYPE_UD));
+	brw_pop_insn_state (&compile);
+
+	brw_fb_WRITE (&compile,
+		      retype (vec16 (brw_acc_reg ()), BRW_REGISTER_TYPE_UW),
+		      0,		/* base reg */
+		      retype (brw_vec8_grf (0), BRW_REGISTER_TYPE_UW),
+		      0,		/* binding table index */
+		      2 + 8,	/* msg length */
+		      0,		/* response length */
+		      TRUE);	/* EOT */
+    }
+
+    program = brw_get_program (&compile, &size);
+    *num_reg = grf;
+
+    i965_stream_align (&device->general, 64);
+    offset = i965_stream_emit (&device->general, program, size);
+
+    cache = _cairo_freelist_alloc (&device->wm_kernel_freelist);
+    if (likely (cache != NULL)) {
+	i965_wm_kernel_init (cache, shader);
+	cache->offset = offset;
+	status = _cairo_hash_table_insert (device->wm_kernels, &cache->entry);
+	if (unlikely (status))
+	    _cairo_freelist_free (&device->wm_kernel_freelist, cache);
+    }
+
+    return offset;
+}
+
+static uint32_t
+create_sf_kernel (i965_device_t *device,
+		  i965_shader_t *shader)
+{
+    struct brw_compile compile;
+    const uint32_t *program;
+    uint32_t size;
+    int msg_len;
+
+    brw_compile_init (&compile, device->is_g4x);
+
+    switch (shader->mask.type.vertex) {
+    default:
+    case VS_NONE:
+	/* use curb plane eq in WM */
+	msg_len = 1;
+	break;
+
+    case VS_SPANS:
+	/* just a constant opacity */
+	brw_MOV (&compile,
+		 brw_message4_reg (1),
+		 brw_vec4_grf (3, 0));
+	msg_len = 2;
+	break;
+
+    case VS_GLYPHS:
+	/* an offset+sf into the glyph cache */
+	brw_MOV (&compile,
+		 brw_acc_reg (),
+		 brw_vec2_grf (3, 0));
+	brw_MAC (&compile,
+		 brw_message4_reg (1),
+		 negate (brw_vec2_grf (1, 4)),
+		 brw_imm_f (1./1024));
+	msg_len = 2;
+	break;
+    }
+
+    brw_urb_WRITE (&compile,
+		   brw_null_reg (),
+		   0,
+		   brw_vec8_grf (0), /* r0, will be copied to m0 */
+		   0,	/* allocate */
+		   1,	/* used */
+		   msg_len,
+		   0,	/* response len */
+		   1,	/* eot */
+		   1,	/* writes complete */
+		   0,	/* offset */
+		   BRW_URB_SWIZZLE_NONE);
+
+    program = brw_get_program (&compile, &size);
+
+    i965_stream_align (&device->general, 64);
+    return i965_stream_emit (&device->general, program, size);
+}
+
+static uint32_t
+i965_sf_kernel (const i965_shader_t *shader)
+{
+    return shader->mask.type.vertex;
+}
+
+static void
+i965_sf_state_init (struct i965_sf_state *key,
+		    const i965_shader_t *shader)
+{
+    key->entry.hash = i965_sf_kernel (shader);
+}
+
+cairo_bool_t
+i965_sf_state_equal (const void *A, const void *B)
+{
+    const cairo_hash_entry_t *a = A, *b = B;
+    return a->hash == b->hash;
+}
+
+/**
+ * Sets up the SF state pointing at an SF kernel.
+ *
+ * The SF kernel does coord interp: for each attribute,
+ * calculate dA/dx and dA/dy.  Hand these interpolation coefficients
+ * back to SF which then hands pixels off to WM.
+ */
+static uint32_t
+gen4_create_sf_state (i965_device_t *device,
+		      i965_shader_t *shader)
+{
+    struct brw_sf_unit_state *state;
+    struct i965_sf_state key, *cache;
+    cairo_status_t status;
+    uint32_t offset;
+
+    i965_sf_state_init (&key, shader);
+    if (i965_sf_state_equal (&key, &device->sf_state))
+	return device->sf_state.offset;
+
+    cache = _cairo_hash_table_lookup (device->sf_states, &key.entry);
+    if (cache != NULL) {
+	offset = cache->offset;
+	goto DONE;
+    }
+
+    offset = create_sf_kernel (device, shader);
+
+    state = i965_stream_alloc (&device->general, 32, sizeof (*state));
+    memset (state, 0, sizeof (*state));
+
+    state->thread0.grf_reg_count = BRW_GRF_BLOCKS (3);
+    assert ((offset & 63) == 0);
+    state->thread0.kernel_start_pointer = offset >> 6;
+    state->sf1.single_program_flow = 1;
+    state->thread3.urb_entry_read_length = 1; /* 1 URB per vertex */
+    state->thread3.urb_entry_read_offset = 1;
+    state->thread3.dispatch_grf_start_reg = 3;
+    state->thread4.max_threads = SF_MAX_THREADS - 1;
+    state->thread4.urb_entry_allocation_size = URB_SF_ENTRY_SIZE - 1;
+    state->thread4.nr_urb_entries = URB_SF_ENTRIES;
+    state->sf6.dest_org_vbias = 0x8;
+    state->sf6.dest_org_hbias = 0x8;
+
+    offset = i965_stream_offsetof (&device->general, state);
+
+    cache = _cairo_freelist_alloc (&device->sf_freelist);
+    if (likely (cache != NULL)) {
+	i965_sf_state_init (cache, shader);
+	cache->offset = offset;
+	status = _cairo_hash_table_insert (device->sf_states, &cache->entry);
+	if (unlikely (status))
+	    _cairo_freelist_free (&device->sf_freelist, cache);
+    }
+
+  DONE:
+    i965_sf_state_init (&device->sf_state, shader);
+    device->sf_state.offset = offset;
+
+    return offset;
+}
+
+static unsigned long
+i965_shader_sampler_hash (const i965_shader_t *shader)
+{
+    unsigned long hash = 0;
+    unsigned int offset = 0;
+
+    if (shader->source.base.bo != NULL) {
+	hash |= (shader->source.base.filter << offset) |
+	        (shader->source.base.extend << (offset + 4));
+	offset += 8;
+    }
+
+    if (shader->mask.base.bo != NULL) {
+	hash |= (shader->mask.base.filter << offset) |
+	        (shader->mask.base.extend << (offset + 4));
+	offset += 8;
+    }
+
+    if (shader->clip.base.bo != NULL) {
+	hash |= (shader->clip.base.filter << offset) |
+	        (shader->clip.base.extend << (offset + 4));
+	offset += 8;
+    }
+
+    if (shader->dst.base.bo != NULL) {
+	hash |= (shader->dst.base.filter << offset) |
+	        (shader->dst.base.extend << (offset + 4));
+	offset += 8;
+    }
+
+    return hash;
+}
+
+static void
+i965_sampler_init (struct i965_sampler *key,
+		   const i965_shader_t *shader)
+{
+    key->entry.hash = i965_shader_sampler_hash (shader);
+}
+
+static void
+emit_sampler_channel (i965_device_t *device,
+		      const union i965_shader_channel *channel,
+		      uint32_t border_color)
+{
+    struct brw_sampler_state *state;
+
+    state = i965_stream_alloc (&device->general, 0, sizeof (*state));
+    memset (state, 0, sizeof (*state));
+
+    state->ss0.lod_preclamp = 1; /* GL mode */
+
+    state->ss0.border_color_mode = BRW_BORDER_COLOR_MODE_LEGACY;
+
+    state->ss0.min_filter = channel->base.filter;
+    state->ss0.mag_filter = channel->base.filter;
+
+    state->ss1.r_wrap_mode = channel->base.extend;
+    state->ss1.s_wrap_mode = channel->base.extend;
+    state->ss1.t_wrap_mode = channel->base.extend;
+
+    assert ((border_color & 31) == 0);
+    state->ss2.border_color_pointer = border_color >> 5;
+}
+
+static uint32_t
+emit_sampler_state_table (i965_device_t *device,
+			  i965_shader_t *shader)
+{
+    struct i965_sampler key, *cache;
+    cairo_status_t status;
+    uint32_t offset;
+
+    if (device->border_color_offset == (uint32_t) -1) {
+	struct brw_sampler_legacy_border_color *border_color;
+
+	border_color = i965_stream_alloc (&device->general, 32,
+					  sizeof (*border_color));
+	border_color->color[0] = 0; /* R */
+	border_color->color[1] = 0; /* G */
+	border_color->color[2] = 0; /* B */
+	border_color->color[3] = 0; /* A */
+
+	device->border_color_offset = i965_stream_offsetof (&device->general,
+							    border_color);
+    } else {
+	i965_sampler_init (&key, shader);
+	cache = _cairo_hash_table_lookup (device->samplers, &key.entry);
+	if (cache != NULL)
+	    return cache->offset;
+    }
+
+    i965_stream_align (&device->general, 32);
+    offset = device->general.used;
+    if (shader->source.base.bo != NULL) {
+	emit_sampler_channel (device,
+			      &shader->source,
+			      device->border_color_offset);
+    }
+    if (shader->mask.base.bo != NULL) {
+	emit_sampler_channel (device,
+			      &shader->mask,
+			      device->border_color_offset);
+    }
+    if (shader->clip.base.bo != NULL) {
+	emit_sampler_channel (device,
+			      &shader->clip,
+			      device->border_color_offset);
+    }
+    if (shader->dst.base.bo != NULL) {
+	emit_sampler_channel (device,
+			      &shader->dst,
+			      device->border_color_offset);
+    }
+
+    cache = _cairo_freelist_alloc (&device->sampler_freelist);
+    if (likely (cache != NULL)) {
+	i965_sampler_init (cache, shader);
+	cache->offset = offset;
+	status = _cairo_hash_table_insert (device->samplers, &cache->entry);
+	if (unlikely (status))
+	    _cairo_freelist_free (&device->sampler_freelist, cache);
+    }
+
+    return offset;
+}
+
+static void
+i965_cc_state_init (struct i965_cc_state *key,
+		    const i965_shader_t *shader)
+{
+    uint32_t src_blend, dst_blend;
+
+    if (shader->need_combine)
+	src_blend = dst_blend = 0;
+    else
+	i965_shader_get_blend_cntl (shader, &src_blend, &dst_blend);
+
+    key->entry.hash = src_blend | ((dst_blend & 0xffff) << 16);
+}
+
+cairo_bool_t
+i965_cc_state_equal (const void *A, const void *B)
+{
+    const cairo_hash_entry_t *a = A, *b = B;
+    return a->hash == b->hash;
+}
+
+static uint32_t
+cc_state_emit (i965_device_t *device, i965_shader_t *shader)
+{
+    struct brw_cc_unit_state *state;
+    struct i965_cc_state key, *cache;
+    cairo_status_t status;
+    uint32_t src_blend, dst_blend;
+    uint32_t offset;
+
+    i965_cc_state_init (&key, shader);
+    if (i965_cc_state_equal (&key, &device->cc_state))
+	return device->cc_state.offset;
+
+    cache = _cairo_hash_table_lookup (device->cc_states, &key.entry);
+    if (cache != NULL) {
+	offset = cache->offset;
+	goto DONE;
+    }
+
+    if (shader->need_combine)
+	src_blend = dst_blend = 0;
+    else
+	i965_shader_get_blend_cntl (shader, &src_blend, &dst_blend);
+
+    state = i965_stream_alloc (&device->general, 64, sizeof (*state));
+    memset (state, 0, sizeof (*state));
+
+    /* XXX Note errata, need to flush render cache when blend_enable 0 -> 1 */
+    /* XXX 2 source blend */
+    state->cc3.blend_enable = ! shader->need_combine;
+    state->cc5.ia_blend_function = BRW_BLENDFUNCTION_ADD;
+    state->cc5.ia_src_blend_factor  = src_blend;
+    state->cc5.ia_dest_blend_factor = dst_blend;
+    state->cc6.blend_function = BRW_BLENDFUNCTION_ADD;
+    state->cc6.clamp_post_alpha_blend = 1;
+    state->cc6.clamp_pre_alpha_blend  = 1;
+    state->cc6.src_blend_factor  = src_blend;
+    state->cc6.dest_blend_factor = dst_blend;
+
+    offset = i965_stream_offsetof (&device->general, state);
+
+    cache = _cairo_freelist_alloc (&device->cc_freelist);
+    if (likely (cache != NULL)) {
+	i965_cc_state_init (cache, shader);
+	cache->offset = offset;
+	status = _cairo_hash_table_insert (device->cc_states, &cache->entry);
+	if (unlikely (status))
+	    _cairo_freelist_free (&device->cc_freelist, cache);
+    }
+
+  DONE:
+    i965_cc_state_init (&device->cc_state, shader);
+    device->cc_state.offset = offset;
+
+    return offset;
+}
+
+static void
+i965_wm_state_init (struct i965_wm_state *key,
+		    const i965_shader_t *shader)
+{
+    key->kernel = i965_wm_kernel_hash (shader);
+    key->sampler = i965_shader_sampler_hash (shader);
+
+    key->entry.hash = key->kernel ^ ((key->sampler) << 16 | (key->sampler >> 16));
+}
+
+cairo_bool_t
+i965_wm_state_equal (const void *A, const void *B)
+{
+    const struct i965_wm_state *a = A, *b = B;
+
+    if (a->entry.hash != b->entry.hash)
+	return FALSE;
+
+    return a->kernel == b->kernel && a->sampler == b->sampler;
+}
+
+static int
+i965_shader_binding_table_count (i965_shader_t *shader)
+{
+    int count;
+
+    count = 1;
+    if (shader->source.type.fragment != FS_CONSTANT)
+	count++;
+    switch (shader->mask.type.fragment) {
+    case FS_NONE:
+    case FS_CONSTANT:
+    case FS_SPANS:
+	break;
+    case FS_LINEAR:
+    case FS_RADIAL:
+    case FS_SURFACE:
+    case FS_GLYPHS:
+	count++;
+    }
+    if (shader->clip.type.fragment == FS_SURFACE)
+	count++;
+    if (shader->dst.type.fragment == FS_SURFACE)
+	count++;
+
+    return count;
+}
+
+static uint32_t
+gen4_create_wm_state (i965_device_t *device,
+		      i965_shader_t *shader)
+{
+    struct brw_wm_unit_state *state;
+    uint32_t sampler;
+    uint32_t kernel;
+
+    struct i965_wm_state key, *cache;
+    cairo_status_t status;
+    int num_reg;
+
+    i965_wm_state_init (&key, shader);
+    if (i965_wm_state_equal (&key, &device->wm_state))
+	return device->wm_state.offset;
+
+    cache = _cairo_hash_table_lookup (device->wm_states, &key.entry);
+    if (cache != NULL) {
+	device->wm_state = *cache;
+	return cache->offset;
+    }
+
+    kernel = create_wm_kernel (device, shader, &num_reg);
+    sampler = emit_sampler_state_table (device, shader);
+
+    state = i965_stream_alloc (&device->general, 32, sizeof (*state));
+    memset (state, 0, sizeof (*state));
+    state->thread0.grf_reg_count = BRW_GRF_BLOCKS (num_reg);
+    assert ((kernel & 63) == 0);
+    state->thread0.kernel_start_pointer = kernel >> 6;
+
+    state->thread3.dispatch_grf_start_reg = 2;
+
+    state->wm4.sampler_count = 1; /* 1-4 samplers used */
+    assert ((sampler & 31) == 0);
+    state->wm4.sampler_state_pointer = sampler >> 5;
+    if (device->is_g4x)
+	state->wm5.max_threads = PS_MAX_THREADS_CTG - 1;
+    else
+	state->wm5.max_threads = PS_MAX_THREADS_BRW - 1;
+    state->wm5.thread_dispatch_enable = 1;
+
+    if (device->is_g4x) {
+	/* XXX contiguous 32 pixel dispatch */
+    }
+    state->wm5.enable_16_pix = 1;
+    /* 8 pixel dispatch and friends */
+    //state->wm5.early_depth_test = 1;
+
+    state->thread1.binding_table_entry_count = i965_shader_binding_table_count(shader);
+    state->thread3.urb_entry_read_length = i965_shader_pue_length (shader);
+    state->thread3.const_urb_entry_read_length = i965_shader_const_urb_length (shader);
+
+    key.offset = i965_stream_offsetof (&device->general, state);
+
+    cache = _cairo_freelist_alloc (&device->wm_state_freelist);
+    if (likely (cache != NULL)) {
+	*cache = key;
+	status = _cairo_hash_table_insert (device->wm_states, &cache->entry);
+	if (unlikely (status))
+	    _cairo_freelist_free (&device->wm_state_freelist, cache);
+    }
+
+    device->wm_state = key;
+    return key.offset;
+}
+
+static uint32_t
+vs_unit_state_emit (i965_device_t *device)
+{
+    if (device->vs_offset == (uint32_t) -1) {
+	struct brw_vs_unit_state *state;
+
+	/* Set up the vertex shader to be disabled (passthrough) */
+	state = i965_stream_alloc (&device->general, 32, sizeof (*state));
+	memset (state, 0, sizeof (*state));
+
+	state->thread4.nr_urb_entries = URB_VS_ENTRIES;
+	state->thread4.urb_entry_allocation_size = URB_VS_ENTRY_SIZE - 1;
+	state->vs6.vert_cache_disable = 1;
+
+	device->vs_offset = i965_stream_offsetof (&device->general, state);
+    }
+
+    return device->vs_offset;
+}
+
+static uint32_t
+i965_get_card_format (cairo_format_t format)
+{
+    switch (format) {
+    case CAIRO_FORMAT_ARGB32:
+	return BRW_SURFACEFORMAT_B8G8R8A8_UNORM;
+    case CAIRO_FORMAT_RGB24:
+	return BRW_SURFACEFORMAT_B8G8R8X8_UNORM;
+    case CAIRO_FORMAT_A8:
+	return BRW_SURFACEFORMAT_A8_UNORM;
+    case CAIRO_FORMAT_A1:
+    default:
+	ASSERT_NOT_REACHED;
+	return 0;
+    }
+}
+
+static uint32_t
+i965_get_dest_format (cairo_format_t format)
+{
+    switch (format) {
+    case CAIRO_FORMAT_ARGB32:
+    case CAIRO_FORMAT_RGB24:
+        return BRW_SURFACEFORMAT_B8G8R8A8_UNORM;
+    case CAIRO_FORMAT_A8:
+        return BRW_SURFACEFORMAT_A8_UNORM;
+    case CAIRO_FORMAT_A1:
+    default:
+	ASSERT_NOT_REACHED;
+	return 0;
+    }
+}
+
+/* XXX silly inline due to compiler bug... */
+static inline void
+i965_stream_add_pending_relocation (i965_stream_t *stream,
+				    uint32_t target_offset,
+				    uint32_t read_domains,
+				    uint32_t write_domain,
+				    uint32_t delta)
+{
+    int n;
+
+    n = stream->num_pending_relocations++;
+    assert (n < stream->max_pending_relocations);
+
+    stream->pending_relocations[n].offset = target_offset;
+    stream->pending_relocations[n].read_domains = read_domains;
+    stream->pending_relocations[n].write_domain = write_domain;;
+    stream->pending_relocations[n].delta = delta;
+}
+
+static uint32_t
+emit_surface_state (i965_device_t *device,
+		    cairo_bool_t is_target,
+		    intel_bo_t *bo,
+		    cairo_format_t format,
+		    int width, int height, int stride,
+		    int type)
+{
+    struct brw_surface_state *state;
+    uint32_t write_domain, read_domains;
+    uint32_t offset;
+
+    state = i965_stream_alloc (&device->surface, 32, sizeof (*state));
+    memset (state, 0, sizeof (*state));
+
+    state->ss0.surface_type = type;
+    if (is_target)
+	state->ss0.surface_format = i965_get_dest_format (format);
+    else
+	state->ss0.surface_format = i965_get_card_format (format);
+
+    state->ss0.data_return_format = BRW_SURFACERETURNFORMAT_FLOAT32;
+    state->ss0.color_blend = 1;
+    if (is_target && device->is_g4x)
+	state->ss0.render_cache_read_mode = 1;
+
+    state->ss1.base_addr = bo->offset;
+
+    state->ss2.height = height - 1;
+    state->ss2.width  = width  - 1;
+    state->ss3.pitch  = stride - 1;
+    state->ss3.tile_walk = bo->tiling == I915_TILING_Y;
+    state->ss3.tiled_surface = bo->tiling != I915_TILING_NONE;
+
+    if (is_target) {
+	read_domains = I915_GEM_DOMAIN_RENDER;
+	write_domain = I915_GEM_DOMAIN_RENDER;
+    } else {
+	read_domains = I915_GEM_DOMAIN_SAMPLER;
+	write_domain = 0;
+    }
+
+    offset = i965_stream_offsetof (&device->surface, state);
+    i965_emit_relocation (device, &device->surface,
+			  bo, 0,
+			  read_domains, write_domain,
+			  offset + offsetof (struct brw_surface_state, ss1.base_addr));
+    return offset;
+}
+
+static uint32_t
+emit_surface_state_for_shader (i965_device_t *device,
+			       const union i965_shader_channel *channel)
+{
+    int type = BRW_SURFACE_2D;
+
+    assert (channel->type.fragment != FS_NONE);
+    assert (channel->type.fragment != FS_CONSTANT);
+
+    if (channel->type.fragment != FS_SURFACE)
+	type = BRW_SURFACE_1D;
+
+    return emit_surface_state (device, FALSE,
+			       channel->base.bo,
+			       channel->base.format,
+			       channel->base.width,
+			       channel->base.height,
+			       channel->base.stride,
+			       type);
+}
+
+cairo_bool_t
+i965_wm_binding_equal (const void *A,
+		       const void *B)
+{
+    const struct i965_wm_binding *a = A, *b = B;
+
+    if (a->entry.hash != b->entry.hash)
+	return FALSE;
+
+    if (a->size != b->size)
+	return FALSE;
+
+    return memcmp (a->table, b->table, sizeof (uint32_t) * a->size) == 0;
+}
+
+static void
+i965_wm_binding_init (struct i965_wm_binding *state,
+		      const uint32_t *table,
+		      int size)
+{
+    int n;
+
+    state->entry.hash = size;
+    state->size = size;
+
+    for (n = 0; n < size; n++) {
+	state->table[n] = table[n];
+	state->entry.hash ^= (table[n] << (8 * n)) |
+	                     (table[n] >> (32 - (8*n)));
+    }
+}
+
+static uint32_t
+emit_binding_table (i965_device_t *device,
+		    i965_shader_t *shader)
+{
+    intel_bo_t *bo;
+    struct i965_wm_binding key, *cache;
+    uint32_t *table;
+    int n = 0;
+
+    table = i965_stream_alloc (&device->surface, 32, 5 * sizeof (uint32_t));
+    if (shader->target->stream != device->surface.serial) {
+	shader->target->stream = device->surface.serial;
+	shader->target->offset = emit_surface_state (device,
+						     TRUE,
+						     to_intel_bo (shader->target->intel.drm.bo),
+						     shader->target->intel.drm.format,
+						     shader->target->intel.drm.width,
+						     shader->target->intel.drm.height,
+						     shader->target->intel.drm.stride,
+						     BRW_SURFACE_2D);
+    }
+    table[n++] = shader->target->offset;
+
+    bo = shader->source.base.bo;
+    if (bo != NULL) {
+	if (bo->opaque0 != device->surface.serial) {
+	    bo->opaque0 = device->surface.serial;
+	    bo->opaque1 = emit_surface_state_for_shader (device, &shader->source);
+	}
+	table[n++] = bo->opaque1;
+    }
+
+    bo = shader->mask.base.bo;
+    if (bo != NULL) {
+	if (bo->opaque0 != device->surface.serial) {
+	    bo->opaque0 = device->surface.serial;
+	    bo->opaque1 = emit_surface_state_for_shader (device, &shader->mask);
+	}
+	table[n++] = bo->opaque1;
+    }
+
+    bo = shader->clip.base.bo;
+    if (bo != NULL) {
+	if (bo->opaque0 != device->surface.serial) {
+	    bo->opaque0 = device->surface.serial;
+	    bo->opaque1 = emit_surface_state_for_shader (device, &shader->clip);
+	}
+	table[n++] = bo->opaque1;
+    }
+
+    bo = shader->dst.base.bo;
+    if (bo != NULL) {
+	if (bo->opaque0 != device->surface.serial) {
+	    bo->opaque0 = device->surface.serial;
+	    bo->opaque1 = emit_surface_state_for_shader (device, &shader->dst);
+	}
+	table[n++] = bo->opaque1;
+    }
+
+    i965_wm_binding_init (&key, table, n);
+    key.offset = i965_stream_offsetof (&device->surface, table);
+
+    if (i965_wm_binding_equal (&key, &device->wm_binding)) {
+	device->surface.used = key.offset;
+	return device->wm_binding.offset;
+    }
+
+    cache = _cairo_hash_table_lookup (device->wm_bindings, &key.entry);
+    if (cache != NULL) {
+	device->surface.used = key.offset;
+	key.offset = cache->offset;
+    }
+
+    device->wm_binding = key;
+    return key.offset;
+}
+
+static void
+i965_emit_invariants (i965_device_t *device)
+{
+    OUT_BATCH (BRW_CS_URB_STATE | 0);
+    OUT_BATCH (((URB_CS_ENTRY_SIZE-1) << 4) | (URB_CS_ENTRIES << 0));
+}
+
+static void
+i965_emit_urb_fences (i965_device_t *device)
+{
+    int urb_vs_start, urb_vs_size;
+    int urb_gs_start, urb_gs_size;
+    int urb_clip_start, urb_clip_size;
+    int urb_sf_start, urb_sf_size;
+    int urb_cs_start, urb_cs_size;
+
+    if (device->have_urb_fences)
+	return;
+
+    /* URB fence */
+    urb_vs_start = 0;
+    urb_vs_size = URB_VS_ENTRIES * URB_VS_ENTRY_SIZE;
+    urb_gs_start = urb_vs_start + urb_vs_size;
+    urb_gs_size = URB_GS_ENTRIES * URB_GS_ENTRY_SIZE;
+    urb_clip_start = urb_gs_start + urb_gs_size;
+    urb_clip_size = URB_CLIP_ENTRIES * URB_CLIP_ENTRY_SIZE;
+    urb_sf_start = urb_clip_start + urb_clip_size;
+    urb_sf_size = URB_SF_ENTRIES * URB_SF_ENTRY_SIZE;
+    urb_cs_start = urb_sf_start + urb_sf_size;
+    urb_cs_size = URB_CS_ENTRIES * URB_CS_ENTRY_SIZE;
+
+    /* erratum: URB_FENCE must not cross a 64-byte cache-line */
+    while ((device->batch.used & 63) > 64-12)
+	OUT_BATCH (MI_NOOP);
+    OUT_BATCH (BRW_URB_FENCE |
+	       UF0_CS_REALLOC |
+	       UF0_SF_REALLOC |
+	       UF0_CLIP_REALLOC |
+	       UF0_GS_REALLOC |
+	       UF0_VS_REALLOC |
+	       1);
+    OUT_BATCH (((urb_clip_start + urb_clip_size) << UF1_CLIP_FENCE_SHIFT) |
+	       ((urb_gs_start + urb_gs_size) << UF1_GS_FENCE_SHIFT) |
+	       ((urb_vs_start + urb_vs_size) << UF1_VS_FENCE_SHIFT));
+    OUT_BATCH (((urb_cs_start + urb_cs_size) << UF2_CS_FENCE_SHIFT) |
+	       ((urb_sf_start + urb_sf_size) << UF2_SF_FENCE_SHIFT));
+
+    device->have_urb_fences = TRUE;
+    device->constants_size = 0;
+}
+
+static void
+i965_emit_base (i965_device_t *device)
+{
+    OUT_BATCH (BRW_STATE_BASE_ADDRESS | 4);
+    if (likely (device->general.num_pending_relocations == 0)) {
+	i965_stream_add_pending_relocation (&device->general,
+					    device->batch.used,
+					    I915_GEM_DOMAIN_INSTRUCTION, 0,
+					    BASE_ADDRESS_MODIFY);
+    }
+    OUT_BATCH (0); /* pending relocation */
+
+    if (likely (device->surface.num_pending_relocations == 0)) {
+	i965_stream_add_pending_relocation (&device->surface,
+					    device->batch.used,
+					    I915_GEM_DOMAIN_INSTRUCTION, 0,
+					    BASE_ADDRESS_MODIFY);
+    }
+    OUT_BATCH (0); /* pending relocation */
+
+    OUT_BATCH (0 | BASE_ADDRESS_MODIFY);
+    /* general state max addr, disabled */
+    OUT_BATCH (0x10000000 | BASE_ADDRESS_MODIFY);
+    /* media object state max addr, disabled */
+    OUT_BATCH (0x10000000 | BASE_ADDRESS_MODIFY);
+}
+
+static void
+i965_emit_vertex_element (i965_device_t *device,
+			  i965_shader_t *shader)
+{
+    uint32_t offset;
+    uint32_t type;
+    int nelem;
+
+    type = 0;
+    nelem = 1;
+    if (shader->mask.type.vertex == VS_SPANS ||
+	shader->mask.type.vertex == VS_GLYPHS)
+    {
+	type = shader->mask.type.vertex;
+	nelem++;
+    }
+
+    if (type == device->vertex_type)
+	return;
+    device->vertex_type = type;
+
+    offset = 0;
+
+    OUT_BATCH (BRW_3DSTATE_VERTEX_ELEMENTS | ((2 * nelem) - 1));
+    OUT_BATCH ((0 << VE0_VERTEX_BUFFER_INDEX_SHIFT) |
+	       VE0_VALID |
+	       (BRW_SURFACEFORMAT_R32G32_FLOAT	<< VE0_FORMAT_SHIFT) |
+	       (offset				<< VE0_OFFSET_SHIFT));
+    OUT_BATCH ((BRW_VFCOMPONENT_STORE_SRC	<< VE1_VFCOMPONENT_0_SHIFT) |
+	       (BRW_VFCOMPONENT_STORE_SRC	<< VE1_VFCOMPONENT_1_SHIFT) |
+	       (BRW_VFCOMPONENT_STORE_0		<< VE1_VFCOMPONENT_2_SHIFT) |
+	       (BRW_VFCOMPONENT_STORE_1_FLT	<< VE1_VFCOMPONENT_3_SHIFT) |
+	       (4 << VE1_DESTINATION_ELEMENT_OFFSET_SHIFT));
+    offset += 8;
+
+    assert (shader->source.type.vertex == VS_NONE);
+    switch (shader->mask.type.vertex) {
+    default:
+    case VS_NONE:
+	break;
+
+    case VS_SPANS:
+	OUT_BATCH((0 << VE0_VERTEX_BUFFER_INDEX_SHIFT) |
+		  VE0_VALID |
+		  (BRW_SURFACEFORMAT_R32_FLOAT << VE0_FORMAT_SHIFT) |
+		  (offset			<< VE0_OFFSET_SHIFT));
+	OUT_BATCH((BRW_VFCOMPONENT_STORE_SRC	<< VE1_VFCOMPONENT_0_SHIFT) |
+		  (BRW_VFCOMPONENT_NOSTORE	<< VE1_VFCOMPONENT_1_SHIFT) |
+		  (BRW_VFCOMPONENT_NOSTORE	<< VE1_VFCOMPONENT_2_SHIFT) |
+		  (BRW_VFCOMPONENT_NOSTORE	<< VE1_VFCOMPONENT_3_SHIFT) |
+		  (8 << VE1_DESTINATION_ELEMENT_OFFSET_SHIFT));
+
+	offset += 4;
+	break;
+
+    case VS_GLYPHS:
+	OUT_BATCH((0 << VE0_VERTEX_BUFFER_INDEX_SHIFT) |
+		  VE0_VALID |
+		  (BRW_SURFACEFORMAT_R16G16_FLOAT << VE0_FORMAT_SHIFT) |
+		  (offset			<< VE0_OFFSET_SHIFT));
+	OUT_BATCH((BRW_VFCOMPONENT_STORE_SRC	<< VE1_VFCOMPONENT_0_SHIFT) |
+		  (BRW_VFCOMPONENT_STORE_SRC	<< VE1_VFCOMPONENT_1_SHIFT) |
+		  (BRW_VFCOMPONENT_NOSTORE	<< VE1_VFCOMPONENT_2_SHIFT) |
+		  (BRW_VFCOMPONENT_NOSTORE	<< VE1_VFCOMPONENT_3_SHIFT) |
+		  (8 << VE1_DESTINATION_ELEMENT_OFFSET_SHIFT));
+
+	offset += 4;
+	break;
+    }
+    assert (shader->clip.type.vertex == VS_NONE);
+    assert (shader->dst.type.vertex == VS_NONE);
+
+    device->vertex_size = offset;
+    i965_stream_align (&device->vertex, device->vertex_size);
+    device->vertex.committed = device->vertex.used;
+
+    device->rectangle_size = 3 * offset;
+}
+
+static cairo_bool_t
+i965_shader_needs_surface_update (const i965_shader_t *shader,
+				  const i965_device_t *device)
+{
+    return device->target != shader->target || shader->target->stream == 0 ||
+	(shader->source.base.bo != NULL && device->source != shader->source.base.bo) ||
+	(shader->mask.base.bo != NULL && device->mask != shader->mask.base.bo) ||
+	(shader->clip.base.bo != NULL && device->clip != shader->clip.base.bo);
+}
+
+static cairo_bool_t
+i965_shader_needs_constants_update (const i965_shader_t *shader,
+				    const i965_device_t *device)
+{
+    if (shader->constants_size == 0)
+	return FALSE;
+
+    if (device->constants_size != shader->constants_size)
+	return TRUE;
+
+    return memcmp (device->constants,
+		   shader->constants,
+		   sizeof (float) * shader->constants_size);
+}
+
+static cairo_bool_t
+i965_shader_needs_state_update (const i965_shader_t *shader,
+				const i965_device_t *device)
+{
+    union {
+	struct i965_sf_state sf;
+	struct i965_wm_state wm;
+	struct i965_cc_state cc;
+    } state;
+
+    i965_sf_state_init (&state.sf, shader);
+    if (! i965_sf_state_equal (&state.sf, &device->sf_state))
+	return TRUE;
+
+    i965_wm_state_init (&state.wm, shader);
+    if (! i965_wm_state_equal (&state.wm, &device->wm_state))
+	return TRUE;
+
+    i965_cc_state_init (&state.cc, shader);
+    if (! i965_cc_state_equal (&state.cc, &device->cc_state))
+	return TRUE;
+
+    return FALSE;
+}
+
+static void
+i965_emit_composite (i965_device_t *device,
+		     i965_shader_t *shader)
+{
+    uint32_t draw_rectangle;
+
+    if (i965_shader_needs_surface_update (shader, device)) {
+	/* Binding table pointers */
+	OUT_BATCH (BRW_3DSTATE_BINDING_TABLE_POINTERS | 4);
+	OUT_BATCH (0); /* vs */
+	OUT_BATCH (0); /* gs */
+	OUT_BATCH (0); /* clip */
+	OUT_BATCH (0); /* sf */
+	/* Only the PS uses the binding table */
+	OUT_BATCH (emit_binding_table (device, shader));
+
+	device->target = shader->target;
+	device->source = shader->source.base.bo;
+	device->mask = shader->mask.base.bo;
+	device->clip = shader->clip.base.bo;
+    }
+
+    /* The drawing rectangle clipping is always on.  Set it to values that
+     * shouldn't do any clipping.
+     */
+    draw_rectangle = DRAW_YMAX (shader->target->intel.drm.height - 1) |
+	             DRAW_XMAX (shader->target->intel.drm.width  - 1);
+    if (draw_rectangle != device->draw_rectangle) {
+	OUT_BATCH (BRW_3DSTATE_DRAWING_RECTANGLE | 2);
+	OUT_BATCH (0x00000000);	/* ymin, xmin */
+	OUT_BATCH (draw_rectangle);
+	OUT_BATCH (0x00000000);	/* yorigin, xorigin */
+	device->draw_rectangle = draw_rectangle;
+    }
+
+    /* skip the depth buffer */
+    /* skip the polygon stipple */
+    /* skip the polygon stipple offset */
+    /* skip the line stipple */
+
+    /* Set the pointers to the 3d pipeline state */
+    if (i965_shader_needs_state_update (shader, device)) {
+	OUT_BATCH (BRW_3DSTATE_PIPELINED_POINTERS | 5);
+	OUT_BATCH (vs_unit_state_emit (device));
+	OUT_BATCH (BRW_GS_DISABLE);
+	OUT_BATCH (BRW_CLIP_DISABLE);
+	OUT_BATCH (gen4_create_sf_state (device, shader));
+	OUT_BATCH (gen4_create_wm_state (device, shader));
+	OUT_BATCH (cc_state_emit (device, shader));
+
+	/* Once the units are initialized, we need to setup the fences */
+	i965_emit_urb_fences (device);
+    }
+
+    if (i965_shader_needs_constants_update (shader, device)) {
+	uint32_t size = (sizeof (float) * shader->constants_size + 63) & -64;
+
+	/* XXX reuse clear/black/white
+	 * ht!
+	*/
+
+	/* XXX CONSTANT_BUFFER Address Offset Disable? INSTPM? */
+
+	assert (size <= 64 * URB_CS_ENTRY_SIZE);
+	assert (((sizeof (float) * shader->constants_size + 31) & -32) == 32 * i965_shader_const_urb_length (shader));
+
+	OUT_BATCH (BRW_CONSTANT_BUFFER | (1 << 8));
+	assert ((device->constant.used & 63) == 0);
+	i965_stream_add_pending_relocation (&device->constant,
+					    device->batch.used,
+					    I915_GEM_DOMAIN_INSTRUCTION, 0,
+					    device->constant.used + size / 64 - 1);
+	OUT_BATCH (0); /* pending relocation */
+
+	device->constants = i965_stream_alloc (&device->constant, 0, size);
+	memcpy (device->constants, shader->constants, size);
+	device->constants_size = shader->constants_size;
+    }
+
+    i965_emit_vertex_element (device, shader);
+}
+
+void
+i965_flush_vertices (i965_device_t *device)
+{
+    int vertex_count, vertex_start;
+
+    if (device->vertex.used == device->vertex.committed)
+	return;
+
+    vertex_start = device->vertex.committed / device->vertex_size;
+    vertex_count =
+	(device->vertex.used - device->vertex.committed) / device->vertex_size;
+
+    assert (vertex_count);
+
+    if (device->vertex_size != device->last_vertex_size) {
+	i965_stream_add_pending_relocation (&device->vertex,
+					    device->batch.used + 8,
+					    I915_GEM_DOMAIN_VERTEX, 0,
+					    0);
+
+	OUT_BATCH (BRW_3DSTATE_VERTEX_BUFFERS | 3);
+	OUT_BATCH ((0 << VB0_BUFFER_INDEX_SHIFT) |
+		   VB0_VERTEXDATA |
+		   (device->vertex_size << VB0_BUFFER_PITCH_SHIFT));
+	OUT_BATCH (0); /* pending relocation */
+	OUT_BATCH (0);
+	OUT_BATCH (0);
+	device->last_vertex_size = device->vertex_size;
+    }
+
+    OUT_BATCH (BRW_3DPRIMITIVE |
+	       BRW_3DPRIMITIVE_VERTEX_SEQUENTIAL |
+	       (_3DPRIM_RECTLIST << BRW_3DPRIMITIVE_TOPOLOGY_SHIFT) |
+	       (0 << 9) |
+	       4);
+    OUT_BATCH (vertex_count);  /* vertex count per instance */
+    OUT_BATCH (vertex_start);  /* start vertex offset */
+    OUT_BATCH (1); /* single instance */
+    OUT_BATCH (0);
+    OUT_BATCH (0);
+
+    device->vertex.committed = device->vertex.used;
+
+#if 1
+    OUT_BATCH (MI_FLUSH);
+#endif
+}
+
+void
+i965_finish_vertices (i965_device_t *device)
+{
+    cairo_status_t status;
+
+    i965_flush_vertices (device);
+
+    i965_stream_commit (device, &device->vertex);
+
+    if (! i965_shader_check_aperture (device->shader, device)) {
+	status = i965_device_flush (device);
+	if (unlikely (status))
+	    longjmp (device->shader->unwind, status);
+
+	status = i965_shader_commit (device->shader, device);
+	assert (status == CAIRO_STATUS_SUCCESS);
+    }
+
+    device->last_vertex_size = 0;
+}
+
+static cairo_bool_t
+i965_shader_needs_update (const i965_shader_t *shader,
+			  const i965_device_t *device)
+{
+    if (i965_shader_needs_surface_update (shader, device))
+	return TRUE;
+
+    if (i965_shader_needs_constants_update (shader, device))
+	return TRUE;
+
+    return i965_shader_needs_state_update (shader, device);
+}
+
+static void
+i965_shader_reduce (i965_shader_t *shader,
+		    const i965_device_t *device)
+{
+    if (shader->op == CAIRO_OPERATOR_OVER &&
+	(i965_wm_kernel_hash (shader) & ~0xff) == 0 &&
+	(shader->source.base.content & CAIRO_CONTENT_ALPHA) == 0)
+    {
+	shader->op = CAIRO_OPERATOR_SOURCE;
+    }
+}
+
+cairo_status_t
+i965_shader_commit (i965_shader_t *shader,
+		    i965_device_t *device)
+{
+    cairo_status_t status;
+
+    if (! shader->committed) {
+	device->shader = shader;
+
+	status = i965_shader_setup_dst (shader);
+	if (unlikely (status))
+	    return status;
+
+	i965_shader_setup_constants (shader);
+	i965_shader_reduce (shader, device);
+
+	if ((status = setjmp (shader->unwind)))
+	    return status;
+
+	shader->committed = TRUE;
+    }
+
+    if (! i965_shader_needs_update (shader, device))
+	return CAIRO_STATUS_SUCCESS;
+
+    /* XXX too many guestimates about likely maximum sizes */
+recheck:
+    if (device->batch.used + 128 > device->batch.size ||
+	! i965_shader_check_aperture (shader, device))
+    {
+	status = i965_device_flush (device);
+	if (unlikely (status))
+	    longjmp (shader->unwind, status);
+    }
+
+    i965_flush_vertices (device);
+
+    if (unlikely (device->surface.used + 128 > device->surface.size ||
+		  device->surface.num_relocations + 4 > device->surface.max_relocations))
+    {
+	i965_stream_commit (device, &device->surface);
+	goto recheck;
+    }
+
+    if (unlikely (device->constant.used + sizeof (device->constants) > device->constant.size ||
+		  device->constant.num_pending_relocations == device->constant.max_pending_relocations))
+    {
+	i965_stream_commit (device, &device->constant);
+	goto recheck;
+    }
+
+    if (unlikely (device->general.used + 512 > device->general.size)) {
+	i965_stream_commit (device, &device->general);
+	i965_general_state_reset (device);
+	goto recheck;
+    }
+
+    if (unlikely (device->batch.used == 0))
+	i965_emit_invariants (device);
+
+    if (unlikely (device->surface.num_pending_relocations == 0 ||
+		  device->general.num_pending_relocations == 0))
+    {
+	i965_emit_base (device);
+    }
+
+    i965_emit_composite (device, shader);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+void
+i965_clipped_vertices (i965_device_t *device,
+		       struct i965_vbo *vbo,
+		       cairo_region_t *clip_region)
+{
+    int i, num_rectangles, size;
+    cairo_status_t status;
+
+    if (vbo->count == 0)
+	return;
+
+    num_rectangles = cairo_region_num_rectangles (clip_region);
+    assert (num_rectangles);
+
+    if (vbo->next ||
+	vbo->count * device->vertex_size + device->vertex.used > device->vertex.size)
+    {
+	i965_finish_vertices (device);
+
+	size = device->rectangle_size;
+	do {
+	    for (i = 0; i < num_rectangles; i++) {
+		cairo_rectangle_int_t rect;
+
+		cairo_region_get_rectangle (clip_region, i, &rect);
+
+		if (unlikely (device->vertex.used + size > device->vertex.size ||
+			      device->batch.used + 64 > device->batch.size ||
+			      ! i965_shader_check_aperture (device->shader, device)))
+		{
+		    status = i965_device_flush (device);
+		    if (unlikely (status))
+			longjmp (device->shader->unwind, status);
+
+		    status = i965_shader_commit (device->shader, device);
+		    assert (status == CAIRO_STATUS_SUCCESS);
+		}
+
+		i965_emit_relocation (device, &device->batch,
+				      vbo->bo, 0,
+				      I915_GEM_DOMAIN_VERTEX, 0,
+				      device->batch.used + 8);
+
+		OUT_BATCH (BRW_3DSTATE_VERTEX_BUFFERS | 3);
+		OUT_BATCH ((0 << VB0_BUFFER_INDEX_SHIFT) |
+			   VB0_VERTEXDATA |
+			   (device->vertex_size << VB0_BUFFER_PITCH_SHIFT));
+		OUT_BATCH (vbo->bo->offset);
+		OUT_BATCH (0);
+		OUT_BATCH (0);
+
+		/* XXX scissor? */
+		OUT_BATCH (BRW_3DSTATE_DRAWING_RECTANGLE | 2);
+		OUT_BATCH (DRAW_YMIN (rect.y) | DRAW_XMIN (rect.x));
+		OUT_BATCH (DRAW_YMAX (rect.y + rect.height - 1) |
+			   DRAW_XMIN (rect.x + rect.width  - 1));
+		OUT_BATCH (0x00000000);	/* yorigin, xorigin */
+
+		OUT_BATCH (BRW_3DPRIMITIVE |
+			   BRW_3DPRIMITIVE_VERTEX_SEQUENTIAL |
+			   (_3DPRIM_RECTLIST << BRW_3DPRIMITIVE_TOPOLOGY_SHIFT) |
+			   (0 << 9) |
+			   4);
+		OUT_BATCH (vbo->count);  /* vertex count per instance */
+		OUT_BATCH (0);  /* start vertex offset */
+		OUT_BATCH (1); /* single instance */
+		OUT_BATCH (0);
+		OUT_BATCH (0);
+	    }
+	} while ((vbo = vbo->next) != NULL);
+	assert (device->last_vertex_size == 0);
+    } else {
+	int vertex_start, vertex_count;
+	void *ptr;
+
+	vertex_start = device->vertex.committed / device->vertex_size;
+	vertex_count = vbo->count;
+
+	size = vertex_count * device->vertex_size;
+	ptr = intel_bo_map (&device->intel, vbo->bo);
+	memcpy (device->vertex.data + device->vertex.used, ptr, size);
+	intel_bo_unmap (vbo->bo);
+	device->vertex.committed = device->vertex.used += size;
+
+	for (i = 0; i < num_rectangles; i++) {
+	    cairo_rectangle_int_t rect;
+
+	    cairo_region_get_rectangle (clip_region, i, &rect);
+
+	    /* XXX scissor? */
+	    OUT_BATCH (BRW_3DSTATE_DRAWING_RECTANGLE | 2);
+	    OUT_BATCH (DRAW_YMIN (rect.y) | DRAW_XMIN (rect.x));
+	    OUT_BATCH (DRAW_YMAX (rect.y + rect.height - 1) |
+		       DRAW_XMIN (rect.x + rect.width  - 1));
+	    OUT_BATCH (0x00000000);	/* yorigin, xorigin */
+
+	    OUT_BATCH (BRW_3DPRIMITIVE |
+		       BRW_3DPRIMITIVE_VERTEX_SEQUENTIAL |
+		       (_3DPRIM_RECTLIST << BRW_3DPRIMITIVE_TOPOLOGY_SHIFT) |
+		       (0 << 9) |
+		       4);
+	    OUT_BATCH (vertex_count);  /* vertex count per instance */
+	    OUT_BATCH (vertex_start);  /* start vertex offset */
+	    OUT_BATCH (1); /* single instance */
+	    OUT_BATCH (0);
+	    OUT_BATCH (0);
+	}
+    }
+
+    device->draw_rectangle = 0;
+}
diff --git a/src/drm/cairo-drm-i965-spans.c b/src/drm/cairo-drm-i965-spans.c
new file mode 100644
index 0000000..9cf6d00
--- /dev/null
+++ b/src/drm/cairo-drm-i965-spans.c
@@ -0,0 +1,408 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-boxes-private.h"
+#include "cairo-error-private.h"
+#include "cairo-drm-i965-private.h"
+
+/* Operates in either immediate or retained mode.
+ * When given a clip region we record the sequence of vbo and then
+ * replay them for each clip rectangle, otherwise we simply emit
+ * the vbo straight into the command stream.
+ */
+
+typedef struct _i965_spans i965_spans_t;
+
+typedef float *
+(*i965_get_rectangle_func_t) (i965_spans_t *spans);
+
+struct _i965_spans {
+    cairo_span_renderer_t renderer;
+
+    i965_device_t *device;
+
+    int xmin, xmax;
+    cairo_bool_t is_bounded;
+    const cairo_rectangle_int_t *extents;
+
+    i965_get_rectangle_func_t get_rectangle;
+    i965_shader_t shader;
+
+    cairo_region_t *clip_region;
+
+    struct i965_vbo head, *tail;
+
+    unsigned int vbo_offset;
+    float *vbo_base;
+};
+
+static float *
+i965_spans_emit_rectangle (i965_spans_t *spans)
+{
+    return i965_add_rectangle (spans->device);
+}
+
+static float *
+i965_spans_accumulate_rectangle (i965_spans_t *spans)
+{
+    float *vertices;
+    uint32_t size;
+
+    size = spans->device->rectangle_size;
+    if (unlikely (spans->vbo_offset + size > I965_VERTEX_SIZE)) {
+	struct i965_vbo *vbo;
+
+	intel_bo_unmap (spans->tail->bo);
+
+	vbo = malloc (sizeof (struct i965_vbo));
+	if (unlikely (vbo == NULL)) {
+	    /* throw error! */
+	}
+
+	spans->tail->next = vbo;
+	spans->tail = vbo;
+
+	vbo->next = NULL;
+	vbo->bo = intel_bo_create (&spans->device->intel, I965_VERTEX_SIZE, FALSE);
+	vbo->count = 0;
+
+	spans->vbo_offset = 0;
+	spans->vbo_base = intel_bo_map (&spans->device->intel, vbo->bo);
+    }
+
+    vertices = spans->vbo_base + spans->vbo_offset;
+    spans->vbo_offset += size;
+    spans->tail->count += 3;
+
+    return vertices;
+}
+
+static void
+i965_span_rectangle (i965_spans_t *spans,
+		     int x0, int x1, int y0, int y1,
+		     int alpha)
+{
+    float *vertices;
+    float a = alpha / 255.;
+
+    vertices = spans->get_rectangle (spans);
+
+    *vertices++ = x1;
+    *vertices++ = y1;
+    *vertices++ = a;
+
+    *vertices++ = x0;
+    *vertices++ = y1;
+    *vertices++ = a;
+
+    *vertices++ = x0;
+    *vertices++ = y0;
+    *vertices++ = a;
+}
+
+static cairo_status_t
+i965_bounded_spans_mono (void *abstract_renderer,
+			 int y, int height,
+			 const cairo_half_open_span_t *half,
+			 unsigned num_spans)
+{
+    i965_spans_t *spans = abstract_renderer;
+
+    if (num_spans == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    do {
+	if (half[0].coverage >= 128) {
+	    i965_span_rectangle (spans,
+				 half[0].x, half[1].x,
+				 y, y + height,
+				 255);
+	}
+	half++;
+    } while (--num_spans > 1);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_bounded_spans (void *abstract_renderer,
+		    int y, int height,
+		    const cairo_half_open_span_t *half,
+		    unsigned num_spans)
+{
+    i965_spans_t *spans = abstract_renderer;
+
+    if (num_spans == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    do {
+	if (half[0].coverage) {
+	    i965_span_rectangle (spans,
+				 half[0].x, half[1].x,
+				 y, y + height,
+				 half[0].coverage);
+	}
+	half++;
+    } while (--num_spans > 1);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_unbounded_spans (void *abstract_renderer,
+		      int y, int height,
+		      const cairo_half_open_span_t *half,
+		      unsigned num_spans)
+{
+    i965_spans_t *spans = abstract_renderer;
+
+    if (num_spans == 0) {
+	i965_span_rectangle (spans,
+			     spans->xmin, spans->xmax,
+			     y, y + height,
+			     0);
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    if (half[0].x != spans->xmin) {
+	i965_span_rectangle (spans,
+			     spans->xmin, half[0].x,
+			     y, y + height,
+			     0);
+    }
+
+    do {
+	i965_span_rectangle (spans,
+			     half[0].x, half[1].x,
+			     y, y + height,
+			     half[0].coverage);
+	half++;
+    } while (--num_spans > 1);
+
+    if (half[0].x != spans->xmax) {
+	i965_span_rectangle (spans,
+			     half[0].x, spans->xmax,
+			     y, y + height,
+			     0);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_unbounded_spans_mono (void *abstract_renderer,
+			   int y, int height,
+			   const cairo_half_open_span_t *half,
+			   unsigned num_spans)
+{
+    i965_spans_t *spans = abstract_renderer;
+
+    if (num_spans == 0) {
+	i965_span_rectangle (spans,
+			     spans->xmin, spans->xmax,
+			     y, y + height,
+			     0);
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    if (half[0].x != spans->xmin) {
+	i965_span_rectangle (spans,
+			     spans->xmin, half[0].x,
+			     y, y + height,
+			     0);
+    }
+
+    do {
+	int alpha = 0;
+	if (half[0].coverage >= 128)
+	    alpha = 255;
+	i965_span_rectangle (spans,
+			     half[0].x, half[1].x,
+			     y, y + height,
+			     alpha);
+	half++;
+    } while (--num_spans > 1);
+
+    if (half[0].x != spans->xmax) {
+	i965_span_rectangle (spans,
+			     half[0].x, spans->xmax,
+			     y, y + height,
+			     0);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_spans_init (i965_spans_t *spans,
+		 i965_surface_t *dst,
+		 cairo_operator_t op,
+		 const cairo_pattern_t *pattern,
+		 cairo_antialias_t antialias,
+		 cairo_clip_t *clip,
+		 const cairo_composite_rectangles_t *extents)
+{
+    cairo_status_t status;
+
+    spans->device = i965_device (dst);
+    i965_shader_init (&spans->shader, dst, op);
+
+    spans->is_bounded = extents->is_bounded;
+    if (extents->is_bounded) {
+	if (antialias == CAIRO_ANTIALIAS_NONE)
+	    spans->renderer.render_rows = i965_bounded_spans_mono;
+	else
+	    spans->renderer.render_rows = i965_bounded_spans;
+
+	spans->extents = &extents->bounded;
+    } else {
+	if (antialias == CAIRO_ANTIALIAS_NONE)
+	    spans->renderer.render_rows = i965_unbounded_spans_mono;
+	else
+	    spans->renderer.render_rows = i965_unbounded_spans;
+
+	spans->extents = &extents->unbounded;
+    }
+    spans->xmin = spans->extents->x;
+    spans->xmax = spans->extents->x + spans->extents->width;
+
+    spans->clip_region = NULL;
+    if (clip != NULL) {
+	cairo_region_t *clip_region = NULL;
+
+	status = _cairo_clip_get_region (clip, &clip_region);
+	assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
+
+	if (clip_region != NULL && cairo_region_num_rectangles (clip_region) == 1)
+	    clip_region = NULL;
+
+	spans->clip_region = clip_region;
+	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+	    i965_shader_set_clip (&spans->shader, clip);
+    }
+
+    spans->head.next  = NULL;
+    spans->head.bo    = NULL;
+    spans->head.count = 0;
+    spans->tail = &spans->head;
+
+    if (spans->clip_region == NULL) {
+	spans->get_rectangle = i965_spans_emit_rectangle;
+    } else {
+	spans->get_rectangle = i965_spans_accumulate_rectangle;
+	spans->head.bo = intel_bo_create (&spans->device->intel,
+					  I965_VERTEX_SIZE, FALSE);
+	if (unlikely (spans->head.bo == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+	spans->vbo_base = intel_bo_map (&spans->device->intel, spans->head.bo);
+    }
+    spans->vbo_offset = 0;
+
+    return i965_shader_acquire_pattern (&spans->shader,
+					&spans->shader.source,
+					pattern, &extents->bounded);
+}
+
+static void
+i965_spans_fini (i965_spans_t *spans)
+{
+    i965_shader_fini (&spans->shader);
+
+    if (spans->head.bo != NULL) {
+	struct i965_vbo *vbo, *next;
+
+	intel_bo_destroy (&spans->device->intel, spans->head.bo);
+	for (vbo = spans->head.next; vbo != NULL; vbo = next) {
+	    next = vbo->next;
+	    intel_bo_destroy (&spans->device->intel, vbo->bo);
+	    free (vbo);
+	}
+    }
+}
+
+cairo_status_t
+i965_clip_and_composite_spans (i965_surface_t		*dst,
+			       cairo_operator_t		 op,
+			       const cairo_pattern_t	*pattern,
+			       cairo_antialias_t	 antialias,
+			       i965_spans_func_t	 draw_func,
+			       void			*draw_closure,
+			       const cairo_composite_rectangles_t*extents,
+			       cairo_clip_t		*clip)
+{
+    i965_spans_t spans;
+    i965_device_t *device;
+    cairo_status_t status;
+
+    if (op == CAIRO_OPERATOR_CLEAR) {
+	pattern = &_cairo_pattern_white.base;
+	op = CAIRO_OPERATOR_DEST_OUT;
+    }
+
+    status = i965_spans_init (&spans, dst, op, pattern, antialias, clip, extents);
+    if (unlikely (status))
+	return status;
+
+    spans.shader.mask.base.content  = CAIRO_CONTENT_ALPHA;
+    spans.shader.mask.type.fragment = FS_SPANS;
+    spans.shader.mask.type.vertex   = VS_SPANS;
+    spans.shader.mask.type.pattern  = PATTERN_BASE;
+
+    status = cairo_device_acquire (dst->intel.drm.base.device);
+    if (unlikely (status))
+	goto CLEANUP_SPANS;
+
+    device = i965_device (dst);
+    status = i965_shader_commit (&spans.shader, device);
+    if (unlikely (status))
+	goto CLEANUP_DEVICE;
+
+    status = draw_func (draw_closure, &spans.renderer, spans.extents);
+    if (spans.clip_region != NULL && status == CAIRO_STATUS_SUCCESS) {
+	intel_bo_unmap (spans.tail->bo);
+	i965_clipped_vertices (device, &spans.head, spans.clip_region);
+    }
+
+  CLEANUP_DEVICE:
+    cairo_device_release (dst->intel.drm.base.device);
+  CLEANUP_SPANS:
+    i965_spans_fini (&spans);
+
+    return status;
+}
diff --git a/src/drm/cairo-drm-i965-surface.c b/src/drm/cairo-drm-i965-surface.c
new file mode 100644
index 0000000..0e0def8
--- /dev/null
+++ b/src/drm/cairo-drm-i965-surface.c
@@ -0,0 +1,1949 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2009 Kristian Høgsberg
+ * Copyright © 2009 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 Kristian Høgsberg.
+ *
+ * Based on the xf86-intel-driver i965 render acceleration code,
+ * authored by:
+ *    Wang Zhenyu <zhenyu.z.wang at intel.com>
+ *    Eric Anholt <eric at anholt.net>
+ *    Carl Worth <cworth at redhat.com>
+ *    Keith Packard <keithp at keithp.com>
+ */
+
+/* XXX
+ *
+ * FIXME: Use brw_PLN for [DevCTG-B+]
+ *
+ */
+
+#include "cairoint.h"
+
+#include "cairo-drm-private.h"
+#include "cairo-drm-ioctl-private.h"
+#include "cairo-drm-intel-private.h"
+#include "cairo-drm-intel-command-private.h"
+#include "cairo-drm-intel-ioctl-private.h"
+#include "cairo-drm-i965-private.h"
+
+#include "cairo-boxes-private.h"
+#include "cairo-composite-rectangles-private.h"
+#include "cairo-error-private.h"
+#include "cairo-region-private.h"
+#include "cairo-surface-offset-private.h"
+
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#define I965_MAX_SIZE 8192
+
+static const cairo_surface_backend_t i965_surface_backend;
+
+static void
+i965_stream_init (i965_stream_t *stream,
+		  uint8_t *data, uint32_t size,
+		  struct i965_pending_relocation *pending, int max_pending,
+		  struct drm_i915_gem_relocation_entry *relocations, int max_relocations)
+
+{
+    stream->used = stream->committed = 0;
+    stream->data = data;
+    stream->size = size;
+    stream->serial = 1;
+
+    stream->num_pending_relocations = 0;
+    stream->max_pending_relocations = max_pending;
+    stream->pending_relocations = pending;
+
+    stream->num_relocations = 0;
+    stream->max_relocations = max_relocations;
+    stream->relocations = relocations;
+}
+
+static void
+i965_add_relocation (i965_device_t *device,
+		     intel_bo_t *bo,
+		     uint32_t read_domains,
+		     uint32_t write_domain)
+{
+    if (bo->exec == NULL) {
+	int i;
+
+	device->exec.gtt_size += bo->base.size;
+
+	i = device->exec.count++;
+	assert (i < ARRAY_LENGTH (device->exec.exec));
+
+	device->exec.exec[i].handle = bo->base.handle;
+	device->exec.exec[i].relocation_count = 0;
+	device->exec.exec[i].relocs_ptr = 0;
+	device->exec.exec[i].alignment  = 0;
+	device->exec.exec[i].offset = 0;
+	device->exec.exec[i].flags  = 0;
+	device->exec.exec[i].rsvd1  = 0;
+	device->exec.exec[i].rsvd2  = 0;
+
+	device->exec.bo[i] = intel_bo_reference (bo);
+	bo->exec = &device->exec.exec[i];
+    }
+
+    if (cairo_list_is_empty (&bo->link))
+	cairo_list_add_tail (&device->flush, &bo->link);
+
+    assert (write_domain == 0 || bo->batch_write_domain == 0 || bo->batch_write_domain == write_domain);
+    bo->batch_read_domains |= read_domains;
+    bo->batch_write_domain |= write_domain;
+}
+
+void
+i965_emit_relocation (i965_device_t *device,
+		      i965_stream_t *stream,
+		      intel_bo_t *target,
+		      uint32_t target_offset,
+		      uint32_t read_domains,
+		      uint32_t write_domain,
+		      uint32_t offset)
+{
+    int n;
+
+    assert (target_offset < target->base.size);
+
+    i965_add_relocation (device, target, read_domains, write_domain);
+
+    n = stream->num_relocations++;
+    assert (n < stream->max_relocations);
+
+    stream->relocations[n].offset = offset;
+    stream->relocations[n].delta  = target_offset;
+    stream->relocations[n].target_handle   = target->base.handle;
+    stream->relocations[n].read_domains    = read_domains;
+    stream->relocations[n].write_domain    = write_domain;
+    stream->relocations[n].presumed_offset = target->offset;
+}
+
+static void
+i965_stream_reset (i965_stream_t *stream)
+{
+    stream->used = stream->committed = 0;
+    stream->num_relocations = 0;
+    stream->num_pending_relocations = 0;
+    if (++stream->serial == 0)
+	stream->serial = 1;
+}
+
+void
+i965_stream_commit (i965_device_t *device,
+		    i965_stream_t *stream)
+{
+    intel_bo_t *bo;
+    int n;
+
+    assert (stream->used);
+
+    bo = intel_bo_create (&device->intel, stream->used, FALSE);
+
+    /* apply pending relocations */
+    for (n = 0; n < stream->num_pending_relocations; n++) {
+	struct i965_pending_relocation *p = &stream->pending_relocations[n];
+
+	i965_emit_relocation (device, &device->batch, bo,
+			      p->delta,
+			      p->read_domains,
+			      p->write_domain,
+			      p->offset);
+	if (bo->offset)
+	    *(uint32_t *) (device->batch.data + p->offset) = bo->offset + p->delta;
+    }
+
+    intel_bo_write (&device->intel, bo, 0, stream->used, stream->data);
+
+    if (stream->num_relocations) {
+	assert (bo->exec != NULL);
+	bo->exec->relocs_ptr = (uintptr_t) stream->relocations;
+	bo->exec->relocation_count = stream->num_relocations;
+    }
+
+    intel_bo_destroy (&device->intel, bo);
+
+    i965_stream_reset (stream);
+}
+
+static void
+sf_states_pluck (void *entry, void *closure)
+{
+    i965_device_t *device = closure;
+
+    _cairo_hash_table_remove (device->sf_states, entry);
+    _cairo_freelist_free (&device->sf_freelist, entry);
+}
+
+static void
+cc_offsets_pluck (void *entry, void *closure)
+{
+    i965_device_t *device = closure;
+
+    _cairo_hash_table_remove (device->cc_states, entry);
+    _cairo_freelist_free (&device->cc_freelist, entry);
+}
+
+static void
+wm_kernels_pluck (void *entry, void *closure)
+{
+    i965_device_t *device = closure;
+
+    _cairo_hash_table_remove (device->wm_kernels, entry);
+    _cairo_freelist_free (&device->wm_kernel_freelist, entry);
+}
+
+static void
+wm_states_pluck (void *entry, void *closure)
+{
+    i965_device_t *device = closure;
+
+    _cairo_hash_table_remove (device->wm_states, entry);
+    _cairo_freelist_free (&device->wm_state_freelist, entry);
+}
+
+static void
+wm_bindings_pluck (void *entry, void *closure)
+{
+    i965_device_t *device = closure;
+
+    _cairo_hash_table_remove (device->wm_bindings, entry);
+    _cairo_freelist_free (&device->wm_binding_freelist, entry);
+}
+
+static void
+samplers_pluck (void *entry, void *closure)
+{
+    i965_device_t *device = closure;
+
+    _cairo_hash_table_remove (device->samplers, entry);
+    _cairo_freelist_free (&device->sampler_freelist, entry);
+}
+
+void
+i965_general_state_reset (i965_device_t *device)
+{
+    _cairo_hash_table_foreach (device->sf_states,
+			       sf_states_pluck,
+			       device);
+
+    _cairo_hash_table_foreach (device->cc_states,
+			       cc_offsets_pluck,
+			       device);
+
+    _cairo_hash_table_foreach (device->wm_kernels,
+			       wm_kernels_pluck,
+			       device);
+
+    _cairo_hash_table_foreach (device->wm_states,
+			       wm_states_pluck,
+			       device);
+
+    _cairo_hash_table_foreach (device->wm_bindings,
+			       wm_bindings_pluck,
+			       device);
+
+    _cairo_hash_table_foreach (device->samplers,
+			       samplers_pluck,
+			       device);
+
+    device->vs_offset = (uint32_t) -1;
+    device->border_color_offset = (uint32_t) -1;
+
+    if (device->general_state != NULL) {
+	intel_bo_destroy (&device->intel, device->general_state);
+	device->general_state = NULL;
+    }
+}
+
+static void
+i965_device_reset (i965_device_t *device)
+{
+    device->exec.count = 0;
+    device->exec.gtt_size = I965_CONSTANT_SIZE +
+	                    I965_VERTEX_SIZE +
+	                    I965_SURFACE_SIZE +
+			    I965_GENERAL_SIZE +
+			    I965_BATCH_SIZE;
+
+    device->sf_state.entry.hash = (uint32_t) -1;
+    device->wm_state.entry.hash = (uint32_t) -1;
+    device->wm_binding.entry.hash = (uint32_t) -1;
+    device->cc_state.entry.hash = (uint32_t) -1;
+
+    device->target = NULL;
+    device->source = NULL;
+    device->mask = NULL;
+    device->clip = NULL;
+
+    device->draw_rectangle = (uint32_t) -1;
+
+    device->vertex_type = (uint32_t) -1;
+    device->vertex_size = 0;
+    device->rectangle_size   = 0;
+    device->last_vertex_size = 0;
+
+    device->constants = NULL;
+    device->constants_size = 0;
+
+    device->have_urb_fences = FALSE;
+}
+
+static cairo_status_t
+i965_exec (i965_device_t *device, uint32_t offset)
+{
+    struct drm_i915_gem_execbuffer2 execbuf;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+    int ret, i;
+
+    execbuf.buffers_ptr = (uintptr_t) device->exec.exec;
+    execbuf.buffer_count = device->exec.count;
+    execbuf.batch_start_offset = offset;
+    execbuf.batch_len = device->batch.used;
+    execbuf.DR1 = 0;
+    execbuf.DR4 = 0;
+    execbuf.num_cliprects = 0;
+    execbuf.cliprects_ptr = 0;
+    execbuf.flags = I915_GEM_3D_PIPELINE;
+    execbuf.rsvd1 = 0;
+    execbuf.rsvd2 = 0;
+
+#if 0
+    printf ("exec: offset=%d, length=%d, buffers=%d\n",
+	    offset, device->batch.used, device->exec.count);
+    intel_dump_batchbuffer ((uint32_t *) device->batch.data,
+			    device->batch.used,
+			    device->intel.base.chip_id);
+#endif
+
+    ret = 0;
+    do {
+	ret = ioctl (device->intel.base.fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
+    } while (ret != 0 && errno == EINTR);
+    if (unlikely (ret)) {
+	int n;
+
+	if (errno == ENOMEM)
+	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+	else
+	    status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
+
+	fprintf (stderr, "Batch submission failed: %d\n", errno);
+	fprintf (stderr, "   gtt size: %zd/%zd\n",
+		 device->exec.gtt_size, device->intel.gtt_avail_size);
+
+	fprintf (stderr, "   %d buffers:\n",
+		 device->exec.count);
+	for (n = 0; n < i; n++) {
+	    fprintf (stderr, "     exec[%d] = %d\n",
+		     n, device->exec.bo[n]->base.size);
+	}
+
+	intel_dump_batchbuffer ((uint32_t *) device->batch.data,
+				device->batch.used,
+				device->intel.base.chip_id);
+    }
+
+    /* XXX any write target within the batch should now be in error */
+    for (i = 0; i < device->exec.count; i++) {
+	cairo_bool_t ret;
+
+	device->exec.bo[i]->offset = device->exec.exec[i].offset;
+	device->exec.bo[i]->exec = NULL;
+	device->exec.bo[i]->batch_read_domains = 0;
+	device->exec.bo[i]->batch_write_domain = 0;
+
+	if (device->exec.bo[i]->purgeable) {
+	    ret = intel_bo_madvise (&device->intel,
+				    device->exec.bo[i],
+				    I915_MADV_DONTNEED);
+	    /* ignore immediate notification of purging */
+	}
+
+	cairo_list_init (&device->exec.bo[i]->link);
+	intel_bo_destroy (&device->intel, device->exec.bo[i]);
+    }
+    cairo_list_init (&device->flush);
+
+    device->exec.count = 0;
+
+    return status;
+}
+
+static inline uint32_t
+next_bo_size (uint32_t v)
+{
+    v = (v + 8191) / 8192;
+
+    v--;
+    v |= v >> 1;
+    v |= v >> 2;
+    v |= v >> 4;
+    v |= v >> 8;
+    v |= v >> 16;
+    v++;
+
+    return v * 8192;
+}
+
+static void
+_copy_to_bo_and_apply_relocations (i965_device_t *device,
+				   intel_bo_t *bo,
+				   i965_stream_t *stream,
+				   uint32_t offset)
+{
+    int n;
+
+    intel_bo_write (&device->intel, bo,
+		    offset, stream->used,
+		    stream->data);
+
+    for (n = 0; n < stream->num_pending_relocations; n++) {
+	struct i965_pending_relocation *p = &stream->pending_relocations[n];
+
+	i965_emit_relocation (device, &device->batch, bo,
+			      p->delta + offset,
+			      p->read_domains,
+			      p->write_domain,
+			      p->offset);
+
+	if (bo->offset) {
+	    *(uint32_t *) (device->batch.data + p->offset) =
+		bo->offset + p->delta + offset;
+	}
+    }
+}
+
+cairo_status_t
+i965_device_flush (i965_device_t *device)
+{
+    cairo_status_t status;
+    uint32_t aligned, max;
+    intel_bo_t *bo;
+    int n;
+
+    if (device->batch.used == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    i965_flush_vertices (device);
+
+    OUT_BATCH (MI_BATCH_BUFFER_END);
+    /* Emit a padding dword if we aren't going to be quad-word aligned. */
+    if (device->batch.used & 4)
+	OUT_BATCH (MI_NOOP);
+
+#if 0
+    printf ("device flush: vertex=%d, constant=%d, surface=%d, general=%d, batch=%d\n",
+	    device->vertex.used,
+	    device->constant.used,
+	    device->surface.used,
+	    device->general.used,
+	    device->batch.used);
+#endif
+
+    /* can we pack the surface state into the tail of the general state? */
+    if (device->general.used == device->general.committed) {
+	if (device->general.used) {
+	    assert (device->general.num_pending_relocations == 1);
+	    assert (device->general_state != NULL);
+	    i965_emit_relocation (device, &device->batch,
+				  device->general_state,
+				  device->general.pending_relocations[0].delta,
+				  device->general.pending_relocations[0].read_domains,
+				  device->general.pending_relocations[0].write_domain,
+				  device->general.pending_relocations[0].offset);
+
+	    if (device->general_state->offset) {
+		*(uint32_t *) (device->batch.data +
+			       device->general.pending_relocations[0].offset) =
+		    device->general_state->offset +
+		    device->general.pending_relocations[0].delta;
+	    }
+	}
+    } else {
+	assert (device->general.num_pending_relocations == 1);
+	if (device->general_state != NULL) {
+	    intel_bo_destroy (&device->intel, device->general_state);
+	    device->general_state = NULL;
+	}
+
+	bo = intel_bo_create (&device->intel,
+			      device->general.used,
+			      FALSE);
+	if (unlikely (bo == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+	aligned = (device->general.used + 31) & -32;
+	if (device->surface.used &&
+	    aligned + device->surface.used <= bo->base.size)
+	{
+	    _copy_to_bo_and_apply_relocations (device, bo, &device->general, 0);
+	    _copy_to_bo_and_apply_relocations (device, bo, &device->surface, aligned);
+
+	    if (device->surface.num_relocations) {
+		for (n = 0; n < device->surface.num_relocations; n++)
+		    device->surface.relocations[n].offset += aligned;
+
+		assert (bo->exec != NULL);
+		bo->exec->relocs_ptr = (uintptr_t) device->surface.relocations;
+		bo->exec->relocation_count = device->surface.num_relocations;
+	    }
+
+	    i965_stream_reset (&device->surface);
+	}
+	else
+	{
+	    _copy_to_bo_and_apply_relocations (device, bo, &device->general, 0);
+	}
+
+	/* Note we don't reset the general state, just mark what data we've committed. */
+	device->general.committed = device->general.used;
+	device->general_state = bo;
+    }
+    device->general.num_pending_relocations = 0;
+
+    /* Combine vertex+constant+surface+batch streams? */
+    max = aligned = device->vertex.used;
+    if (device->constant.used) {
+	aligned = (aligned + 63) & -64;
+	aligned += device->constant.used;
+	if (device->constant.used > max)
+	    max = device->constant.used;
+    }
+    if (device->surface.used) {
+	aligned = (aligned + 31) & -32;
+	aligned += device->surface.used;
+	if (device->surface.used > max)
+	    max = device->surface.used;
+    }
+    aligned = (aligned + 63) & -64;
+    aligned += device->batch.used;
+    if (device->batch.used > max)
+	max = device->batch.used;
+    if (aligned <= next_bo_size (max)) {
+	int batch_num_relocations;
+
+	if (aligned <= 8192)
+	    max = aligned;
+
+	bo = intel_bo_create (&device->intel, max, FALSE);
+	if (unlikely (bo == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+	assert (aligned <= bo->base.size);
+
+	if (device->vertex.used)
+	    _copy_to_bo_and_apply_relocations (device, bo, &device->vertex, 0);
+
+	aligned = device->vertex.used;
+	if (device->constant.used) {
+	    aligned = (aligned + 63) & -64;
+	    _copy_to_bo_and_apply_relocations (device, bo, &device->constant, aligned);
+	    aligned += device->constant.used;
+	}
+
+	batch_num_relocations = device->batch.num_relocations;
+	if (device->surface.used) {
+	    aligned = (aligned + 31) & -32;
+	    _copy_to_bo_and_apply_relocations (device, bo, &device->surface, aligned);
+
+	    batch_num_relocations = device->batch.num_relocations;
+	    if (device->surface.num_relocations) {
+		assert (device->batch.num_relocations + device->surface.num_relocations < device->batch.max_relocations);
+
+		memcpy (device->batch.relocations + device->batch.num_relocations,
+			device->surface.relocations,
+			sizeof (device->surface.relocations[0]) * device->surface.num_relocations);
+
+		for (n = 0; n < device->surface.num_relocations; n++)
+		    device->batch.relocations[device->batch.num_relocations + n].offset += aligned;
+
+		device->batch.num_relocations += device->surface.num_relocations;
+	    }
+
+	    aligned += device->surface.used;
+	}
+
+	aligned = (aligned + 63) & -64;
+	intel_bo_write (&device->intel, bo,
+			aligned, device->batch.used,
+			device->batch.data);
+
+	for (n = 0; n < batch_num_relocations; n++)
+	    device->batch.relocations[n].offset += aligned;
+
+	if (device->exec.bo[device->exec.count-1] == bo) {
+	    assert (bo->exec == &device->exec.exec[device->exec.count-1]);
+
+	    bo->exec->relocation_count = device->batch.num_relocations;
+	    bo->exec->relocs_ptr = (uintptr_t) device->batch.relocations;
+	    intel_bo_destroy (&device->intel, bo);
+	} else {
+	    assert (bo->exec ==  NULL);
+
+	    n = device->exec.count++;
+	    device->exec.exec[n].handle = bo->base.handle;
+	    device->exec.exec[n].relocation_count = device->batch.num_relocations;
+	    device->exec.exec[n].relocs_ptr = (uintptr_t) device->batch.relocations;
+	    device->exec.exec[n].alignment = 0;
+	    device->exec.exec[n].offset = 0;
+	    device->exec.exec[n].flags = 0;
+	    device->exec.exec[n].rsvd1 = 0;
+	    device->exec.exec[n].rsvd2 = 0;
+
+	    /* transfer ownership to the exec */
+	    device->exec.bo[n] = bo;
+	}
+    } else {
+	i965_stream_commit (device, &device->vertex);
+
+	if (device->constant.used && device->surface.used){
+	    aligned = (device->constant.used + 31) & -32;
+	    aligned += device->surface.used;
+
+	    max = MAX (device->constant.used, device->surface.used);
+	    if (aligned <= next_bo_size (max)) {
+		if (aligned <= 8192)
+		    max = aligned;
+
+		bo = intel_bo_create (&device->intel, max, FALSE);
+		if (unlikely (bo == NULL))
+		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+		assert (aligned <= bo->base.size);
+
+		_copy_to_bo_and_apply_relocations (device, bo, &device->constant, 0);
+
+		aligned = (device->constant.used + 31) & -32;
+
+		_copy_to_bo_and_apply_relocations (device, bo, &device->surface, aligned);
+
+		if (device->surface.num_relocations) {
+		    assert (bo->exec != NULL);
+
+		    for (n = 0; n < device->surface.num_relocations; n++)
+			device->surface.relocations[n].offset += aligned;
+
+		    bo->exec->relocs_ptr = (uintptr_t) device->surface.relocations;
+		    bo->exec->relocation_count = device->surface.num_relocations;
+		}
+
+		i965_stream_reset (&device->surface);
+		i965_stream_reset (&device->constant);
+
+		intel_bo_destroy (&device->intel, bo);
+	    }
+	} else {
+	    if (device->constant.used)
+		i965_stream_commit (device, &device->constant);
+	    if (device->surface.used)
+		i965_stream_commit (device, &device->surface);
+	}
+
+	bo = intel_bo_create (&device->intel, device->batch.used, FALSE);
+	if (unlikely (bo == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+	intel_bo_write (&device->intel, bo,
+			0, device->batch.used,
+			device->batch.data);
+
+	n = device->exec.count++;
+	device->exec.exec[n].handle = bo->base.handle;
+	device->exec.exec[n].relocation_count = device->batch.num_relocations;
+	device->exec.exec[n].relocs_ptr = (uintptr_t) device->batch.relocations;
+	device->exec.exec[n].alignment = 0;
+	device->exec.exec[n].offset = 0;
+	device->exec.exec[n].flags = 0;
+	device->exec.exec[n].rsvd1 = 0;
+	device->exec.exec[n].rsvd2 = 0;
+
+	/* transfer ownership to the exec */
+	device->exec.bo[n] = bo;
+	aligned = 0;
+    }
+
+    intel_glyph_cache_unmap (&device->intel);
+
+    status = i965_exec (device, aligned);
+
+    i965_stream_reset (&device->vertex);
+    i965_stream_reset (&device->surface);
+    i965_stream_reset (&device->constant);
+    i965_stream_reset (&device->batch);
+
+    intel_glyph_cache_unpin (&device->intel);
+    intel_snapshot_cache_thaw (&device->intel);
+
+    i965_device_reset (device);
+
+    return status;
+}
+
+static cairo_status_t
+i965_surface_finish (void *abstract_surface)
+{
+    i965_surface_t *surface = abstract_surface;
+
+    return intel_surface_finish (&surface->intel);
+}
+
+static cairo_status_t
+i965_surface_flush (void *abstract_surface)
+{
+    i965_surface_t *surface = abstract_surface;
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
+
+    if (surface->intel.drm.fallback != NULL)
+	return intel_surface_flush (abstract_surface);
+
+    /* Forgo flushing on finish as the user cannot access the surface directly. */
+    if (! surface->intel.drm.base.finished &&
+	to_intel_bo (surface->intel.drm.bo)->exec != NULL)
+    {
+	status = cairo_device_acquire (surface->intel.drm.base.device);
+	if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	    i965_device_t *device;
+
+	    device = i965_device (surface);
+	    status = i965_device_flush (device);
+	    cairo_device_release (&device->intel.base.base);
+	}
+    }
+
+    return status;
+}
+
+/* rasterisation */
+
+static cairo_status_t
+_composite_boxes_spans (void				*closure,
+			cairo_span_renderer_t		*renderer,
+			const cairo_rectangle_int_t	*extents)
+{
+    cairo_boxes_t *boxes = closure;
+    cairo_rectangular_scan_converter_t converter;
+    struct _cairo_boxes_chunk *chunk;
+    cairo_status_t status;
+
+    _cairo_rectangular_scan_converter_init (&converter, extents);
+    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	cairo_box_t *box = chunk->base;
+	int i;
+
+	for (i = 0; i < chunk->count; i++) {
+	    status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
+	    if (unlikely (status))
+		goto CLEANUP;
+	}
+    }
+
+    status = converter.base.generate (&converter.base, renderer);
+
+  CLEANUP:
+    converter.base.destroy (&converter.base);
+    return status;
+}
+
+cairo_status_t
+i965_fixup_unbounded (i965_surface_t *dst,
+		      const cairo_composite_rectangles_t *extents,
+		      cairo_clip_t *clip)
+{
+    i965_shader_t shader;
+    cairo_status_t status;
+
+    i965_shader_init (&shader, dst, CAIRO_OPERATOR_CLEAR);
+
+    if (clip != NULL) {
+	cairo_region_t *clip_region = NULL;
+
+	status = _cairo_clip_get_region (clip, &clip_region);
+	assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+	assert (clip_region == NULL);
+
+	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+	    i965_shader_set_clip (&shader, clip);
+    } else {
+	if (extents->bounded.width  == extents->unbounded.width &&
+	    extents->bounded.height == extents->unbounded.height)
+	{
+	    return CAIRO_STATUS_SUCCESS;
+	}
+    }
+
+    status = i965_shader_acquire_pattern (&shader,
+					  &shader.source,
+					  &_cairo_pattern_clear.base,
+					  &extents->unbounded);
+    if (unlikely (status)) {
+	i965_shader_fini (&shader);
+	return status;
+    }
+
+    status = i965_shader_commit (&shader, i965_device (dst));
+    if (unlikely (status)) {
+	i965_shader_fini (&shader);
+	return status;
+    }
+
+    /* top */
+    if (extents->bounded.y != extents->unbounded.y) {
+	cairo_rectangle_int_t rect;
+
+	rect.x = extents->unbounded.x;
+	rect.y = extents->unbounded.y;
+	rect.width  = extents->unbounded.width;
+	rect.height = extents->bounded.y - rect.y;
+
+	i965_shader_add_rectangle (&shader,
+				   rect.x, rect.y,
+				   rect.width, rect.height);
+    }
+
+    /* left */
+    if (extents->bounded.x != extents->unbounded.x) {
+	cairo_rectangle_int_t rect;
+
+	rect.x = extents->unbounded.x;
+	rect.y = extents->bounded.y;
+	rect.width  = extents->bounded.x - extents->unbounded.x;
+	rect.height = extents->bounded.height;
+
+	i965_shader_add_rectangle (&shader,
+				   rect.x, rect.y,
+				   rect.width, rect.height);
+    }
+
+    /* right */
+    if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) {
+	cairo_rectangle_int_t rect;
+
+	rect.x = extents->bounded.x + extents->bounded.width;
+	rect.y = extents->bounded.y;
+	rect.width  = extents->unbounded.x + extents->unbounded.width - rect.x;
+	rect.height = extents->bounded.height;
+
+	i965_shader_add_rectangle (&shader,
+				   rect.x, rect.y,
+				   rect.width, rect.height);
+    }
+
+    /* bottom */
+    if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) {
+	cairo_rectangle_int_t rect;
+
+	rect.x = extents->unbounded.x;
+	rect.y = extents->bounded.y + extents->bounded.height;
+	rect.width  = extents->unbounded.width;
+	rect.height = extents->unbounded.y + extents->unbounded.height - rect.y;
+
+	i965_shader_add_rectangle (&shader,
+				   rect.x, rect.y,
+				   rect.width, rect.height);
+    }
+
+    i965_shader_fini (&shader);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i965_fixup_unbounded_boxes (i965_surface_t *dst,
+			    const cairo_composite_rectangles_t *extents,
+			    cairo_clip_t *clip,
+			    cairo_boxes_t *boxes)
+{
+    cairo_boxes_t clear;
+    cairo_box_t box;
+    cairo_region_t *clip_region = NULL;
+    cairo_status_t status;
+    struct _cairo_boxes_chunk *chunk;
+    i965_shader_t shader;
+    int i;
+
+    if (boxes->num_boxes <= 1)
+	return i965_fixup_unbounded (dst, extents, clip);
+
+    i965_shader_init (&shader, dst, CAIRO_OPERATOR_CLEAR);
+    if (clip != NULL) {
+	status = _cairo_clip_get_region (clip, &clip_region);
+	assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+	if (status == CAIRO_INT_STATUS_UNSUPPORTED)
+	    i965_shader_set_clip (&shader, clip);
+    }
+
+    status = i965_shader_acquire_pattern (&shader,
+					  &shader.source,
+					  &_cairo_pattern_clear.base,
+					  &extents->unbounded);
+    if (unlikely (status)) {
+	i965_shader_fini (&shader);
+	return status;
+    }
+
+    _cairo_boxes_init (&clear);
+
+    box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
+    box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
+    box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
+    box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
+
+    if (clip_region == NULL) {
+	cairo_boxes_t tmp;
+
+	_cairo_boxes_init (&tmp);
+
+	status = _cairo_boxes_add (&tmp, &box);
+	assert (status == CAIRO_STATUS_SUCCESS);
+
+	tmp.chunks.next = &boxes->chunks;
+	tmp.num_boxes += boxes->num_boxes;
+
+	status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
+							  CAIRO_FILL_RULE_WINDING,
+							  &clear);
+
+	tmp.chunks.next = NULL;
+    } else {
+	pixman_box32_t *pbox;
+
+	pbox = pixman_region32_rectangles (&clip_region->rgn, &i);
+	_cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i);
+
+	status = _cairo_boxes_add (&clear, &box);
+	assert (status == CAIRO_STATUS_SUCCESS);
+
+	for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	    for (i = 0; i < chunk->count; i++) {
+		status = _cairo_boxes_add (&clear, &chunk->base[i]);
+		if (unlikely (status)) {
+		    _cairo_boxes_fini (&clear);
+		    return status;
+		}
+	    }
+	}
+
+	status = _cairo_bentley_ottmann_tessellate_boxes (&clear,
+							  CAIRO_FILL_RULE_WINDING,
+							  &clear);
+    }
+
+    if (likely (status == CAIRO_STATUS_SUCCESS && clear.num_boxes)) {
+	status = i965_shader_commit (&shader, i965_device (dst));
+	if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	    for (chunk = &clear.chunks; chunk != NULL; 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);
+
+		    i965_shader_add_rectangle (&shader, x1, y1, x2 - x1, y2 - y1);
+		}
+	    }
+	}
+	i965_shader_fini (&shader);
+    }
+
+    _cairo_boxes_fini (&clear);
+
+    return status;
+}
+
+static cairo_status_t
+_composite_boxes (i965_surface_t *dst,
+		  cairo_operator_t op,
+		  const cairo_pattern_t *pattern,
+		  cairo_boxes_t *boxes,
+		  cairo_antialias_t antialias,
+		  cairo_clip_t *clip,
+		  const cairo_composite_rectangles_t *extents)
+{
+    cairo_bool_t need_clip_surface = FALSE;
+    cairo_region_t *clip_region = NULL;
+    const struct _cairo_boxes_chunk *chunk;
+    cairo_status_t status;
+    i965_shader_t shader;
+    int i;
+
+    /* If the boxes are not pixel-aligned, we will need to compute a real mask */
+    if (antialias != CAIRO_ANTIALIAS_NONE) {
+	if (! boxes->is_pixel_aligned)
+	    return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    i965_shader_init (&shader, dst, op);
+
+    status = i965_shader_acquire_pattern (&shader,
+					  &shader.source,
+					  pattern,
+					  &extents->bounded);
+    if (unlikely (status))
+	return status;
+
+    if (clip != NULL) {
+	status = _cairo_clip_get_region (clip, &clip_region);
+	assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+	need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+	if (need_clip_surface)
+	    i965_shader_set_clip (&shader, clip);
+    }
+
+    status = i965_shader_commit (&shader, i965_device (dst));
+    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	    cairo_box_t *box = chunk->base;
+	    for (i = 0; i < chunk->count; i++) {
+		int x1 = _cairo_fixed_integer_round (box[i].p1.x);
+		int y1 = _cairo_fixed_integer_round (box[i].p1.y);
+		int x2 = _cairo_fixed_integer_round (box[i].p2.x);
+		int y2 = _cairo_fixed_integer_round (box[i].p2.y);
+
+		if (x2 > x1 && y2 > y1)
+		    i965_shader_add_rectangle (&shader, x1, y1, x2 - x1, y2 - y1);
+	    }
+	}
+    }
+    i965_shader_fini (&shader);
+
+    if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded)
+	status = i965_fixup_unbounded_boxes (dst, extents, clip, boxes);
+
+    return status;
+}
+
+static cairo_status_t
+_clip_and_composite_boxes (i965_surface_t *dst,
+			   cairo_operator_t op,
+			   const cairo_pattern_t *src,
+			   cairo_boxes_t *boxes,
+			   cairo_antialias_t antialias,
+			   const cairo_composite_rectangles_t *extents,
+			   cairo_clip_t *clip)
+{
+    cairo_status_t status;
+
+    if (boxes->num_boxes == 0) {
+	if (extents->is_bounded)
+	    return CAIRO_STATUS_SUCCESS;
+
+	return i965_fixup_unbounded (dst, extents, clip);
+    }
+
+    /* Use a fast path if the boxes are pixel aligned */
+    status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents);
+    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	return status;
+
+    /* Otherwise render the boxes via an implicit mask and composite in the usual
+     * fashion.
+     */
+    return i965_clip_and_composite_spans (dst, op, src, antialias,
+					  _composite_boxes_spans, boxes,
+					  extents, clip);
+}
+
+static cairo_bool_t
+box_is_aligned (const cairo_box_t *box)
+{
+    return
+	_cairo_fixed_is_integer (box->p1.x) &&
+	_cairo_fixed_is_integer (box->p1.y) &&
+	_cairo_fixed_is_integer (box->p2.x) &&
+	_cairo_fixed_is_integer (box->p2.y);
+}
+
+static inline cairo_status_t
+_clip_to_boxes (cairo_clip_t **clip,
+		const cairo_composite_rectangles_t *extents,
+		cairo_box_t **boxes,
+		int *num_boxes)
+{
+    cairo_status_t status;
+    const cairo_rectangle_int_t *rect;
+
+    rect = extents->is_bounded ? &extents->bounded: &extents->unbounded;
+
+    if (*clip == NULL)
+	goto EXTENTS;
+
+    status = _cairo_clip_rectangle (*clip, rect);
+    if (unlikely (status))
+	return status;
+
+    status = _cairo_clip_get_boxes (*clip, boxes, num_boxes);
+    if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
+	if (extents->is_bounded || (*num_boxes == 1 && box_is_aligned (*boxes)))
+	    *clip = NULL;
+	return status;
+    }
+
+  EXTENTS:
+    _cairo_box_from_rectangle (&(*boxes)[0], rect);
+    *num_boxes = 1;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+i965_surface_paint (void			*abstract_dst,
+		    cairo_operator_t		 op,
+		    const cairo_pattern_t	*source,
+		    cairo_clip_t		*clip)
+{
+    i965_surface_t *dst = abstract_dst;
+    cairo_composite_rectangles_t extents;
+    cairo_boxes_t boxes;
+    cairo_box_t *clip_boxes = boxes.boxes_embedded;
+    cairo_clip_t local_clip;
+    cairo_bool_t have_clip = FALSE;
+    int num_boxes = ARRAY_LENGTH (boxes.boxes_embedded);
+    cairo_status_t status;
+
+    /* XXX unsupported operators? use pixel shader blending, eventually */
+
+    status = _cairo_composite_rectangles_init_for_paint (&extents,
+							 dst->intel.drm.width,
+							 dst->intel.drm.height,
+							 op, source,
+							 clip);
+    if (unlikely (status))
+	return status;
+
+    if (clip != NULL && _cairo_clip_contains_rectangle (clip, &extents))
+	clip = NULL;
+
+    if (clip != NULL) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	have_clip = TRUE;
+    }
+
+    status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+    if (unlikely (status)) {
+	if (have_clip)
+	    _cairo_clip_fini (&local_clip);
+
+	return status;
+    }
+
+    _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
+    status = _clip_and_composite_boxes (dst, op, source,
+					&boxes, CAIRO_ANTIALIAS_DEFAULT,
+					&extents, clip);
+    if (clip_boxes != boxes.boxes_embedded)
+	free (clip_boxes);
+
+    if (have_clip)
+	_cairo_clip_fini (&local_clip);
+
+    return status;
+}
+
+static cairo_int_status_t
+i965_surface_mask (void				*abstract_dst,
+		   cairo_operator_t		 op,
+		   const cairo_pattern_t	*source,
+		   const cairo_pattern_t	*mask,
+		   cairo_clip_t			*clip)
+{
+    i965_surface_t *dst = abstract_dst;
+    cairo_composite_rectangles_t extents;
+    i965_shader_t shader;
+    cairo_clip_t local_clip;
+    cairo_region_t *clip_region = NULL;
+    cairo_bool_t need_clip_surface = FALSE;
+    cairo_bool_t have_clip = FALSE;
+    cairo_status_t status;
+
+    status = _cairo_composite_rectangles_init_for_mask (&extents,
+							dst->intel.drm.width,
+							dst->intel.drm.height,
+							op, source, mask, clip);
+    if (unlikely (status))
+	return status;
+
+    if (clip != NULL && _cairo_clip_contains_rectangle (clip, &extents))
+	clip = NULL;
+
+    if (clip != NULL && extents.is_bounded) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	status = _cairo_clip_rectangle (clip, &extents.bounded);
+	if (unlikely (status)) {
+	    _cairo_clip_fini (&local_clip);
+	    return status;
+	}
+
+	have_clip = TRUE;
+    }
+
+    i965_shader_init (&shader, dst, op);
+
+    status = i965_shader_acquire_pattern (&shader,
+					  &shader.source,
+					  source,
+					  &extents.bounded);
+    if (unlikely (status))
+	goto BAIL;
+
+    status = i965_shader_acquire_pattern (&shader,
+					  &shader.mask,
+					  mask,
+					  &extents.bounded);
+    if (unlikely (status))
+	goto BAIL;
+
+    if (clip != NULL) {
+	status = _cairo_clip_get_region (clip, &clip_region);
+	assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+	need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
+	if (need_clip_surface)
+	    i965_shader_set_clip (&shader, clip);
+    }
+
+    status = i965_shader_commit (&shader, i965_device (dst));
+    if (unlikely (status))
+	goto BAIL;
+
+    if (clip_region != NULL) {
+	unsigned int n, num_rectangles;
+
+	num_rectangles = cairo_region_num_rectangles (clip_region);
+	for (n = 0; n < num_rectangles; n++) {
+	    cairo_rectangle_int_t rect;
+
+	    cairo_region_get_rectangle (clip_region, n, &rect);
+
+	    i965_shader_add_rectangle (&shader,
+				       rect.x, rect.y,
+				       rect.width, rect.height);
+	}
+    } else {
+	i965_shader_add_rectangle (&shader,
+				   extents.bounded.x,
+				   extents.bounded.y,
+				   extents.bounded.width,
+				   extents.bounded.height);
+    }
+
+    if (! extents.is_bounded)
+	status = i965_fixup_unbounded (dst, &extents, clip);
+
+  BAIL:
+    i965_shader_fini (&shader);
+    if (have_clip)
+	_cairo_clip_fini (&local_clip);
+
+    return status;
+}
+
+typedef struct {
+    cairo_polygon_t		polygon;
+    cairo_fill_rule_t		 fill_rule;
+    cairo_antialias_t		 antialias;
+} composite_polygon_info_t;
+
+static cairo_status_t
+_composite_polygon_spans (void                          *closure,
+			  cairo_span_renderer_t		*renderer,
+			  const cairo_rectangle_int_t   *extents)
+{
+    composite_polygon_info_t *info = closure;
+    cairo_botor_scan_converter_t converter;
+    cairo_status_t status;
+    cairo_box_t box;
+
+    box.p1.x = _cairo_fixed_from_int (extents->x);
+    box.p1.y = _cairo_fixed_from_int (extents->y);
+    box.p2.x = _cairo_fixed_from_int (extents->x + extents->width);
+    box.p2.y = _cairo_fixed_from_int (extents->y + extents->height);
+
+    _cairo_botor_scan_converter_init (&converter, &box, info->fill_rule);
+
+    status = converter.base.add_polygon (&converter.base, &info->polygon);
+    if (likely (status == CAIRO_STATUS_SUCCESS))
+	status = converter.base.generate (&converter.base, renderer);
+
+    converter.base.destroy (&converter.base);
+
+    return status;
+}
+
+static cairo_int_status_t
+i965_surface_stroke (void			*abstract_dst,
+		     cairo_operator_t		 op,
+		     const cairo_pattern_t	*source,
+		     cairo_path_fixed_t		*path,
+		     const cairo_stroke_style_t	*stroke_style,
+		     const cairo_matrix_t	*ctm,
+		     const cairo_matrix_t	*ctm_inverse,
+		     double			 tolerance,
+		     cairo_antialias_t		 antialias,
+		     cairo_clip_t		*clip)
+{
+    i965_surface_t *dst = abstract_dst;
+    cairo_composite_rectangles_t extents;
+    composite_polygon_info_t info;
+    cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+    int num_boxes = ARRAY_LENGTH (boxes_stack);
+    cairo_clip_t local_clip;
+    cairo_bool_t have_clip = FALSE;
+    cairo_status_t status;
+
+    status = _cairo_composite_rectangles_init_for_stroke (&extents,
+							  dst->intel.drm.width,
+							  dst->intel.drm.height,
+							  op, source,
+							  path, stroke_style, ctm,
+							  clip);
+    if (unlikely (status))
+	return status;
+
+    if (clip != NULL && _cairo_clip_contains_rectangle (clip, &extents))
+	clip = NULL;
+
+    if (clip != NULL) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	have_clip = TRUE;
+    }
+
+    status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+    if (unlikely (status)) {
+	if (have_clip)
+	    _cairo_clip_fini (&local_clip);
+
+	return status;
+    }
+
+    if (path->is_rectilinear) {
+	cairo_boxes_t boxes;
+
+	_cairo_boxes_init (&boxes);
+	_cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
+	status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
+								stroke_style,
+								ctm,
+								&boxes);
+	if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	    status = _clip_and_composite_boxes (dst, op, source,
+						&boxes, antialias,
+						&extents, clip);
+	}
+
+	_cairo_boxes_fini (&boxes);
+
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    goto CLEANUP_BOXES;
+    }
+
+    _cairo_polygon_init (&info.polygon);
+    _cairo_polygon_limit (&info.polygon, clip_boxes, num_boxes);
+
+    status = _cairo_path_fixed_stroke_to_polygon (path,
+						  stroke_style,
+						  ctm, ctm_inverse,
+						  tolerance,
+						  &info.polygon);
+    if (unlikely (status))
+	goto CLEANUP_POLYGON;
+
+    if (extents.is_bounded) {
+	cairo_rectangle_int_t rect;
+
+	_cairo_box_round_to_rectangle (&info.polygon.extents, &rect);
+	if (! _cairo_rectangle_intersect (&extents.bounded, &rect))
+	    goto CLEANUP_POLYGON;
+    }
+
+    if (info.polygon.num_edges == 0) {
+	if (! extents.is_bounded)
+	    status = i965_fixup_unbounded (dst, &extents, clip);
+    } else {
+	info.fill_rule = CAIRO_FILL_RULE_WINDING;
+	info.antialias = antialias;
+	status = i965_clip_and_composite_spans (dst, op, source, antialias,
+						_composite_polygon_spans, &info,
+						&extents, clip);
+    }
+
+CLEANUP_POLYGON:
+    _cairo_polygon_fini (&info.polygon);
+
+CLEANUP_BOXES:
+    if (clip_boxes != boxes_stack)
+	free (clip_boxes);
+
+    if (have_clip)
+	_cairo_clip_fini (&local_clip);
+
+    return status;
+}
+
+static cairo_int_status_t
+i965_surface_fill (void			*abstract_dst,
+		   cairo_operator_t	 op,
+		   const cairo_pattern_t*source,
+		   cairo_path_fixed_t	*path,
+		   cairo_fill_rule_t	 fill_rule,
+		   double		 tolerance,
+		   cairo_antialias_t	 antialias,
+		   cairo_clip_t		*clip)
+{
+    i965_surface_t *dst = abstract_dst;
+    cairo_composite_rectangles_t extents;
+    composite_polygon_info_t info;
+    cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
+    cairo_clip_t local_clip;
+    cairo_bool_t have_clip = FALSE;
+    int num_boxes = ARRAY_LENGTH (boxes_stack);
+    cairo_status_t status;
+
+    status = _cairo_composite_rectangles_init_for_fill (&extents,
+							dst->intel.drm.width,
+							dst->intel.drm.height,
+							op, source, path,
+							clip);
+    if (unlikely (status))
+	return status;
+
+    if (clip != NULL && _cairo_clip_contains_rectangle (clip, &extents))
+	clip = NULL;
+
+    if (clip != NULL) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	have_clip = TRUE;
+    }
+
+    status = _clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
+    if (unlikely (status)) {
+	if (have_clip)
+	    _cairo_clip_fini (&local_clip);
+
+	return status;
+    }
+
+    assert (! path->is_empty_fill);
+
+    if (_cairo_path_fixed_is_rectilinear_fill (path)) {
+	cairo_boxes_t boxes;
+
+	_cairo_boxes_init (&boxes);
+	_cairo_boxes_limit (&boxes, clip_boxes, num_boxes);
+	status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
+							      fill_rule,
+							      &boxes);
+	if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	    status = _clip_and_composite_boxes (dst, op, source,
+						&boxes, antialias,
+						&extents, clip);
+	}
+
+	_cairo_boxes_fini (&boxes);
+
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    goto CLEANUP_BOXES;
+    }
+
+    _cairo_polygon_init (&info.polygon);
+    _cairo_polygon_limit (&info.polygon, clip_boxes, num_boxes);
+
+    status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &info.polygon);
+    if (unlikely (status))
+	goto CLEANUP_POLYGON;
+
+    if (extents.is_bounded) {
+	cairo_rectangle_int_t rect;
+
+	_cairo_box_round_to_rectangle (&info.polygon.extents, &rect);
+	if (! _cairo_rectangle_intersect (&extents.bounded, &rect))
+	    goto CLEANUP_POLYGON;
+    }
+
+    if (info.polygon.num_edges == 0) {
+	if (! extents.is_bounded)
+	    status = i965_fixup_unbounded (dst, &extents, clip);
+    } else {
+	info.fill_rule = fill_rule;
+	info.antialias = antialias;
+	status = i965_clip_and_composite_spans (dst, op, source, antialias,
+						_composite_polygon_spans, &info,
+						&extents, clip);
+    }
+
+CLEANUP_POLYGON:
+    _cairo_polygon_fini (&info.polygon);
+
+CLEANUP_BOXES:
+    if (clip_boxes != boxes_stack)
+	free (clip_boxes);
+
+    if (have_clip)
+	_cairo_clip_fini (&local_clip);
+
+    return status;
+}
+
+static const cairo_surface_backend_t i965_surface_backend = {
+    CAIRO_SURFACE_TYPE_DRM,
+
+    _cairo_drm_surface_create_similar,
+    i965_surface_finish,
+    intel_surface_acquire_source_image,
+    intel_surface_release_source_image,
+
+    NULL, NULL, NULL,
+    NULL, /* composite */
+    NULL, /* fill */
+    NULL, /* trapezoids */
+    NULL, /* span */
+    NULL, /* check-span */
+
+    NULL, /* copy_page */
+    NULL, /* show_page */
+    _cairo_drm_surface_get_extents,
+    NULL, /* old-glyphs */
+    _cairo_drm_surface_get_font_options,
+
+    i965_surface_flush,
+    NULL, /* mark_dirty */
+    intel_scaled_font_fini,
+    intel_scaled_glyph_fini,
+
+    i965_surface_paint,
+    i965_surface_mask,
+    i965_surface_stroke,
+    i965_surface_fill,
+    i965_surface_glyphs,
+};
+
+static void
+i965_surface_init (i965_surface_t *surface,
+	           cairo_content_t content,
+		   cairo_drm_device_t *device)
+{
+    intel_surface_init (&surface->intel, &i965_surface_backend, device, content);
+    surface->stream = 0;
+}
+
+static inline int cairo_const
+i965_tiling_stride (uint32_t tiling, int stride)
+{
+    if (tiling == I915_TILING_NONE)
+	return stride;
+
+    return (stride + 127) & -128;
+}
+
+static inline int cairo_const
+i965_tiling_height (uint32_t tiling, int height)
+{
+    switch (tiling) {
+    default:
+    case I915_TILING_NONE: return (height + 1) & -2;
+    case I915_TILING_X: return (height + 7) & -8;
+    case I915_TILING_Y: return (height + 31) & -32;
+    }
+}
+
+cairo_surface_t *
+i965_surface_create_internal (cairo_drm_device_t *base_dev,
+		              cairo_content_t content,
+			      int width, int height,
+			      uint32_t tiling,
+			      cairo_bool_t gpu_target)
+{
+    i965_surface_t *surface;
+    cairo_status_t status_ignored;
+
+    surface = malloc (sizeof (i965_surface_t));
+    if (unlikely (surface == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    i965_surface_init (surface, content, base_dev);
+
+    if (width && height) {
+	uint32_t size;
+
+	surface->intel.drm.width  = width;
+	surface->intel.drm.height = height;
+
+	width = (width + 3) & -4;
+	surface->intel.drm.stride = cairo_format_stride_for_width (surface->intel.drm.format,
+							      width);
+	surface->intel.drm.stride = (surface->intel.drm.stride + 63) & ~63;
+
+#if 0
+	/* check for tiny surfaces for which tiling is irrelevant */
+	if (height * surface->intel.drm.stride < 4096)
+	    tiling = I915_TILING_NONE;
+#endif
+	surface->intel.drm.stride = i965_tiling_stride (tiling,
+						       	surface->intel.drm.stride);
+
+	height = i965_tiling_height (tiling, height);
+	assert (height <= I965_MAX_SIZE);
+
+	size = surface->intel.drm.stride * height;
+	if (tiling != I915_TILING_NONE)
+	    size = (size + 4095) & -4096;
+
+	surface->intel.drm.bo = &intel_bo_create (to_intel_device (&base_dev->base),
+						  size, gpu_target)->base;
+	if (surface->intel.drm.bo == NULL) {
+	    status_ignored = _cairo_drm_surface_finish (&surface->intel.drm);
+	    free (surface);
+	    return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+	}
+
+	intel_bo_set_tiling (to_intel_device (&base_dev->base),
+			     to_intel_bo (surface->intel.drm.bo),
+			     tiling, surface->intel.drm.stride);
+
+	assert (surface->intel.drm.bo->size >= (size_t) surface->intel.drm.stride*height);
+    }
+
+    return &surface->intel.drm.base;
+}
+
+static cairo_surface_t *
+i965_surface_create (cairo_drm_device_t *device,
+		     cairo_content_t content, int width, int height)
+{
+    return i965_surface_create_internal (device, content, width, height,
+	                                 I965_TILING_DEFAULT, TRUE);
+}
+
+static cairo_surface_t *
+i965_surface_create_for_name (cairo_drm_device_t *base_dev,
+			      unsigned int name,
+			      cairo_format_t format,
+			      int width, int height, int stride)
+{
+    i965_device_t *device;
+    i965_surface_t *surface;
+    cairo_content_t content;
+    cairo_status_t status_ignored;
+    int min_stride;
+
+    min_stride = cairo_format_stride_for_width (format, (width + 3) & -4);
+    if (stride < min_stride || stride & 63)
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE));
+
+    if (format == CAIRO_FORMAT_A1)
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+
+    switch (format) {
+    case CAIRO_FORMAT_ARGB32:
+	content = CAIRO_CONTENT_COLOR_ALPHA;
+	break;
+    case CAIRO_FORMAT_RGB24:
+	content = CAIRO_CONTENT_COLOR;
+	break;
+    case CAIRO_FORMAT_A8:
+	content = CAIRO_CONTENT_ALPHA;
+	break;
+    default:
+    case CAIRO_FORMAT_A1:
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+    }
+
+    surface = malloc (sizeof (i965_surface_t));
+    if (unlikely (surface == NULL))
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+
+    i965_surface_init (surface, content, base_dev);
+
+    device = (i965_device_t *) base_dev;
+    surface->intel.drm.bo = &intel_bo_create_for_name (&device->intel, name)->base;
+    if (unlikely (surface->intel.drm.bo == NULL)) {
+	status_ignored = _cairo_drm_surface_finish (&surface->intel.drm);
+	free (surface);
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+    }
+
+    surface->intel.drm.width = width;
+    surface->intel.drm.height = height;
+    surface->intel.drm.stride = stride;
+
+    return &surface->intel.drm.base;
+}
+
+static cairo_status_t
+i965_surface_enable_scan_out (void *abstract_surface)
+{
+    i965_surface_t *surface = abstract_surface;
+    intel_bo_t *bo;
+
+    if (unlikely (surface->intel.drm.bo == NULL))
+	return _cairo_error (CAIRO_STATUS_INVALID_SIZE);
+
+    bo = to_intel_bo (surface->intel.drm.bo);
+    if (bo->tiling != I915_TILING_X) {
+	i965_device_t *device = i965_device (surface);
+	cairo_surface_pattern_t pattern;
+	cairo_surface_t *clone;
+	cairo_status_t status;
+
+	clone = i965_surface_create_internal (&device->intel.base,
+					      surface->intel.drm.base.content,
+					      surface->intel.drm.width,
+					      surface->intel.drm.height,
+					      I915_TILING_X,
+					      TRUE);
+	if (unlikely (clone->status))
+	    return clone->status;
+
+	/* 2D blit? */
+	_cairo_pattern_init_for_surface (&pattern, &surface->intel.drm.base);
+	pattern.base.filter = CAIRO_FILTER_NEAREST;
+
+	status = _cairo_surface_paint (clone,
+				       CAIRO_OPERATOR_SOURCE,
+				       &pattern.base,
+				       NULL);
+
+	_cairo_pattern_fini (&pattern.base);
+
+	if (unlikely (status)) {
+	    cairo_surface_destroy (clone);
+	    return status;
+	}
+
+	/* swap buffer objects */
+	surface->intel.drm.bo = ((cairo_drm_surface_t *) clone)->bo;
+	((cairo_drm_surface_t *) clone)->bo = &bo->base;
+	bo = to_intel_bo (surface->intel.drm.bo);
+
+	cairo_surface_destroy (clone);
+    }
+
+    if (unlikely (bo->tiling == I915_TILING_Y))
+	return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_int_status_t
+_i965_device_flush (cairo_drm_device_t *device)
+{
+    cairo_status_t status;
+
+    status = cairo_device_acquire (&device->base);
+    if (likely (status == CAIRO_STATUS_SUCCESS))
+	status = i965_device_flush ((i965_device_t *) device);
+
+    cairo_device_release (&device->base);
+
+    return status;
+}
+
+static cairo_int_status_t
+_i965_device_throttle (cairo_drm_device_t *device)
+{
+    cairo_status_t status;
+
+    status = cairo_device_acquire (&device->base);
+    if (unlikely (status))
+	return status;
+
+    status = i965_device_flush ((i965_device_t *) device);
+    intel_throttle ((intel_device_t *) device);
+
+    cairo_device_release (&device->base);
+
+    return status;
+}
+
+static void
+_i965_device_destroy (void *base)
+{
+    i965_device_t *device = base;
+
+    i965_device_reset (device);
+    i965_general_state_reset (device);
+
+    _cairo_hash_table_destroy (device->sf_states);
+    _cairo_hash_table_destroy (device->samplers);
+    _cairo_hash_table_destroy (device->cc_states);
+    _cairo_hash_table_destroy (device->wm_kernels);
+    _cairo_hash_table_destroy (device->wm_states);
+    _cairo_hash_table_destroy (device->wm_bindings);
+
+    _cairo_freelist_fini (&device->sf_freelist);
+    _cairo_freelist_fini (&device->cc_freelist);
+    _cairo_freelist_fini (&device->wm_kernel_freelist);
+    _cairo_freelist_fini (&device->wm_state_freelist);
+    _cairo_freelist_fini (&device->wm_binding_freelist);
+    _cairo_freelist_fini (&device->sampler_freelist);
+
+    intel_device_fini (&device->intel);
+    free (device);
+}
+
+static cairo_bool_t
+hash_equal (const void *A, const void *B)
+{
+    const cairo_hash_entry_t *a = A, *b = B;
+    return a->hash == b->hash;
+}
+
+cairo_drm_device_t *
+_cairo_drm_i965_device_create (int fd, dev_t dev, int vendor_id, int chip_id)
+{
+    i965_device_t *device;
+    uint64_t gtt_size;
+    cairo_status_t status;
+
+    if (! intel_info (fd, &gtt_size))
+	return  NULL;
+
+    device = malloc (sizeof (i965_device_t));
+    if (unlikely (device == NULL))
+	return (cairo_drm_device_t *) _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY);
+
+    status = intel_device_init (&device->intel, fd);
+    if (unlikely (status))
+	goto CLEANUP;
+
+    device->is_g4x = IS_G4X (chip_id);
+    //device->is_g5x = IS_G5X (chip_id);
+
+    device->intel.base.surface.create = i965_surface_create;
+    device->intel.base.surface.create_for_name = i965_surface_create_for_name;
+    device->intel.base.surface.create_from_cacheable_image = NULL;
+    device->intel.base.surface.enable_scan_out = i965_surface_enable_scan_out;
+
+    device->intel.base.device.flush = _i965_device_flush;
+    device->intel.base.device.throttle = _i965_device_throttle;
+    device->intel.base.device.destroy = _i965_device_destroy;
+
+    device->sf_states = _cairo_hash_table_create (i965_sf_state_equal);
+    if (unlikely (device->sf_states == NULL))
+	goto CLEANUP_INTEL;
+
+    _cairo_freelist_init (&device->sf_freelist,
+			  sizeof (struct i965_sf_state));
+
+
+    device->cc_states = _cairo_hash_table_create (i965_cc_state_equal);
+    if (unlikely (device->cc_states == NULL))
+	goto CLEANUP_SF;
+
+    _cairo_freelist_init (&device->cc_freelist,
+			  sizeof (struct i965_cc_state));
+
+
+    device->wm_kernels = _cairo_hash_table_create (hash_equal);
+    if (unlikely (device->wm_kernels == NULL))
+	goto CLEANUP_CC;
+
+    _cairo_freelist_init (&device->wm_kernel_freelist,
+			  sizeof (struct i965_wm_kernel));
+
+    device->wm_states = _cairo_hash_table_create (i965_wm_state_equal);
+    if (unlikely (device->wm_states == NULL))
+	goto CLEANUP_WM_KERNEL;
+
+    _cairo_freelist_init (&device->wm_state_freelist,
+			  sizeof (struct i965_wm_state));
+
+
+    device->wm_bindings = _cairo_hash_table_create (i965_wm_binding_equal);
+    if (unlikely (device->wm_bindings == NULL))
+	goto CLEANUP_WM_STATE;
+
+    _cairo_freelist_init (&device->wm_binding_freelist,
+			  sizeof (struct i965_wm_binding));
+
+    device->samplers = _cairo_hash_table_create (hash_equal);
+    if (unlikely (device->samplers == NULL))
+	goto CLEANUP_WM_BINDING;
+
+    _cairo_freelist_init (&device->sampler_freelist,
+			  sizeof (struct i965_sampler));
+
+    i965_stream_init (&device->batch,
+		      device->batch_base, sizeof (device->batch_base),
+		      NULL, 0,
+		      device->batch_relocations,
+		      ARRAY_LENGTH (device->batch_relocations));
+
+    i965_stream_init (&device->surface,
+		      device->surface_base, sizeof (device->surface_base),
+		      device->surface_pending_relocations,
+		      ARRAY_LENGTH (device->surface_pending_relocations),
+		      device->surface_relocations,
+		      ARRAY_LENGTH (device->surface_relocations));
+
+    i965_stream_init (&device->general,
+		      device->general_base, sizeof (device->general_base),
+		      device->general_pending_relocations,
+		      ARRAY_LENGTH (device->general_pending_relocations),
+		      NULL, 0);
+
+    i965_stream_init (&device->vertex,
+		      device->vertex_base, sizeof (device->vertex_base),
+		      device->vertex_pending_relocations,
+		      ARRAY_LENGTH (device->vertex_pending_relocations),
+		      NULL, 0);
+
+    i965_stream_init (&device->constant,
+		      device->constant_base, sizeof (device->constant_base),
+		      device->constant_pending_relocations,
+		      ARRAY_LENGTH (device->constant_pending_relocations),
+		      NULL, 0);
+
+    cairo_list_init (&device->flush);
+    i965_device_reset (device);
+    device->vs_offset = (uint32_t) -1;
+    device->border_color_offset = (uint32_t) -1;
+    device->general_state = NULL;
+
+    return _cairo_drm_device_init (&device->intel.base,
+				   fd, dev, vendor_id, chip_id,
+				   I965_MAX_SIZE);
+
+  CLEANUP_WM_BINDING:
+    _cairo_hash_table_destroy (device->wm_bindings);
+  CLEANUP_WM_STATE:
+    _cairo_hash_table_destroy (device->wm_states);
+  CLEANUP_WM_KERNEL:
+    _cairo_hash_table_destroy (device->wm_kernels);
+  CLEANUP_CC:
+    _cairo_hash_table_destroy (device->cc_states);
+  CLEANUP_SF:
+    _cairo_hash_table_destroy (device->sf_states);
+  CLEANUP_INTEL:
+    intel_device_fini (&device->intel);
+  CLEANUP:
+    free (device);
+    return (cairo_drm_device_t *) _cairo_device_create_in_error (status);
+}
diff --git a/src/drm/cairo-drm-intel-brw-defines.h b/src/drm/cairo-drm-intel-brw-defines.h
new file mode 100644
index 0000000..b2be36f
--- /dev/null
+++ b/src/drm/cairo-drm-intel-brw-defines.h
@@ -0,0 +1,824 @@
+/**************************************************************************
+ *
+ * Copyright 2005 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef CAIRO_DRM_INTEL_BRW_DEFINES_H
+#define CAIRO_DRM_INTEL_BRW_DEFINES_H
+
+/* 3D state: */
+#define _3DOP_3DSTATE_PIPELINED       0x0
+#define _3DOP_3DSTATE_NONPIPELINED    0x1
+#define _3DOP_3DCONTROL               0x2
+#define _3DOP_3DPRIMITIVE             0x3
+
+#define _3DSTATE_PIPELINED_POINTERS       0x00
+#define _3DSTATE_BINDING_TABLE_POINTERS   0x01
+#define _3DSTATE_VERTEX_BUFFERS           0x08
+#define _3DSTATE_VERTEX_ELEMENTS          0x09
+#define _3DSTATE_INDEX_BUFFER             0x0A
+#define _3DSTATE_VF_STATISTICS            0x0B
+#define _3DSTATE_DRAWING_RECTANGLE            0x00
+#define _3DSTATE_CONSTANT_COLOR               0x01
+#define _3DSTATE_SAMPLER_PALETTE_LOAD         0x02
+#define _3DSTATE_CHROMA_KEY                   0x04
+#define _3DSTATE_DEPTH_BUFFER                 0x05
+#define _3DSTATE_POLY_STIPPLE_OFFSET          0x06
+#define _3DSTATE_POLY_STIPPLE_PATTERN         0x07
+#define _3DSTATE_LINE_STIPPLE                 0x08
+#define _3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP    0x09
+#define _3DCONTROL    0x00
+#define _3DPRIMITIVE  0x00
+
+#define PIPE_CONTROL_NOWRITE          0x00
+#define PIPE_CONTROL_WRITEIMMEDIATE   0x01
+#define PIPE_CONTROL_WRITEDEPTH       0x02
+#define PIPE_CONTROL_WRITETIMESTAMP   0x03
+
+#define PIPE_CONTROL_GTTWRITE_PROCESS_LOCAL 0x00
+#define PIPE_CONTROL_GTTWRITE_GLOBAL        0x01
+
+#define BRW_3D(Pipeline,Opcode,Subopcode) ((3 << 29) | \
+					   ((Pipeline) << 27) | \
+					   ((Opcode) << 24) | \
+					   ((Subopcode) << 16))
+
+#define BRW_PIPE_CONTROL			BRW_3D(3, 2, 0)
+#define BRW_PIPE_CONTROL_NOWRITE       (0 << 14)
+#define BRW_PIPE_CONTROL_WRITE_QWORD   (1 << 14)
+#define BRW_PIPE_CONTROL_WRITE_DEPTH   (2 << 14)
+#define BRW_PIPE_CONTROL_WRITE_TIME    (3 << 14)
+#define BRW_PIPE_CONTROL_DEPTH_STALL   (1 << 13)
+#define BRW_PIPE_CONTROL_WC_FLUSH      (1 << 12)
+#define BRW_PIPE_CONTROL_IS_FLUSH      (1 << 11)
+#define BRW_PIPE_CONTROL_NOTIFY_ENABLE (1 << 8)
+#define BRW_PIPE_CONTROL_GLOBAL_GTT    (1 << 2)
+#define BRW_PIPE_CONTROL_LOCAL_PGTT    (0 << 2)
+
+#define _3DPRIM_POINTLIST         0x01
+#define _3DPRIM_LINELIST          0x02
+#define _3DPRIM_LINESTRIP         0x03
+#define _3DPRIM_TRILIST           0x04
+#define _3DPRIM_TRISTRIP          0x05
+#define _3DPRIM_TRIFAN            0x06
+#define _3DPRIM_QUADLIST          0x07
+#define _3DPRIM_QUADSTRIP         0x08
+#define _3DPRIM_LINELIST_ADJ      0x09
+#define _3DPRIM_LINESTRIP_ADJ     0x0A
+#define _3DPRIM_TRILIST_ADJ       0x0B
+#define _3DPRIM_TRISTRIP_ADJ      0x0C
+#define _3DPRIM_TRISTRIP_REVERSE  0x0D
+#define _3DPRIM_POLYGON           0x0E
+#define _3DPRIM_RECTLIST          0x0F
+#define _3DPRIM_LINELOOP          0x10
+#define _3DPRIM_POINTLIST_BF      0x11
+#define _3DPRIM_LINESTRIP_CONT    0x12
+#define _3DPRIM_LINESTRIP_BF      0x13
+#define _3DPRIM_LINESTRIP_CONT_BF 0x14
+#define _3DPRIM_TRIFAN_NOSTIPPLE  0x15
+
+#define _3DPRIM_VERTEXBUFFER_ACCESS_SEQUENTIAL 0
+#define _3DPRIM_VERTEXBUFFER_ACCESS_RANDOM     1
+
+#define BRW_ANISORATIO_2     0
+#define BRW_ANISORATIO_4     1
+#define BRW_ANISORATIO_6     2
+#define BRW_ANISORATIO_8     3
+#define BRW_ANISORATIO_10    4
+#define BRW_ANISORATIO_12    5
+#define BRW_ANISORATIO_14    6
+#define BRW_ANISORATIO_16    7
+
+#define BRW_BLENDFACTOR_ONE                 0x1
+#define BRW_BLENDFACTOR_SRC_COLOR           0x2
+#define BRW_BLENDFACTOR_SRC_ALPHA           0x3
+#define BRW_BLENDFACTOR_DST_ALPHA           0x4
+#define BRW_BLENDFACTOR_DST_COLOR           0x5
+#define BRW_BLENDFACTOR_SRC_ALPHA_SATURATE  0x6
+#define BRW_BLENDFACTOR_CONST_COLOR         0x7
+#define BRW_BLENDFACTOR_CONST_ALPHA         0x8
+#define BRW_BLENDFACTOR_SRC1_COLOR          0x9
+#define BRW_BLENDFACTOR_SRC1_ALPHA          0x0A
+#define BRW_BLENDFACTOR_ZERO                0x11
+#define BRW_BLENDFACTOR_INV_SRC_COLOR       0x12
+#define BRW_BLENDFACTOR_INV_SRC_ALPHA       0x13
+#define BRW_BLENDFACTOR_INV_DST_ALPHA       0x14
+#define BRW_BLENDFACTOR_INV_DST_COLOR       0x15
+#define BRW_BLENDFACTOR_INV_CONST_COLOR     0x17
+#define BRW_BLENDFACTOR_INV_CONST_ALPHA     0x18
+#define BRW_BLENDFACTOR_INV_SRC1_COLOR      0x19
+#define BRW_BLENDFACTOR_INV_SRC1_ALPHA      0x1A
+
+#define BRW_BLENDFUNCTION_ADD               0
+#define BRW_BLENDFUNCTION_SUBTRACT          1
+#define BRW_BLENDFUNCTION_REVERSE_SUBTRACT  2
+#define BRW_BLENDFUNCTION_MIN               3
+#define BRW_BLENDFUNCTION_MAX               4
+
+#define BRW_ALPHATEST_FORMAT_UNORM8         0
+#define BRW_ALPHATEST_FORMAT_FLOAT32        1
+
+#define BRW_CHROMAKEY_KILL_ON_ANY_MATCH  0
+#define BRW_CHROMAKEY_REPLACE_BLACK      1
+
+#define BRW_CLIP_API_OGL     0
+#define BRW_CLIP_API_DX      1
+
+#define BRW_CLIPMODE_NORMAL              0
+#define BRW_CLIPMODE_CLIP_ALL            1
+#define BRW_CLIPMODE_CLIP_NON_REJECTED   2
+#define BRW_CLIPMODE_REJECT_ALL          3
+#define BRW_CLIPMODE_ACCEPT_ALL          4
+
+#define BRW_CLIP_NDCSPACE     0
+#define BRW_CLIP_SCREENSPACE  1
+
+#define BRW_COMPAREFUNCTION_ALWAYS       0
+#define BRW_COMPAREFUNCTION_NEVER        1
+#define BRW_COMPAREFUNCTION_LESS         2
+#define BRW_COMPAREFUNCTION_EQUAL        3
+#define BRW_COMPAREFUNCTION_LEQUAL       4
+#define BRW_COMPAREFUNCTION_GREATER      5
+#define BRW_COMPAREFUNCTION_NOTEQUAL     6
+#define BRW_COMPAREFUNCTION_GEQUAL       7
+
+#define BRW_COVERAGE_PIXELS_HALF     0
+#define BRW_COVERAGE_PIXELS_1        1
+#define BRW_COVERAGE_PIXELS_2        2
+#define BRW_COVERAGE_PIXELS_4        3
+
+#define BRW_CULLMODE_BOTH        0
+#define BRW_CULLMODE_NONE        1
+#define BRW_CULLMODE_FRONT       2
+#define BRW_CULLMODE_BACK        3
+
+#define BRW_DEFAULTCOLOR_R8G8B8A8_UNORM      0
+#define BRW_DEFAULTCOLOR_R32G32B32A32_FLOAT  1
+
+#define BRW_DEPTHFORMAT_D32_FLOAT_S8X24_UINT     0
+#define BRW_DEPTHFORMAT_D32_FLOAT                1
+#define BRW_DEPTHFORMAT_D24_UNORM_S8_UINT        2
+#define BRW_DEPTHFORMAT_D16_UNORM                5
+
+#define BRW_FLOATING_POINT_IEEE_754        0
+#define BRW_FLOATING_POINT_NON_IEEE_754    1
+
+#define BRW_FRONTWINDING_CW      0
+#define BRW_FRONTWINDING_CCW     1
+
+#define BRW_INDEX_BYTE     0
+#define BRW_INDEX_WORD     1
+#define BRW_INDEX_DWORD    2
+
+#define BRW_LOGICOPFUNCTION_CLEAR            0
+#define BRW_LOGICOPFUNCTION_NOR              1
+#define BRW_LOGICOPFUNCTION_AND_INVERTED     2
+#define BRW_LOGICOPFUNCTION_COPY_INVERTED    3
+#define BRW_LOGICOPFUNCTION_AND_REVERSE      4
+#define BRW_LOGICOPFUNCTION_INVERT           5
+#define BRW_LOGICOPFUNCTION_XOR              6
+#define BRW_LOGICOPFUNCTION_NAND             7
+#define BRW_LOGICOPFUNCTION_AND              8
+#define BRW_LOGICOPFUNCTION_EQUIV            9
+#define BRW_LOGICOPFUNCTION_NOOP             10
+#define BRW_LOGICOPFUNCTION_OR_INVERTED      11
+#define BRW_LOGICOPFUNCTION_COPY             12
+#define BRW_LOGICOPFUNCTION_OR_REVERSE       13
+#define BRW_LOGICOPFUNCTION_OR               14
+#define BRW_LOGICOPFUNCTION_SET              15
+
+#define BRW_MAPFILTER_NEAREST        0x0
+#define BRW_MAPFILTER_LINEAR         0x1
+#define BRW_MAPFILTER_ANISOTROPIC    0x2
+
+#define BRW_MIPFILTER_NONE        0
+#define BRW_MIPFILTER_NEAREST     1
+#define BRW_MIPFILTER_LINEAR      3
+
+#define BRW_POLYGON_FRONT_FACING     0
+#define BRW_POLYGON_BACK_FACING      1
+
+#define BRW_PREFILTER_ALWAYS     0x0
+#define BRW_PREFILTER_NEVER      0x1
+#define BRW_PREFILTER_LESS       0x2
+#define BRW_PREFILTER_EQUAL      0x3
+#define BRW_PREFILTER_LEQUAL     0x4
+#define BRW_PREFILTER_GREATER    0x5
+#define BRW_PREFILTER_NOTEQUAL   0x6
+#define BRW_PREFILTER_GEQUAL     0x7
+
+#define BRW_PROVOKING_VERTEX_0    0
+#define BRW_PROVOKING_VERTEX_1    1
+#define BRW_PROVOKING_VERTEX_2    2
+
+#define BRW_RASTRULE_UPPER_LEFT  0
+#define BRW_RASTRULE_UPPER_RIGHT 1
+
+#define BRW_RENDERTARGET_CLAMPRANGE_UNORM    0
+#define BRW_RENDERTARGET_CLAMPRANGE_SNORM    1
+#define BRW_RENDERTARGET_CLAMPRANGE_FORMAT   2
+
+#define BRW_STENCILOP_KEEP               0
+#define BRW_STENCILOP_ZERO               1
+#define BRW_STENCILOP_REPLACE            2
+#define BRW_STENCILOP_INCRSAT            3
+#define BRW_STENCILOP_DECRSAT            4
+#define BRW_STENCILOP_INCR               5
+#define BRW_STENCILOP_DECR               6
+#define BRW_STENCILOP_INVERT             7
+
+#define BRW_SURFACE_MIPMAPLAYOUT_BELOW   0
+#define BRW_SURFACE_MIPMAPLAYOUT_RIGHT   1
+
+#define BRW_SURFACEFORMAT_R32G32B32A32_FLOAT             0x000 
+#define BRW_SURFACEFORMAT_R32G32B32A32_SINT              0x001 
+#define BRW_SURFACEFORMAT_R32G32B32A32_UINT              0x002 
+#define BRW_SURFACEFORMAT_R32G32B32A32_UNORM             0x003 
+#define BRW_SURFACEFORMAT_R32G32B32A32_SNORM             0x004 
+#define BRW_SURFACEFORMAT_R64G64_FLOAT                   0x005 
+#define BRW_SURFACEFORMAT_R32G32B32X32_FLOAT             0x006 
+#define BRW_SURFACEFORMAT_R32G32B32A32_SSCALED           0x007
+#define BRW_SURFACEFORMAT_R32G32B32A32_USCALED           0x008
+#define BRW_SURFACEFORMAT_R32G32B32_FLOAT                0x040 
+#define BRW_SURFACEFORMAT_R32G32B32_SINT                 0x041 
+#define BRW_SURFACEFORMAT_R32G32B32_UINT                 0x042 
+#define BRW_SURFACEFORMAT_R32G32B32_UNORM                0x043 
+#define BRW_SURFACEFORMAT_R32G32B32_SNORM                0x044 
+#define BRW_SURFACEFORMAT_R32G32B32_SSCALED              0x045 
+#define BRW_SURFACEFORMAT_R32G32B32_USCALED              0x046 
+#define BRW_SURFACEFORMAT_R16G16B16A16_UNORM             0x080 
+#define BRW_SURFACEFORMAT_R16G16B16A16_SNORM             0x081 
+#define BRW_SURFACEFORMAT_R16G16B16A16_SINT              0x082 
+#define BRW_SURFACEFORMAT_R16G16B16A16_UINT              0x083 
+#define BRW_SURFACEFORMAT_R16G16B16A16_FLOAT             0x084 
+#define BRW_SURFACEFORMAT_R32G32_FLOAT                   0x085 
+#define BRW_SURFACEFORMAT_R32G32_SINT                    0x086 
+#define BRW_SURFACEFORMAT_R32G32_UINT                    0x087 
+#define BRW_SURFACEFORMAT_R32_FLOAT_X8X24_TYPELESS       0x088 
+#define BRW_SURFACEFORMAT_X32_TYPELESS_G8X24_UINT        0x089 
+#define BRW_SURFACEFORMAT_L32A32_FLOAT                   0x08A 
+#define BRW_SURFACEFORMAT_R32G32_UNORM                   0x08B 
+#define BRW_SURFACEFORMAT_R32G32_SNORM                   0x08C 
+#define BRW_SURFACEFORMAT_R64_FLOAT                      0x08D 
+#define BRW_SURFACEFORMAT_R16G16B16X16_UNORM             0x08E 
+#define BRW_SURFACEFORMAT_R16G16B16X16_FLOAT             0x08F 
+#define BRW_SURFACEFORMAT_A32X32_FLOAT                   0x090 
+#define BRW_SURFACEFORMAT_L32X32_FLOAT                   0x091 
+#define BRW_SURFACEFORMAT_I32X32_FLOAT                   0x092 
+#define BRW_SURFACEFORMAT_R16G16B16A16_SSCALED           0x093
+#define BRW_SURFACEFORMAT_R16G16B16A16_USCALED           0x094
+#define BRW_SURFACEFORMAT_R32G32_SSCALED                 0x095
+#define BRW_SURFACEFORMAT_R32G32_USCALED                 0x096
+#define BRW_SURFACEFORMAT_B8G8R8A8_UNORM                 0x0C0 
+#define BRW_SURFACEFORMAT_B8G8R8A8_UNORM_SRGB            0x0C1 
+#define BRW_SURFACEFORMAT_R10G10B10A2_UNORM              0x0C2 
+#define BRW_SURFACEFORMAT_R10G10B10A2_UNORM_SRGB         0x0C3 
+#define BRW_SURFACEFORMAT_R10G10B10A2_UINT               0x0C4 
+#define BRW_SURFACEFORMAT_R10G10B10_SNORM_A2_UNORM       0x0C5 
+#define BRW_SURFACEFORMAT_R8G8B8A8_UNORM                 0x0C7 
+#define BRW_SURFACEFORMAT_R8G8B8A8_UNORM_SRGB            0x0C8 
+#define BRW_SURFACEFORMAT_R8G8B8A8_SNORM                 0x0C9 
+#define BRW_SURFACEFORMAT_R8G8B8A8_SINT                  0x0CA 
+#define BRW_SURFACEFORMAT_R8G8B8A8_UINT                  0x0CB 
+#define BRW_SURFACEFORMAT_R16G16_UNORM                   0x0CC 
+#define BRW_SURFACEFORMAT_R16G16_SNORM                   0x0CD 
+#define BRW_SURFACEFORMAT_R16G16_SINT                    0x0CE 
+#define BRW_SURFACEFORMAT_R16G16_UINT                    0x0CF 
+#define BRW_SURFACEFORMAT_R16G16_FLOAT                   0x0D0 
+#define BRW_SURFACEFORMAT_B10G10R10A2_UNORM              0x0D1 
+#define BRW_SURFACEFORMAT_B10G10R10A2_UNORM_SRGB         0x0D2 
+#define BRW_SURFACEFORMAT_R11G11B10_FLOAT                0x0D3 
+#define BRW_SURFACEFORMAT_R32_SINT                       0x0D6 
+#define BRW_SURFACEFORMAT_R32_UINT                       0x0D7 
+#define BRW_SURFACEFORMAT_R32_FLOAT                      0x0D8 
+#define BRW_SURFACEFORMAT_R24_UNORM_X8_TYPELESS          0x0D9 
+#define BRW_SURFACEFORMAT_X24_TYPELESS_G8_UINT           0x0DA 
+#define BRW_SURFACEFORMAT_L16A16_UNORM                   0x0DF 
+#define BRW_SURFACEFORMAT_I24X8_UNORM                    0x0E0 
+#define BRW_SURFACEFORMAT_L24X8_UNORM                    0x0E1 
+#define BRW_SURFACEFORMAT_A24X8_UNORM                    0x0E2 
+#define BRW_SURFACEFORMAT_I32_FLOAT                      0x0E3 
+#define BRW_SURFACEFORMAT_L32_FLOAT                      0x0E4 
+#define BRW_SURFACEFORMAT_A32_FLOAT                      0x0E5 
+#define BRW_SURFACEFORMAT_B8G8R8X8_UNORM                 0x0E9 
+#define BRW_SURFACEFORMAT_B8G8R8X8_UNORM_SRGB            0x0EA 
+#define BRW_SURFACEFORMAT_R8G8B8X8_UNORM                 0x0EB 
+#define BRW_SURFACEFORMAT_R8G8B8X8_UNORM_SRGB            0x0EC 
+#define BRW_SURFACEFORMAT_R9G9B9E5_SHAREDEXP             0x0ED 
+#define BRW_SURFACEFORMAT_B10G10R10X2_UNORM              0x0EE 
+#define BRW_SURFACEFORMAT_L16A16_FLOAT                   0x0F0 
+#define BRW_SURFACEFORMAT_R32_UNORM                      0x0F1 
+#define BRW_SURFACEFORMAT_R32_SNORM                      0x0F2 
+#define BRW_SURFACEFORMAT_R10G10B10X2_USCALED            0x0F3
+#define BRW_SURFACEFORMAT_R8G8B8A8_SSCALED               0x0F4
+#define BRW_SURFACEFORMAT_R8G8B8A8_USCALED               0x0F5
+#define BRW_SURFACEFORMAT_R16G16_SSCALED                 0x0F6
+#define BRW_SURFACEFORMAT_R16G16_USCALED                 0x0F7
+#define BRW_SURFACEFORMAT_R32_SSCALED                    0x0F8
+#define BRW_SURFACEFORMAT_R32_USCALED                    0x0F9
+#define BRW_SURFACEFORMAT_B5G6R5_UNORM                   0x100 
+#define BRW_SURFACEFORMAT_B5G6R5_UNORM_SRGB              0x101 
+#define BRW_SURFACEFORMAT_B5G5R5A1_UNORM                 0x102 
+#define BRW_SURFACEFORMAT_B5G5R5A1_UNORM_SRGB            0x103 
+#define BRW_SURFACEFORMAT_B4G4R4A4_UNORM                 0x104 
+#define BRW_SURFACEFORMAT_B4G4R4A4_UNORM_SRGB            0x105 
+#define BRW_SURFACEFORMAT_R8G8_UNORM                     0x106 
+#define BRW_SURFACEFORMAT_R8G8_SNORM                     0x107 
+#define BRW_SURFACEFORMAT_R8G8_SINT                      0x108 
+#define BRW_SURFACEFORMAT_R8G8_UINT                      0x109 
+#define BRW_SURFACEFORMAT_R16_UNORM                      0x10A 
+#define BRW_SURFACEFORMAT_R16_SNORM                      0x10B 
+#define BRW_SURFACEFORMAT_R16_SINT                       0x10C 
+#define BRW_SURFACEFORMAT_R16_UINT                       0x10D 
+#define BRW_SURFACEFORMAT_R16_FLOAT                      0x10E 
+#define BRW_SURFACEFORMAT_I16_UNORM                      0x111 
+#define BRW_SURFACEFORMAT_L16_UNORM                      0x112 
+#define BRW_SURFACEFORMAT_A16_UNORM                      0x113 
+#define BRW_SURFACEFORMAT_L8A8_UNORM                     0x114 
+#define BRW_SURFACEFORMAT_I16_FLOAT                      0x115
+#define BRW_SURFACEFORMAT_L16_FLOAT                      0x116
+#define BRW_SURFACEFORMAT_A16_FLOAT                      0x117 
+#define BRW_SURFACEFORMAT_R5G5_SNORM_B6_UNORM            0x119 
+#define BRW_SURFACEFORMAT_B5G5R5X1_UNORM                 0x11A 
+#define BRW_SURFACEFORMAT_B5G5R5X1_UNORM_SRGB            0x11B
+#define BRW_SURFACEFORMAT_R8G8_SSCALED                   0x11C
+#define BRW_SURFACEFORMAT_R8G8_USCALED                   0x11D
+#define BRW_SURFACEFORMAT_R16_SSCALED                    0x11E
+#define BRW_SURFACEFORMAT_R16_USCALED                    0x11F
+#define BRW_SURFACEFORMAT_R8_UNORM                       0x140 
+#define BRW_SURFACEFORMAT_R8_SNORM                       0x141 
+#define BRW_SURFACEFORMAT_R8_SINT                        0x142 
+#define BRW_SURFACEFORMAT_R8_UINT                        0x143 
+#define BRW_SURFACEFORMAT_A8_UNORM                       0x144 
+#define BRW_SURFACEFORMAT_I8_UNORM                       0x145 
+#define BRW_SURFACEFORMAT_L8_UNORM                       0x146 
+#define BRW_SURFACEFORMAT_P4A4_UNORM                     0x147 
+#define BRW_SURFACEFORMAT_A4P4_UNORM                     0x148
+#define BRW_SURFACEFORMAT_R8_SSCALED                     0x149
+#define BRW_SURFACEFORMAT_R8_USCALED                     0x14A
+#define BRW_SURFACEFORMAT_R1_UINT                        0x181 
+#define BRW_SURFACEFORMAT_YCRCB_NORMAL                   0x182 
+#define BRW_SURFACEFORMAT_YCRCB_SWAPUVY                  0x183 
+#define BRW_SURFACEFORMAT_BC1_UNORM                      0x186 
+#define BRW_SURFACEFORMAT_BC2_UNORM                      0x187 
+#define BRW_SURFACEFORMAT_BC3_UNORM                      0x188 
+#define BRW_SURFACEFORMAT_BC4_UNORM                      0x189 
+#define BRW_SURFACEFORMAT_BC5_UNORM                      0x18A 
+#define BRW_SURFACEFORMAT_BC1_UNORM_SRGB                 0x18B 
+#define BRW_SURFACEFORMAT_BC2_UNORM_SRGB                 0x18C 
+#define BRW_SURFACEFORMAT_BC3_UNORM_SRGB                 0x18D 
+#define BRW_SURFACEFORMAT_MONO8                          0x18E 
+#define BRW_SURFACEFORMAT_YCRCB_SWAPUV                   0x18F 
+#define BRW_SURFACEFORMAT_YCRCB_SWAPY                    0x190 
+#define BRW_SURFACEFORMAT_DXT1_RGB                       0x191 
+#define BRW_SURFACEFORMAT_FXT1                           0x192 
+#define BRW_SURFACEFORMAT_R8G8B8_UNORM                   0x193 
+#define BRW_SURFACEFORMAT_R8G8B8_SNORM                   0x194 
+#define BRW_SURFACEFORMAT_R8G8B8_SSCALED                 0x195 
+#define BRW_SURFACEFORMAT_R8G8B8_USCALED                 0x196 
+#define BRW_SURFACEFORMAT_R64G64B64A64_FLOAT             0x197 
+#define BRW_SURFACEFORMAT_R64G64B64_FLOAT                0x198 
+#define BRW_SURFACEFORMAT_BC4_SNORM                      0x199 
+#define BRW_SURFACEFORMAT_BC5_SNORM                      0x19A 
+#define BRW_SURFACEFORMAT_R16G16B16_UNORM                0x19C 
+#define BRW_SURFACEFORMAT_R16G16B16_SNORM                0x19D 
+#define BRW_SURFACEFORMAT_R16G16B16_SSCALED              0x19E 
+#define BRW_SURFACEFORMAT_R16G16B16_USCALED              0x19F
+
+#define BRW_SURFACERETURNFORMAT_FLOAT32  0
+#define BRW_SURFACERETURNFORMAT_S1       1
+
+#define BRW_SURFACE_1D      0
+#define BRW_SURFACE_2D      1
+#define BRW_SURFACE_3D      2
+#define BRW_SURFACE_CUBE    3
+#define BRW_SURFACE_BUFFER  4
+#define BRW_SURFACE_NULL    7
+
+#define BRW_BORDER_COLOR_MODE_DEFAULT	0
+#define BRW_BORDER_COLOR_MODE_LEGACY	1
+
+#define BRW_TEXCOORDMODE_WRAP            0
+#define BRW_TEXCOORDMODE_MIRROR          1
+#define BRW_TEXCOORDMODE_CLAMP           2
+#define BRW_TEXCOORDMODE_CUBE            3
+#define BRW_TEXCOORDMODE_CLAMP_BORDER    4
+#define BRW_TEXCOORDMODE_MIRROR_ONCE     5
+
+#define BRW_THREAD_PRIORITY_NORMAL   0
+#define BRW_THREAD_PRIORITY_HIGH     1
+
+#define BRW_TILEWALK_XMAJOR                 0
+#define BRW_TILEWALK_YMAJOR                 1
+
+#define BRW_VERTEX_SUBPIXEL_PRECISION_8BITS  0
+#define BRW_VERTEX_SUBPIXEL_PRECISION_4BITS  1
+
+#define BRW_VERTEXBUFFER_ACCESS_VERTEXDATA     0
+#define BRW_VERTEXBUFFER_ACCESS_INSTANCEDATA   1
+
+#define BRW_VFCOMPONENT_NOSTORE      0
+#define BRW_VFCOMPONENT_STORE_SRC    1
+#define BRW_VFCOMPONENT_STORE_0      2
+#define BRW_VFCOMPONENT_STORE_1_FLT  3
+#define BRW_VFCOMPONENT_STORE_1_INT  4
+#define BRW_VFCOMPONENT_STORE_VID    5
+#define BRW_VFCOMPONENT_STORE_IID    6
+#define BRW_VFCOMPONENT_STORE_PID    7
+
+
+
+/* Execution Unit (EU) defines */
+
+#define BRW_ALIGN_1   0
+#define BRW_ALIGN_16  1
+
+#define BRW_ADDRESS_DIRECT                        0
+#define BRW_ADDRESS_REGISTER_INDIRECT_REGISTER    1
+
+#define BRW_CHANNEL_X     0
+#define BRW_CHANNEL_Y     1
+#define BRW_CHANNEL_Z     2
+#define BRW_CHANNEL_W     3
+
+#define BRW_COMPRESSION_NONE          0
+#define BRW_COMPRESSION_2NDHALF       1
+#define BRW_COMPRESSION_COMPRESSED    2
+
+#define BRW_CONDITIONAL_NONE  0
+#define BRW_CONDITIONAL_Z     1
+#define BRW_CONDITIONAL_NZ    2
+#define BRW_CONDITIONAL_EQ    1	/* Z */
+#define BRW_CONDITIONAL_NEQ   2	/* NZ */
+#define BRW_CONDITIONAL_G     3
+#define BRW_CONDITIONAL_GE    4
+#define BRW_CONDITIONAL_L     5
+#define BRW_CONDITIONAL_LE    6
+#define BRW_CONDITIONAL_C     7
+#define BRW_CONDITIONAL_O     8
+
+#define BRW_DEBUG_NONE        0
+#define BRW_DEBUG_BREAKPOINT  1
+
+#define BRW_DEPENDENCY_NORMAL         0
+#define BRW_DEPENDENCY_NOTCLEARED     1
+#define BRW_DEPENDENCY_NOTCHECKED     2
+#define BRW_DEPENDENCY_DISABLE        3
+
+#define BRW_EXECUTE_1     0
+#define BRW_EXECUTE_2     1
+#define BRW_EXECUTE_4     2
+#define BRW_EXECUTE_8     3
+#define BRW_EXECUTE_16    4
+#define BRW_EXECUTE_32    5
+
+#define BRW_HORIZONTAL_STRIDE_0   0
+#define BRW_HORIZONTAL_STRIDE_1   1
+#define BRW_HORIZONTAL_STRIDE_2   2
+#define BRW_HORIZONTAL_STRIDE_4   3
+
+#define BRW_INSTRUCTION_NORMAL    0
+#define BRW_INSTRUCTION_SATURATE  1
+
+#define BRW_MASK_ENABLE   0
+#define BRW_MASK_DISABLE  1
+
+#define BRW_OPCODE_MOV        1
+#define BRW_OPCODE_SEL        2
+#define BRW_OPCODE_NOT        4
+#define BRW_OPCODE_AND        5
+#define BRW_OPCODE_OR         6
+#define BRW_OPCODE_XOR        7
+#define BRW_OPCODE_SHR        8
+#define BRW_OPCODE_SHL        9
+#define BRW_OPCODE_RSR        10
+#define BRW_OPCODE_RSL        11
+#define BRW_OPCODE_ASR        12
+#define BRW_OPCODE_CMP        16
+#define BRW_OPCODE_JMPI       32
+#define BRW_OPCODE_IF         34
+#define BRW_OPCODE_IFF        35
+#define BRW_OPCODE_ELSE       36
+#define BRW_OPCODE_ENDIF      37
+#define BRW_OPCODE_DO         38
+#define BRW_OPCODE_WHILE      39
+#define BRW_OPCODE_BREAK      40
+#define BRW_OPCODE_CONTINUE   41
+#define BRW_OPCODE_HALT       42
+#define BRW_OPCODE_MSAVE      44
+#define BRW_OPCODE_MRESTORE   45
+#define BRW_OPCODE_PUSH       46
+#define BRW_OPCODE_POP        47
+#define BRW_OPCODE_WAIT       48
+#define BRW_OPCODE_SEND       49
+#define BRW_OPCODE_ADD        64
+#define BRW_OPCODE_MUL        65
+#define BRW_OPCODE_AVG        66
+#define BRW_OPCODE_FRC        67
+#define BRW_OPCODE_RNDU       68
+#define BRW_OPCODE_RNDD       69
+#define BRW_OPCODE_RNDE       70
+#define BRW_OPCODE_RNDZ       71
+#define BRW_OPCODE_MAC        72
+#define BRW_OPCODE_MACH       73
+#define BRW_OPCODE_LZD        74
+#define BRW_OPCODE_SAD2       80
+#define BRW_OPCODE_SADA2      81
+#define BRW_OPCODE_DP4        84
+#define BRW_OPCODE_DPH        85
+#define BRW_OPCODE_DP3        86
+#define BRW_OPCODE_DP2        87
+#define BRW_OPCODE_DPA2       88
+#define BRW_OPCODE_LINE       89
+#define BRW_OPCODE_NOP        126
+
+#define BRW_PREDICATE_NONE             0
+#define BRW_PREDICATE_NORMAL           1
+#define BRW_PREDICATE_ALIGN1_ANYV             2
+#define BRW_PREDICATE_ALIGN1_ALLV             3
+#define BRW_PREDICATE_ALIGN1_ANY2H            4
+#define BRW_PREDICATE_ALIGN1_ALL2H            5
+#define BRW_PREDICATE_ALIGN1_ANY4H            6
+#define BRW_PREDICATE_ALIGN1_ALL4H            7
+#define BRW_PREDICATE_ALIGN1_ANY8H            8
+#define BRW_PREDICATE_ALIGN1_ALL8H            9
+#define BRW_PREDICATE_ALIGN1_ANY16H           10
+#define BRW_PREDICATE_ALIGN1_ALL16H           11
+#define BRW_PREDICATE_ALIGN16_REPLICATE_X     2
+#define BRW_PREDICATE_ALIGN16_REPLICATE_Y     3
+#define BRW_PREDICATE_ALIGN16_REPLICATE_Z     4
+#define BRW_PREDICATE_ALIGN16_REPLICATE_W     5
+#define BRW_PREDICATE_ALIGN16_ANY4H           6
+#define BRW_PREDICATE_ALIGN16_ALL4H           7
+
+#define BRW_ARCHITECTURE_REGISTER_FILE    0
+#define BRW_GENERAL_REGISTER_FILE         1
+#define BRW_MESSAGE_REGISTER_FILE         2
+#define BRW_IMMEDIATE_VALUE               3
+
+#define BRW_REGISTER_TYPE_UD  0
+#define BRW_REGISTER_TYPE_D   1
+#define BRW_REGISTER_TYPE_UW  2
+#define BRW_REGISTER_TYPE_W   3
+#define BRW_REGISTER_TYPE_UB  4
+#define BRW_REGISTER_TYPE_B   5
+#define BRW_REGISTER_TYPE_VF  5	/* packed float vector, immediates only? */
+#define BRW_REGISTER_TYPE_HF  6
+#define BRW_REGISTER_TYPE_V   6	/* packed int vector, immediates only, uword dest only */
+#define BRW_REGISTER_TYPE_F   7
+
+#define BRW_ARF_NULL                  0x00
+#define BRW_ARF_ADDRESS               0x10
+#define BRW_ARF_ACCUMULATOR           0x20   
+#define BRW_ARF_FLAG                  0x30
+#define BRW_ARF_MASK                  0x40
+#define BRW_ARF_MASK_STACK            0x50
+#define BRW_ARF_MASK_STACK_DEPTH      0x60
+#define BRW_ARF_STATE                 0x70
+#define BRW_ARF_CONTROL               0x80
+#define BRW_ARF_NOTIFICATION_COUNT    0x90
+#define BRW_ARF_IP                    0xA0
+
+#define BRW_AMASK   0
+#define BRW_IMASK   1
+#define BRW_LMASK   2
+#define BRW_CMASK   3
+
+
+
+#define BRW_THREAD_NORMAL     0
+#define BRW_THREAD_ATOMIC     1
+#define BRW_THREAD_SWITCH     2
+
+#define BRW_VERTICAL_STRIDE_0                 0
+#define BRW_VERTICAL_STRIDE_1                 1
+#define BRW_VERTICAL_STRIDE_2                 2
+#define BRW_VERTICAL_STRIDE_4                 3
+#define BRW_VERTICAL_STRIDE_8                 4
+#define BRW_VERTICAL_STRIDE_16                5
+#define BRW_VERTICAL_STRIDE_32                6
+#define BRW_VERTICAL_STRIDE_64                7
+#define BRW_VERTICAL_STRIDE_128               8
+#define BRW_VERTICAL_STRIDE_256               9
+#define BRW_VERTICAL_STRIDE_ONE_DIMENSIONAL   0xF
+
+#define BRW_WIDTH_1       0
+#define BRW_WIDTH_2       1
+#define BRW_WIDTH_4       2
+#define BRW_WIDTH_8       3
+#define BRW_WIDTH_16      4
+
+#define BRW_STATELESS_BUFFER_BOUNDARY_1K      0
+#define BRW_STATELESS_BUFFER_BOUNDARY_2K      1
+#define BRW_STATELESS_BUFFER_BOUNDARY_4K      2
+#define BRW_STATELESS_BUFFER_BOUNDARY_8K      3
+#define BRW_STATELESS_BUFFER_BOUNDARY_16K     4
+#define BRW_STATELESS_BUFFER_BOUNDARY_32K     5
+#define BRW_STATELESS_BUFFER_BOUNDARY_64K     6
+#define BRW_STATELESS_BUFFER_BOUNDARY_128K    7
+#define BRW_STATELESS_BUFFER_BOUNDARY_256K    8
+#define BRW_STATELESS_BUFFER_BOUNDARY_512K    9
+#define BRW_STATELESS_BUFFER_BOUNDARY_1M      10
+#define BRW_STATELESS_BUFFER_BOUNDARY_2M      11
+
+#define BRW_POLYGON_FACING_FRONT      0
+#define BRW_POLYGON_FACING_BACK       1
+
+#define BRW_MESSAGE_TARGET_NULL               0
+#define BRW_MESSAGE_TARGET_MATH               1
+#define BRW_MESSAGE_TARGET_SAMPLER            2
+#define BRW_MESSAGE_TARGET_GATEWAY            3
+#define BRW_MESSAGE_TARGET_DATAPORT_READ      4
+#define BRW_MESSAGE_TARGET_DATAPORT_WRITE     5
+#define BRW_MESSAGE_TARGET_URB                6
+#define BRW_MESSAGE_TARGET_THREAD_SPAWNER     7
+
+#define BRW_SAMPLER_RETURN_FORMAT_FLOAT32     0
+#define BRW_SAMPLER_RETURN_FORMAT_UINT32      2
+#define BRW_SAMPLER_RETURN_FORMAT_SINT32      3
+
+#define BRW_SAMPLER_MESSAGE_SIMD8_SAMPLE              0
+#define BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE             0
+#define BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE_BIAS        0
+#define BRW_SAMPLER_MESSAGE_SIMD8_KILLPIX             1
+#define BRW_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_LOD        1
+#define BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE_LOD         1
+#define BRW_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_GRADIENTS  2
+#define BRW_SAMPLER_MESSAGE_SIMD8_SAMPLE_GRADIENTS    2
+#define BRW_SAMPLER_MESSAGE_SIMD4X2_SAMPLE_COMPARE    0
+#define BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE_COMPARE     2
+#define BRW_SAMPLER_MESSAGE_SIMD4X2_RESINFO           2
+#define BRW_SAMPLER_MESSAGE_SIMD8_RESINFO             2
+#define BRW_SAMPLER_MESSAGE_SIMD16_RESINFO            2
+#define BRW_SAMPLER_MESSAGE_SIMD4X2_LD                3
+#define BRW_SAMPLER_MESSAGE_SIMD8_LD                  3
+#define BRW_SAMPLER_MESSAGE_SIMD16_LD                 3
+
+#define BRW_DATAPORT_OWORD_BLOCK_1_OWORDLOW   0
+#define BRW_DATAPORT_OWORD_BLOCK_1_OWORDHIGH  1
+#define BRW_DATAPORT_OWORD_BLOCK_2_OWORDS     2
+#define BRW_DATAPORT_OWORD_BLOCK_4_OWORDS     3
+#define BRW_DATAPORT_OWORD_BLOCK_8_OWORDS     4
+
+#define BRW_DATAPORT_OWORD_DUAL_BLOCK_1OWORD     0
+#define BRW_DATAPORT_OWORD_DUAL_BLOCK_4OWORDS    2
+
+#define BRW_DATAPORT_DWORD_SCATTERED_BLOCK_8DWORDS   2
+#define BRW_DATAPORT_DWORD_SCATTERED_BLOCK_16DWORDS  3
+
+#define BRW_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ          0
+#define BRW_DATAPORT_READ_MESSAGE_OWORD_DUAL_BLOCK_READ     1
+#define BRW_DATAPORT_READ_MESSAGE_DWORD_BLOCK_READ          2
+#define BRW_DATAPORT_READ_MESSAGE_DWORD_SCATTERED_READ      3
+
+#define BRW_DATAPORT_READ_TARGET_DATA_CACHE      0
+#define BRW_DATAPORT_READ_TARGET_RENDER_CACHE    1
+#define BRW_DATAPORT_READ_TARGET_SAMPLER_CACHE   2
+
+#define BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE                0
+#define BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE_REPLICATED     1
+#define BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD8_DUAL_SOURCE_SUBSPAN01         2
+#define BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD8_DUAL_SOURCE_SUBSPAN23         3
+#define BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD8_SINGLE_SOURCE_SUBSPAN01       4
+
+#define BRW_DATAPORT_WRITE_MESSAGE_OWORD_BLOCK_WRITE                0
+#define BRW_DATAPORT_WRITE_MESSAGE_OWORD_DUAL_BLOCK_WRITE           1
+#define BRW_DATAPORT_WRITE_MESSAGE_DWORD_BLOCK_WRITE                2
+#define BRW_DATAPORT_WRITE_MESSAGE_DWORD_SCATTERED_WRITE            3
+#define BRW_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE              4
+#define BRW_DATAPORT_WRITE_MESSAGE_STREAMED_VERTEX_BUFFER_WRITE     5
+#define BRW_DATAPORT_WRITE_MESSAGE_FLUSH_RENDER_CACHE               7
+
+#define BRW_MATH_FUNCTION_INV                              1
+#define BRW_MATH_FUNCTION_LOG                              2
+#define BRW_MATH_FUNCTION_EXP                              3
+#define BRW_MATH_FUNCTION_SQRT                             4
+#define BRW_MATH_FUNCTION_RSQ                              5
+#define BRW_MATH_FUNCTION_SIN                              6 /* was 7 */
+#define BRW_MATH_FUNCTION_COS                              7 /* was 8 */
+#define BRW_MATH_FUNCTION_SINCOS                           8 /* was 6 */
+#define BRW_MATH_FUNCTION_TAN                              9
+#define BRW_MATH_FUNCTION_POW                              10
+#define BRW_MATH_FUNCTION_INT_DIV_QUOTIENT_AND_REMAINDER   11
+#define BRW_MATH_FUNCTION_INT_DIV_QUOTIENT                 12
+#define BRW_MATH_FUNCTION_INT_DIV_REMAINDER                13
+
+#define BRW_MATH_INTEGER_UNSIGNED     0
+#define BRW_MATH_INTEGER_SIGNED       1
+
+#define BRW_MATH_PRECISION_FULL        0
+#define BRW_MATH_PRECISION_PARTIAL     1
+
+#define BRW_MATH_SATURATE_NONE         0
+#define BRW_MATH_SATURATE_SATURATE     1
+
+#define BRW_MATH_DATA_VECTOR  0
+#define BRW_MATH_DATA_SCALAR  1
+
+#define BRW_URB_OPCODE_WRITE  0
+
+#define BRW_URB_SWIZZLE_NONE          0
+#define BRW_URB_SWIZZLE_INTERLEAVE    1
+#define BRW_URB_SWIZZLE_TRANSPOSE     2
+
+#define BRW_SCRATCH_SPACE_SIZE_1K     0
+#define BRW_SCRATCH_SPACE_SIZE_2K     1
+#define BRW_SCRATCH_SPACE_SIZE_4K     2
+#define BRW_SCRATCH_SPACE_SIZE_8K     3
+#define BRW_SCRATCH_SPACE_SIZE_16K    4
+#define BRW_SCRATCH_SPACE_SIZE_32K    5
+#define BRW_SCRATCH_SPACE_SIZE_64K    6
+#define BRW_SCRATCH_SPACE_SIZE_128K   7
+#define BRW_SCRATCH_SPACE_SIZE_256K   8
+#define BRW_SCRATCH_SPACE_SIZE_512K   9
+#define BRW_SCRATCH_SPACE_SIZE_1M     10
+#define BRW_SCRATCH_SPACE_SIZE_2M     11
+
+
+
+
+#define CMD_URB_FENCE                 0x6000
+#define CMD_CONST_BUFFER_STATE        0x6001
+#define CMD_CONST_BUFFER              0x6002
+
+#define CMD_STATE_BASE_ADDRESS        0x6101
+#define CMD_STATE_INSN_POINTER        0x6102
+#define CMD_PIPELINE_SELECT           0x6104
+
+#define CMD_PIPELINED_STATE_POINTERS  0x7800
+#define CMD_BINDING_TABLE_PTRS        0x7801
+#define CMD_VERTEX_BUFFER             0x7808
+#define CMD_VERTEX_ELEMENT            0x7809
+#define CMD_INDEX_BUFFER              0x780a
+#define CMD_VF_STATISTICS             0x780b
+
+#define CMD_DRAW_RECT                 0x7900
+#define CMD_BLEND_CONSTANT_COLOR      0x7901
+#define CMD_CHROMA_KEY                0x7904
+#define CMD_DEPTH_BUFFER              0x7905
+#define CMD_POLY_STIPPLE_OFFSET       0x7906
+#define CMD_POLY_STIPPLE_PATTERN      0x7907
+#define CMD_LINE_STIPPLE_PATTERN      0x7908
+#define CMD_GLOBAL_DEPTH_OFFSET_CLAMP 0x7908
+
+#define CMD_PIPE_CONTROL              0x7a00
+
+#define CMD_3D_PRIM                   0x7b00
+
+#define CMD_MI_FLUSH                  0x0200
+
+
+/* Various values from the R0 vertex header:
+ */
+#define R02_PRIM_END    0x1
+#define R02_PRIM_START  0x2
+
+/* media pipeline */
+
+#define BRW_VFE_MODE_GENERIC		0x0
+#define BRW_VFE_MODE_VLD_MPEG2		0x1
+#define BRW_VFE_MODE_IS			0x2
+#define BRW_VFE_MODE_AVC_MC		0x4
+#define BRW_VFE_MODE_AVC_IT		0x7
+#define BRW_VFE_MODE_VC1_IT		0xB
+
+#define BRW_VFE_DEBUG_COUNTER_FREE	0
+#define BRW_VFE_DEBUG_COUNTER_FROZEN	1
+#define BRW_VFE_DEBUG_COUNTER_ONCE	2
+#define BRW_VFE_DEBUG_COUNTER_ALWAYS	3
+
+/* VLD_STATE */
+#define BRW_MPEG_TOP_FIELD		1
+#define BRW_MPEG_BOTTOM_FIELD		2
+#define BRW_MPEG_FRAME			3
+#define BRW_MPEG_QSCALE_LINEAR		0
+#define BRW_MPEG_QSCALE_NONLINEAR	1
+#define BRW_MPEG_ZIGZAG_SCAN		0
+#define BRW_MPEG_ALTER_VERTICAL_SCAN	1
+#define BRW_MPEG_I_PICTURE		1
+#define BRW_MPEG_P_PICTURE		2
+#define BRW_MPEG_B_PICTURE		3
+
+#endif
diff --git a/src/drm/cairo-drm-intel-brw-eu-emit.c b/src/drm/cairo-drm-intel-brw-eu-emit.c
new file mode 100644
index 0000000..05bac0a
--- /dev/null
+++ b/src/drm/cairo-drm-intel-brw-eu-emit.c
@@ -0,0 +1,1089 @@
+/*
+   Copyright (C) Intel Corp.  2006.  All Rights Reserved.
+   Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
+   develop this 3D driver.
+
+   Permission is hereby granted, free of charge, to any person obtaining
+   a copy of this software and associated documentation files (the
+   "Software"), to deal in the Software without restriction, including
+   without limitation the rights to use, copy, modify, merge, publish,
+   distribute, sublicense, and/or sell copies of the Software, and to
+   permit persons to whom the Software is furnished to do so, subject to
+   the following conditions:
+
+   The above copyright notice and this permission notice (including the
+   next paragraph) shall be included in all copies or substantial
+   portions of the Software.
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+   IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ **********************************************************************/
+/*
+ * Authors:
+ *   Keith Whitwell <keith at tungstengraphics.com>
+ */
+
+#include "cairoint.h"
+#include "cairo-drm-intel-brw-eu.h"
+
+#include <string.h>
+
+/***********************************************************************
+ * Internal helper for constructing instructions
+ */
+
+static void guess_execution_size( struct brw_instruction *insn,
+				  struct brw_reg reg )
+{
+    if (reg.width == BRW_WIDTH_8 &&
+	insn->header.compression_control == BRW_COMPRESSION_COMPRESSED)
+	insn->header.execution_size = BRW_EXECUTE_16;
+    else
+	insn->header.execution_size = reg.width;	/* note - definitions are compatible */
+}
+
+
+void
+brw_instruction_set_destination (struct brw_instruction *insn,
+				 struct brw_reg dest)
+{
+    insn->bits1.da1.dest_reg_file = dest.file;
+    insn->bits1.da1.dest_reg_type = dest.type;
+    insn->bits1.da1.dest_address_mode = dest.address_mode;
+
+    if (dest.address_mode == BRW_ADDRESS_DIRECT) {
+	insn->bits1.da1.dest_reg_nr = dest.nr;
+
+	if (insn->header.access_mode == BRW_ALIGN_1) {
+	    insn->bits1.da1.dest_subreg_nr = dest.subnr;
+	    if (dest.hstride == BRW_HORIZONTAL_STRIDE_0)
+		dest.hstride = BRW_HORIZONTAL_STRIDE_1;
+	    insn->bits1.da1.dest_horiz_stride = dest.hstride;
+	} else {
+	    insn->bits1.da16.dest_subreg_nr = dest.subnr / 16;
+	    insn->bits1.da16.dest_writemask = dest.dw1.bits.writemask;
+	}
+    } else {
+	insn->bits1.ia1.dest_subreg_nr = dest.subnr;
+
+	/* These are different sizes in align1 vs align16:
+	*/
+	if (insn->header.access_mode == BRW_ALIGN_1) {
+	    insn->bits1.ia1.dest_indirect_offset = dest.dw1.bits.indirect_offset;
+	    if (dest.hstride == BRW_HORIZONTAL_STRIDE_0)
+		dest.hstride = BRW_HORIZONTAL_STRIDE_1;
+	    insn->bits1.ia1.dest_horiz_stride = dest.hstride;
+	} else {
+	    insn->bits1.ia16.dest_indirect_offset = dest.dw1.bits.indirect_offset;
+	}
+    }
+
+    /* NEW: Set the execution size based on dest.width and
+     * insn->compression_control:
+     */
+    guess_execution_size(insn, dest);
+}
+
+void
+brw_instruction_set_source0 (struct brw_instruction *insn,
+			     struct brw_reg reg)
+{
+    assert(reg.file != BRW_MESSAGE_REGISTER_FILE);
+
+    insn->bits1.da1.src0_reg_file = reg.file;
+    insn->bits1.da1.src0_reg_type = reg.type;
+    insn->bits2.da1.src0_abs = reg.abs;
+    insn->bits2.da1.src0_negate = reg.negate;
+    insn->bits2.da1.src0_address_mode = reg.address_mode;
+
+    if (reg.file == BRW_IMMEDIATE_VALUE) {
+	insn->bits3.ud = reg.dw1.ud;
+
+	/* Required to set some fields in src1 as well:
+	*/
+	insn->bits1.da1.src1_reg_file = 0; /* arf */
+	insn->bits1.da1.src1_reg_type = reg.type;
+    } else {
+	if (reg.address_mode == BRW_ADDRESS_DIRECT) {
+	    if (insn->header.access_mode == BRW_ALIGN_1) {
+		insn->bits2.da1.src0_subreg_nr = reg.subnr;
+		insn->bits2.da1.src0_reg_nr = reg.nr;
+	    } else {
+		insn->bits2.da16.src0_subreg_nr = reg.subnr / 16;
+		insn->bits2.da16.src0_reg_nr = reg.nr;
+	    }
+	} else {
+	    insn->bits2.ia1.src0_subreg_nr = reg.subnr;
+
+	    if (insn->header.access_mode == BRW_ALIGN_1) {
+		insn->bits2.ia1.src0_indirect_offset = reg.dw1.bits.indirect_offset;
+	    } else {
+		insn->bits2.ia16.src0_subreg_nr = reg.dw1.bits.indirect_offset;
+	    }
+	}
+
+	if (insn->header.access_mode == BRW_ALIGN_1) {
+	    if (reg.width == BRW_WIDTH_1 &&
+		insn->header.execution_size == BRW_EXECUTE_1) {
+		insn->bits2.da1.src0_horiz_stride = BRW_HORIZONTAL_STRIDE_0;
+		insn->bits2.da1.src0_width = BRW_WIDTH_1;
+		insn->bits2.da1.src0_vert_stride = BRW_VERTICAL_STRIDE_0;
+	    } else {
+		insn->bits2.da1.src0_horiz_stride = reg.hstride;
+		insn->bits2.da1.src0_width = reg.width;
+		insn->bits2.da1.src0_vert_stride = reg.vstride;
+	    }
+	} else {
+	    insn->bits2.da16.src0_swz_x = BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_X);
+	    insn->bits2.da16.src0_swz_y = BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_Y);
+	    insn->bits2.da16.src0_swz_z = BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_Z);
+	    insn->bits2.da16.src0_swz_w = BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_W);
+
+	    /* This is an oddity of the fact we're using the same
+	     * descriptions for registers in align_16 as align_1:
+	     */
+	    if (reg.vstride == BRW_VERTICAL_STRIDE_8)
+		insn->bits2.da16.src0_vert_stride = BRW_VERTICAL_STRIDE_4;
+	    else
+		insn->bits2.da16.src0_vert_stride = reg.vstride;
+	}
+    }
+}
+
+
+void brw_set_src1( struct brw_instruction *insn,
+		   struct brw_reg reg )
+{
+    assert(reg.file != BRW_MESSAGE_REGISTER_FILE);
+
+    insn->bits1.da1.src1_reg_file = reg.file;
+    insn->bits1.da1.src1_reg_type = reg.type;
+    insn->bits3.da1.src1_abs = reg.abs;
+    insn->bits3.da1.src1_negate = reg.negate;
+
+    /* Only src1 can be immediate in two-argument instructions.
+    */
+    assert(insn->bits1.da1.src0_reg_file != BRW_IMMEDIATE_VALUE);
+
+    if (reg.file == BRW_IMMEDIATE_VALUE) {
+	insn->bits3.ud = reg.dw1.ud;
+    }
+    else {
+	/* This is a hardware restriction, which may or may not be lifted
+	 * in the future:
+	 */
+	assert (reg.address_mode == BRW_ADDRESS_DIRECT);
+	//assert (reg.file == BRW_GENERAL_REGISTER_FILE);
+
+	if (insn->header.access_mode == BRW_ALIGN_1) {
+	    insn->bits3.da1.src1_subreg_nr = reg.subnr;
+	    insn->bits3.da1.src1_reg_nr = reg.nr;
+	}
+	else {
+	    insn->bits3.da16.src1_subreg_nr = reg.subnr / 16;
+	    insn->bits3.da16.src1_reg_nr = reg.nr;
+	}
+
+	if (insn->header.access_mode == BRW_ALIGN_1) {
+	    if (reg.width == BRW_WIDTH_1 &&
+		insn->header.execution_size == BRW_EXECUTE_1) {
+		insn->bits3.da1.src1_horiz_stride = BRW_HORIZONTAL_STRIDE_0;
+		insn->bits3.da1.src1_width = BRW_WIDTH_1;
+		insn->bits3.da1.src1_vert_stride = BRW_VERTICAL_STRIDE_0;
+	    }
+	    else {
+		insn->bits3.da1.src1_horiz_stride = reg.hstride;
+		insn->bits3.da1.src1_width = reg.width;
+		insn->bits3.da1.src1_vert_stride = reg.vstride;
+	    }
+	}
+	else {
+	    insn->bits3.da16.src1_swz_x = BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_X);
+	    insn->bits3.da16.src1_swz_y = BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_Y);
+	    insn->bits3.da16.src1_swz_z = BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_Z);
+	    insn->bits3.da16.src1_swz_w = BRW_GET_SWZ(reg.dw1.bits.swizzle, BRW_CHANNEL_W);
+
+	    /* This is an oddity of the fact we're using the same
+	     * descriptions for registers in align_16 as align_1:
+	     */
+	    if (reg.vstride == BRW_VERTICAL_STRIDE_8)
+		insn->bits3.da16.src1_vert_stride = BRW_VERTICAL_STRIDE_4;
+	    else
+		insn->bits3.da16.src1_vert_stride = reg.vstride;
+	}
+    }
+}
+
+
+
+static void brw_set_math_message( struct brw_instruction *insn,
+				  uint32_t msg_length,
+				  uint32_t response_length,
+				  uint32_t function,
+				  uint32_t integer_type,
+				  int low_precision,
+				  int saturate,
+				  uint32_t dataType )
+{
+    brw_set_src1 (insn, brw_imm_d (0));
+
+    insn->bits3.math.function = function;
+    insn->bits3.math.int_type = integer_type;
+    insn->bits3.math.precision = low_precision;
+    insn->bits3.math.saturate = saturate;
+    insn->bits3.math.data_type = dataType;
+    insn->bits3.math.response_length = response_length;
+    insn->bits3.math.msg_length = msg_length;
+    insn->bits3.math.msg_target = BRW_MESSAGE_TARGET_MATH;
+    insn->bits3.math.end_of_thread = 0;
+}
+
+static void brw_set_urb_message( struct brw_instruction *insn,
+				 int allocate,
+				 int used,
+				 uint32_t msg_length,
+				 uint32_t response_length,
+				 int end_of_thread,
+				 int complete,
+				 uint32_t offset,
+				 uint32_t swizzle_control )
+{
+    brw_set_src1 (insn, brw_imm_d (0));
+
+    insn->bits3.urb.opcode = 0;	/* ? */
+    insn->bits3.urb.offset = offset;
+    insn->bits3.urb.swizzle_control = swizzle_control;
+    insn->bits3.urb.allocate = allocate;
+    insn->bits3.urb.used = used;	/* ? */
+    insn->bits3.urb.complete = complete;
+    insn->bits3.urb.response_length = response_length;
+    insn->bits3.urb.msg_length = msg_length;
+    insn->bits3.urb.msg_target = BRW_MESSAGE_TARGET_URB;
+    insn->bits3.urb.end_of_thread = end_of_thread;
+}
+
+void
+brw_instruction_set_dp_write_message (struct brw_instruction *insn,
+				      uint32_t binding_table_index,
+				      uint32_t msg_control,
+				      uint32_t msg_type,
+				      uint32_t msg_length,
+				      uint32_t pixel_scoreboard_clear,
+				      uint32_t response_length,
+				      uint32_t end_of_thread)
+{
+    brw_set_src1 (insn, brw_imm_d (0));
+
+    insn->bits3.dp_write.binding_table_index = binding_table_index;
+    insn->bits3.dp_write.msg_control = msg_control;
+    insn->bits3.dp_write.pixel_scoreboard_clear = pixel_scoreboard_clear;
+    insn->bits3.dp_write.msg_type = msg_type;
+    insn->bits3.dp_write.send_commit_msg = 0;
+    insn->bits3.dp_write.response_length = response_length;
+    insn->bits3.dp_write.msg_length = msg_length;
+    insn->bits3.dp_write.msg_target = BRW_MESSAGE_TARGET_DATAPORT_WRITE;
+    insn->bits3.urb.end_of_thread = end_of_thread;
+}
+
+static void brw_set_dp_read_message( struct brw_instruction *insn,
+				     uint32_t binding_table_index,
+				     uint32_t msg_control,
+				     uint32_t msg_type,
+				     uint32_t target_cache,
+				     uint32_t msg_length,
+				     uint32_t response_length,
+				     uint32_t end_of_thread )
+{
+    brw_set_src1 (insn, brw_imm_d (0));
+
+    insn->bits3.dp_read.binding_table_index = binding_table_index;
+    insn->bits3.dp_read.msg_control = msg_control;
+    insn->bits3.dp_read.msg_type = msg_type;
+    insn->bits3.dp_read.target_cache = target_cache;
+    insn->bits3.dp_read.response_length = response_length;
+    insn->bits3.dp_read.msg_length = msg_length;
+    insn->bits3.dp_read.msg_target = BRW_MESSAGE_TARGET_DATAPORT_READ;
+    insn->bits3.dp_read.end_of_thread = end_of_thread;
+}
+
+static void
+brw_set_sampler_message (struct brw_instruction *insn,
+			 cairo_bool_t is_g4x,
+			 uint32_t binding_table_index,
+			 uint32_t sampler,
+			 uint32_t msg_type,
+			 uint32_t response_length,
+			 uint32_t msg_length,
+			 cairo_bool_t eot)
+{
+    brw_set_src1 (insn, brw_imm_d (0));
+
+    if (is_g4x) {
+	/* XXX presume the driver is sane! */
+	insn->bits3.sampler_g4x.binding_table_index = binding_table_index;
+	insn->bits3.sampler_g4x.sampler = sampler;
+	insn->bits3.sampler_g4x.msg_type = msg_type;
+	insn->bits3.sampler_g4x.response_length = response_length;
+	insn->bits3.sampler_g4x.msg_length = msg_length;
+	insn->bits3.sampler_g4x.end_of_thread = eot;
+	insn->bits3.sampler_g4x.msg_target = BRW_MESSAGE_TARGET_SAMPLER;
+    } else {
+	insn->bits3.sampler.binding_table_index = binding_table_index;
+	insn->bits3.sampler.sampler = sampler;
+	insn->bits3.sampler.msg_type = msg_type;
+	insn->bits3.sampler.return_format = BRW_SAMPLER_RETURN_FORMAT_FLOAT32;
+	insn->bits3.sampler.response_length = response_length;
+	insn->bits3.sampler.msg_length = msg_length;
+	insn->bits3.sampler.end_of_thread = eot;
+	insn->bits3.sampler.msg_target = BRW_MESSAGE_TARGET_SAMPLER;
+    }
+}
+
+struct brw_instruction *
+brw_next_instruction (struct brw_compile *p,
+		      uint32_t opcode)
+{
+    struct brw_instruction *insn;
+
+    assert(p->nr_insn + 1 < BRW_EU_MAX_INSN);
+
+    insn = &p->store[p->nr_insn++];
+    memcpy(insn, p->current, sizeof(*insn));
+
+    /* Reset this one-shot flag: */
+    if (p->current->header.destreg__conditonalmod) {
+	p->current->header.destreg__conditonalmod = 0;
+	p->current->header.predicate_control = BRW_PREDICATE_NORMAL;
+    }
+
+    insn->header.opcode = opcode;
+    return insn;
+}
+
+static struct brw_instruction *brw_alu1( struct brw_compile *p,
+					 uint32_t opcode,
+					 struct brw_reg dest,
+					 struct brw_reg src )
+{
+    struct brw_instruction *insn = brw_next_instruction(p, opcode);
+    brw_instruction_set_destination(insn, dest);
+    brw_instruction_set_source0(insn, src);
+    return insn;
+}
+
+static struct brw_instruction *brw_alu2(struct brw_compile *p,
+					uint32_t opcode,
+					struct brw_reg dest,
+					struct brw_reg src0,
+					struct brw_reg src1 )
+{
+    struct brw_instruction *insn = brw_next_instruction(p, opcode);
+    brw_instruction_set_destination(insn, dest);
+    brw_instruction_set_source0(insn, src0);
+    brw_set_src1(insn, src1);
+    return insn;
+}
+
+
+/***********************************************************************
+ * Convenience routines.
+ */
+#define ALU1(OP)					\
+    struct brw_instruction *brw_##OP(struct brw_compile *p,			\
+				     struct brw_reg dest,			\
+				     struct brw_reg src0)			\
+{							\
+    return brw_alu1(p, BRW_OPCODE_##OP, dest, src0);	\
+}
+
+#define ALU2(OP)					\
+    struct brw_instruction *brw_##OP(struct brw_compile *p,			\
+				     struct brw_reg dest,			\
+				     struct brw_reg src0,			\
+				     struct brw_reg src1)			\
+{							\
+    return brw_alu2(p, BRW_OPCODE_##OP, dest, src0, src1);	\
+}
+
+
+    ALU1(MOV)
+    ALU2(SEL)
+    ALU1(NOT)
+    ALU2(AND)
+    ALU2(OR)
+    ALU2(XOR)
+    ALU2(SHR)
+    ALU2(SHL)
+    ALU2(RSR)
+    ALU2(RSL)
+    ALU2(ASR)
+    ALU2(ADD)
+    ALU2(MUL)
+    ALU1(FRC)
+    ALU1(RNDD)
+    ALU1(RNDZ)
+    ALU2(MAC)
+    ALU2(MACH)
+    ALU1(LZD)
+    ALU2(DP4)
+    ALU2(DPH)
+    ALU2(DP3)
+    ALU2(DP2)
+ALU2(LINE)
+
+
+
+
+void brw_NOP(struct brw_compile *p)
+{
+    struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_NOP);
+    brw_instruction_set_destination(insn, retype(brw_vec4_grf(0,0), BRW_REGISTER_TYPE_UD));
+    brw_instruction_set_source0(insn, retype(brw_vec4_grf(0,0), BRW_REGISTER_TYPE_UD));
+    brw_set_src1(insn, brw_imm_ud(0x0));
+}
+
+
+
+
+
+/***********************************************************************
+ * Comparisons, if/else/endif
+ */
+
+struct brw_instruction *brw_JMPI(struct brw_compile *p,
+				 struct brw_reg dest,
+				 struct brw_reg src0,
+				 struct brw_reg src1)
+{
+    struct brw_instruction *insn = brw_alu2(p, BRW_OPCODE_JMPI, dest, src0, src1);
+
+    p->current->header.predicate_control = BRW_PREDICATE_NONE;
+
+    return insn;
+}
+
+/* EU takes the value from the flag register and pushes it onto some
+ * sort of a stack (presumably merging with any flag value already on
+ * the stack).  Within an if block, the flags at the top of the stack
+ * control execution on each channel of the unit, eg. on each of the
+ * 16 pixel values in our wm programs.
+ *
+ * When the matching 'else' instruction is reached (presumably by
+ * countdown of the instruction count patched in by our ELSE/ENDIF
+ * functions), the relevent flags are inverted.
+ *
+ * When the matching 'endif' instruction is reached, the flags are
+ * popped off.  If the stack is now empty, normal execution resumes.
+ *
+ * No attempt is made to deal with stack overflow (14 elements?).
+ */
+struct brw_instruction *brw_IF(struct brw_compile *p, uint32_t execute_size)
+{
+    struct brw_instruction *insn;
+
+    if (p->single_program_flow) {
+	assert(execute_size == BRW_EXECUTE_1);
+
+	insn = brw_next_instruction(p, BRW_OPCODE_ADD);
+	insn->header.predicate_inverse = 1;
+    } else {
+	insn = brw_next_instruction(p, BRW_OPCODE_IF);
+    }
+
+    /* Override the defaults for this instruction:
+    */
+    brw_instruction_set_destination (insn, brw_ip_reg ());
+    brw_instruction_set_source0 (insn, brw_ip_reg ());
+    brw_set_src1 (insn, brw_imm_d (0));
+
+    insn->header.execution_size = execute_size;
+    insn->header.compression_control = BRW_COMPRESSION_NONE;
+    insn->header.predicate_control = BRW_PREDICATE_NORMAL;
+    insn->header.mask_control = BRW_MASK_ENABLE;
+    if (!p->single_program_flow)
+	insn->header.thread_control = BRW_THREAD_SWITCH;
+
+    p->current->header.predicate_control = BRW_PREDICATE_NONE;
+
+    return insn;
+}
+
+
+struct brw_instruction *brw_ELSE(struct brw_compile *p,
+				 struct brw_instruction *if_insn)
+{
+    struct brw_instruction *insn;
+
+    if (p->single_program_flow) {
+	insn = brw_next_instruction(p, BRW_OPCODE_ADD);
+    } else {
+	insn = brw_next_instruction(p, BRW_OPCODE_ELSE);
+    }
+
+    brw_instruction_set_destination (insn, brw_ip_reg ());
+    brw_instruction_set_source0 (insn, brw_ip_reg ());
+    brw_set_src1 (insn, brw_imm_d (0));
+
+    insn->header.compression_control = BRW_COMPRESSION_NONE;
+    insn->header.execution_size = if_insn->header.execution_size;
+    insn->header.mask_control = BRW_MASK_ENABLE;
+    if (!p->single_program_flow)
+	insn->header.thread_control = BRW_THREAD_SWITCH;
+
+    /* Patch the if instruction to point at this instruction.
+    */
+    if (p->single_program_flow) {
+	assert(if_insn->header.opcode == BRW_OPCODE_ADD);
+
+	if_insn->bits3.ud = (insn - if_insn + 1) * 16;
+    } else {
+	assert(if_insn->header.opcode == BRW_OPCODE_IF);
+
+	if_insn->bits3.if_else.jump_count = insn - if_insn;
+	if_insn->bits3.if_else.pop_count = 1;
+	if_insn->bits3.if_else.pad0 = 0;
+    }
+
+    return insn;
+}
+
+void brw_ENDIF(struct brw_compile *p,
+	       struct brw_instruction *patch_insn)
+{
+    if (p->single_program_flow) {
+	/* In single program flow mode, there's no need to execute an ENDIF,
+	 * since we don't need to do any stack operations, and if we're executing
+	 * currently, we want to just continue executing.
+	 */
+	struct brw_instruction *next = &p->store[p->nr_insn];
+
+	assert(patch_insn->header.opcode == BRW_OPCODE_ADD);
+
+	patch_insn->bits3.ud = (next - patch_insn) * 16;
+    } else {
+	struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_ENDIF);
+
+	brw_instruction_set_destination(insn, retype(brw_vec4_grf(0,0), BRW_REGISTER_TYPE_UD));
+	brw_instruction_set_source0(insn, retype(brw_vec4_grf(0,0), BRW_REGISTER_TYPE_UD));
+	brw_set_src1 (insn, brw_imm_d (0));
+
+	insn->header.compression_control = BRW_COMPRESSION_NONE;
+	insn->header.execution_size = patch_insn->header.execution_size;
+	insn->header.mask_control = BRW_MASK_ENABLE;
+	insn->header.thread_control = BRW_THREAD_SWITCH;
+
+	assert(patch_insn->bits3.if_else.jump_count == 0);
+
+	/* Patch the if or else instructions to point at this or the next
+	 * instruction respectively.
+	 */
+	if (patch_insn->header.opcode == BRW_OPCODE_IF) {
+	    /* Automagically turn it into an IFF:
+	    */
+	    patch_insn->header.opcode = BRW_OPCODE_IFF;
+	    patch_insn->bits3.if_else.jump_count = insn - patch_insn + 1;
+	    patch_insn->bits3.if_else.pop_count = 0;
+	    patch_insn->bits3.if_else.pad0 = 0;
+	} else if (patch_insn->header.opcode == BRW_OPCODE_ELSE) {
+	    patch_insn->bits3.if_else.jump_count = insn - patch_insn + 1;
+	    patch_insn->bits3.if_else.pop_count = 1;
+	    patch_insn->bits3.if_else.pad0 = 0;
+	} else {
+	    assert(0);
+	}
+
+	/* Also pop item off the stack in the endif instruction:
+	*/
+	insn->bits3.if_else.jump_count = 0;
+	insn->bits3.if_else.pop_count = 1;
+	insn->bits3.if_else.pad0 = 0;
+    }
+}
+
+struct brw_instruction *brw_BREAK(struct brw_compile *p)
+{
+    struct brw_instruction *insn;
+    insn = brw_next_instruction(p, BRW_OPCODE_BREAK);
+    brw_instruction_set_destination(insn, brw_ip_reg());
+    brw_instruction_set_source0(insn, brw_ip_reg());
+    brw_set_src1(insn, brw_imm_d (0));
+    insn->header.compression_control = BRW_COMPRESSION_NONE;
+    insn->header.execution_size = BRW_EXECUTE_8;
+    /* insn->header.mask_control = BRW_MASK_DISABLE; */
+    insn->bits3.if_else.pad0 = 0;
+    return insn;
+}
+
+struct brw_instruction *brw_CONT(struct brw_compile *p)
+{
+    struct brw_instruction *insn;
+    insn = brw_next_instruction(p, BRW_OPCODE_CONTINUE);
+    brw_instruction_set_destination(insn, brw_ip_reg());
+    brw_instruction_set_source0(insn, brw_ip_reg());
+    brw_set_src1 (insn, brw_imm_d (0));
+    insn->header.compression_control = BRW_COMPRESSION_NONE;
+    insn->header.execution_size = BRW_EXECUTE_8;
+    /* insn->header.mask_control = BRW_MASK_DISABLE; */
+    insn->bits3.if_else.pad0 = 0;
+    return insn;
+}
+
+/* DO/WHILE loop:
+*/
+struct brw_instruction *brw_DO(struct brw_compile *p, uint32_t execute_size)
+{
+    if (p->single_program_flow) {
+	return &p->store[p->nr_insn];
+    } else {
+	struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_DO);
+
+	/* Override the defaults for this instruction:
+	*/
+	brw_instruction_set_destination(insn, brw_null_reg());
+	brw_instruction_set_source0(insn, brw_null_reg());
+	brw_set_src1(insn, brw_null_reg());
+
+	insn->header.compression_control = BRW_COMPRESSION_NONE;
+	insn->header.execution_size = execute_size;
+	insn->header.predicate_control = BRW_PREDICATE_NONE;
+	/* insn->header.mask_control = BRW_MASK_ENABLE; */
+	/* insn->header.mask_control = BRW_MASK_DISABLE; */
+
+	return insn;
+    }
+}
+
+
+
+struct brw_instruction *brw_WHILE(struct brw_compile *p,
+				  struct brw_instruction *do_insn)
+{
+    struct brw_instruction *insn;
+
+    if (p->single_program_flow)
+	insn = brw_next_instruction(p, BRW_OPCODE_ADD);
+    else
+	insn = brw_next_instruction(p, BRW_OPCODE_WHILE);
+
+    brw_instruction_set_destination(insn, brw_ip_reg());
+    brw_instruction_set_source0(insn, brw_ip_reg());
+    brw_set_src1 (insn, brw_imm_d (0));
+
+    insn->header.compression_control = BRW_COMPRESSION_NONE;
+
+    if (p->single_program_flow) {
+	insn->header.execution_size = BRW_EXECUTE_1;
+
+	insn->bits3.d = (do_insn - insn) * 16;
+    } else {
+	insn->header.execution_size = do_insn->header.execution_size;
+
+	assert(do_insn->header.opcode == BRW_OPCODE_DO);
+	insn->bits3.if_else.jump_count = do_insn - insn + 1;
+	insn->bits3.if_else.pop_count = 0;
+	insn->bits3.if_else.pad0 = 0;
+    }
+
+    /*    insn->header.mask_control = BRW_MASK_ENABLE; */
+
+    /* insn->header.mask_control = BRW_MASK_DISABLE; */
+    p->current->header.predicate_control = BRW_PREDICATE_NONE;
+    return insn;
+}
+
+
+/* FORWARD JUMPS:
+*/
+void brw_land_fwd_jump(struct brw_compile *p,
+		       struct brw_instruction *jmp_insn)
+{
+    struct brw_instruction *landing = &p->store[p->nr_insn];
+
+    assert(jmp_insn->header.opcode == BRW_OPCODE_JMPI);
+    assert(jmp_insn->bits1.da1.src1_reg_file = BRW_IMMEDIATE_VALUE);
+
+    jmp_insn->bits3.ud = (landing - jmp_insn) - 1;
+}
+
+
+
+/* To integrate with the above, it makes sense that the comparison
+ * instruction should populate the flag register.  It might be simpler
+ * just to use the flag reg for most WM tasks?
+ */
+void brw_CMP(struct brw_compile *p,
+	     struct brw_reg dest,
+	     uint32_t conditional,
+	     struct brw_reg src0,
+	     struct brw_reg src1)
+{
+    struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_CMP);
+
+    insn->header.destreg__conditonalmod = conditional;
+    brw_instruction_set_destination(insn, dest);
+    brw_instruction_set_source0(insn, src0);
+    brw_set_src1(insn, src1);
+
+    /*    guess_execution_size(insn, src0); */
+
+
+    /* Make it so that future instructions will use the computed flag
+     * value until brw_set_predicate_control_flag_value() is called
+     * again.
+     */
+    if (dest.file == BRW_ARCHITECTURE_REGISTER_FILE &&
+	dest.nr == 0) {
+	p->current->header.predicate_control = BRW_PREDICATE_NORMAL;
+	p->flag_value = 0xff;
+    }
+}
+
+
+
+/***********************************************************************
+ * Helpers for the various SEND message types:
+ */
+
+/* Invert 8 values
+*/
+void brw_math( struct brw_compile *p,
+	       struct brw_reg dest,
+	       uint32_t function,
+	       uint32_t saturate,
+	       uint32_t msg_reg_nr,
+	       struct brw_reg src,
+	       uint32_t data_type,
+	       uint32_t precision )
+{
+    struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_SEND);
+    uint32_t msg_length = (function == BRW_MATH_FUNCTION_POW) ? 2 : 1;
+    uint32_t response_length = (function == BRW_MATH_FUNCTION_SINCOS) ? 2 : 1;
+
+    /* Example code doesn't set predicate_control for send
+     * instructions.
+     */
+    insn->header.predicate_control = 0;
+    insn->header.destreg__conditonalmod = msg_reg_nr;
+
+    response_length = 1;
+
+    brw_instruction_set_destination(insn, dest);
+    brw_instruction_set_source0(insn, src);
+    brw_set_math_message(insn,
+			 msg_length, response_length,
+			 function,
+			 BRW_MATH_INTEGER_UNSIGNED,
+			 precision,
+			 saturate,
+			 data_type);
+}
+
+/* Use 2 send instructions to invert 16 elements
+*/
+void brw_math_16( struct brw_compile *p,
+		  struct brw_reg dest,
+		  uint32_t function,
+		  uint32_t saturate,
+		  uint32_t msg_reg_nr,
+		  struct brw_reg src,
+		  uint32_t precision )
+{
+    struct brw_instruction *insn;
+    uint32_t msg_length = (function == BRW_MATH_FUNCTION_POW) ? 2 : 1;
+    uint32_t response_length = (function == BRW_MATH_FUNCTION_SINCOS) ? 2 : 1;
+
+    /* First instruction:
+    */
+    brw_push_insn_state(p);
+    brw_set_predicate_control_flag_value(p, 0xff);
+    brw_set_compression_control(p, BRW_COMPRESSION_NONE);
+
+    insn = brw_next_instruction(p, BRW_OPCODE_SEND);
+    insn->header.destreg__conditonalmod = msg_reg_nr;
+
+    brw_instruction_set_destination(insn, dest);
+    brw_instruction_set_source0(insn, src);
+    brw_set_math_message(insn,
+			 msg_length, response_length,
+			 function,
+			 BRW_MATH_INTEGER_UNSIGNED,
+			 precision,
+			 saturate,
+			 BRW_MATH_DATA_VECTOR);
+
+    /* Second instruction:
+    */
+    insn = brw_next_instruction(p, BRW_OPCODE_SEND);
+    insn->header.compression_control = BRW_COMPRESSION_2NDHALF;
+    insn->header.destreg__conditonalmod = msg_reg_nr+1;
+
+    brw_instruction_set_destination(insn, offset(dest,1));
+    brw_instruction_set_source0(insn, src);
+    brw_set_math_message(insn,
+			 msg_length, response_length,
+			 function,
+			 BRW_MATH_INTEGER_UNSIGNED,
+			 precision,
+			 saturate,
+			 BRW_MATH_DATA_VECTOR);
+
+    brw_pop_insn_state(p);
+}
+
+
+
+
+void brw_dp_WRITE_16( struct brw_compile *p,
+		      struct brw_reg src,
+		      uint32_t msg_reg_nr,
+		      uint32_t scratch_offset )
+{
+    {
+	brw_push_insn_state(p);
+	brw_set_mask_control(p, BRW_MASK_DISABLE);
+	brw_set_compression_control(p, BRW_COMPRESSION_NONE);
+
+	brw_MOV (p,
+		retype (brw_vec1_grf (0, 2), BRW_REGISTER_TYPE_D),
+		brw_imm_d (scratch_offset));
+
+	brw_pop_insn_state(p);
+    }
+
+    {
+	uint32_t msg_length = 3;
+	struct brw_reg dest = retype(brw_null_reg(), BRW_REGISTER_TYPE_UW);
+	struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_SEND);
+
+	insn->header.predicate_control = 0; /* XXX */
+	insn->header.compression_control = BRW_COMPRESSION_NONE;
+	insn->header.destreg__conditonalmod = msg_reg_nr;
+
+	brw_instruction_set_destination(insn, dest);
+	brw_instruction_set_source0(insn, src);
+
+	brw_instruction_set_dp_write_message(insn,
+					     255, /* bti */
+					     BRW_DATAPORT_OWORD_BLOCK_4_OWORDS, /* msg_control */
+					     BRW_DATAPORT_WRITE_MESSAGE_OWORD_BLOCK_WRITE, /* msg_type */
+					     msg_length,
+					     0, /* pixel scoreboard */
+					     0, /* response_length */
+					     0); /* eot */
+    }
+
+}
+
+
+void brw_dp_READ_16( struct brw_compile *p,
+		     struct brw_reg dest,
+		     uint32_t msg_reg_nr,
+		     uint32_t scratch_offset )
+{
+    {
+	brw_push_insn_state(p);
+	brw_set_compression_control(p, BRW_COMPRESSION_NONE);
+	brw_set_mask_control(p, BRW_MASK_DISABLE);
+
+	brw_MOV (p,
+		retype (brw_vec1_grf (0, 2), BRW_REGISTER_TYPE_D),
+		brw_imm_d (scratch_offset));
+
+	brw_pop_insn_state(p);
+    }
+
+    {
+	struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_SEND);
+
+	insn->header.predicate_control = 0; /* XXX */
+	insn->header.compression_control = BRW_COMPRESSION_NONE;
+	insn->header.destreg__conditonalmod = msg_reg_nr;
+
+	brw_instruction_set_destination(insn, dest);	/* UW? */
+	brw_instruction_set_source0(insn, retype(brw_vec8_grf(0), BRW_REGISTER_TYPE_UW));
+
+	brw_set_dp_read_message(insn,
+				255, /* bti */
+				3,  /* msg_control */
+				BRW_DATAPORT_READ_MESSAGE_OWORD_BLOCK_READ, /* msg_type */
+				1, /* target cache */
+				1, /* msg_length */
+				2, /* response_length */
+				0); /* eot */
+    }
+}
+
+
+void brw_fb_WRITE(struct brw_compile *p,
+		  struct brw_reg dest,
+		  uint32_t msg_reg_nr,
+		  struct brw_reg src0,
+		  uint32_t binding_table_index,
+		  uint32_t msg_length,
+		  uint32_t response_length,
+		  int eot)
+{
+    struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_SEND);
+
+    insn->header.predicate_control = 0; /* XXX */
+    insn->header.compression_control = BRW_COMPRESSION_NONE;
+    insn->header.destreg__conditonalmod = msg_reg_nr;
+
+    brw_instruction_set_destination(insn, dest);
+    brw_instruction_set_source0(insn, src0);
+    brw_instruction_set_dp_write_message(insn,
+					 binding_table_index,
+					 BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE, /* msg_control */
+					 BRW_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE, /* msg_type */
+					 msg_length,
+					 1,	/* pixel scoreboard */
+					 response_length,
+					 eot);
+}
+
+
+
+void brw_SAMPLE (struct brw_compile *p,
+		 struct brw_reg dest,
+		 uint32_t msg_reg_nr,
+		 struct brw_reg src0,
+		 uint32_t binding_table_index,
+		 uint32_t sampler,
+		 uint32_t writemask,
+		 uint32_t msg_type,
+		 uint32_t response_length,
+		 uint32_t msg_length,
+		 cairo_bool_t eot)
+{
+    int need_stall = 0;
+
+    if(writemask == 0) {
+	/*       printf("%s: zero writemask??\n", __FUNCTION__); */
+	return;
+    }
+
+    /* Hardware doesn't do destination dependency checking on send
+     * instructions properly.  Add a workaround which generates the
+     * dependency by other means.  In practice it seems like this bug
+     * only crops up for texture samples, and only where registers are
+     * written by the send and then written again later without being
+     * read in between.  Luckily for us, we already track that
+     * information and use it to modify the writemask for the
+     * instruction, so that is a guide for whether a workaround is
+     * needed.
+     */
+    if (writemask != WRITEMASK_XYZW) {
+	uint32_t dst_offset = 0;
+	uint32_t i, newmask = 0, len = 0;
+
+	for (i = 0; i < 4; i++) {
+	    if (writemask & (1<<i))
+		break;
+	    dst_offset += 2;
+	}
+	for (; i < 4; i++) {
+	    if (!(writemask & (1<<i)))
+		break;
+	    newmask |= 1<<i;
+	    len++;
+	}
+
+	if (newmask != writemask) {
+	    need_stall = 1;
+	    /*	 printf("need stall %x %x\n", newmask , writemask); */
+	}
+	else {
+	    struct brw_reg m1 = brw_message_reg(msg_reg_nr);
+
+	    newmask = ~newmask & WRITEMASK_XYZW;
+
+	    brw_push_insn_state(p);
+
+	    brw_set_compression_control(p, BRW_COMPRESSION_NONE);
+	    brw_set_mask_control(p, BRW_MASK_DISABLE);
+
+	    brw_MOV(p, m1, brw_vec8_grf(0));
+	    brw_MOV(p, get_element_ud(m1, 2), brw_imm_ud(newmask << 12));
+
+	    brw_pop_insn_state(p);
+
+	    src0 = retype(brw_null_reg(), BRW_REGISTER_TYPE_UW);
+	    dest = offset(dest, dst_offset);
+	    response_length = len * 2;
+	}
+    }
+
+    {
+	struct brw_instruction *insn = brw_next_instruction(p, BRW_OPCODE_SEND);
+
+	insn->header.predicate_control = 0; /* XXX */
+	insn->header.compression_control = BRW_COMPRESSION_NONE;
+	insn->header.destreg__conditonalmod = msg_reg_nr;
+
+	brw_instruction_set_destination(insn, dest);
+	brw_instruction_set_source0(insn, src0);
+	brw_set_sampler_message (insn, p->is_g4x,
+				 binding_table_index,
+				 sampler,
+				 msg_type,
+				 response_length,
+				 msg_length,
+				 eot);
+    }
+
+    if (need_stall)
+    {
+	struct brw_reg reg = vec8(offset(dest, response_length-1));
+
+	/*  mov (8) r9.0<1>:f    r9.0<8;8,1>:f    { Align1 }
+	*/
+	brw_push_insn_state(p);
+	brw_set_compression_control(p, 0);
+	brw_MOV(p, reg, reg);
+	brw_pop_insn_state(p);
+    }
+}
+
+/* All these variables are pretty confusing - we might be better off
+ * using bitmasks and macros for this, in the old style.  Or perhaps
+ * just having the caller instantiate the fields in dword3 itself.
+ */
+void brw_urb_WRITE(struct brw_compile *p,
+		   struct brw_reg dest,
+		   uint32_t msg_reg_nr,
+		   struct brw_reg src0,
+