[cairo-commit] 11 commits - boilerplate/cairo-boilerplate-drm.c boilerplate/cairo-boilerplate-xcb.c boilerplate/Makefile.win32.features build/configure.ac.features build/configure.ac.warnings build/Makefile.win32.features build/Makefile.win32.features-h configure.ac src/cairo-boxes.c src/cairo-boxes-private.h src/cairo-clip.c src/cairo-composite-rectangles.c src/cairo-drm.h src/cairo-drm-xr.h src/cairo-fixed-private.h src/cairo-freelist.c src/cairo-freelist-private.h src/cairo-gl-glyphs.c src/cairo-gstate.c src/cairo-image-surface.c src/cairoint.h src/cairo-list-private.h src/cairo-pattern.c src/cairo-rtree.c src/cairo-rtree-private.h src/cairo-xcb-surface-render.c src/drm src/Makefile.sources src/Makefile.win32.features util/cairo-script

Chris Wilson ickle at kemper.freedesktop.org
Wed May 12 13:00:28 PDT 2010


 boilerplate/Makefile.win32.features        |   10 
 boilerplate/cairo-boilerplate-drm.c        |   12 
 boilerplate/cairo-boilerplate-xcb.c        |   12 
 build/Makefile.win32.features              |    1 
 build/Makefile.win32.features-h            |    3 
 build/configure.ac.features                |    1 
 build/configure.ac.warnings                |    4 
 configure.ac                               |   13 
 src/Makefile.sources                       |    7 
 src/Makefile.win32.features                |   14 
 src/cairo-boxes-private.h                  |    4 
 src/cairo-boxes.c                          |   31 
 src/cairo-clip.c                           |    4 
 src/cairo-composite-rectangles.c           |    7 
 src/cairo-drm-xr.h                         |   66 
 src/cairo-drm.h                            |    4 
 src/cairo-fixed-private.h                  |   18 
 src/cairo-freelist-private.h               |    1 
 src/cairo-freelist.c                       |    7 
 src/cairo-gl-glyphs.c                      |    3 
 src/cairo-gstate.c                         |   31 
 src/cairo-image-surface.c                  |    2 
 src/cairo-list-private.h                   |   31 
 src/cairo-pattern.c                        |   24 
 src/cairo-rtree-private.h                  |   16 
 src/cairo-rtree.c                          |   46 
 src/cairo-xcb-surface-render.c             |   85 -
 src/cairoint.h                             |    7 
 src/drm/cairo-drm-gallium-surface.c        |  514 +++---
 src/drm/cairo-drm-i915-glyphs.c            |   82 -
 src/drm/cairo-drm-i915-private.h           |  153 +
 src/drm/cairo-drm-i915-shader.c            |  866 ++++++----
 src/drm/cairo-drm-i915-spans.c             |  146 +
 src/drm/cairo-drm-i915-surface.c           | 1701 ++++++++++++++++----
 src/drm/cairo-drm-i965-glyphs.c            |   36 
 src/drm/cairo-drm-i965-private.h           |    2 
 src/drm/cairo-drm-i965-shader.c            |   11 
 src/drm/cairo-drm-i965-spans.c             |   16 
 src/drm/cairo-drm-i965-surface.c           |  146 +
 src/drm/cairo-drm-intel-debug.c            |    1 
 src/drm/cairo-drm-intel-ioctl-private.h    |   25 
 src/drm/cairo-drm-intel-private.h          |   92 -
 src/drm/cairo-drm-intel-surface.c          |   90 -
 src/drm/cairo-drm-intel.c                  |  532 +++---
 src/drm/cairo-drm-private.h                |   10 
 src/drm/cairo-drm-radeon-surface.c         |   60 
 src/drm/cairo-drm-surface.c                |   37 
 src/drm/cairo-drm-xr.c                     | 2377 +++++++++++++++++++++++++++++
 util/cairo-script/cairo-script-operators.c |   74 
 49 files changed, 5823 insertions(+), 1612 deletions(-)

New commits:
commit 0870c6fb5b39dcc04fa376123848adde2d06d2ce
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Apr 15 20:31:24 2010 +0100

    gcc-4.5 warnings and optimisation flags.

diff --git a/build/configure.ac.warnings b/build/configure.ac.warnings
index 5b561e1..2f5745f 100644
--- a/build/configure.ac.warnings
+++ b/build/configure.ac.warnings
@@ -17,7 +17,7 @@ MAYBE_WARN="-Wall -Wextra \
 -Wbad-function-cast -Wvolatile-register-var \
 -Wstrict-aliasing=2 -Winit-self -Wunsafe-loop-optimizations \
 -Wno-missing-field-initializers -Wno-unused-parameter \
--Wno-attributes -Wno-long-long -Winline"
+-Wno-attributes -Wno-long-long -Winline -Wlogical-op"
 
 dnl Sun Studio 12 likes to rag at us for abusing enums like
 dnl having cairo_status_t variables hold cairo_int_status_t
@@ -27,7 +27,7 @@ MAYBE_WARN="$MAYBE_WARN -erroff=E_ENUM_TYPE_MISMATCH_ARG \
 
 dnl We also abuse the warning-flag facility to enable other compiler
 dnl options.  Namely, the following:
-MAYBE_WARN="$MAYBE_WARN -fno-strict-aliasing -fno-common"
+MAYBE_WARN="$MAYBE_WARN -fno-strict-aliasing -fno-common -flto"
 
 dnl Also to turn various gcc/glibc-specific preprocessor checks
 MAYBE_WARN="$MAYBE_WARN -Wp,-D_FORTIFY_SOURCE=2"
commit cf0933a05aedb66b5d8999c84b935349b25dd974
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon Apr 12 10:42:14 2010 +0100

    gallium: Refresh.
    
    Catch up with changes in APIs, still no substance and the integration
    with winsys handles needs review.

diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features
index 50ee95c..2a27d6b 100644
--- a/boilerplate/Makefile.win32.features
+++ b/boilerplate/Makefile.win32.features
@@ -209,14 +209,6 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_png_private)
 enabled_cairo_boilerplate_sources += $(cairo_boilerplate_png_sources)
 endif
 
-supported_cairo_boilerplate_headers += $(cairo_boilerplate_glew_headers)
-all_cairo_boilerplate_headers += $(cairo_boilerplate_glew_headers)
-all_cairo_boilerplate_private += $(cairo_boilerplate_glew_private)
-all_cairo_boilerplate_sources += $(cairo_boilerplate_glew_sources)
-enabled_cairo_boilerplate_headers += $(cairo_boilerplate_glew_headers)
-enabled_cairo_boilerplate_private += $(cairo_boilerplate_glew_private)
-enabled_cairo_boilerplate_sources += $(cairo_boilerplate_glew_sources)
-
 unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_gl_headers)
 all_cairo_boilerplate_headers += $(cairo_boilerplate_gl_headers)
 all_cairo_boilerplate_private += $(cairo_boilerplate_gl_private)
diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h
index f5eae80..1e66889 100644
--- a/build/Makefile.win32.features-h
+++ b/build/Makefile.win32.features-h
@@ -62,7 +62,6 @@ endif
 ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1)
 	@echo "#define CAIRO_HAS_PNG_FUNCTIONS 1" >> src/cairo-features.h
 endif
-	@echo "#define CAIRO_HAS_GLEW_FUNCTIONS 1" >> src/cairo-features.h
 ifeq ($(CAIRO_HAS_GL_SURFACE),1)
 	@echo "#define CAIRO_HAS_GL_SURFACE 1" >> src/cairo-features.h
 endif
diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features
index c9223c2..a4efe77 100644
--- a/src/Makefile.win32.features
+++ b/src/Makefile.win32.features
@@ -287,14 +287,6 @@ ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1)
 enabled_cairo_pkgconf += cairo-png.pc
 endif
 
-supported_cairo_headers += $(cairo_glew_headers)
-all_cairo_headers += $(cairo_glew_headers)
-all_cairo_private += $(cairo_glew_private)
-all_cairo_sources += $(cairo_glew_sources)
-enabled_cairo_headers += $(cairo_glew_headers)
-enabled_cairo_private += $(cairo_glew_private)
-enabled_cairo_sources += $(cairo_glew_sources)
-
 unsupported_cairo_headers += $(cairo_gl_headers)
 all_cairo_headers += $(cairo_gl_headers)
 all_cairo_private += $(cairo_gl_private)
diff --git a/src/drm/cairo-drm-gallium-surface.c b/src/drm/cairo-drm-gallium-surface.c
index 7defe0c..76fbae6 100644
--- a/src/drm/cairo-drm-gallium-surface.c
+++ b/src/drm/cairo-drm-gallium-surface.c
@@ -34,20 +34,23 @@
 #include "cairoint.h"
 
 #include "cairo-drm-private.h"
+#include "cairo-error-private.h"
 
 #include <dlfcn.h>
 
 #include <state_tracker/drm_api.h>
-#include <pipe/p_inlines.h>
+#include <pipe/p_format.h>
 #include <pipe/p_screen.h>
 #include <pipe/p_context.h>
+#include <pipe/p_state.h>
+
+#include <util/u_inlines.h>
 
 typedef struct _gallium_surface gallium_surface_t;
 typedef struct _gallium_device gallium_device_t;
 
 struct _gallium_device {
-    cairo_drm_device_t base;
-    cairo_mutex_t mutex;
+    cairo_drm_device_t drm;
 
     void *dlhandle;
     struct drm_api *api;
@@ -59,34 +62,25 @@ struct _gallium_device {
 };
 
 struct _gallium_surface {
-    cairo_drm_surface_t base;
+    cairo_drm_surface_t drm;
 
-    struct pipe_buffer *buffer;
     enum pipe_format pipe_format;
 
-    struct pipe_texture *texture;
+    struct pipe_resource *texture;
+    struct pipe_transfer *map_transfer;
 
     cairo_surface_t *fallback;
 };
 
 static cairo_surface_t *
 gallium_surface_create_internal (gallium_device_t *device,
-				 cairo_content_t content,
 				 enum pipe_format format,
 				 int width, int height);
 
-static gallium_device_t *
-gallium_device_acquire (cairo_drm_device_t *base_dev)
-{
-    gallium_device_t *device = (gallium_device_t *) base_dev;
-    CAIRO_MUTEX_LOCK (device->mutex);
-    return device;
-}
-
-static void
-gallium_device_release (gallium_device_t *device)
+static inline gallium_device_t *
+gallium_device (gallium_surface_t *surface)
 {
-    CAIRO_MUTEX_UNLOCK (device->mutex);
+    return (gallium_device_t *) surface->drm.base.device;
 }
 
 static cairo_format_t
@@ -103,6 +97,19 @@ _cairo_format_from_pipe_format (enum pipe_format format)
 }
 
 static enum pipe_format
+pipe_format_from_format (cairo_format_t format)
+{
+    switch ((int) format) {
+    case CAIRO_FORMAT_A8:
+	return PIPE_FORMAT_A8_UNORM;
+    case CAIRO_FORMAT_ARGB32:
+	return PIPE_FORMAT_A8R8G8B8_UNORM;
+    default:
+	return (enum pipe_format) -1;
+    }
+}
+
+static enum pipe_format
 pipe_format_from_content (cairo_content_t content)
 {
     if (content == CAIRO_CONTENT_ALPHA)
@@ -115,13 +122,17 @@ static cairo_bool_t
 format_is_supported_destination (gallium_device_t *device,
 	                         enum pipe_format format)
 {
+    if (format == (enum pipe_format) -1)
+	return FALSE;
+
     return device->screen->is_format_supported (device->screen,
 					        format,
 						0,
-						PIPE_TEXTURE_USAGE_RENDER_TARGET,
+						PIPE_BIND_RENDER_TARGET,
 						0);
 }
 
+#if 0
 static cairo_bool_t
 format_is_supported_source (gallium_device_t *device,
 	                    enum pipe_format format)
@@ -129,9 +140,10 @@ format_is_supported_source (gallium_device_t *device,
     return device->screen->is_format_supported (device->screen,
 					        format,
 						0,
-						PIPE_TEXTURE_USAGE_SAMPLER,
+						PIPE_BIND_SAMPLER_VIEW,
 						0);
 }
+#endif
 
 static cairo_surface_t *
 gallium_surface_create_similar (void			*abstract_src,
@@ -140,26 +152,32 @@ gallium_surface_create_similar (void			*abstract_src,
 				int			 height)
 {
     gallium_surface_t *other = abstract_src;
-    gallium_device_t *device;
+    gallium_device_t *device = gallium_device (other);
     enum pipe_format pipe_format;
     cairo_surface_t *surface = NULL;
+    cairo_status_t status;
 
-    device = gallium_device_acquire (other->base.device);
+    status = cairo_device_acquire (&device->drm.base);
+    if (unlikely (status))
+	return _cairo_surface_create_in_error (status);
 
     if (MAX (width, height) > device->max_size)
 	goto RELEASE;
 
-    pipe_format = pipe_format_from_content (content);
+    if (content == other->drm.base.content)
+	pipe_format = other->pipe_format;
+    else
+	pipe_format = pipe_format_from_content (content);
 
     if (! format_is_supported_destination (device, pipe_format))
 	goto RELEASE;
 
     surface = gallium_surface_create_internal (device,
-					       content, pipe_format,
+					       pipe_format,
 					       width, height);
 
 RELEASE:
-    gallium_device_release (device);
+    cairo_device_release (&device->drm.base);
 
     return surface;
 }
@@ -168,24 +186,56 @@ static cairo_status_t
 gallium_surface_finish (void *abstract_surface)
 {
     gallium_surface_t *surface = abstract_surface;
-    gallium_device_t *device;
+    gallium_device_t *device = gallium_device (surface);
+    cairo_status_t status;
 
-    device = gallium_device_acquire (surface->base.device);
-    device->screen->buffer_destroy (surface->buffer);
-    gallium_device_release (device);
+    status = cairo_device_acquire (&device->drm.base);
+    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	pipe_resource_reference (&surface->texture, NULL);
+	cairo_device_release (&device->drm.base);
+    }
 
-    return _cairo_drm_surface_finish (&surface->base);
+    return _cairo_drm_surface_finish (&surface->drm);
 }
 
-static void
-gallium_surface_unmap (void *closure)
+static cairo_surface_t *
+gallium_surface_map_to_image (gallium_surface_t *surface)
 {
-    gallium_surface_t *surface = closure;
-    gallium_device_t *device;
+    gallium_device_t *device = gallium_device (surface);
+    cairo_status_t status;
+    void *ptr = NULL;
+
+    status = cairo_device_acquire (&device->drm.base);
+    if (unlikely (status))
+	return _cairo_surface_create_in_error (status);
+
+    surface->map_transfer =
+	  pipe_get_transfer (device->pipe,
+			     surface->texture, 0, 0, 0,
+			     PIPE_TRANSFER_MAP_DIRECTLY |
+			     PIPE_TRANSFER_READ_WRITE,
+			     0, 0,
+			     surface->drm.width,
+			     surface->drm.height);
+    if (likely (surface->map_transfer != NULL))
+	ptr = device->pipe->transfer_map (device->pipe, surface->map_transfer);
+
+    cairo_device_release (&device->drm.base);
+
+    if (unlikely (ptr == NULL)) {
+	if (surface->map_transfer != NULL) {
+	    device->pipe->transfer_destroy (device->pipe,
+					    surface->map_transfer);
+	    surface->map_transfer = NULL;
+	}
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
+    }
 
-    device = gallium_device_acquire (surface->base.device);
-    pipe_buffer_unmap (device->screen, surface->buffer);
-    gallium_device_release (device);
+    return cairo_image_surface_create_for_data (ptr,
+						surface->drm.format,
+						surface->drm.width,
+						surface->drm.height,
+						surface->map_transfer->stride);
 }
 
 static cairo_status_t
@@ -194,10 +244,11 @@ gallium_surface_acquire_source_image (void *abstract_surface,
 				      void **image_extra)
 {
     gallium_surface_t *surface = abstract_surface;
-    gallium_device_t *device;
+    gallium_device_t *device = gallium_device (surface);
     cairo_format_t format;
-    cairo_image_surface_t *image;
+    cairo_surface_t *image;
     cairo_status_t status;
+    struct pipe_transfer *transfer;
     void *ptr;
 
     if (surface->fallback != NULL) {
@@ -207,14 +258,12 @@ gallium_surface_acquire_source_image (void *abstract_surface,
 	return CAIRO_STATUS_SUCCESS;
     }
 
-    if (unlikely (surface->base.width == 0 || surface->base.height == 0)) {
-	image = (cairo_image_surface_t *)
-	    cairo_image_surface_create (surface->base.format, 0, 0);
-	status = image->base.status;
-	if (unlikely (status))
-	    return status;
+    if (unlikely (surface->drm.width == 0 || surface->drm.height == 0)) {
+	image = cairo_image_surface_create (surface->drm.format, 0, 0);
+	if (unlikely (image->status))
+	    return image->status;
 
-	*image_out = image;
+	*image_out = (cairo_image_surface_t *) image;
 	*image_extra = NULL;
 	return CAIRO_STATUS_SUCCESS;
     }
@@ -223,30 +272,28 @@ gallium_surface_acquire_source_image (void *abstract_surface,
     if (format == CAIRO_FORMAT_INVALID)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
 
-    device = gallium_device_acquire (surface->base.device);
-    ptr = pipe_buffer_map (device->screen, surface->buffer,
-			   PIPE_BUFFER_USAGE_CPU_READ);
-    gallium_device_release (device);
-
-    image = (cairo_image_surface_t *)
-	cairo_image_surface_create_for_data (ptr, format,
-					     surface->base.width,
-					     surface->base.height,
-					     surface->base.stride);
-    if (unlikely (image->base.status))
-	return image->base.status;
-
-    status = _cairo_user_data_array_set_data (&image->base.user_data,
-					      (cairo_user_data_key_t *) &surface->fallback,
-					      surface,
-					      gallium_surface_unmap);
-    if (unlikely (status)) {
-	cairo_surface_destroy (&image->base);
+    status = cairo_device_acquire (&device->drm.base);
+    if (unlikely (status))
 	return status;
-    }
+
+    transfer = pipe_get_transfer (device->pipe,
+				  surface->texture, 0, 0, 0,
+				  PIPE_TRANSFER_READ,
+				  0, 0,
+				  surface->drm.width,
+				  surface->drm.height);
+    ptr = device->pipe->transfer_map (device->pipe, transfer);
+    cairo_device_release (&device->drm.base);
+
+    image = cairo_image_surface_create_for_data (ptr, format,
+						 surface->drm.width,
+						 surface->drm.height,
+						 surface->drm.stride);
+    if (unlikely (image->status))
+	return image->status;
 
     *image_out = (cairo_image_surface_t *) image;
-    *image_extra = NULL;
+    *image_extra = transfer;
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -256,101 +303,161 @@ gallium_surface_release_source_image (void *abstract_surface,
 				      void *image_extra)
 {
     cairo_surface_destroy (&image->base);
+
+    if (image_extra != NULL) {
+	gallium_device_t *device = gallium_device (abstract_surface);
+
+	device->pipe->transfer_unmap (device->pipe, image_extra);
+	device->pipe->transfer_destroy (device->pipe, image_extra);
+    }
 }
 
 static cairo_status_t
-gallium_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)
+gallium_surface_flush (void *abstract_surface)
 {
     gallium_surface_t *surface = abstract_surface;
-    gallium_device_t *device;
-    cairo_surface_t *image;
-    cairo_format_t format;
+    gallium_device_t *device = gallium_device (surface);
     cairo_status_t status;
-    void *ptr;
 
-    assert (surface->fallback == NULL);
+    if (surface->fallback == NULL) {
+	device->pipe->flush (device->pipe,
+			     PIPE_FLUSH_RENDER_CACHE,
+			     NULL);
+	return CAIRO_STATUS_SUCCESS;
+    }
 
-    format = _cairo_format_from_pipe_format (surface->pipe_format);
-    if (format == CAIRO_FORMAT_INVALID)
-	return CAIRO_INT_STATUS_UNSUPPORTED;
+    /* kill any outstanding maps */
+    cairo_surface_finish (surface->fallback);
 
-    device = gallium_device_acquire (surface->base.device);
-    ptr = pipe_buffer_map (device->screen, surface->buffer,
-			   PIPE_BUFFER_USAGE_CPU_READ_WRITE);
-    gallium_device_release (device);
+    status = cairo_device_acquire (&device->drm.base);
+    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+	device->pipe->transfer_unmap (device->pipe,
+				      surface->map_transfer);
+	device->pipe->transfer_destroy (device->pipe,
+					surface->map_transfer);
+	surface->map_transfer = NULL;
+	cairo_device_release (&device->drm.base);
+    }
 
-    image = cairo_image_surface_create_for_data (ptr, format,
-						 surface->base.width,
-						 surface->base.height,
-						 surface->base.stride);
-    if (unlikely (image->status))
-	return image->status;
+    status = cairo_surface_status (surface->fallback);
+    cairo_surface_destroy (surface->fallback);
+    surface->fallback = NULL;
 
-    status = _cairo_user_data_array_set_data (&image->user_data,
-					      (cairo_user_data_key_t *) &surface->fallback,
-					      surface,
-					      gallium_surface_unmap);
-    if (unlikely (status)) {
-	cairo_surface_destroy (image);
-	return status;
+    return status;
+}
+
+static cairo_int_status_t
+gallium_surface_paint (void			*abstract_surface,
+			  cairo_operator_t	 op,
+			  const cairo_pattern_t	*source,
+			  cairo_clip_t		*clip)
+{
+    gallium_surface_t *surface = abstract_surface;
+
+    if (surface->fallback == NULL) {
+	/* XXX insert magic */
+	surface->fallback = gallium_surface_map_to_image (surface);
     }
 
-    surface->fallback = cairo_surface_reference (image);
+    return _cairo_surface_paint (surface->fallback, op, source, clip);
+}
 
-    *image_out = (cairo_image_surface_t *) image;
-    *image_extra = NULL;
+static cairo_int_status_t
+gallium_surface_mask (void			*abstract_surface,
+			 cairo_operator_t	 op,
+			 const cairo_pattern_t	*source,
+			 const cairo_pattern_t	*mask,
+			 cairo_clip_t		*clip)
+{
+    gallium_surface_t *surface = abstract_surface;
 
-    image_rect_out->x = 0;
-    image_rect_out->y = 0;
-    image_rect_out->width  = surface->base.width;
-    image_rect_out->height = surface->base.height;
+    if (surface->fallback == NULL) {
+	/* XXX insert magic */
+	surface->fallback = gallium_surface_map_to_image (surface);
+    }
 
-    return CAIRO_STATUS_SUCCESS;
+    return _cairo_surface_mask (surface->fallback,
+				op, source, mask,
+				clip);
 }
 
-static void
-gallium_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)
+static cairo_int_status_t
+gallium_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)
 {
-    /* Keep the fallback until we flush, either explicitly or at the
-     * end of this device. The idea is to avoid excess migration of
-     * the buffer between GPU and CPU domains.
-     */
-    cairo_surface_destroy (&image->base);
+    gallium_surface_t *surface = abstract_surface;
+
+    if (surface->fallback == NULL) {
+	/* XXX insert magic */
+	surface->fallback = gallium_surface_map_to_image (surface);
+    }
+
+    return _cairo_surface_stroke (surface->fallback,
+				  op, source,
+				  path, style,
+				  ctm, ctm_inverse,
+				  tolerance, antialias,
+				  clip);
 }
 
-static cairo_status_t
-gallium_surface_flush (void *abstract_surface)
+static cairo_int_status_t
+gallium_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)
 {
     gallium_surface_t *surface = abstract_surface;
-    gallium_device_t *device;
-    cairo_status_t status;
 
-    if (surface->fallback == NULL)
-	return CAIRO_STATUS_SUCCESS;
+    if (surface->fallback == NULL) {
+	/* XXX insert magic */
+	surface->fallback = gallium_surface_map_to_image (surface);
+    }
 
-    /* kill any outstanding maps */
-    cairo_surface_finish (surface->fallback);
+    return _cairo_surface_fill (surface->fallback,
+				op, source,
+				path, fill_rule,
+				tolerance, antialias,
+				clip);
+}
 
-    device = gallium_device_acquire (surface->base.device);
-    pipe_buffer_flush_mapped_range (device->screen,
-				    surface->buffer,
-				    0,
-				    surface->base.stride * surface->base.height);
-    gallium_device_release (device);
+static cairo_int_status_t
+gallium_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)
+{
+    gallium_surface_t *surface = abstract_surface;
 
-    status = cairo_surface_status (surface->fallback);
-    cairo_surface_destroy (surface->fallback);
-    surface->fallback = NULL;
+    *num_remaining = 0;
 
-    return status;
+    if (surface->fallback == NULL) {
+	/* XXX insert magic */
+	surface->fallback = gallium_surface_map_to_image (surface);
+    }
+
+    return _cairo_surface_show_text_glyphs (surface->fallback,
+					    op, source,
+					    NULL, 0,
+					    glyphs, num_glyphs,
+					    NULL, 0, 0,
+					    scaled_font,
+					    clip);
 }
 
 static const cairo_surface_backend_t gallium_surface_backend = {
@@ -360,9 +467,9 @@ static const cairo_surface_backend_t gallium_surface_backend = {
 
     gallium_surface_acquire_source_image,
     gallium_surface_release_source_image,
-    gallium_surface_acquire_dest_image,
-    gallium_surface_release_dest_image,
 
+    NULL, //gallium_surface_acquire_dest_image,
+    NULL, //gallium_surface_release_dest_image,
     NULL, //gallium_surface_clone_similar,
     NULL, //gallium_surface_composite,
     NULL, //gallium_surface_fill_rectangles,
@@ -379,11 +486,11 @@ static const cairo_surface_backend_t gallium_surface_backend = {
     NULL, //gallium_surface_scaled_font_fini,
     NULL, //gallium_surface_scaled_glyph_fini,
 
-    _cairo_drm_surface_paint,
-    _cairo_drm_surface_mask,
-    _cairo_drm_surface_stroke,
-    _cairo_drm_surface_fill,
-    _cairo_drm_surface_show_glyphs,
+    gallium_surface_paint,
+    gallium_surface_mask,
+    gallium_surface_stroke,
+    gallium_surface_fill,
+    gallium_surface_glyphs,
 
     NULL, /* snapshot */
 
@@ -412,6 +519,8 @@ _gallium_fake_bo_create (uint32_t size, uint32_t name)
 {
     cairo_drm_bo_t *bo;
 
+    /* XXX integrate with winsys handle */
+
     bo = malloc (sizeof (cairo_drm_bo_t));
 
     CAIRO_REFERENCE_COUNT_INIT (&bo->ref_count, 1);
@@ -430,38 +539,45 @@ _gallium_fake_bo_release (void *dev, void *bo)
 
 static cairo_surface_t *
 gallium_surface_create_internal (gallium_device_t *device,
-				 cairo_content_t content,
 				 enum pipe_format pipe_format,
 				 int width, int height)
 {
     gallium_surface_t *surface;
+    struct pipe_resource template;
     cairo_status_t status;
+    cairo_format_t format;
     int stride, size;
 
     surface = malloc (sizeof (gallium_surface_t));
     if (unlikely (surface == NULL))
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    _cairo_surface_init (&surface->base.base,
+    format = _cairo_format_from_pipe_format (pipe_format);
+    _cairo_surface_init (&surface->drm.base,
 			 &gallium_surface_backend,
-			 content);
-    _cairo_drm_surface_init (&surface->base, &device->base);
+			 &device->drm.base,
+			 _cairo_content_from_format (format));
+    _cairo_drm_surface_init (&surface->drm, format, width, height);
 
     stride = gallium_format_stride_for_width (pipe_format, width);
     size = stride * height;
 
-    surface->base.width = width;
-    surface->base.height = height;
-    surface->base.stride = stride;
-    surface->base.bo = _gallium_fake_bo_create (size, 0);
-
-    surface->buffer = pipe_buffer_create (device->screen,
-					  0,
-					  PIPE_BUFFER_USAGE_GPU_READ_WRITE |
-					  PIPE_BUFFER_USAGE_CPU_READ_WRITE,
-					  size);
-    if (unlikely (surface->buffer == NULL)) {
-	status = _cairo_drm_surface_finish (&surface->base);
+    surface->drm.stride = stride;
+    surface->drm.bo = _gallium_fake_bo_create (size, 0);
+
+    memset(&template, 0, sizeof(template));
+    template.target = PIPE_TEXTURE_2D;
+    template.format = pipe_format;
+    template.width0 = width;
+    template.height0 = height;
+    template.depth0 = 1;
+    template.last_level = 0;
+    template.bind = PIPE_BIND_RENDER_TARGET;
+    surface->texture = device->screen->resource_create (device->screen,
+							&template);
+
+    if (unlikely (surface->texture == NULL)) {
+	status = _cairo_drm_surface_finish (&surface->drm);
 	free (surface);
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
     }
@@ -469,42 +585,43 @@ gallium_surface_create_internal (gallium_device_t *device,
     surface->pipe_format = pipe_format;
     surface->texture = NULL;
 
-    return &surface->base.base;
+    return &surface->drm.base;
 }
 
 static cairo_surface_t *
 gallium_surface_create (cairo_drm_device_t *base_dev,
-			cairo_content_t content,
+			cairo_format_t format,
 			int width, int height)
 {
-    gallium_device_t *device;
+    gallium_device_t *device = (gallium_device_t *) base_dev;
     cairo_surface_t *surface;
     enum pipe_format pipe_format;
+    cairo_status_t status;
 
-    device = gallium_device_acquire (base_dev);
+    status = cairo_device_acquire (&device->drm.base);
 
     if (MAX (width, height) > device->max_size) {
 	surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
 	goto RELEASE;
     }
 
-    pipe_format = pipe_format_from_content (content);
-
+    pipe_format = pipe_format_from_format (format);
     if (! format_is_supported_destination (device, pipe_format)) {
 	surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
 	goto RELEASE;
     }
 
     surface = gallium_surface_create_internal (device,
-					       content, pipe_format,
+					       pipe_format,
 					       width, height);
 
 RELEASE:
-    gallium_device_release (device);
+    cairo_device_release (&device->drm.base);
 
     return surface;
 }
 
+#if 0
 static cairo_surface_t *
 gallium_surface_create_for_name (cairo_drm_device_t *base_dev,
 				 unsigned int name,
@@ -534,50 +651,53 @@ gallium_surface_create_for_name (cairo_drm_device_t *base_dev,
 	break;
     }
 
-    device = gallium_device_acquire (base_dev);
+    status = cairo_device_acquire (&device->drm.base);
 
     if (MAX (width, height) > device->max_size) {
-	gallium_device_release (device);
+	cairo_device_release (&device->drm.base);
 	free (surface);
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
     }
 
     if (! format_is_supported_destination (device, surface->pipe_format)) {
-	gallium_device_release (device);
+	cairo_device_release (&device->drm.base);
 	free (surface);
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
     }
 
     content = _cairo_content_from_format (format);
-    _cairo_surface_init (&surface->base.base,
+    _cairo_surface_init (&surface->drm.base,
 			 &gallium_surface_backend,
 			 content);
-    _cairo_drm_surface_init (&surface->base, base_dev);
+    _cairo_drm_surface_init (&surface->drm, base_dev);
 
-    surface->base.bo = _gallium_fake_bo_create (height * stride, name);
+    surface->drm.bo = _gallium_fake_bo_create (height * stride, name);
 
-    surface->base.width  = width;
-    surface->base.height = height;
-    surface->base.stride = stride;
+    surface->drm.width  = width;
+    surface->drm.height = height;
+    surface->drm.stride = stride;
 
+#if 0
+    /* XXX screen->create_from_handle */
     surface->buffer = device->api->buffer_from_handle (device->api,
 						       device->screen,
 						       "cairo-gallium alien",
 						       name);
     if (unlikely (surface->buffer == NULL)) {
-	status = _cairo_drm_surface_finish (&surface->base);
-	gallium_device_release (device);
+	status = _cairo_drm_surface_finish (&surface->drm);
+	cairo_device_release (&device->drm.base);
 	free (surface);
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
     }
+#endif
 
     surface->texture = NULL;
 
     surface->fallback = NULL;
 
-    gallium_device_release (device);
+    cairo_device_release (&device->drm.base);
 
-    return &surface->base.base;
+    return &surface->drm.base;
 }
 
 static cairo_int_status_t
@@ -587,18 +707,19 @@ gallium_surface_flink (void *abstract_surface)
     gallium_device_t *device;
     cairo_status_t status = CAIRO_STATUS_SUCCESS;
 
-    device = gallium_device_acquire (surface->base.device);
+    status = cairo_device_acquire (&device->drm.base);
     if (! device->api->global_handle_from_buffer (device->api,
 						  device->screen,
 						  surface->buffer,
-						  &surface->base.bo->name))
+						  &surface->drm.bo->name))
     {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
     }
-    gallium_device_release (device);
+    cairo_device_release (&device->drm.base);
 
     return status;
 }
+#endif
 
 static void
 gallium_device_destroy (void *abstract_device)
@@ -609,8 +730,6 @@ gallium_device_destroy (void *abstract_device)
     device->screen->destroy (device->screen);
     device->api->destroy (device->api);
 
-    CAIRO_MUTEX_FINI (device->mutex);
-
     dlclose (device->dlhandle);
     free (device);
 }
@@ -649,20 +768,18 @@ _cairo_drm_gallium_device_create (int fd, dev_t dev, int vendor_id, int chip_id)
 
     device->dlhandle = handle;
 
-    CAIRO_MUTEX_INIT (device->mutex);
-
-    device->base.status = CAIRO_STATUS_SUCCESS;
-
-    device->base.surface.create = gallium_surface_create;
-    device->base.surface.create_for_name = gallium_surface_create_for_name;
-    device->base.surface.enable_scan_out = NULL;
-    device->base.surface.flink = gallium_surface_flink;
+    device->drm.surface.create = gallium_surface_create;
+    device->drm.surface.create_for_name = NULL;
+    //device->drm.surface.create_for_name = gallium_surface_create_for_name;
+    device->drm.surface.enable_scan_out = NULL;
+    //device->drm.surface.flink = gallium_surface_flink;
+    device->drm.surface.flink = NULL;
 
-    device->base.device.flush = NULL;
-    device->base.device.throttle = NULL;
-    device->base.device.destroy = gallium_device_destroy;
+    device->drm.device.flush = NULL;
+    device->drm.device.throttle = NULL;
+    device->drm.device.destroy = gallium_device_destroy;
 
-    device->base.bo.release = _gallium_fake_bo_release;
+    device->drm.bo.release = _gallium_fake_bo_release;
 
     device->api = ctor ();
     if (device->api == NULL) {
@@ -679,13 +796,16 @@ _cairo_drm_gallium_device_create (int fd, dev_t dev, int vendor_id, int chip_id)
     device->max_size = 1 << device->screen->get_param (device->screen,
 						       PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
 
-    device->pipe = device->api->create_context (device->api, device->screen);
+    device->pipe = device->screen->context_create (device->screen, device);
     if (device->pipe == NULL) {
 	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	goto CLEANUP_SCREEN;
     }
 
-    return _cairo_drm_device_init (&device->base, fd, dev, device->max_size);
+    return _cairo_drm_device_init (&device->drm,
+				   fd, dev,
+				   0, 0,
+				   device->max_size);
 
 CLEANUP_SCREEN:
     device->screen->destroy (device->screen);
commit bd672d080ca0036ef1b88d26583e6af36f541461
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Mar 26 19:37:08 2010 +0000

    drm: code dump, sorry.
    
    Lots upon lots of tiny fixes mixed in with experimental code. :(

diff --git a/boilerplate/Makefile.win32.features b/boilerplate/Makefile.win32.features
index 31bd4e0..50ee95c 100644
--- a/boilerplate/Makefile.win32.features
+++ b/boilerplate/Makefile.win32.features
@@ -169,6 +169,16 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_drm_private)
 enabled_cairo_boilerplate_sources += $(cairo_boilerplate_drm_sources)
 endif
 
+unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_drm_xr_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_drm_xr_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_drm_xr_private)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_drm_xr_sources)
+ifeq ($(CAIRO_HAS_DRM_XR_FUNCTIONS),1)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_drm_xr_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_drm_xr_private)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_drm_xr_sources)
+endif
+
 unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_gallium_headers)
 all_cairo_boilerplate_headers += $(cairo_boilerplate_gallium_headers)
 all_cairo_boilerplate_private += $(cairo_boilerplate_gallium_private)
@@ -199,6 +209,14 @@ enabled_cairo_boilerplate_private += $(cairo_boilerplate_png_private)
 enabled_cairo_boilerplate_sources += $(cairo_boilerplate_png_sources)
 endif
 
+supported_cairo_boilerplate_headers += $(cairo_boilerplate_glew_headers)
+all_cairo_boilerplate_headers += $(cairo_boilerplate_glew_headers)
+all_cairo_boilerplate_private += $(cairo_boilerplate_glew_private)
+all_cairo_boilerplate_sources += $(cairo_boilerplate_glew_sources)
+enabled_cairo_boilerplate_headers += $(cairo_boilerplate_glew_headers)
+enabled_cairo_boilerplate_private += $(cairo_boilerplate_glew_private)
+enabled_cairo_boilerplate_sources += $(cairo_boilerplate_glew_sources)
+
 unsupported_cairo_boilerplate_headers += $(cairo_boilerplate_gl_headers)
 all_cairo_boilerplate_headers += $(cairo_boilerplate_gl_headers)
 all_cairo_boilerplate_private += $(cairo_boilerplate_gl_private)
diff --git a/boilerplate/cairo-boilerplate-drm.c b/boilerplate/cairo-boilerplate-drm.c
index f79bcca..93709af 100644
--- a/boilerplate/cairo-boilerplate-drm.c
+++ b/boilerplate/cairo-boilerplate-drm.c
@@ -46,12 +46,20 @@ _cairo_boilerplate_drm_create_surface (const char		 *name,
 				       void			**closure)
 {
     cairo_device_t *device;
+    cairo_format_t format;
 
     device = cairo_drm_device_default ();
     if (device == NULL)
 	return NULL; /* skip tests if no supported h/w found */
 
-    return *closure = cairo_drm_surface_create (device, content, width, height);
+    switch (content) {
+    case CAIRO_CONTENT_ALPHA: format = CAIRO_FORMAT_A8; break;
+    case CAIRO_CONTENT_COLOR: format = CAIRO_FORMAT_RGB24; break;
+    default:
+    case CAIRO_CONTENT_COLOR_ALPHA: format = CAIRO_FORMAT_ARGB32; break;
+    }
+
+    return *closure = cairo_drm_surface_create (device, format, width, height);
 }
 
 static void
@@ -59,7 +67,7 @@ _cairo_boilerplate_drm_synchronize (void *closure)
 {
     cairo_surface_t *image;
 
-    image = cairo_drm_surface_map (closure);
+    image = cairo_drm_surface_map_to_image (closure);
     if (cairo_surface_status (image) == CAIRO_STATUS_SUCCESS)
 	cairo_drm_surface_unmap (closure, image);
 }
diff --git a/build/Makefile.win32.features b/build/Makefile.win32.features
index 2f40eb2..5c283ac 100644
--- a/build/Makefile.win32.features
+++ b/build/Makefile.win32.features
@@ -15,6 +15,7 @@ CAIRO_HAS_SKIA_SURFACE=0
 CAIRO_HAS_OS2_SURFACE=0
 CAIRO_HAS_BEOS_SURFACE=0
 CAIRO_HAS_DRM_SURFACE=0
+CAIRO_HAS_DRM_XR_FUNCTIONS=0
 CAIRO_HAS_GALLIUM_SURFACE=0
 CAIRO_HAS_XCB_DRM_FUNCTIONS=0
 CAIRO_HAS_PNG_FUNCTIONS=1
diff --git a/build/Makefile.win32.features-h b/build/Makefile.win32.features-h
index f7c07ac..f5eae80 100644
--- a/build/Makefile.win32.features-h
+++ b/build/Makefile.win32.features-h
@@ -50,6 +50,9 @@ endif
 ifeq ($(CAIRO_HAS_DRM_SURFACE),1)
 	@echo "#define CAIRO_HAS_DRM_SURFACE 1" >> src/cairo-features.h
 endif
+ifeq ($(CAIRO_HAS_DRM_XR_FUNCTIONS),1)
+	@echo "#define CAIRO_HAS_DRM_XR_FUNCTIONS 1" >> src/cairo-features.h
+endif
 ifeq ($(CAIRO_HAS_GALLIUM_SURFACE),1)
 	@echo "#define CAIRO_HAS_GALLIUM_SURFACE 1" >> src/cairo-features.h
 endif
@@ -59,6 +62,7 @@ endif
 ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1)
 	@echo "#define CAIRO_HAS_PNG_FUNCTIONS 1" >> src/cairo-features.h
 endif
+	@echo "#define CAIRO_HAS_GLEW_FUNCTIONS 1" >> src/cairo-features.h
 ifeq ($(CAIRO_HAS_GL_SURFACE),1)
 	@echo "#define CAIRO_HAS_GL_SURFACE 1" >> src/cairo-features.h
 endif
diff --git a/build/configure.ac.features b/build/configure.ac.features
index 593f4a6..1e40de8 100644
--- a/build/configure.ac.features
+++ b/build/configure.ac.features
@@ -394,6 +394,7 @@ AC_DEFUN([CAIRO_REPORT],
 	echo "  X11-xcb functions: $use_xlib_xcb"
 	echo "  XCB-drm functions: $use_xcb_drm"
 	echo "  XCB-shm functions: $use_xcb_shm"
+	echo "  DRM-Xr functions: $use_drm_xr"
 	echo ""
 	echo "The following features and utilities:"
 	echo "  cairo-trace:                $use_trace"
diff --git a/configure.ac b/configure.ac
index 5c3e0ba..493fdc1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -258,6 +258,19 @@ CAIRO_ENABLE_SURFACE_BACKEND(drm, DRM, no, [
   use_drm="no (requires $drm_REQUIRES, udev is available from git://git.kernel.org/pub/scm/linux/hotplug/udev.git)"])
 ])
 
+CAIRO_ENABLE_FUNCTIONS(drm_xr, DRM Xr (DDX), no, [
+  if test "x$use_drm" == "xyes"; then
+      drm_xr_REQUIRES="xorg-server >= 1.6 xproto xextproto >= 7.0.99.1 renderproto x11"
+      PKG_CHECK_MODULES(drm_xr, $drm_xr_REQUIRES, ,
+			[AC_MSG_RESULT(no)
+			use_drm_xr="no (requires $drm_xr)"])
+      drm_xr_CFLAGS=`echo "$drm_xr_CFLAGS" | $SED -e 's/-fvisibility=hidden//g'`
+  else
+    use_drm_xr="no (requires --enable-drm)"
+  fi
+])
+AM_CONDITIONAL(BUILD_DRM_XR, test "x$use_drm_xr" = "xyes")
+
 CAIRO_ENABLE_SURFACE_BACKEND(gallium, Gallium3D, no, [
   if test "x$use_drm" = "xyes"; then
       AC_ARG_WITH([gallium],
diff --git a/src/Makefile.sources b/src/Makefile.sources
index a40404b..c45e339 100644
--- a/src/Makefile.sources
+++ b/src/Makefile.sources
@@ -356,6 +356,13 @@ cairo_drm_sources = drm/cairo-drm.c \
 		    drm/cairo-drm-radeon-surface.c
 cairo_gallium_sources = drm/cairo-drm-gallium-surface.c
 
+if BUILD_DRM_XR
+cairo_drm_headers += cairo-drm-xr.h
+cairo_drm_sources += \
+		     drm/cairo-drm-xr.c \
+		     $(NULL)
+endif
+
 cairo_script_headers = cairo-script.h
 cairo_script_sources = cairo-script-surface.c
 
diff --git a/src/Makefile.win32.features b/src/Makefile.win32.features
index 42fb696..c9223c2 100644
--- a/src/Makefile.win32.features
+++ b/src/Makefile.win32.features
@@ -231,6 +231,20 @@ ifeq ($(CAIRO_HAS_DRM_SURFACE),1)
 enabled_cairo_pkgconf += cairo-drm.pc
 endif
 
+unsupported_cairo_headers += $(cairo_drm_xr_headers)
+all_cairo_headers += $(cairo_drm_xr_headers)
+all_cairo_private += $(cairo_drm_xr_private)
+all_cairo_sources += $(cairo_drm_xr_sources)
+ifeq ($(CAIRO_HAS_DRM_XR_FUNCTIONS),1)
+enabled_cairo_headers += $(cairo_drm_xr_headers)
+enabled_cairo_private += $(cairo_drm_xr_private)
+enabled_cairo_sources += $(cairo_drm_xr_sources)
+endif
+all_cairo_pkgconf += cairo-drm-xr.pc
+ifeq ($(CAIRO_HAS_DRM_XR_FUNCTIONS),1)
+enabled_cairo_pkgconf += cairo-drm-xr.pc
+endif
+
 unsupported_cairo_headers += $(cairo_gallium_headers)
 all_cairo_headers += $(cairo_gallium_headers)
 all_cairo_private += $(cairo_gallium_private)
@@ -273,6 +287,14 @@ ifeq ($(CAIRO_HAS_PNG_FUNCTIONS),1)
 enabled_cairo_pkgconf += cairo-png.pc
 endif
 
+supported_cairo_headers += $(cairo_glew_headers)
+all_cairo_headers += $(cairo_glew_headers)
+all_cairo_private += $(cairo_glew_private)
+all_cairo_sources += $(cairo_glew_sources)
+enabled_cairo_headers += $(cairo_glew_headers)
+enabled_cairo_private += $(cairo_glew_private)
+enabled_cairo_sources += $(cairo_glew_sources)
+
 unsupported_cairo_headers += $(cairo_gl_headers)
 all_cairo_headers += $(cairo_gl_headers)
 all_cairo_private += $(cairo_gl_private)
diff --git a/src/cairo-boxes-private.h b/src/cairo-boxes-private.h
index 783fcc6..3af0fbd 100644
--- a/src/cairo-boxes-private.h
+++ b/src/cairo-boxes-private.h
@@ -72,6 +72,10 @@ _cairo_boxes_add (cairo_boxes_t *boxes,
 		  const cairo_box_t *box);
 
 cairo_private void
+_cairo_boxes_extents (const cairo_boxes_t *boxes,
+		      cairo_rectangle_int_t *extents);
+
+cairo_private void
 _cairo_boxes_clear (cairo_boxes_t *boxes);
 
 cairo_private void
diff --git a/src/cairo-boxes.c b/src/cairo-boxes.c
index ca26536..31bfc0e 100644
--- a/src/cairo-boxes.c
+++ b/src/cairo-boxes.c
@@ -240,6 +240,37 @@ _cairo_boxes_add (cairo_boxes_t *boxes,
 }
 
 void
+_cairo_boxes_extents (const cairo_boxes_t *boxes,
+		      cairo_rectangle_int_t *extents)
+{
+    const struct _cairo_boxes_chunk *chunk;
+    cairo_box_t box;
+    int i;
+
+    box.p1.y = box.p1.x = INT_MAX;
+    box.p2.y = box.p2.x = INT_MIN;
+
+    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	const cairo_box_t *b = chunk->base;
+	for (i = 0; i < chunk->count; i++) {
+	    if (b[i].p1.x < box.p1.x)
+		box.p1.x = b[i].p1.x;
+
+	    if (b[i].p1.y < box.p1.y)
+		box.p1.y = b[i].p1.y;
+
+	    if (b[i].p2.x > box.p2.x)
+		box.p2.x = b[i].p2.x;
+
+	    if (b[i].p2.y > box.p2.y)
+		box.p2.y = b[i].p2.y;
+	}
+    }
+
+    _cairo_box_round_to_rectangle (&box, extents);
+}
+
+void
 _cairo_boxes_clear (cairo_boxes_t *boxes)
 {
     struct _cairo_boxes_chunk *chunk, *next;
diff --git a/src/cairo-composite-rectangles.c b/src/cairo-composite-rectangles.c
index 0aebee3..ccd8884 100644
--- a/src/cairo-composite-rectangles.c
+++ b/src/cairo-composite-rectangles.c
@@ -66,9 +66,10 @@ _cairo_composite_rectangles_init (cairo_composite_rectangles_t *extents,
     extents->is_bounded = _cairo_operator_bounded_by_either (op);
 
     _cairo_pattern_get_extents (source, &extents->source);
-    if (extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE) {
-	if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source))
-	    return FALSE;
+    if (! _cairo_rectangle_intersect (&extents->bounded, &extents->source) &&
+	extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_SOURCE)
+    {
+	return FALSE;
     }
 
     return TRUE;
diff --git a/src/cairo-drm-xr.h b/src/cairo-drm-xr.h
new file mode 100644
index 0000000..d135924
--- /dev/null
+++ b/src/cairo-drm-xr.h
@@ -0,0 +1,66 @@
+/* Cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2010 Intel Coropration
+ *
+ * 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 Chris Wilson.
+ */
+
+#ifndef CAIRO_DRM_XR_H
+#define CAIRO_DRM_XR_H
+
+#include "cairo.h"
+
+#if CAIRO_HAS_DRM_XR_FUNCTIONS
+
+CAIRO_BEGIN_DECLS
+
+typedef struct _xr_screen xr_screen_t;
+
+cairo_public xr_screen_t *
+cairo_drm_xr_enable (ScreenPtr screen, int fd);
+
+cairo_public void
+cairo_drm_xr_pixmap_link_bo (xr_screen_t *xr,
+			     PixmapPtr pixmap,
+			     uint32_t name,
+			     cairo_format_t format,
+			     int width,
+			     int height,
+			     int stride);
+
+cairo_public void
+cairo_drm_xr_pixmap_unlink_bo (xr_screen_t *xr,
+			       PixmapPtr pixmap);
+
+CAIRO_END_DECLS
+
+#else  /* CAIRO_HAS_DRM_XR_FUNCTIOSN */
+# error Cairo was not compiled with support for the DRM Xr DDX functions
+#endif /* CAIRO_HAS_DRM_XR_FUNCTIOSN */
+
+#endif /* CAIRO_DRM_XR_H */
diff --git a/src/cairo-drm.h b/src/cairo-drm.h
index 80068e7..907610d 100644
--- a/src/cairo-drm.h
+++ b/src/cairo-drm.h
@@ -58,7 +58,7 @@ cairo_drm_device_throttle (cairo_device_t *device);
 
 cairo_public cairo_surface_t *
 cairo_drm_surface_create (cairo_device_t *device,
-			  cairo_content_t content,
+			  cairo_format_t format,
 			  int width, int height);
 
 cairo_public cairo_surface_t *
@@ -105,7 +105,7 @@ cairo_drm_surface_get_stride (cairo_surface_t *surface);
  *  will also disassociate the mapping.)
 */
 cairo_public cairo_surface_t *
-cairo_drm_surface_map (cairo_surface_t *surface);
+cairo_drm_surface_map_to_image (cairo_surface_t *surface);
 
 cairo_public void
 cairo_drm_surface_unmap (cairo_surface_t *drm_surface,
diff --git a/src/cairo-fixed-private.h b/src/cairo-fixed-private.h
index 9deec80..66898a2 100644
--- a/src/cairo-fixed-private.h
+++ b/src/cairo-fixed-private.h
@@ -135,6 +135,16 @@ _cairo_fixed_from_26_6 (uint32_t i)
 #endif
 }
 
+static inline cairo_fixed_t
+_cairo_fixed_from_16_16 (uint32_t i)
+{
+#if CAIRO_FIXED_FRAC_BITS > 16
+    return i << (CAIRO_FIXED_FRAC_BITS - 16);
+#else
+    return i >> (16 - CAIRO_FIXED_FRAC_BITS);
+#endif
+}
+
 static inline double
 _cairo_fixed_to_double (cairo_fixed_t f)
 {
@@ -242,7 +252,7 @@ _cairo_fixed_16_16_from_double (double d)
 }
 
 static inline int
-_cairo_fixed_16_16_floor (cairo_fixed_t f)
+_cairo_fixed_16_16_floor (cairo_fixed_16_16_t f)
 {
     if (f >= 0)
 	return f >> 16;
@@ -250,6 +260,12 @@ _cairo_fixed_16_16_floor (cairo_fixed_t f)
 	return -((-f - 1) >> 16) - 1;
 }
 
+static inline double
+_cairo_fixed_16_16_to_double (cairo_fixed_16_16_t f)
+{
+    return ((double) f) / (double) (1 << 16);
+}
+
 #if CAIRO_FIXED_BITS == 32
 
 static inline cairo_fixed_t
diff --git a/src/cairo-freelist-private.h b/src/cairo-freelist-private.h
index 43dde29..47ed232 100644
--- a/src/cairo-freelist-private.h
+++ b/src/cairo-freelist-private.h
@@ -111,7 +111,6 @@ _cairo_freepool_reset (cairo_freepool_t *freepool)
     freepool->embedded_pool.data = freepool->embedded_data;
 }
 
-
 cairo_private void *
 _cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool);
 
diff --git a/src/cairo-freelist.c b/src/cairo-freelist.c
index eb42043..d596eab 100644
--- a/src/cairo-freelist.c
+++ b/src/cairo-freelist.c
@@ -84,7 +84,6 @@ _cairo_freelist_free (cairo_freelist_t *freelist, void *voidnode)
     }
 }
 
-
 void
 _cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize)
 {
@@ -98,8 +97,7 @@ _cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize)
     freepool->embedded_pool.rem = sizeof (freepool->embedded_data);
     freepool->embedded_pool.data = freepool->embedded_data;
 
-    VG (VALGRIND_MAKE_MEM_NOACCESS (freepool->embedded_data,
-				    sizeof (freepool->embedded_data)));
+    VG (VALGRIND_MAKE_MEM_NOACCESS (freepool->embedded_data, sizeof (freepool->embedded_data)));
 }
 
 void
@@ -154,8 +152,7 @@ _cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool)
     pool->rem = poolsize - freepool->nodesize;
     pool->data = (uint8_t *) (pool + 1) + freepool->nodesize;
 
-    VG (VALGRIND_MAKE_MEM_NOACCESS (pool->data, poolsize));
-    VG (VALGRIND_MAKE_MEM_UNDEFINED (pool->data, freepool->nodesize));
+    VG (VALGRIND_MAKE_MEM_NOACCESS (pool->data, pool->rem));
 
     return pool + 1;
 }
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 92b30ef..b98d108 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -264,7 +264,7 @@ _pixman_format_to_masks (pixman_format_code_t	 format,
     }
 }
 
-static pixman_format_code_t
+pixman_format_code_t
 _cairo_format_to_pixman_format_code (cairo_format_t format)
 {
     pixman_format_code_t ret;
diff --git a/src/cairo-list-private.h b/src/cairo-list-private.h
index 3d4bbed..ddfd0a4 100644
--- a/src/cairo-list-private.h
+++ b/src/cairo-list-private.h
@@ -73,19 +73,38 @@ typedef struct _cairo_list {
 	     &pos->member != (head);					\
 	     pos = cairo_list_entry(pos->member.prev, type, member))
 
+#define cairo_list_foreach_entry_reverse_safe(pos, n, type, head, member)	\
+	for (pos = cairo_list_entry((head)->prev, type, member),\
+	     n = cairo_list_entry (pos->member.prev, type, member);\
+	     &pos->member != (head);					\
+	     pos = n, n = cairo_list_entry (n->member.prev, type, member))
+
 #ifdef CAIRO_LIST_DEBUG
 static inline void
+_cairo_list_validate (const cairo_list_t *link)
+{
+    assert (link->next->prev == link);
+    assert (link->prev->next == link);
+}
+static inline void
 cairo_list_validate (const cairo_list_t *head)
 {
     cairo_list_t *link;
 
-    cairo_list_foreach (link, head) {
-	assert (link->next->prev == link);
-	assert (link->prev->next == link);
-    }
+    cairo_list_foreach (link, head)
+	_cairo_list_validate (link);
+}
+static inline cairo_bool_t
+cairo_list_is_empty (const cairo_list_t *head);
+static inline void
+cairo_list_validate_is_empty (const cairo_list_t *head)
+{
+    assert (head->next == NULL || (cairo_list_is_empty (head) && head->next == head->prev));
 }
 #else
+#define _cairo_list_validate(link)
 #define cairo_list_validate(head)
+#define cairo_list_validate_is_empty(head)
 #endif
 
 static inline void
@@ -110,6 +129,7 @@ static inline void
 cairo_list_add (cairo_list_t *entry, cairo_list_t *head)
 {
     cairo_list_validate (head);
+    cairo_list_validate_is_empty (entry);
     __cairo_list_add (entry, head, head->next);
     cairo_list_validate (head);
 }
@@ -118,6 +138,7 @@ static inline void
 cairo_list_add_tail (cairo_list_t *entry, cairo_list_t *head)
 {
     cairo_list_validate (head);
+    cairo_list_validate_is_empty (entry);
     __cairo_list_add (entry, head->prev, head);
     cairo_list_validate (head);
 }
@@ -157,10 +178,8 @@ cairo_list_move_tail (cairo_list_t *entry, cairo_list_t *head)
 static inline void
 cairo_list_swap (cairo_list_t *entry, cairo_list_t *other)
 {
-    cairo_list_validate (head);
     __cairo_list_add (entry, other->prev, other->next);
     cairo_list_init (other);
-    cairo_list_validate (head);
 }
 
 static inline cairo_bool_t
diff --git a/src/cairoint.h b/src/cairoint.h
index 805c574..5cf0bcf 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -2180,6 +2180,9 @@ cairo_private cairo_surface_t *
 _cairo_image_surface_create_for_pixman_image (pixman_image_t		*pixman_image,
 					      pixman_format_code_t	 pixman_format);
 
+pixman_format_code_t
+_cairo_format_to_pixman_format_code (cairo_format_t format);
+
 cairo_private cairo_bool_t
 _pixman_format_from_masks (cairo_format_masks_t *masks,
 			   pixman_format_code_t *format_ret);
@@ -2519,6 +2522,10 @@ _cairo_pattern_is_opaque (const cairo_pattern_t *pattern,
 cairo_private cairo_bool_t
 _cairo_pattern_is_clear (const cairo_pattern_t *pattern);
 
+cairo_private_no_warn cairo_filter_t
+_cairo_pattern_analyze_filter (const cairo_pattern_t	*pattern,
+			       double			*pad_out);
+
 enum {
     CAIRO_PATTERN_ACQUIRE_NONE = 0x0,
     CAIRO_PATTERN_ACQUIRE_NO_REFLECT = 0x1
diff --git a/src/drm/cairo-drm-i915-glyphs.c b/src/drm/cairo-drm-i915-glyphs.c
index d202500..40c8106 100644
--- a/src/drm/cairo-drm-i915-glyphs.c
+++ b/src/drm/cairo-drm-i915-glyphs.c
@@ -41,6 +41,25 @@
 #include "cairo-rtree-private.h"
 
 static void
+i915_emit_glyph_rectangle_zero (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
+     */
+
+    v = i915_add_rectangle (device);
+    *v++ = x2; *v++ = y2;
+    *v++ = x1; *v++ = y2;
+    *v++ = x1; *v++ = y1;
+}
+
+static void
 i915_emit_glyph_rectangle_constant (i915_device_t *device,
 				    i915_shader_t *shader,
 				    int x1, int y1,
@@ -91,6 +110,7 @@ i915_emit_glyph_rectangle_general (i915_device_t *device,
     *v++ = x2; *v++ = y2;
     s = x2, t = y2;
     switch (shader->source.type.vertex) {
+    case VS_ZERO:
     case VS_CONSTANT:
 	break;
     case VS_LINEAR:
@@ -111,6 +131,7 @@ i915_emit_glyph_rectangle_general (i915_device_t *device,
     *v++ = x1; *v++ = y2;
     s = x1, t = y2;
     switch (shader->source.type.vertex) {
+    case VS_ZERO:
     case VS_CONSTANT:
 	break;
     case VS_LINEAR:
@@ -131,6 +152,7 @@ i915_emit_glyph_rectangle_general (i915_device_t *device,
     *v++ = x1; *v++ = y1;
     s = x1, t = y2;
     switch (shader->source.type.vertex) {
+    case VS_ZERO:
     case VS_CONSTANT:
 	break;
     case VS_LINEAR:
@@ -168,7 +190,7 @@ i915_surface_mask_internal (i915_surface_t *dst,
     cairo_region_t *clip_region = NULL;
     cairo_status_t status;
 
-    i915_shader_init (&shader, dst, op);
+    i915_shader_init (&shader, dst, op, 1.);
 
     status = i915_shader_acquire_pattern (&shader, &shader.source,
 					  source, &extents->bounded);
@@ -176,6 +198,7 @@ i915_surface_mask_internal (i915_surface_t *dst,
 	return status;
 
     shader.mask.type.vertex = VS_TEXTURE_16;
+    shader.mask.type.pattern = PATTERN_TEXTURE;
     shader.mask.type.fragment = FS_TEXTURE;
     shader.mask.base.content = mask->intel.drm.base.content;
     shader.mask.base.texfmt = TEXCOORDFMT_2D_16;
@@ -188,20 +211,19 @@ i915_surface_mask_internal (i915_surface_t *dst,
 	i915_texture_extend (CAIRO_EXTEND_NONE);
 
     cairo_matrix_init_translate (&shader.mask.base.matrix,
-				 -extents->bounded.x + NEAREST_BIAS,
-				 -extents->bounded.y + NEAREST_BIAS);
+				 -extents->bounded.x,
+				 -extents->bounded.y);
     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.bo = intel_bo_reference (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;
@@ -240,7 +262,7 @@ i915_surface_mask_internal (i915_surface_t *dst,
 			      extents->bounded.y + extents->bounded.height);
     }
 
-    if ((extents->is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) == 0)
+    if (! extents->is_bounded)
 	status = i915_fixup_unbounded (dst, extents, clip);
 
 CLEANUP_DEVICE:
@@ -300,16 +322,32 @@ i915_surface_glyphs (void			*abstract_surface,
 	have_clip = TRUE;
     }
 
-    if (overlap || (extents.is_bounded & CAIRO_OPERATOR_BOUND_BY_MASK) == 0) {
-	cairo_content_t content;
+    if (clip != NULL) {
+	status = _cairo_clip_get_region (clip, &clip_region);
+	if (unlikely (_cairo_status_is_error (status) ||
+		      status == CAIRO_INT_STATUS_NOTHING_TO_DO))
+	{
+	    if (have_clip)
+		_cairo_clip_fini (&local_clip);
+	    return status;
+	}
+    }
+
+    if (i915_surface_needs_tiling (surface)) {
+	ASSERT_NOT_REACHED;
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    if (overlap || ! extents.is_bounded) {
+	cairo_format_t format;
 
-	content = CAIRO_CONTENT_ALPHA;
+	format = CAIRO_FORMAT_A8;
 	if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
-	    content |= CAIRO_CONTENT_COLOR;
+	    format = CAIRO_FORMAT_ARGB32;
 
 	mask = (i915_surface_t *)
 	    i915_surface_create_internal (&i915_device (surface)->intel.base,
-					  CAIRO_CONTENT_ALPHA,
+					  format,
 					  extents.bounded.width,
 					  extents.bounded.height,
 					  I915_TILING_DEFAULT,
@@ -317,16 +355,13 @@ i915_surface_glyphs (void			*abstract_surface,
 	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);
+	status = i915_surface_clear (mask);
 	if (unlikely (status)) {
 	    cairo_surface_destroy (&mask->intel.drm.base);
 	    return status;
 	}
 
-	i915_shader_init (&shader, mask, CAIRO_OPERATOR_ADD);
+	i915_shader_init (&shader, mask, CAIRO_OPERATOR_ADD, 1.);
 
 	status = i915_shader_acquire_pattern (&shader, &shader.source,
 					      &_cairo_pattern_white.base,
@@ -339,7 +374,7 @@ i915_surface_glyphs (void			*abstract_surface,
 	mask_x = -extents.bounded.x;
 	mask_y = -extents.bounded.y;
     } else {
-	i915_shader_init (&shader, surface, op);
+	i915_shader_init (&shader, surface, op, 1.);
 
 	status = i915_shader_acquire_pattern (&shader, &shader.source,
 					      source, &extents.bounded);
@@ -348,7 +383,6 @@ i915_surface_glyphs (void			*abstract_surface,
 
 	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;
@@ -370,6 +404,9 @@ i915_surface_glyphs (void			*abstract_surface,
 	i915_texture_extend (CAIRO_EXTEND_NONE);
 
     switch (shader.source.type.vertex) {
+    case VS_ZERO:
+	emit_func = i915_emit_glyph_rectangle_zero;
+	break;
     case VS_CONSTANT:
 	emit_func = i915_emit_glyph_rectangle_constant;
 	break;
@@ -466,8 +503,13 @@ i915_surface_glyphs (void			*abstract_surface,
 	    last_bo = cache->buffer.bo;
 	}
 
-	x1 += mask_x; x2 += mask_x;
-	y1 += mask_y; y2 += mask_y;
+	x2 = x1 + glyph->width;
+	y2 = y1 + glyph->height;
+
+	if (mask_x)
+	    x1 += mask_x, x2 += mask_x;
+	if (mask_y)
+	    y1 += mask_y, y2 += mask_y;
 
 	/* XXX clip glyph */
 	emit_func (device, &shader, x1, y1, x2, y2, glyph);
diff --git a/src/drm/cairo-drm-i915-private.h b/src/drm/cairo-drm-i915-private.h
index e95375f..f03d5d7 100644
--- a/src/drm/cairo-drm-i915-private.h
+++ b/src/drm/cairo-drm-i915-private.h
@@ -36,6 +36,8 @@
 #include "cairo-drm-intel-ioctl-private.h"
 #include "cairo-freelist-private.h"
 
+#include <setjmp.h>
+
 #define I915_VERBOSE 1
 
 #define I915_MAX_TEX_INDIRECT 4
@@ -652,17 +654,22 @@ struct i915_device {
 
     cairo_bool_t debug;
 
+    i915_shader_t *shader; /* note: only valid during geometry emission */
+
     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;
+	size_t gtt_avail_size;
+	size_t est_gtt_size;
+	size_t total_gtt_size;
 
-	struct drm_i915_gem_relocation_entry reloc[I915_MAX_RELOCS];
+	uint16_t fences;
+	uint16_t fences_avail;
 	uint16_t reloc_count;
-
+	uint16_t exec_count;
 	uint16_t used;
+
+	struct drm_i915_gem_exec_object2 exec[I915_MAX_RELOCS];
+	struct drm_i915_gem_relocation_entry reloc[I915_MAX_RELOCS];
     } batch;
 
     uint32_t vbo;
@@ -677,8 +684,6 @@ struct i915_device {
     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;
@@ -691,9 +696,12 @@ struct i915_device {
     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_samplers[2*4];
+    uint32_t current_maps[4*4];
     uint32_t current_n_samplers;
+    uint32_t current_n_maps;
     uint32_t last_source_fragment;
+    uint32_t clear_alpha;
 
     cairo_list_t image_caches[2];
 
@@ -709,6 +717,7 @@ enum {
 };
 
 typedef enum {
+    VS_ZERO,
     VS_CONSTANT,
     VS_LINEAR,
     VS_TEXTURE,
@@ -744,6 +753,7 @@ struct i915_surface {
     uint32_t map0, map1;
     uint32_t colorbuf;
 
+    cairo_bool_t deferred_clear;
     uint32_t offset;
     uint32_t is_current_texture;
 
@@ -787,8 +797,10 @@ struct i915_shader {
 
     cairo_operator_t op;
     uint32_t blend;
+    float opacity;
     cairo_content_t content;
 
+    cairo_bool_t committed;
     cairo_bool_t need_combine;
 
     i915_add_rectangle_func_t add_rectangle;
@@ -834,6 +846,8 @@ struct i915_shader {
 	    i915_packed_pixel_t pixel;
 	} surface;
     } source, mask, clip, dst;
+
+    jmp_buf unwind;
 };
 
 enum i915_shader_linear_mode {
@@ -862,11 +876,12 @@ i915_clip_and_composite_spans (i915_surface_t		*dst,
 			       i915_spans_func_t	 draw_func,
 			       void			*draw_closure,
 			       const cairo_composite_rectangles_t*extents,
-			       cairo_clip_t		*clip);
+			       cairo_clip_t		*clip,
+			       double			 opacity);
 
 cairo_private cairo_surface_t *
 i915_surface_create_internal (cairo_drm_device_t *base_dev,
-		              cairo_content_t content,
+		              cairo_format_t format,
 			      int width, int height,
 			      uint32_t tiling,
 			      cairo_bool_t gpu_target);
@@ -904,8 +919,9 @@ i915_tiling_stride (int format, uint32_t stride)
 {
     uint32_t tile_width;
 
+    /* use 64B alignment so that the buffer may be used as a scanout */
     if (format == I915_TILING_NONE)
-	return (stride + 31) & -32;
+	return (stride + 63) & -64;
 
     tile_width = 512;
     /* XXX Currently the kernel enforces a tile_width of 512 for TILING_Y.
@@ -943,7 +959,7 @@ i915_tiling_size (uint32_t tiling, uint32_t size)
     return fence;
 }
 
-static inline cairo_bool_t cairo_pure
+static inline cairo_bool_t cairo_const
 i915_texture_filter_is_nearest (cairo_filter_t filter)
 {
     switch (filter) {
@@ -959,7 +975,7 @@ i915_texture_filter_is_nearest (cairo_filter_t filter)
     }
 }
 
-static inline uint32_t cairo_pure
+static inline uint32_t cairo_const
 i915_texture_filter (cairo_filter_t filter)
 {
     switch (filter) {
@@ -979,7 +995,7 @@ i915_texture_filter (cairo_filter_t filter)
     }
 }
 
-static inline uint32_t cairo_pure
+static inline uint32_t cairo_const
 i915_texture_extend (cairo_extend_t extend)
 {
     switch (extend) {
@@ -1003,7 +1019,7 @@ i915_texture_extend (cairo_extend_t extend)
     }
 }
 
-static inline uint32_t cairo_pure
+static inline uint32_t cairo_const
 BUF_tiling (uint32_t tiling)
 {
     switch (tiling) {
@@ -1015,7 +1031,8 @@ BUF_tiling (uint32_t tiling)
 }
 
 #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 OUT_RELOC(surface, read, write) i915_batch_emit_reloc (device, to_intel_bo (surface->intel.drm.bo), surface->offset, read, write, FALSE)
+#define OUT_RELOC_FENCED(surface, read, write) i915_batch_emit_reloc (device, to_intel_bo (surface->intel.drm.bo), surface->offset, read, write, TRUE)
 
 #define FS_LOCALS							\
     uint32_t *_shader_start
@@ -1039,26 +1056,54 @@ i915_batch_space (i915_device_t *device)
 }
 
 static inline cairo_bool_t
-i915_check_aperture_size (const i915_device_t *device, int relocs, size_t size)
+i915_check_aperture_size (const i915_device_t *device, int relocs, size_t est_size, size_t size)
 {
-    return device->batch.reloc_count + relocs < I915_MAX_RELOCS &&
-	   device->batch.gtt_size + size <= device->intel.gtt_avail_size;
+    return device->batch.reloc_count + relocs < I915_MAX_RELOCS - 2 &&
+	   device->batch.est_gtt_size + est_size <= device->batch.gtt_avail_size &&
+	   device->batch.total_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;
+    uint32_t relocs = 0, est_size = 0, size = 0;
+
+    while (count--) {
+	const intel_bo_t *bo = *bo_array++;
+	if (bo->exec == NULL) {
+	    relocs++;
+	    size += bo->base.size;
+	    if (!bo->busy)
+		est_size += bo->base.size;
+	}
+    }
+
+    return i915_check_aperture_size (device, relocs, est_size, size);
+}
+
+static inline cairo_bool_t
+i915_check_aperture_and_fences (const i915_device_t *device, intel_bo_t **bo_array, int count)
+{
+    uint32_t relocs = 0, est_size = 0, size = 0;
+    uint32_t fences = 0;
 
     while (count--) {
 	const intel_bo_t *bo = *bo_array++;
 	if (bo->exec == NULL) {
 	    relocs++;
 	    size += bo->base.size;
+	    if (!bo->busy)
+		est_size += bo->base.size;
+	    if (bo->tiling != I915_TILING_NONE)
+		fences++;
+	} else if (bo->tiling != I915_TILING_NONE) {
+	    if ((bo->exec->flags & EXEC_OBJECT_NEEDS_FENCE) == 0)
+		fences++;
 	}
     }
 
-    return i915_check_aperture_size (device, relocs, size);
+    return i915_check_aperture_size (device, relocs, est_size, size) &&
+	   device->batch.fences + fences <= device->batch.fences_avail;
 }
 
 #define BATCH_PTR(device) &(device)->batch_base[(device)->batch.used]
@@ -1073,7 +1118,8 @@ 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);
+		      uint32_t write_domain,
+		      cairo_bool_t needs_fence);
 
 static inline void
 i915_batch_fill_reloc (i915_device_t *device, uint32_t pos,
@@ -1084,7 +1130,8 @@ i915_batch_fill_reloc (i915_device_t *device, uint32_t pos,
 {
     i915_batch_add_reloc (device, pos,
 	                  bo, offset,
-			  read_domains, write_domain);
+			  read_domains, write_domain,
+			  FALSE);
     device->batch_base[pos] = bo->offset + offset;
 }
 
@@ -1093,15 +1140,20 @@ i915_batch_emit_reloc (i915_device_t *device,
 		       intel_bo_t *bo,
 		       uint32_t offset,
 		       uint32_t read_domains,
-		       uint32_t write_domain)
+		       uint32_t write_domain,
+		       cairo_bool_t needs_fence)
 {
     i915_batch_add_reloc (device, device->batch.used,
 	                  bo, offset,
-			  read_domains, write_domain);
+			  read_domains, write_domain,
+			  needs_fence);
     i915_batch_emit_dword (device, bo->offset + offset);
 }
 
 cairo_private void
+i915_vbo_flush (i915_device_t *device);
+
+cairo_private void
 i915_vbo_finish (i915_device_t *device);
 
 cairo_private  cairo_status_t
@@ -1114,6 +1166,7 @@ i915_add_rectangle (i915_device_t *device)
     uint32_t size;
 
     assert (device->floats_per_vertex);
+    assert (device->rectangle_size == 3*device->floats_per_vertex*sizeof(float));
 
     size = device->rectangle_size;
     if (unlikely (device->vbo_offset + size > I915_VBO_SIZE))
@@ -1131,10 +1184,17 @@ i915_device (i915_surface_t *surface)
     return (i915_device_t *) surface->intel.drm.base.device;
 }
 
+cairo_private cairo_status_t
+i915_surface_clear (i915_surface_t *dst);
+
+cairo_private void
+i915_set_dst (i915_device_t *device, i915_surface_t *dst);
+
 cairo_private void
 i915_shader_init (i915_shader_t *shader,
 		  i915_surface_t *dst,
-		  cairo_operator_t op);
+		  cairo_operator_t op,
+		  double opacity);
 
 cairo_private cairo_status_t
 i915_shader_acquire_pattern (i915_shader_t *shader,
@@ -1168,4 +1228,43 @@ i915_fixup_unbounded (i915_surface_t *dst,
 		      const cairo_composite_rectangles_t *extents,
 		      cairo_clip_t *clip);
 
+static inline cairo_bool_t
+i915_surface_needs_tiling (i915_surface_t *dst)
+{
+    return dst->intel.drm.width > 2048 || dst->intel.drm.height > 2048;
+}
+
+cairo_private cairo_status_t
+i915_surface_copy_subimage (i915_device_t *device,
+			    i915_surface_t *src,
+			    const cairo_rectangle_int_t *extents,
+			    cairo_bool_t flush,
+			    i915_surface_t **clone_out);
+
+static inline uint32_t
+pack_float (float f)
+{
+    union {
+	float f;
+	uint32_t ui;
+    } t;
+    t.f = f;
+    return t.ui;
+}
+
+static inline cairo_status_t
+i915_surface_fallback_flush (i915_surface_t *surface)
+{
+    cairo_status_t status;
+
+    if (unlikely (surface->intel.drm.fallback != NULL))
+	return intel_surface_flush (&surface->intel);
+
+    status = CAIRO_STATUS_SUCCESS;
+    if (unlikely (surface->deferred_clear))
+	status = i915_surface_clear (surface);
+
+    return status;
+}
+
 #endif /* CAIRO_DRM_I915_PRIVATE_H */
diff --git a/src/drm/cairo-drm-i915-shader.c b/src/drm/cairo-drm-i915-shader.c
index 4a7c6b9..1ecf762 100644
--- a/src/drm/cairo-drm-i915-shader.c
+++ b/src/drm/cairo-drm-i915-shader.c
@@ -35,6 +35,7 @@
 
 #include "cairo-error-private.h"
 #include "cairo-drm-i915-private.h"
+#include "cairo-surface-offset-private.h"
 #include "cairo-surface-subsurface-private.h"
 #include "cairo-surface-snapshot-private.h"
 
@@ -149,7 +150,7 @@ i915_packed_pixel_surface_create (i915_device_t *device,
 			 content);
 
     surface->bo = intel_bo_create (&device->intel, size, FALSE);
-    assert (tiling == I915_TILING_NONE);
+    assert (surface->bo->tiling == I915_TILING_NONE);
     if (unlikely (surface->bo == NULL)) {
 	free (surface);
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
@@ -233,8 +234,6 @@ i915_packed_pixel_surface_create (i915_device_t *device,
 		data += size;
 	    }
 	}
-
-	intel_bo_unmap (surface->bo);
     }
 
     surface->device = device;
@@ -535,13 +534,6 @@ i915_shader_get_num_tex_coords (const i915_shader_t *shader)
      (((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)
@@ -563,6 +555,7 @@ i915_set_shader_program (i915_device_t *device,
 	(i915_shader_channel_key (&shader->mask)   <<  8) |
 	(i915_shader_channel_key (&shader->clip)   << 16) |
 	(shader->op << 24) |
+	((shader->opacity < 1.) << 30) |
 	(((shader->content & CAIRO_CONTENT_ALPHA) == CAIRO_CONTENT_ALPHA) << 31);
     if (n == device->current_program)
 	return;
@@ -814,6 +807,13 @@ i915_set_shader_program (i915_device_t *device,
 	}
     }
 
+    if (shader->opacity < 1.) {
+	i915_fs_mul (source_reg,
+		     i915_fs_operand_reg (source_reg),
+		     i915_fs_operand_reg (FS_C0 + constant_offset));
+	constant_offset++;
+    }
+
     /* need to preserve order of src, mask, clip, dst */
     mask_reg = ~0;
     if (shader->clip.type.fragment == FS_TEXTURE) {
@@ -924,10 +924,15 @@ i915_set_shader_program (i915_device_t *device,
 		    source_reg = mask_reg;
 		} else {
 		    out_reg = FS_OC;
-		    if (shader->content == CAIRO_CONTENT_ALPHA)
-			out_reg = FS_R3;
-		    i915_fs_mov (out_reg,
-				 i915_fs_operand_reg_pure (mask_reg, source_pure));
+		    if ((shader->content & CAIRO_CONTENT_COLOR) == 0) {
+			if (source_pure & (1 << 3))
+			    i915_fs_mov (out_reg, i915_fs_operand (mask_reg, W, W, W, W));
+			else
+			    i915_fs_mov (out_reg, i915_fs_operand_zero ());
+		    } else {
+			i915_fs_mov (out_reg,
+				     i915_fs_operand_impure (mask_reg, W, source_pure));
+		    }
 		    source_reg = out_reg;
 		}
 	    } else if (mask_reg) {
@@ -945,7 +950,7 @@ i915_set_shader_program (i915_device_t *device,
 		source_reg = out_reg;
 	    }
 	} else {
-	    /* (source OP dest)  LERP_clip dest */
+	    /* (source OP dest) LERP_clip dest */
 	    if (source_reg == ~0U) {
 		if (source_pure == 0) {
 		    i915_fs_mov (FS_R3,
@@ -981,11 +986,15 @@ i915_set_shader_program (i915_device_t *device,
 	    }
 
 	    source_reg = FS_OC;
-	    if (shader->content != CAIRO_CONTENT_COLOR_ALPHA)
-		source_reg = FS_R3;
-	    i915_fs_add (source_reg,
-			 i915_fs_operand_reg (FS_R3),
-			 i915_fs_operand_reg (mask_reg));
+	    if ((shader->content & CAIRO_CONTENT_COLOR) == 0) {
+		i915_fs_add (source_reg,
+			     i915_fs_operand (FS_R3, W, W, W, W),
+			     i915_fs_operand (mask_reg, W, W, W, W));
+	    } else {
+		i915_fs_add (source_reg,
+			     i915_fs_operand_reg (FS_R3),
+			     i915_fs_operand_reg (mask_reg));
+	    }
 	}
     }
 
@@ -1147,7 +1156,7 @@ i915_shader_acquire_solid (i915_shader_t *shader,
 	src->base.content = content;
 	src->type.fragment = src == &shader->source ? FS_DIFFUSE : FS_CONSTANT;
     }
-    src->type.vertex = VS_CONSTANT;
+    src->type.vertex = src->type.fragment == FS_ZERO ? VS_ZERO : VS_CONSTANT;
     src->type.pattern = PATTERN_CONSTANT;
 
     return CAIRO_STATUS_SUCCESS;
@@ -1276,20 +1285,38 @@ i915_surface_clone (i915_device_t *device,
     i915_surface_t *clone;
     cairo_status_t status;
 
+#if 0
     clone =
 	i915_surface_create_from_cacheable_image_internal (device, image);
     if (unlikely (clone->intel.drm.base.status))
 	return clone->intel.drm.base.status;
+#else
+    cairo_format_t format;
 
-    status = intel_snapshot_cache_insert (&device->intel, &clone->intel);
-    if (unlikely (status)) {
-	cairo_surface_destroy (&clone->intel.drm.base);
-	return status;
-    }
+    format = image->format;
+    if (format == CAIRO_FORMAT_A1)
+	format = CAIRO_FORMAT_A8;
+
+    clone = (i915_surface_t *)
+	i915_surface_create_internal (&device->intel.base,
+				      format,
+				      image->width,
+				      image->height,
+				      I915_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),
+				 image,
+				 0, 0,
+				 image->width, image->height,
+				 0, 0);
 
-    _cairo_surface_attach_snapshot (&image->base,
-				    &clone->intel.drm.base,
-				    intel_surface_detach_snapshot);
+    if (unlikely (status))
+	return status;
+#endif
 
     *clone_out = clone;
     return CAIRO_STATUS_SUCCESS;
@@ -1303,10 +1330,15 @@ i915_surface_clone_subimage (i915_device_t *device,
 {
     i915_surface_t *clone;
     cairo_status_t status;
+    cairo_format_t format;
+
+    format = image->format;
+    if (format == CAIRO_FORMAT_A1)
+	format = CAIRO_FORMAT_A8;
 
     clone = (i915_surface_t *)
 	i915_surface_create_internal (&device->intel.base,
-				      image->base.content,
+				      format,
 				      extents->width,
 				      extents->height,
 				      I915_TILING_NONE,
@@ -1314,9 +1346,8 @@ i915_surface_clone_subimage (i915_device_t *device,
     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),
+    status = intel_bo_put_image (&device->intel,
 				 to_intel_bo (clone->intel.drm.bo),
-				 clone->intel.drm.stride,
 				 image,
 				 extents->x, extents->y,
 				 extents->width, extents->height,
@@ -1330,6 +1361,60 @@ i915_surface_clone_subimage (i915_device_t *device,
 }
 
 static cairo_status_t
+i915_surface_render_pattern (i915_device_t *device,
+			     const cairo_surface_pattern_t *pattern,
+			     const cairo_rectangle_int_t *extents,
+			     i915_surface_t **clone_out)
+{
+    i915_surface_t *clone;
+    cairo_surface_t *image;
+    cairo_status_t status;
+    void *ptr;
+
+    clone = (i915_surface_t *)
+	i915_surface_create_internal (&device->intel.base,
+				      _cairo_format_from_content (pattern->surface->content),
+				      extents->width,
+				      extents->height,
+				      I915_TILING_NONE,
+				      FALSE);
+    if (unlikely (clone->intel.drm.base.status))
+	return clone->intel.drm.base.status;
+
+    ptr = intel_bo_map (&device->intel,
+			to_intel_bo (clone->intel.drm.bo));
+    if (unlikely (ptr == NULL)) {
+	cairo_surface_destroy (&clone->intel.drm.base);
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    }
+
+    image = cairo_image_surface_create_for_data (ptr,
+						 clone->intel.drm.format,
+						 clone->intel.drm.width,
+						 clone->intel.drm.height,
+						 clone->intel.drm.stride);
+    if (unlikely (image->status)) {
+	cairo_surface_destroy (&clone->intel.drm.base);
+	return image->status;
+    }
+
+    status = _cairo_surface_offset_paint (image,
+					  extents->x, extents->y,
+					  CAIRO_OPERATOR_SOURCE,
+					  &pattern->base,
+					  NULL);
+    cairo_surface_destroy (image);
+
+    if (unlikely (status)) {
+	cairo_surface_destroy (&clone->intel.drm.base);
+	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,
@@ -1385,6 +1470,46 @@ i915_shader_acquire_solid_surface (i915_shader_t *shader,
     return CAIRO_STATUS_SUCCESS;
 }
 
+static cairo_filter_t
+sampled_area (const cairo_surface_pattern_t *pattern,
+	      const cairo_rectangle_int_t *extents,
+	      cairo_rectangle_int_t *sample)
+{
+    cairo_rectangle_int_t surface_extents;
+    cairo_filter_t filter;
+    double x1, x2, y1, y2;
+    double pad;
+
+    x1 = extents->x;
+    y1 = extents->y;
+    x2 = extents->x + (int) extents->width;
+    y2 = extents->y + (int) extents->height;
+
+    if (_cairo_matrix_is_translation (&pattern->base.matrix)) {
+	x1 += pattern->base.matrix.x0; x2 += pattern->base.matrix.x0;
+	y1 += pattern->base.matrix.y0; y2 += pattern->base.matrix.y0;
+    } else {
+	_cairo_matrix_transform_bounding_box (&pattern->base.matrix,
+					      &x1, &y1, &x2, &y2,
+					      NULL);
+    }
+
+    filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
+    sample->x = floor (x1 - pad);
+    sample->y = floor (y1 - pad);
+    sample->width  = ceil (x2 + pad) - sample->x;
+    sample->height = ceil (y2 + pad) - sample->y;
+
+    if (_cairo_surface_get_extents (pattern->surface, &surface_extents)) {
+	cairo_bool_t is_empty;
+
+	is_empty = _cairo_rectangle_intersect (sample,
+					       &surface_extents);
+    }
+
+    return filter;
+}
+
 static cairo_status_t
 i915_shader_acquire_surface (i915_shader_t *shader,
 			     union i915_shader_channel *src,
@@ -1399,10 +1524,15 @@ i915_shader_acquire_surface (i915_shader_t *shader,
     int src_x = 0, src_y = 0;
     cairo_surface_t *free_me = NULL;
     cairo_status_t status;
+    cairo_rectangle_int_t sample;
 
     assert (src->type.fragment == (i915_fragment_shader_t) -1);
     drm = surface = pattern->surface;
 
+    extend = pattern->base.extend;
+    src->base.matrix = pattern->base.matrix;
+    filter = sampled_area (pattern, extents, &sample);
+
 #if CAIRO_HAS_XCB_SURFACE && CAIRO_HAS_XCB_DRM_FUNCTIONS
     if (surface->type == CAIRO_SURFACE_TYPE_XCB) {
 	cairo_surface_t *xcb = surface;
@@ -1440,11 +1570,11 @@ i915_shader_acquire_surface (i915_shader_t *shader,
 		cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) surface;
 		int x;
 
-		if (s->intel.drm.fallback != NULL) {
-		    status = intel_surface_flush (s);
-		    if (unlikely (status))
-			return status;
-		}
+		status = i915_surface_fallback_flush (s);
+		if (unlikely (status))
+		    return status;
+
+		/* XXX blt subimage and cache snapshot */
 
 		if (to_intel_bo (s->intel.drm.bo)->batch_write_domain) {
 		    /* XXX pipelined flush of RENDER/TEXTURE cache */
@@ -1473,18 +1603,23 @@ i915_shader_acquire_surface (i915_shader_t *shader,
 	    }
 	} 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)
-	    {
-		if (s->intel.drm.fallback != NULL) {
-		    status = intel_surface_flush (s);
+	    if (s->intel.drm.base.device == shader->target->intel.drm.base.device) {
+		status = i915_surface_fallback_flush (s);
+		if (unlikely (status))
+		    return status;
+
+		if (s == shader->target || i915_surface_needs_tiling (s)) {
+		    status = i915_surface_copy_subimage (i915_device (shader->target),
+							 s, &sample, TRUE, &s);
 		    if (unlikely (status))
 			return status;
-		}
 
+		    free_me = drm = &s->intel.drm.base;
+		}
 
 		src->type.fragment = FS_TEXTURE;
 		src->surface.pixel = NONE;
+
 		surface_width  = s->intel.drm.width;
 		surface_height = s->intel.drm.height;
 
@@ -1509,8 +1644,6 @@ i915_shader_acquire_surface (i915_shader_t *shader,
 	    _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
@@ -1520,23 +1653,59 @@ i915_shader_acquire_surface (i915_shader_t *shader,
 				     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);
+	    if (sample.width > 2048 || sample.height > 2048) {
+		status = i915_surface_render_pattern (i915_device (shader->target),
+						      pattern, extents,
+						      &s);
+		if (unlikely (status))
+		    return status;
+
+		extend = CAIRO_EXTEND_NONE;
+		filter = CAIRO_FILTER_NEAREST;
+		cairo_matrix_init_translate (&src->base.matrix,
+					     -extents->x, -extents->y);
 	    } 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;
-	    }
+		cairo_image_surface_t *image;
+		void *image_extra;
+
+		status = _cairo_surface_acquire_source_image (surface, &image, &image_extra);
+		if (unlikely (status))
+		    return status;
+
+		if (image->width  < 2048 &&
+		    image->height < 2048 &&
+		    sample.width  >= image->width / 4 &&
+		    sample.height >= image->height /4)
+		{
+
+		    status = i915_surface_clone (i915_device (shader->target),
+						 image, &s);
+
+		    if (likely (status == CAIRO_STATUS_SUCCESS)) {
+			_cairo_surface_attach_snapshot (surface,
+							&s->intel.drm.base,
+							intel_surface_detach_snapshot);
+
+			status = intel_snapshot_cache_insert (&i915_device (shader->target)->intel,
+							      &s->intel);
+			if (unlikely (status)) {
+			    cairo_surface_finish (&s->intel.drm.base);
+			    cairo_surface_destroy (&s->intel.drm.base);
+			}
+		    }
+		}
+		else
+		{
+		    status = i915_surface_clone_subimage (i915_device (shader->target),
+							  image, &sample, &s);
+		    src_x = -extents->x;
+		    src_y = -extents->y;
+		}
 
-	    _cairo_surface_release_source_image (surface, image, image_extra);
-	    if (unlikely (status))
-		return status;
+		_cairo_surface_release_source_image (surface, image, image_extra);
+		if (unlikely (status))
+		    return status;
+	    }
 
 	    free_me = &s->intel.drm.base;
 	}
@@ -1559,11 +1728,10 @@ i915_shader_acquire_surface (i915_shader_t *shader,
     /* 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)
+	sample.x >= 0 && sample.y >= 0 &&
+	sample.x + sample.width  <= surface_width &&
+	sample.y + sample.height <= surface_height)
     {
 	extend = CAIRO_EXTEND_NONE;
     }
@@ -1576,10 +1744,6 @@ i915_shader_acquire_surface (i915_shader_t *shader,
     }
     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);
@@ -1588,11 +1752,8 @@ i915_shader_acquire_surface (i915_shader_t *shader,
 	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);
 
@@ -1720,14 +1881,44 @@ i915_shader_channel_init (union i915_shader_channel *channel)
     channel->base.mode = 0;
 }
 
+static void
+i915_shader_channel_fini (i915_device_t *device,
+			   union i915_shader_channel *channel)
+{
+    switch (channel->type.pattern) {
+    case PATTERN_TEXTURE:
+    case PATTERN_BASE:
+    case PATTERN_LINEAR:
+    case PATTERN_RADIAL:
+	if (channel->base.bo != NULL)
+	    intel_bo_destroy (&device->intel, channel->base.bo);
+	break;
+
+    default:
+    case PATTERN_CONSTANT:
+	break;
+    }
+}
+
+static void
+i915_shader_channel_reset (i915_device_t *device,
+			   union i915_shader_channel *channel)
+{
+    i915_shader_channel_fini (device, channel);
+    i915_shader_channel_init (channel);
+}
+
 void
 i915_shader_init (i915_shader_t *shader,
 		  i915_surface_t *dst,
-		  cairo_operator_t op)
+		  cairo_operator_t op,
+		  double opacity)
 {
+    shader->committed = FALSE;
     shader->device = i915_device (dst);
     shader->target = dst;
     shader->op = op;
+    shader->opacity = opacity;
 
     shader->blend = i915_get_blend (op, dst);
     shader->need_combine = FALSE;
@@ -1744,216 +1935,219 @@ 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;
+    uint32_t n_samplers, n_maps, n;
+    uint32_t samplers[2*4];
+    uint32_t maps[4*4];
+    uint32_t mask, s, m;
 
-    n_samplers =
+    n_maps =
 	shader->source.base.n_samplers +
 	shader->mask.base.n_samplers +
 	shader->clip.base.n_samplers +
 	shader->dst.base.n_samplers;
-    assert (n_samplers <= 4);
+    assert (n_maps <= 4);
 
-    if (n_samplers == 0)
+    if (n_maps == 0)
 	return;
 
-    mask  = (1 << n_samplers) - 1;
+    n_samplers =
+	!! shader->source.base.bo +
+	!! shader->mask.base.bo +
+	!! shader->clip.base.bo +
+	!! shader->dst.base.bo;
+
+    mask  = (1 << n_maps) - 1;
 
     /* We check for repeated setting of sample state mainly to catch
      * continuation of text strings across multiple show-glyphs.
      */
-    tu = 0;
+    s = m = 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];
+	samplers[s++] = shader->source.base.sampler[0];
+	samplers[s++] = shader->source.base.sampler[1];
+	maps[m++] = shader->source.base.bo->base.handle;
 	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];
+	    maps[m++] = shader->source.base.offset[n];
+	    maps[m++] = shader->source.base.map[2*n+0];
+	    maps[m++] = 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];
+	samplers[s++] = shader->mask.base.sampler[0];
+	samplers[s++] = shader->mask.base.sampler[1];
+	maps[m++] = shader->mask.base.bo->base.handle;
 	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];
+	    maps[m++] = shader->mask.base.offset[n];
+	    maps[m++] = shader->mask.base.map[2*n+0];
+	    maps[m++] = 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];
+	samplers[s++] = shader->clip.base.sampler[0];
+	samplers[s++] = shader->clip.base.sampler[1];
+	maps[m++] = shader->clip.base.bo->base.handle;
 	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];
+	    maps[m++] = shader->clip.base.offset[n];
+	    maps[m++] = shader->clip.base.map[2*n+0];
+	    maps[m++] = 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];
+	samplers[s++] = shader->dst.base.sampler[0];
+	samplers[s++] = shader->dst.base.sampler[1];
+	maps[m++] = shader->dst.base.bo->base.handle;
 	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];
+	    maps[m++] = shader->dst.base.offset[n];
+	    maps[m++] = shader->dst.base.map[2*n+0];
+	    maps[m++] = shader->dst.base.map[2*n+1];
 	}
     }
 
-    if (tu == device->current_n_samplers &&
-	memcmp (device->current_samplers,
-		samplers,
-		tu * sizeof (uint32_t)) == 0)
+    if (n_maps > device->current_n_maps ||
+	memcmp (device->current_maps,
+		maps,
+		m * sizeof (uint32_t)))
     {
-	return;
-    }
-    device->current_n_samplers = tu;
-    memcpy (device->current_samplers, samplers, tu * sizeof (uint32_t));
+	memcpy (device->current_maps, maps, m * sizeof (uint32_t));
+	device->current_n_maps = n_maps;
 
-    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 (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;
-	    }
+	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;
+	    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;
 	    }
-
-	default:
+	} else
 	    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;
-	    }
+	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;
+	    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;
 	    }
-
-	default:
+	} else
 	    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) {
+	OUT_DWORD (_3DSTATE_MAP_STATE | (3 * n_maps));
+	OUT_DWORD (mask);
 	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);
+				   I915_GEM_DOMAIN_SAMPLER, 0,
+				   FALSE);
 	    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);
+				   I915_GEM_DOMAIN_SAMPLER, 0,
+				   FALSE);
 	    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);
+				   I915_GEM_DOMAIN_SAMPLER, 0,
+				   FALSE);
 	    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);
+				   I915_GEM_DOMAIN_SAMPLER, 0,
+				   FALSE);
 	    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) {
+    if (n_samplers > device->current_n_samplers ||
+	memcmp (device->current_samplers,
+		samplers,
+		s * sizeof (uint32_t)))
+    {
+	device->current_n_samplers = s;
+	memcpy (device->current_samplers, samplers, s * sizeof (uint32_t));
+
+	OUT_DWORD (_3DSTATE_SAMPLER_STATE | (3 * n_maps));
+	OUT_DWORD (mask);
+	s = 0;
 	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));
+		       (s << SS3_TEXTUREMAP_INDEX_SHIFT));
 	    OUT_DWORD (0x0);
-	    tu++;
+	    s++;
 	}
-    }
-    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));
+		       (s << SS3_TEXTUREMAP_INDEX_SHIFT));
 	    OUT_DWORD (0x0);
-	    tu++;
+	    s++;
 	}
-    }
-    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));
+		       (s << SS3_TEXTUREMAP_INDEX_SHIFT));
 	    OUT_DWORD (0x0);
-	    tu++;
+	    s++;
 	}
-    }
-    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));
+		       (s << SS3_TEXTUREMAP_INDEX_SHIFT));
 	    OUT_DWORD (0x0);
-	    tu++;
+	    s++;
 	}
     }
 }
@@ -2047,17 +2241,6 @@ i915_set_constants (i915_device_t *device,
     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)
@@ -2108,7 +2291,7 @@ static void
 i915_set_shader_constants (i915_device_t *device,
 	                   const i915_shader_t *shader)
 {
-    uint32_t constants[4*4*3];
+    uint32_t constants[4*4*3+4];
     unsigned n_constants;
 
     n_constants = 0;
@@ -2131,6 +2314,14 @@ i915_set_shader_constants (i915_device_t *device,
     }
     n_constants += pack_constants (&shader->mask, constants + n_constants);
 
+    if (shader->opacity < 1.) {
+	constants[n_constants+0] =
+	    constants[n_constants+1] =
+	    constants[n_constants+2] =
+	    constants[n_constants+3] = pack_float (shader->opacity);
+	n_constants += 4;
+    }
+
     if (n_constants != 0 &&
 	(device->current_n_constants != n_constants ||
 	 memcmp (device->current_constants, constants, n_constants*4)))
@@ -2150,74 +2341,77 @@ i915_shader_needs_update (const i915_shader_t *shader,
 	return TRUE;
 
     count =
+	!! shader->source.base.bo +
+	!! shader->mask.base.bo +
+	!! shader->clip.base.bo +
+	!! shader->dst.base.bo;
+    if (count > device->current_n_samplers)
+	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)
+    if (count > device->current_n_maps)
 	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)
+    if (count) {
+	count = 0;
+	if (shader->source.base.bo != NULL) {
+	    buf[count++] = shader->source.base.sampler[0];
+	    buf[count++] = shader->source.base.sampler[1];
+	}
+	if (shader->mask.base.bo != NULL) {
+	    buf[count++] = shader->mask.base.sampler[0];
+	    buf[count++] = shader->mask.base.sampler[1];
+	}
+	if (shader->clip.base.bo != NULL) {
+	    buf[count++] = shader->clip.base.sampler[0];
+	    buf[count++] = shader->clip.base.sampler[1];
+	}
+	if (shader->dst.base.bo != NULL) {
+	    buf[count++] = shader->dst.base.sampler[0];
+	    buf[count++] = shader->dst.base.sampler[1];
+	}
+	if (memcmp (device->current_samplers, buf, count * sizeof (uint32_t)))
 	    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];
-		}
+	count = 0;
+	if (shader->source.base.bo != NULL) {
+	    buf[count++] = shader->source.base.bo->base.handle;
+	    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->mask.base.bo != NULL) {
+	    buf[count++] = shader->mask.base.bo->base.handle;
+	    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->clip.base.bo != NULL) {
+	    buf[count++] = shader->clip.base.bo->base.handle;
+	    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];
-		}
+	}
+	if (shader->dst.base.bo != NULL) {
+	    buf[count++] = shader->dst.base.bo->base.handle;
+	    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 (memcmp (device->current_maps, buf, count * sizeof (uint32_t)))
+	    return TRUE;
     }
 
     if (i915_shader_get_texcoords (shader) != device->current_texcoords)
@@ -2253,30 +2447,30 @@ i915_shader_needs_update (const i915_shader_t *shader,
 	(i915_shader_channel_key (&shader->mask)   <<  8) |
 	(i915_shader_channel_key (&shader->clip)   << 16) |
 	(shader->op << 24) |
+	((shader->opacity < 1.) << 30) |
 	(((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)
+void
+i915_set_dst (i915_device_t *device, i915_surface_t *dst)
 {
-    i915_surface_t *dst;
-    intel_bo_t *bo;
     uint32_t size;
 
-    dst = shader->target;
-    if (device->current_target == dst)
-	return;
+    if (device->current_target != dst) {
+	intel_bo_t *bo;
+
+	bo = to_intel_bo (dst->intel.drm.bo);
+	assert (bo != NULL);
 
-    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);
 
-    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);
+	device->current_target = dst;
+    }
 
     if (dst->colorbuf != device->current_colorbuf) {
 	OUT_DWORD (_3DSTATE_DST_BUF_VARS_CMD);
@@ -2293,8 +2487,13 @@ i915_set_shader_target (i915_device_t *device,
 	OUT_DWORD (0);  /* origin */
 	device->current_size = size;
     }
+}
 
-    device->current_target = dst;
+static void
+i915_set_shader_target (i915_device_t *device,
+		        const i915_shader_t *shader)
+{
+    i915_set_dst (device, shader->target);
 }
 
 int
@@ -2354,47 +2553,9 @@ 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;
-    }
+    i915_shader_channel_fini (device, &shader->source);
+    i915_shader_channel_fini (device, &shader->mask);
+    i915_shader_channel_fini (device, &shader->clip);
 }
 
 void
@@ -2411,7 +2572,6 @@ i915_shader_set_clip (i915_shader_t *shader,
     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;
@@ -2420,7 +2580,7 @@ i915_shader_set_clip (i915_shader_t *shader,
     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.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;
@@ -2437,8 +2597,7 @@ i915_shader_set_clip (i915_shader_t *shader,
 			     1. / s->intel.drm.width,
 			     1. / s->intel.drm.height);
     cairo_matrix_translate (&shader->clip.base.matrix,
-			    NEAREST_BIAS - clip_x,
-			    NEAREST_BIAS - clip_y);
+			    -clip_x, -clip_y);
 }
 
 static cairo_status_t
@@ -2473,7 +2632,7 @@ i915_shader_check_aperture (i915_shader_t *shader,
 }
 
 static void
-i915_shader_combine_mask (i915_shader_t *shader)
+i915_shader_combine_mask (i915_shader_t *shader, i915_device_t *device)
 {
     if (shader->mask.type.fragment == (i915_fragment_shader_t) -1 ||
 	shader->mask.type.fragment == FS_CONSTANT)
@@ -2492,24 +2651,22 @@ i915_shader_combine_mask (i915_shader_t *shader)
     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;
+	i915_shader_channel_reset (device, &shader->mask);
     }
 
     if (shader->mask.type.fragment == FS_ZERO) {
+	i915_shader_channel_fini (device, &shader->source);
+
 	shader->source.type.fragment = FS_ZERO;
-	shader->source.type.vertex = VS_CONSTANT;
+	shader->source.type.vertex = VS_ZERO;
 	shader->source.base.texfmt = TEXCOORDFMT_NOT_PRESENT;
 	shader->source.base.mode = 0;
+	shader->source.base.n_samplers = 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;
+	i915_shader_channel_reset (device, &shader->mask);
+	i915_shader_channel_reset (device, &shader->clip);
     }
 }
 
@@ -2533,7 +2690,6 @@ i915_shader_setup_dst (i915_shader_t *shader)
     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;
@@ -2558,9 +2714,6 @@ i915_shader_setup_dst (i915_shader_t *shader)
     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
@@ -2608,6 +2761,7 @@ i915_composite_vertex (float *v,
 
     *v++ = x; *v++ = y;
     switch (shader->source.type.vertex) {
+    case VS_ZERO:
     case VS_CONSTANT:
 	break;
     case VS_LINEAR:
@@ -2625,6 +2779,7 @@ i915_composite_vertex (float *v,
 	break;
     }
     switch (shader->mask.type.vertex) {
+    case VS_ZERO:
     case VS_CONSTANT:
 	break;
     case VS_LINEAR:
@@ -2659,14 +2814,13 @@ i915_shader_add_rectangle_general (const i915_shader_t *shader,
     /* XXX overflow! */
 }
 
-static cairo_status_t
+void
 i915_vbo_flush (i915_device_t *device)
 {
+    assert (device->floats_per_vertex);
     assert (device->vertex_count);
 
     if (device->vbo == 0) {
-	assert (device->floats_per_vertex);
-
 	OUT_DWORD (_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
 		   I1_LOAD_S (0) |
 		   I1_LOAD_S (1) |
@@ -2684,8 +2838,6 @@ i915_vbo_flush (i915_device_t *device)
 
     device->vertex_index += device->vertex_count;
     device->vertex_count = 0;
-
-    return CAIRO_STATUS_SUCCESS;
 }
 
 cairo_status_t
@@ -2697,9 +2849,20 @@ i915_shader_commit (i915_shader_t *shader,
 
     assert (CAIRO_MUTEX_IS_LOCKED (device->intel.base.base.mutex));
 
-    i915_shader_combine_source (shader, device);
-    i915_shader_combine_mask (shader);
-    i915_shader_setup_dst (shader);
+    if (! shader->committed) {
+	device->shader = shader;
+
+	i915_shader_combine_mask (shader, device);
+	i915_shader_combine_source (shader, device);
+	i915_shader_setup_dst (shader);
+
+	shader->add_rectangle = i915_shader_add_rectangle_general;
+
+	if ((status = setjmp (shader->unwind)))
+	    return status;
+
+	shader->committed = TRUE;
+    }
 
     if (i915_shader_needs_update (shader, device)) {
 	if (i915_batch_space (device) < 256) {
@@ -2708,11 +2871,8 @@ i915_shader_commit (i915_shader_t *shader,
 		return status;
 	}
 
-	if (device->vertex_count) {
-	    status = i915_vbo_flush (device);
-	    if (unlikely (status))
-		return status;
-	}
+	if (device->vertex_count)
+	    i915_vbo_flush (device);
 
 	status = i915_shader_check_aperture (shader, device);
 	if (unlikely (status))
@@ -2726,9 +2886,6 @@ i915_shader_commit (i915_shader_t *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;
@@ -2741,11 +2898,8 @@ i915_shader_commit (i915_shader_t *shader,
 	goto update_shader;
     }
 
-    if (device->vertex_count) {
-	status = i915_vbo_flush (device);
-	if (unlikely (status))
-	    return status;
-    }
+    if (device->vertex_count)
+	i915_vbo_flush (device);
 
     if (device->vbo) {
 	device->batch_base[device->vbo_max_index] |= device->vertex_index;
diff --git a/src/drm/cairo-drm-i915-spans.c b/src/drm/cairo-drm-i915-spans.c
index 99a53d5..b3f4e0a 100644
--- a/src/drm/cairo-drm-i915-spans.c
+++ b/src/drm/cairo-drm-i915-spans.c
@@ -78,8 +78,6 @@ struct _i915_spans {
 	unsigned int count;
     } head, *tail;
 
-    int rectangle_size;
-
     unsigned int vbo_offset;
     float *vbo_base;
 };
@@ -96,12 +94,10 @@ i915_accumulate_rectangle (i915_spans_t *spans)
     float *vertices;
     uint32_t size;
 
-    size = spans->rectangle_size;
+    size = spans->device->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! */
@@ -111,7 +107,9 @@ i915_accumulate_rectangle (i915_spans_t *spans)
 	spans->tail = vbo;
 
 	vbo->next = NULL;
-	vbo->bo = intel_bo_create (&spans->device->intel, I915_VBO_SIZE, FALSE);
+	vbo->bo = intel_bo_create (&spans->device->intel,
+				   I915_VBO_SIZE, I915_VBO_SIZE,
+				   FALSE, I915_TILING_NONE, 0);
 	vbo->count = 0;
 
 	spans->vbo_offset = 0;
@@ -126,6 +124,25 @@ i915_accumulate_rectangle (i915_spans_t *spans)
 }
 
 static void
+i915_span_zero (i915_spans_t *spans,
+		int x0, int x1, int y0, int y1,
+		int alpha)
+{
+    float *vertices;
+
+    vertices = spans->get_rectangle (spans);
+
+    *vertices++ = x1;
+    *vertices++ = y1;
+
+    *vertices++ = x0;
+    *vertices++ = y1;
+
+    *vertices++ = x0;
+    *vertices++ = y0;
+}
+
+static void
 i915_span_constant (i915_spans_t *spans,
 		    int x0, int x1, int y0, int y1,
 		    int alpha)
@@ -264,6 +281,7 @@ i915_span_generic (i915_spans_t *spans,
     *vertices++ = x1; *vertices++ = y1;
     s = x1, t = y1;
     switch (spans->shader.source.type.vertex) {
+    case VS_ZERO:
     case VS_CONSTANT:
 	break;
     case VS_LINEAR:
@@ -294,6 +312,7 @@ i915_span_generic (i915_spans_t *spans,
     *vertices++ = x0; *vertices++ = y1;
     s = x0, t = y1;
     switch (spans->shader.source.type.vertex) {
+    case VS_ZERO:
     case VS_CONSTANT:
 	break;
     case VS_LINEAR:
@@ -324,6 +343,7 @@ i915_span_generic (i915_spans_t *spans,
     *vertices++ = x0; *vertices++ = y0;
     s = x0, t = y0;
     switch (spans->shader.source.type.vertex) {
+    case VS_ZERO:
     case VS_CONSTANT:
 	break;
     case VS_LINEAR:
@@ -352,6 +372,78 @@ i915_span_generic (i915_spans_t *spans,
 }
 
 static cairo_status_t
+i915_zero_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;
+    int x0, x1;
+
+    if (num_spans == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    do {
+	while (num_spans && half[0].coverage < 128)
+	    half++, num_spans--;
+	if (num_spans == 0)
+	    break;
+
+	x0 = x1 = half[0].x;
+	while (num_spans--) {
+	    half++;
+
+	    x1 = half[0].x;
+	    if (half[0].coverage < 128)
+		break;
+	}
+
+	i915_span_zero (spans,
+			x0, x1,
+			y, y + height,
+			0);
+    } while (num_spans);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_zero_spans (void *abstract_renderer,
+		 int y, int height,
+		 const cairo_half_open_span_t *half,
+		 unsigned num_spans)
+{
+    i915_spans_t *spans = abstract_renderer;
+    int x0, x1;
+
+    if (num_spans == 0)
+	return CAIRO_STATUS_SUCCESS;
+
+    do {
+	while (num_spans && half[0].coverage == 0)
+	    half++, num_spans--;
+	if (num_spans == 0)
+	    break;
+
+	x0 = x1 = half[0].x;
+	while (num_spans--) {
+	    half++;
+
+	    x1 = half[0].x;
+	    if (half[0].coverage == 0)
+		break;
+	}
+
+	i915_span_zero (spans,
+			x0, x1,
+			y, y + height,
+			0);
+    } while (num_spans);
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
 i915_bounded_spans_mono (void *abstract_renderer,
 			 int y, int height,
 			 const cairo_half_open_span_t *half,
@@ -491,6 +583,7 @@ i915_spans_init (i915_spans_t *spans,
 		 const cairo_pattern_t *pattern,
 		 cairo_antialias_t antialias,
 		 cairo_clip_t *clip,
+		 double opacity,
 		 const cairo_composite_rectangles_t *extents)
 {
     cairo_status_t status;
@@ -542,7 +635,8 @@ i915_spans_init (i915_spans_t *spans,
 	assert (! extents->is_bounded);
 	spans->get_rectangle = i915_accumulate_rectangle;
 	spans->head.bo = intel_bo_create (&spans->device->intel,
-					  I915_VBO_SIZE, FALSE);
+					  I915_VBO_SIZE, I915_VBO_SIZE,
+					  FALSE, I915_TILING_NONE, 0);
 	if (unlikely (spans->head.bo == NULL))
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
@@ -550,7 +644,7 @@ i915_spans_init (i915_spans_t *spans,
     }
     spans->vbo_offset = 0;
 
-    i915_shader_init (&spans->shader, dst, op);
+    i915_shader_init (&spans->shader, dst, op, opacity);
     if (spans->need_clip_surface)
 	i915_shader_set_clip (&spans->shader, clip);
 
@@ -559,7 +653,6 @@ i915_spans_init (i915_spans_t *spans,
     if (unlikely (status))
 	return status;
 
-    spans->rectangle_size = 3 * (2 + i915_shader_num_texcoords (&spans->shader));
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -568,9 +661,6 @@ i915_spans_fini (i915_spans_t *spans)
 {
     i915_shader_fini (&spans->shader);
 
-    if (spans->tail->bo && spans->tail->bo->virtual)
-	intel_bo_unmap (spans->tail->bo);
-
     if (spans->head.bo != NULL) {
 	struct vbo *vbo, *next;
 
@@ -591,19 +681,25 @@ i915_clip_and_composite_spans (i915_surface_t		*dst,
 			       i915_spans_func_t	 draw_func,
 			       void			*draw_closure,
 			       const cairo_composite_rectangles_t*extents,
-			       cairo_clip_t		*clip)
+			       cairo_clip_t		*clip,
+			       double opacity)
 {
     i915_spans_t spans;
     i915_device_t *device;
     cairo_status_t status;
     struct vbo *vbo;
 
+    if (i915_surface_needs_tiling (dst)) {
+	ASSERT_NOT_REACHED;
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
     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);
+    status = i915_spans_init (&spans, dst, op, pattern, antialias, clip, opacity, extents);
     if (unlikely (status))
 	return status;
 
@@ -615,13 +711,28 @@ i915_clip_and_composite_spans (i915_surface_t		*dst,
     if (unlikely (status))
 	goto CLEANUP_SPANS;
 
+    if (dst->deferred_clear) {
+	status = i915_surface_clear (dst);
+	if (unlikely (status))
+	    goto CLEANUP_SPANS;
+    }
+
     device = i915_device (dst);
     status = i915_shader_commit (&spans.shader, device);
     if (unlikely (status))
 	goto CLEANUP_DEVICE;
 
-    if (!spans.shader.need_combine && ! spans.need_clip_surface) {
+    if (! spans.shader.need_combine && ! spans.need_clip_surface) {
 	switch (spans.shader.source.type.vertex) {
+	case VS_ZERO:
+	    spans.span = i915_span_zero;
+	    if (extents->is_bounded) {
+		if (antialias == CAIRO_ANTIALIAS_NONE)
+		    spans.renderer.render_rows = i915_zero_spans_mono;
+		else
+		    spans.renderer.render_rows = i915_zero_spans;
+	    }
+	    break;
 	case VS_CONSTANT:
 	    spans.span = i915_span_constant;
 	    break;
@@ -644,8 +755,6 @@ i915_clip_and_composite_spans (i915_surface_t		*dst,
 
     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);
@@ -656,7 +765,8 @@ i915_clip_and_composite_spans (i915_surface_t		*dst,
 
 	    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);
+				   I915_GEM_DOMAIN_VERTEX, 0,
+				   FALSE);
 	    OUT_DWORD ((device->floats_per_vertex << S1_VERTEX_WIDTH_SHIFT) |
 		       (device->floats_per_vertex << S1_VERTEX_PITCH_SHIFT) |
 		       vbo->count);
diff --git a/src/drm/cairo-drm-i915-surface.c b/src/drm/cairo-drm-i915-surface.c
index 5e04982..b9adf92 100644
--- a/src/drm/cairo-drm-i915-surface.c
+++ b/src/drm/cairo-drm-i915-surface.c
@@ -114,16 +114,6 @@
 #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,
@@ -189,8 +179,6 @@ static const uint32_t i915_batch_setup[] = {
 
 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);
@@ -228,64 +216,85 @@ i915_bo_exec (i915_device_t *device, intel_bo_t *bo, uint32_t offset)
     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;
+    if (device->debug & I915_DEBUG_SYNC && ret == 0)
+	ret = ! intel_bo_wait (&device->intel, bo);
+
+    if (0 && ret) {
+	int n, m;
 
 	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, "   gtt size: (%zd/%zd), (%zd/%zd)\n",
+		 device->batch.est_gtt_size, device->batch.gtt_avail_size,
+		 device->batch.total_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);
+	for (n = 0; n < device->batch.exec_count; n++) {
+	    fprintf (stderr, "  exec[%d] = %d, %d/%d bytes, gtt = %qx\n",
+		    n,
+		    device->batch.exec[n].handle,
+		    n == device->batch.exec_count - 1 ? bo->base.size : device->batch.target_bo[n]->base.size,
+		    n == device->batch.exec_count - 1 ? bo->full_size : device->batch.target_bo[n]->full_size,
+		    device->batch.exec[n].offset);
+	}
+	for (n = 0; n < device->batch.reloc_count; n++) {
+	    for (m = 0; m < device->batch.exec_count; m++)
+		if (device->batch.exec[m].handle == device->batch.reloc[n].target_handle)
+		    break;
+
+	    fprintf (stderr, "  reloc[%d] = %d @ %qx -> %qx + %qx\n", n,
+		     device->batch.reloc[n].target_handle,
+		     device->batch.reloc[n].offset,
+		     (unsigned long long) device->batch.exec[m].offset,
+		     (unsigned long long) device->batch.reloc[n].delta);
+
+	    device->batch_base[(device->batch.reloc[n].offset - sizeof (device->batch_header)) / 4] =
+		device->batch.exec[m].offset + device->batch.reloc[n].delta;
 	}
 
 	intel_dump_batchbuffer (device->batch_header,
 				execbuf.batch_len,
 				device->intel.base.chip_id);
     }
+    assert (ret == 0);
 
     VG (VALGRIND_MAKE_MEM_DEFINED (device->batch.exec, sizeof (device->batch.exec[0]) * i));
 
     bo->offset = device->batch.exec[i].offset;
+    bo->busy = TRUE;
+    if (bo->virtual)
+	intel_bo_unmap (bo);
+    bo->cpu = FALSE;
+
     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]);
+	intel_bo_t *bo = device->batch.target_bo[cnt];
+
+	bo->offset = device->batch.exec[cnt].offset;
+	bo->exec = NULL;
+	bo->busy = TRUE;
+	bo->batch_read_domains = 0;
+	bo->batch_write_domain = 0;
+	cairo_list_del (&bo->cache_list);
+
+	if (bo->virtual)
+	    intel_bo_unmap (bo);
+	bo->cpu = FALSE;
+
+	intel_bo_destroy (&device->intel, bo);
     }
+    assert (cairo_list_is_empty (&device->intel.bo_in_flight));
 
     device->batch.exec_count = 0;
     device->batch.reloc_count = 0;
+    device->batch.fences = 0;
 
-    device->batch.gtt_size = I915_BATCH_SIZE;
+    device->batch.est_gtt_size = I915_BATCH_SIZE;
+    device->batch.total_gtt_size = I915_BATCH_SIZE;
 
     return ret == 0 ? CAIRO_STATUS_SUCCESS : _cairo_error (CAIRO_STATUS_NO_MEMORY);
 }
@@ -296,12 +305,20 @@ i915_batch_add_reloc (i915_device_t *device,
 		      intel_bo_t *bo,
 		      uint32_t offset,
 		      uint32_t read_domains,
-		      uint32_t write_domain)
+		      uint32_t write_domain,
+		      cairo_bool_t needs_fence)
 {
     int index;
 
+    assert (offset < bo->base.size);
+
     if (bo->exec == NULL) {
-	device->batch.gtt_size += bo->base.size;
+	device->batch.total_gtt_size += bo->base.size;
+
+	if (! bo->busy)
+	    device->batch.est_gtt_size += bo->base.size;
+
+	assert (device->batch.exec_count < ARRAY_LENGTH (device->batch.exec));
 
 	index = device->batch.exec_count++;
 	device->batch.exec[index].handle = bo->base.handle;
@@ -318,6 +335,31 @@ i915_batch_add_reloc (i915_device_t *device,
 	bo->exec = &device->batch.exec[index];
     }
 
+    if (bo->tiling != I915_TILING_NONE) {
+	uint32_t alignment;
+
+#if 0
+	/* We presume that we will want to use a fence with X tiled objects... */
+	if (needs_fence || bo->tiling == I915_TILING_X)
+	    alignment = bo->full_size;
+	else
+	    alignment = 2*((bo->stride + 4095) & -4096);
+#else
+	alignment = bo->full_size;
+#endif
+	if (bo->exec->alignment < alignment)
+	    bo->exec->alignment = alignment;
+
+	if (needs_fence && (bo->exec->flags & EXEC_OBJECT_NEEDS_FENCE) == 0) {
+	    bo->exec->flags |= EXEC_OBJECT_NEEDS_FENCE;
+	    device->batch.fences++;
+
+	    intel_bo_set_tiling (&device->intel, bo);
+	}
+    }
+
+    assert (device->batch.reloc_count < ARRAY_LENGTH (device->batch.reloc));
+
     index = device->batch.reloc_count++;
     device->batch.reloc[index].offset = (pos << 2) + sizeof (device->batch_header);
     device->batch.reloc[index].delta = offset;
@@ -334,20 +376,124 @@ i915_batch_add_reloc (i915_device_t *device,
 void
 i915_vbo_finish (i915_device_t *device)
 {
+    intel_bo_t *vbo;
+
     assert (CAIRO_MUTEX_IS_LOCKED (device->intel.base.base.mutex));
+    assert (device->vbo_used);
+
+    if (device->vertex_count) {
+	if (device->vbo == 0) {
+	    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 (device->last_vbo != NULL) {
+	intel_bo_in_flight_add (&device->intel, device->last_vbo);
+	intel_bo_destroy (&device->intel, device->last_vbo);
+    }
 
-    if (device->vbo_used == 0)
-	return;
+    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, device->vbo_used,
+			   FALSE, I915_TILING_NONE, 0);
+    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;
+
+    device->vbo_used = device->vbo_offset = 0;
+    device->vertex_index = device->vertex_count = 0;
+
+    if (! i915_check_aperture_size (device, 1, I915_VBO_SIZE, I915_VBO_SIZE)) {
+	cairo_status_t status;
+
+	status = i915_batch_flush (device);
+	if (unlikely (status))
+	    longjmp (device->shader->unwind, status);
+
+	status = i915_shader_commit (device->shader, device);
+	if (unlikely (status))
+	    longjmp (device->shader->unwind, status);
+    }
+}
+
+/* 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_texcoords = ~0;
+    device->current_blend = 0;
+    device->current_n_constants = 0;
+    device->current_n_samplers = 0;
+    device->current_n_maps = 0;
+    device->current_colorbuf = 0;
+    device->current_diffuse = 0;
+    device->current_program = ~0;
+    device->clear_alpha = ~0;
+
+    device->last_source_fragment = ~0;
+}
+
+static void
+i915_batch_cleanup (i915_device_t *device)
+{
+    int i;
+
+    for (i = 0; i < device->batch.exec_count; i++) {
+	intel_bo_t *bo = device->batch.target_bo[i];
+
+	bo->exec = NULL;
+	bo->batch_read_domains = 0;
+	bo->batch_write_domain = 0;
+	cairo_list_del (&bo->cache_list);
+
+	intel_bo_destroy (&device->intel, bo);
+    }
+
+    device->batch.exec_count = 0;
+    device->batch.reloc_count = 0;
+}
+
+static void
+i915_batch_vbo_finish (i915_device_t *device)
+{
+    assert (CAIRO_MUTEX_IS_LOCKED (device->intel.base.base.mutex));
 
     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) |
@@ -355,7 +501,7 @@ i915_vbo_finish (i915_device_t *device)
 		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));
+			(device->floats_per_vertex << S1_VERTEX_PITCH_SHIFT));
 	    }
 
 	    OUT_DWORD (PRIM3D_RECTLIST |
@@ -364,18 +510,15 @@ i915_vbo_finish (i915_device_t *device)
 	    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);
+	vbo = intel_bo_create (&device->intel,
+			       device->vbo_used, device->vbo_used,
+			       FALSE, I915_TILING_NONE, 0);
 	i915_batch_fill_reloc (device, device->vbo,
 			       vbo, 0,
 			       I915_GEM_DOMAIN_VERTEX, 0);
@@ -399,48 +542,6 @@ i915_vbo_finish (i915_device_t *device)
     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)
 {
@@ -451,7 +552,8 @@ i915_batch_flush (i915_device_t *device)
 
     assert (CAIRO_MUTEX_IS_LOCKED (device->intel.base.base.mutex));
 
-    i915_vbo_finish (device);
+    if (device->vbo_used)
+	i915_batch_vbo_finish (device);
 
     if (device->batch.used == 0)
 	return CAIRO_STATUS_SUCCESS;
@@ -462,20 +564,12 @@ i915_batch_flush (i915_device_t *device)
 
     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;
 
@@ -487,10 +581,9 @@ i915_batch_flush (i915_device_t *device)
 	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);
+	batch = intel_bo_create (&device->intel,
+				 length, length,
+				 FALSE, I915_TILING_NONE, 0);
 	if (unlikely (batch == NULL)) {
 	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	    i915_batch_cleanup (device);
@@ -501,10 +594,6 @@ i915_batch_flush (i915_device_t *device)
     }
     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:
@@ -543,14 +632,44 @@ i915_add_rectangles (i915_device_t *device, int num_rects, int *count)
 }
 #endif
 
+static cairo_surface_t *
+i915_surface_create_similar (void *abstract_other,
+			     cairo_content_t content,
+			     int width, int height)
+{
+    i915_surface_t *other;
+    cairo_format_t format;
+    uint32_t tiling = I915_TILING_DEFAULT;
+
+    other = abstract_other;
+    if (content == other->intel.drm.base.content)
+	format = other->intel.drm.format;
+    else
+	format = _cairo_format_from_content (content);
+
+    if (width * _cairo_format_bits_per_pixel (format) > 8 * 32*1024 || height > 64*1024)
+	return NULL;
+
+    /* we presume that a similar surface will be used for blitting */
+    if (i915_surface_needs_tiling (other))
+	tiling = I915_TILING_X;
+
+    return i915_surface_create_internal ((cairo_drm_device_t *) other->intel.drm.base.device,
+					 format,
+					 width, height,
+					 tiling, TRUE);
+}
+
 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)
+    if (surface->stencil != NULL) {
+	intel_bo_in_flight_add (&device->intel, surface->stencil);
 	intel_bo_destroy (&device->intel, surface->stencil);
+    }
 
     if (surface->is_current_texture) {
 	if (surface->is_current_texture & CURRENT_SOURCE)
@@ -570,6 +689,7 @@ i915_surface_finish (void *abstract_surface)
 	intel_buffer_cache_t *cache = node->container;
 
 	if (--cache->ref_count == 0) {
+	    intel_bo_in_flight_add (&device->intel, cache->buffer.bo);
 	    intel_bo_destroy (&device->intel, cache->buffer.bo);
 	    _cairo_rtree_fini (&cache->rtree);
 	    cairo_list_del (&cache->link);
@@ -581,7 +701,7 @@ i915_surface_finish (void *abstract_surface)
 	}
     }
 
-    return _cairo_drm_surface_finish (&surface->intel.drm);
+    return intel_surface_finish (&surface->intel);
 }
 
 static cairo_status_t
@@ -610,6 +730,7 @@ static cairo_status_t
 i915_surface_flush (void *abstract_surface)
 {
     i915_surface_t *surface = abstract_surface;
+    cairo_status_t status;
 
     if (surface->intel.drm.fallback == NULL) {
 	if (surface->intel.drm.base.finished) {
@@ -617,6 +738,12 @@ i915_surface_flush (void *abstract_surface)
 	    return CAIRO_STATUS_SUCCESS;
 	}
 
+	if (surface->deferred_clear) {
+	    status = i915_surface_clear (surface);
+	    if (unlikely (status))
+		return status;
+	}
+
 	return i915_surface_batch_flush (surface);
     }
 
@@ -666,7 +793,7 @@ i915_fixup_unbounded (i915_surface_t *dst,
 	cairo_region_t *clip_region = NULL;
 
 	status = _cairo_clip_get_region (clip, &clip_region);
-	assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+	assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
 	assert (clip_region == NULL);
 
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
@@ -680,7 +807,7 @@ i915_fixup_unbounded (i915_surface_t *dst,
     }
 
     if (clip != NULL) {
-	i915_shader_init (&shader, dst, CAIRO_OPERATOR_DEST_OVER);
+	i915_shader_init (&shader, dst, CAIRO_OPERATOR_DEST_OVER, 1.);
 	i915_shader_set_clip (&shader, clip);
 	status = i915_shader_acquire_pattern (&shader,
 					      &shader.source,
@@ -688,7 +815,7 @@ i915_fixup_unbounded (i915_surface_t *dst,
 					      &extents->unbounded);
 	assert (status == CAIRO_STATUS_SUCCESS);
     } else {
-	i915_shader_init (&shader, dst, CAIRO_OPERATOR_CLEAR);
+	i915_shader_init (&shader, dst, CAIRO_OPERATOR_CLEAR, 1.);
 	status = i915_shader_acquire_pattern (&shader,
 					      &shader.source,
 					      &_cairo_pattern_clear.base,
@@ -780,7 +907,7 @@ i915_fixup_unbounded_boxes (i915_surface_t *dst,
 
     if (clip != NULL) {
 	status = _cairo_clip_get_region (clip, &clip_region);
-	assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+	assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
 	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	    clip = NULL;
     }
@@ -830,7 +957,7 @@ i915_fixup_unbounded_boxes (i915_surface_t *dst,
 	i915_device_t *device;
 
 	if (clip != NULL) {
-	    i915_shader_init (&shader, dst, CAIRO_OPERATOR_DEST_OVER);
+	    i915_shader_init (&shader, dst, CAIRO_OPERATOR_DEST_OVER, 1.);
 	    i915_shader_set_clip (&shader, clip);
 	    status = i915_shader_acquire_pattern (&shader,
 						  &shader.source,
@@ -838,7 +965,7 @@ i915_fixup_unbounded_boxes (i915_surface_t *dst,
 						  &extents->unbounded);
 	    assert (status == CAIRO_STATUS_SUCCESS);
 	} else {
-	    i915_shader_init (&shader, dst, CAIRO_OPERATOR_CLEAR);
+	    i915_shader_init (&shader, dst, CAIRO_OPERATOR_CLEAR, 1.);
 	    status = i915_shader_acquire_pattern (&shader,
 						  &shader.source,
 						  &_cairo_pattern_clear.base,
@@ -876,6 +1003,573 @@ err_shader:
     return status;
 }
 
+static cairo_bool_t
+i915_can_blt (i915_surface_t *dst,
+	      const cairo_pattern_t *pattern)
+{
+    const cairo_surface_pattern_t *spattern;
+    i915_surface_t *src;
+
+    spattern = (const cairo_surface_pattern_t *) pattern;
+    src = (i915_surface_t *) spattern->surface;
+
+    if (src->intel.drm.base.device != dst->intel.drm.base.device)
+	return FALSE;
+
+    if (! i915_surface_needs_tiling (dst))
+	return FALSE;
+
+    if (! _cairo_matrix_is_translation (&pattern->matrix))
+	return FALSE;
+
+    if (! (pattern->filter == CAIRO_FILTER_NEAREST ||
+	   pattern->filter == CAIRO_FILTER_FAST))
+    {
+	if (! _cairo_fixed_is_integer (_cairo_fixed_from_double (pattern->matrix.x0)) ||
+	    ! _cairo_fixed_is_integer (_cairo_fixed_from_double (pattern->matrix.y0)))
+	{
+	    return FALSE;
+	}
+    }
+
+    return _cairo_format_bits_per_pixel (src->intel.drm.format) ==
+	_cairo_format_bits_per_pixel (dst->intel.drm.format);
+}
+
+static cairo_status_t
+i915_blt (i915_surface_t *src,
+	  i915_surface_t *dst,
+	  int src_x, int src_y,
+	  int width, int height,
+	  int dst_x, int dst_y,
+	  cairo_bool_t flush)
+{
+    i915_device_t *device;
+    intel_bo_t *bo_array[2];
+    cairo_status_t status;
+    int br13, cmd;
+
+    bo_array[0] = to_intel_bo (dst->intel.drm.bo);
+    bo_array[1] = to_intel_bo (src->intel.drm.bo);
+
+    status = i915_surface_fallback_flush (src);
+    if (unlikely (status))
+	return status;
+
+    device = i915_device (dst);
+    status = cairo_device_acquire (&device->intel.base.base);
+    if (unlikely (status))
+	return status;
+
+    if (! i915_check_aperture_and_fences (device, bo_array, 2) ||
+	i915_batch_space (device) < 9)
+    {
+	status = i915_batch_flush (device);
+	if (unlikely (status))
+	    goto CLEANUP;
+    }
+
+    cmd = XY_SRC_COPY_BLT_CMD;
+    br13 = (0xCC << 16) | dst->intel.drm.stride;
+    switch (dst->intel.drm.format) {
+    default:
+    case CAIRO_FORMAT_INVALID:
+    case CAIRO_FORMAT_A1:
+	ASSERT_NOT_REACHED;
+    case CAIRO_FORMAT_A8:
+	break;
+    case CAIRO_FORMAT_RGB16_565:
+	br13 |= BR13_565;
+	break;
+    case CAIRO_FORMAT_RGB24:
+    case CAIRO_FORMAT_ARGB32:
+	br13 |= BR13_8888;
+	cmd |= XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
+	break;
+    }
+
+    OUT_DWORD (cmd);
+    OUT_DWORD (br13);
+    OUT_DWORD ((dst_y << 16) | dst_x);
+    OUT_DWORD (((dst_y + height) << 16) | (dst_x + width));
+    OUT_RELOC_FENCED (dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+    OUT_DWORD ((src_y << 16) | src_x);
+    OUT_DWORD (src->intel.drm.stride);
+    OUT_RELOC_FENCED (src, I915_GEM_DOMAIN_RENDER, 0);
+    /* require explicit RenderCache flush for 2D -> 3D sampler? */
+    if (flush)
+	OUT_DWORD (MI_FLUSH);
+
+CLEANUP:
+    cairo_device_release (&device->intel.base.base);
+    return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+i915_surface_copy_subimage (i915_device_t *device,
+			    i915_surface_t *src,
+			    const cairo_rectangle_int_t *extents,
+			    cairo_bool_t flush,
+			    i915_surface_t **clone_out)
+{
+    i915_surface_t *clone;
+    cairo_status_t status;
+
+    clone = (i915_surface_t *)
+	i915_surface_create_internal (&device->intel.base,
+				      src->intel.drm.format,
+				      extents->width,
+				      extents->height,
+				      I915_TILING_X, TRUE);
+    if (unlikely (clone->intel.drm.base.status))
+	return clone->intel.drm.base.status;
+
+    status = i915_blt (src, clone,
+		       extents->x, extents->y,
+		       extents->width, extents->height,
+		       0, 0,
+		       flush);
+
+    if (unlikely (status)) {
+	cairo_surface_destroy (&clone->intel.drm.base);
+	return status;
+    }
+
+    *clone_out = clone;
+    return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+i915_clear_boxes (i915_surface_t *dst,
+		  const cairo_boxes_t *boxes)
+{
+    i915_device_t *device = i915_device (dst);
+    const struct _cairo_boxes_chunk *chunk;
+    cairo_status_t status;
+    intel_bo_t *bo_array[1] = { to_intel_bo (dst->intel.drm.bo) };
+    int cmd, br13, clear = 0, i;
+
+    cmd = XY_COLOR_BLT_CMD;
+    br13 = (0xCC << 16) | dst->intel.drm.stride;
+    switch (dst->intel.drm.format) {
+    default:
+    case CAIRO_FORMAT_INVALID:
+    case CAIRO_FORMAT_A1:
+	ASSERT_NOT_REACHED;
+    case CAIRO_FORMAT_A8:
+	break;
+    case CAIRO_FORMAT_RGB16_565:
+	br13 |= BR13_565;
+	break;
+    case CAIRO_FORMAT_RGB24:
+	clear = 0xff000000;
+    case CAIRO_FORMAT_ARGB32:
+	br13 |= BR13_8888;
+	cmd |= XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
+	break;
+    }
+
+    status = cairo_device_acquire (&device->intel.base.base);
+    if (unlikely (status))
+	return status;
+
+    if (! i915_check_aperture_and_fences (device, bo_array, 1) ||
+	i915_batch_space (device) < 6 * boxes->num_boxes)
+    {
+	status = i915_batch_flush (device);
+	if (unlikely (status))
+	    goto RELEASE;
+    }
+
+    if (device->vertex_count)
+	i915_vbo_flush (device);
+
+    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	const cairo_box_t *box = chunk->base;
+	for (i = 0; i < chunk->count; i++) {
+	    int x1 = _cairo_fixed_integer_round (box[i].p1.x);
+	    int x2 = _cairo_fixed_integer_round (box[i].p2.x);
+	    int y1 = _cairo_fixed_integer_round (box[i].p1.y);
+	    int y2 = _cairo_fixed_integer_round (box[i].p2.y);
+
+	    if (x2 <= x1 || y2 <= y1)
+		continue;
+
+	    OUT_DWORD (cmd);
+	    OUT_DWORD (br13);
+	    OUT_DWORD ((y1 << 16) | x1);
+	    OUT_DWORD ((y2 << 16) | x2);
+	    OUT_RELOC_FENCED (dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+	    OUT_DWORD (clear);
+	}
+    }
+
+RELEASE:
+    cairo_device_release (&device->intel.base.base);
+    return status;
+}
+
+static cairo_status_t
+i915_surface_extract_X_from_Y (i915_device_t *device,
+			       i915_surface_t *src,
+			       const cairo_rectangle_int_t *extents,
+			       i915_surface_t **clone_out)
+{
+    i915_surface_t *clone;
+    i915_shader_t shader;
+    cairo_surface_pattern_t pattern;
+    cairo_rectangle_int_t rect;
+    cairo_status_t status;
+
+    status = i915_surface_fallback_flush (src);
+    if (unlikely (status))
+	return status;
+
+    clone = (i915_surface_t *)
+	i915_surface_create_internal (&device->intel.base,
+				      src->intel.drm.format,
+				      extents->width,
+				      extents->height,
+				      I915_TILING_X, TRUE);
+    if (unlikely (clone->intel.drm.base.status))
+	return clone->intel.drm.base.status;
+
+    i915_shader_init (&shader, clone, CAIRO_OPERATOR_SOURCE, 1.);
+
+    _cairo_pattern_init_for_surface (&pattern, &src->intel.drm.base);
+    pattern.base.filter = CAIRO_FILTER_NEAREST;
+    cairo_matrix_init_translate (&pattern.base.matrix, extents->x, extents->y);
+
+    rect.x = rect.y = 0;
+    rect.width = extents->width;
+    rect.height = extents->height;
+    status = i915_shader_acquire_pattern (&shader, &shader.source, &pattern.base, &rect);
+    _cairo_pattern_fini (&pattern.base);
+
+    if (unlikely (status))
+	goto err_shader;
+
+    status = cairo_device_acquire (&device->intel.base.base);
+    if (unlikely (status))
+	goto err_shader;
+
+    status = i915_shader_commit (&shader, device);
+    if (unlikely (status))
+	goto err_device;
+
+    shader.add_rectangle (&shader, 0, 0, extents->width, extents->height);
+
+    cairo_device_release (&device->intel.base.base);
+    i915_shader_fini (&shader);
+
+    *clone_out = clone;
+    return CAIRO_STATUS_SUCCESS;
+
+err_device:
+    cairo_device_release (&device->intel.base.base);
+err_shader:
+    i915_shader_fini (&shader);
+    cairo_surface_destroy (&clone->intel.drm.base);
+    return status;
+}
+
+static cairo_status_t
+i915_blt_boxes (i915_surface_t *dst,
+		const cairo_pattern_t *pattern,
+		const cairo_rectangle_int_t *extents,
+		const cairo_boxes_t *boxes)
+{
+    const cairo_surface_pattern_t *spattern;
+    i915_device_t *device;
+    i915_surface_t *src;
+    cairo_surface_t *free_me = NULL;
+    const struct _cairo_boxes_chunk *chunk;
+    cairo_status_t status;
+    int br13, cmd, tx, ty;
+    intel_bo_t *bo_array[2];
+    int i;
+
+    if (! i915_can_blt (dst, pattern))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    spattern = (const cairo_surface_pattern_t *) pattern;
+    src = (i915_surface_t *) spattern->surface;
+
+    if (src->intel.drm.base.is_clear)
+	return i915_clear_boxes (dst, boxes);
+
+    if (pattern->extend != CAIRO_EXTEND_NONE &&
+	(extents->x + tx < 0 ||
+	 extents->y + ty < 0 ||
+	 extents->x + tx + extents->width  > src->intel.drm.width ||
+	 extents->y + ty + extents->height > src->intel.drm.height))
+    {
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    status = i915_surface_fallback_flush (src);
+    if (unlikely (status))
+	return status;
+
+    tx = _cairo_lround (pattern->matrix.x0);
+    ty = _cairo_lround (pattern->matrix.y0);
+
+    device = i915_device (dst);
+    if (to_intel_bo (src->intel.drm.bo)->tiling == I915_TILING_Y) {
+	cairo_rectangle_int_t extents;
+
+	_cairo_boxes_extents (boxes, &extents);
+	extents.x += tx;
+	extents.y += ty;
+
+	status = i915_surface_extract_X_from_Y (device, src, &extents, &src);
+	if (unlikely (status))
+	    return status;
+
+	free_me = &src->intel.drm.base;
+	tx = -extents.x;
+	ty = -extents.y;
+    }
+
+    bo_array[0] = to_intel_bo (dst->intel.drm.bo);
+    bo_array[1] = to_intel_bo (src->intel.drm.bo);
+
+    status = cairo_device_acquire (&device->intel.base.base);
+    if (unlikely (status))
+	goto CLEANUP_SURFACE;
+
+    if (! i915_check_aperture_and_fences (device, bo_array, 2) ||
+	i915_batch_space (device) < 8 * boxes->num_boxes)
+    {
+	status = i915_batch_flush (device);
+	if (unlikely (status))
+	    goto CLEANUP_DEVICE;
+    }
+
+    cmd = XY_SRC_COPY_BLT_CMD;
+    br13 = (0xCC << 16) | dst->intel.drm.stride;
+    switch (dst->intel.drm.format) {
+    default:
+    case CAIRO_FORMAT_INVALID:
+    case CAIRO_FORMAT_A1:
+	ASSERT_NOT_REACHED;
+    case CAIRO_FORMAT_A8:
+	break;
+    case CAIRO_FORMAT_RGB16_565:
+	br13 |= BR13_565;
+	break;
+    case CAIRO_FORMAT_RGB24:
+    case CAIRO_FORMAT_ARGB32:
+	br13 |= BR13_8888;
+	cmd |= XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
+	break;
+    }
+
+    for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) {
+	const cairo_box_t *box = chunk->base;
+	for (i = 0; i < chunk->count; i++) {
+	    int x1 = _cairo_fixed_integer_round (box[i].p1.x);
+	    int x2 = _cairo_fixed_integer_round (box[i].p2.x);
+	    int y1 = _cairo_fixed_integer_round (box[i].p1.y);
+	    int y2 = _cairo_fixed_integer_round (box[i].p2.y);
+
+	    if (x1 + tx < 0)
+		x1 = -tx;
+	    if (x2 + tx > src->intel.drm.width)
+		x2 = src->intel.drm.width - tx;
+
+	    if (y1 + ty < 0)
+		y1 = -ty;
+	    if (y2 + ty > src->intel.drm.height)
+		y2 = src->intel.drm.height - ty;
+
+	    if (x2 <= x1 || y2 <= y1)
+		continue;
+	    if (x2 < 0 || y2 < 0)
+		continue;
+	    if (x1 >= dst->intel.drm.width || y2 >= dst->intel.drm.height)
+		continue;
+
+	    OUT_DWORD (cmd);
+	    OUT_DWORD (br13);
+	    OUT_DWORD ((y1 << 16) | x1);
+	    OUT_DWORD ((y2 << 16) | x2);
+	    OUT_RELOC_FENCED (dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+	    OUT_DWORD (((y1 + ty) << 16) | (x1 + tx));
+	    OUT_DWORD (src->intel.drm.stride);
+	    OUT_RELOC_FENCED (src, I915_GEM_DOMAIN_RENDER, 0);
+	}
+    }
+
+    /* XXX fixup blank portions */
+
+CLEANUP_DEVICE:
+    cairo_device_release (&device->intel.base.base);
+CLEANUP_SURFACE:
+    cairo_surface_destroy (free_me);
+    return status;
+}
+
+static cairo_status_t
+_upload_image_inplace (i915_surface_t *surface,
+		       const cairo_pattern_t *source,
+		       const cairo_rectangle_int_t *extents,
+		       const cairo_boxes_t *boxes)
+{
+    i915_device_t *device;
+    const cairo_surface_pattern_t *pattern;
+    cairo_image_surface_t *image;
+    const struct _cairo_boxes_chunk *chunk;
+    intel_bo_t *bo;
+    int tx, ty, i;
+
+    if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    pattern = (const cairo_surface_pattern_t *) source;
+    if (pattern->surface->type != CAIRO_SURFACE_TYPE_IMAGE)
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty))
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+
+    image = (cairo_image_surface_t *) pattern->surface;
+    if (source->extend != CAIRO_EXTEND_NONE &&
+	(extents->x + tx < 0 ||
+	 extents->y + ty < 0 ||
+	 extents->x + tx + extents->width  > image->width ||
+	 extents->y + ty + extents->height > image->height))
+    {
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    device = i915_device (surface);
+    bo = to_intel_bo (surface->intel.drm.bo);
+    if (bo->exec != NULL || ! intel_bo_is_inactive (&device->intel, bo)) {
+	intel_bo_t *new_bo;
+	cairo_bool_t need_clear = FALSE;
+
+	if (boxes->num_boxes != 1 ||
+	    extents->width < surface->intel.drm.width ||
+	    extents->height < surface->intel.drm.height)
+	{
+	    if (! surface->intel.drm.base.is_clear)
+		return CAIRO_INT_STATUS_UNSUPPORTED;
+
+	    need_clear = TRUE;
+	}
+
+	new_bo = intel_bo_create (&device->intel,
+				  bo->full_size, bo->base.size,
+				  FALSE, bo->tiling, bo->stride);
+	if (unlikely (new_bo == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+	intel_bo_in_flight_add (&device->intel, bo);
+	intel_bo_destroy (&device->intel, bo);
+
+	bo = new_bo;
+	surface->intel.drm.bo = &bo->base;
+
+	if (need_clear) {
+	    memset (intel_bo_map (&device->intel, bo), 0,
+		    bo->stride * surface->intel.drm.height);
+	}
+    }
+
+    if (image->format == surface->intel.drm.format) {
+	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 x2 = _cairo_fixed_integer_round (box[i].p2.x);
+		int y1 = _cairo_fixed_integer_round (box[i].p1.y);
+		int y2 = _cairo_fixed_integer_round (box[i].p2.y);
+		cairo_status_t status;
+
+		if (x1 + tx < 0)
+		    x1 = -tx;
+		if (x2 + tx > image->width)
+		    x2 = image->width - tx;
+
+		if (y1 + ty < 0)
+		    y1 = -ty;
+		if (y2 + ty > image->height)
+		    y2 = image->height - ty;
+
+		if (x2 <= x1 || y2 <= y1)
+		    continue;
+		if (x2 < 0 || y2 < 0)
+		    continue;
+		if (x1 >= surface->intel.drm.width || y2 >= surface->intel.drm.height)
+		    continue;
+
+		status = intel_bo_put_image (&device->intel,
+					     bo,
+					     image,
+					     x1 + tx, y1 + ty,
+					     x2 - x1, y2 - y1,
+					     x1, y1);
+		if (unlikely (status))
+		    return status;
+	    }
+	}
+    } else {
+	pixman_image_t *dst;
+	void *ptr;
+
+	ptr = intel_bo_map (&device->intel, bo);
+	if (unlikely (ptr == NULL))
+	    return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
+
+	dst = pixman_image_create_bits (_cairo_format_to_pixman_format_code (surface->intel.drm.format),
+					surface->intel.drm.width,
+					surface->intel.drm.height,
+					ptr,
+					surface->intel.drm.stride);
+	if (unlikely (dst == NULL))
+	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+
+	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 x2 = _cairo_fixed_integer_round (box[i].p2.x);
+		int y1 = _cairo_fixed_integer_round (box[i].p1.y);
+		int y2 = _cairo_fixed_integer_round (box[i].p2.y);
+
+		if (x1 + tx < 0)
+		    x1 = -tx;
+		if (x2 + tx > image->width)
+		    x2 = image->width - tx;
+
+		if (y1 + ty < 0)
+		    y1 = -ty;
+		if (y2 + ty > image->height)
+		    y2 = image->height - ty;
+
+		if (x2 <= x1 || y2 <= y1)
+		    continue;
+		if (x2 < 0 || y2 < 0)
+		    continue;
+		if (x1 >= surface->intel.drm.width || y2 >= surface->intel.drm.height)
+		    continue;
+
+		pixman_image_composite32 (PIXMAN_OP_SRC,
+					  image->pixman_image, NULL, dst,
+					  x1 + tx, y1 + ty,
+					  0, 0,
+					  x1, y1,
+					  x2 - x1, y2 - y1);
+	    }
+	}
+
+	pixman_image_unref (dst);
+    }
+
+    return CAIRO_STATUS_SUCCESS;
+}
+
 static cairo_status_t
 _composite_boxes (i915_surface_t *dst,
 		  cairo_operator_t op,
@@ -883,6 +1577,7 @@ _composite_boxes (i915_surface_t *dst,
 		  cairo_boxes_t *boxes,
 		  cairo_antialias_t antialias,
 		  cairo_clip_t *clip,
+		  double opacity,
 		  const cairo_composite_rectangles_t *extents)
 {
     cairo_bool_t need_clip_surface = FALSE;
@@ -899,7 +1594,24 @@ _composite_boxes (i915_surface_t *dst,
 	    return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
-    i915_shader_init (&shader, dst, op);
+    if (clip == NULL && op == CAIRO_OPERATOR_SOURCE && opacity == 1.) {
+	if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	    status = i915_blt_boxes (dst, pattern, &extents->bounded, boxes);
+	    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
+		status = _upload_image_inplace (dst, pattern,
+						&extents->bounded, boxes);
+	    }
+	    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+		return status;
+	}
+    }
+
+    if (i915_surface_needs_tiling (dst)) {
+	ASSERT_NOT_REACHED;
+	return CAIRO_INT_STATUS_UNSUPPORTED;
+    }
+
+    i915_shader_init (&shader, dst, op, opacity);
 
     status = i915_shader_acquire_pattern (&shader,
 					  &shader.source,
@@ -910,7 +1622,7 @@ _composite_boxes (i915_surface_t *dst,
 
     if (clip != NULL) {
 	status = _cairo_clip_get_region (clip, &clip_region);
-	assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+	assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);
 	need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
 	if (need_clip_surface)
 	    i915_shader_set_clip (&shader, clip);
@@ -949,6 +1661,113 @@ _composite_boxes (i915_surface_t *dst,
     return status;
 }
 
+cairo_status_t
+i915_surface_clear (i915_surface_t *dst)
+{
+    i915_device_t *device;
+    cairo_status_t status;
+    intel_bo_t *bo_array[1] = { to_intel_bo (dst->intel.drm.bo) };
+
+    device = i915_device (dst);
+    status = cairo_device_acquire (&device->intel.base.base);
+    if (unlikely (status))
+	return status;
+
+    if (i915_surface_needs_tiling (dst)) {
+	int cmd, br13, clear = 0;
+
+	if (! i915_check_aperture_and_fences (device, bo_array, 1) ||
+	    i915_batch_space (device) < 6)
+	{
+	    status = i915_batch_flush (device);
+	    if (unlikely (status)) {
+		cairo_device_release (&device->intel.base.base);
+		return status;
+	    }
+	}
+
+	if (device->vertex_count)
+	    i915_vbo_flush (device);
+
+	cmd = XY_COLOR_BLT_CMD;
+	br13 = (0xCC << 16) | dst->intel.drm.stride;
+	switch (dst->intel.drm.format) {
+	default:
+	case CAIRO_FORMAT_INVALID:
+	case CAIRO_FORMAT_A1:
+	    ASSERT_NOT_REACHED;
+	case CAIRO_FORMAT_A8:
+	    break;
+	case CAIRO_FORMAT_RGB16_565:
+	    br13 |= BR13_565;
+	    break;
+	case CAIRO_FORMAT_RGB24:
+	    clear = 0xff000000;
+	case CAIRO_FORMAT_ARGB32:
+	    br13 |= BR13_8888;
+	    cmd |= XY_BLT_WRITE_ALPHA | XY_BLT_WRITE_RGB;
+	    break;
+	}
+
+	OUT_DWORD (cmd);
+	OUT_DWORD (br13);
+	OUT_DWORD (0);
+	OUT_DWORD ((dst->intel.drm.height << 16) |
+		   dst->intel.drm.width);
+	OUT_RELOC_FENCED (dst,
+			  I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+	OUT_DWORD (clear);
+    } else {
+	if (! i915_check_aperture (device, bo_array, 1) ||
+	    i915_batch_space (device) < 24)
+	{
+	    status = i915_batch_flush (device);
+	    if (unlikely (status)) {
+		cairo_device_release (&device->intel.base.base);
+		return status;
+	    }
+	}
+
+	if (device->vertex_count)
+	    i915_vbo_flush (device);
+
+	i915_set_dst (device, dst);
+
+	/* set clear parameters */
+	if (device->clear_alpha != (dst->intel.drm.base.content & CAIRO_CONTENT_ALPHA)) {
+	    device->clear_alpha = dst->intel.drm.base.content & CAIRO_CONTENT_ALPHA;
+	    OUT_DWORD (_3DSTATE_CLEAR_PARAMETERS);
+	    OUT_DWORD (CLEARPARAM_CLEAR_RECT | CLEARPARAM_WRITE_COLOR);
+	    /* ZONE_INIT color */
+	    if (device->clear_alpha) /* XXX depends on pixel format, 16bit needs replication, 8bit? */
+		OUT_DWORD (0x00000000);
+	    else
+		OUT_DWORD (0xff000000);
+	    OUT_DWORD (0); /* ZONE_INIT depth */
+	    /* CLEAR_RECT color */
+	    if (device->clear_alpha)
+		OUT_DWORD (0x00000000);
+	    else
+		OUT_DWORD (0xff000000);
+	    OUT_DWORD (0); /* CLEAR_RECT depth */
+	    OUT_DWORD (0); /* CLEAR_RECT stencil */
+	}
+
+	OUT_DWORD (PRIM3D_CLEAR_RECT | 5);
+	OUT_DWORD (pack_float (dst->intel.drm.width));
+	OUT_DWORD (pack_float (dst->intel.drm.height));
+	OUT_DWORD (0);
+	OUT_DWORD (pack_float (dst->intel.drm.height));
+	OUT_DWORD (0);
+	OUT_DWORD (0);
+    }
+
+    cairo_device_release (&device->intel.base.base);
+
+    dst->deferred_clear = FALSE;
+    return status;
+}
+
 static cairo_status_t
 _clip_and_composite_boxes (i915_surface_t *dst,
 			   cairo_operator_t op,
@@ -956,7 +1775,8 @@ _clip_and_composite_boxes (i915_surface_t *dst,
 			   cairo_boxes_t *boxes,
 			   cairo_antialias_t antialias,
 			   const cairo_composite_rectangles_t *extents,
-			   cairo_clip_t *clip)
+			   cairo_clip_t *clip,
+			   double opacity)
 {
     cairo_status_t status;
 
@@ -967,8 +1787,30 @@ _clip_and_composite_boxes (i915_surface_t *dst,
 	return i915_fixup_unbounded (dst, extents, clip);
     }
 
+    if (clip == NULL &&
+	(op == CAIRO_OPERATOR_SOURCE || (op == CAIRO_OPERATOR_OVER && dst->intel.drm.base.is_clear)) &&
+	opacity == 1. &&
+	boxes->num_boxes == 1 &&
+	extents->bounded.width  == dst->intel.drm.width &&
+	extents->bounded.height == dst->intel.drm.height)
+    {
+	op = CAIRO_OPERATOR_SOURCE;
+	dst->deferred_clear = FALSE;
+
+	status = _upload_image_inplace (dst, src,
+					&extents->bounded, boxes);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
+    }
+
+    if (dst->deferred_clear) {
+	status = i915_surface_clear (dst);
+	if (unlikely (status))
+	    return status;
+    }
+
     /* Use a fast path if the boxes are pixel aligned */
-    status = _composite_boxes (dst, op, src, boxes, antialias, clip, extents);
+    status = _composite_boxes (dst, op, src, boxes, antialias, clip, opacity, extents);
     if (status != CAIRO_INT_STATUS_UNSUPPORTED)
 	return status;
 
@@ -977,7 +1819,7 @@ _clip_and_composite_boxes (i915_surface_t *dst,
      */
     return i915_clip_and_composite_spans (dst, op, src, antialias,
 					  _composite_boxes_spans, boxes,
-					  extents, clip);
+					  extents, clip, opacity);
 }
 
 static cairo_clip_path_t *
@@ -999,11 +1841,162 @@ _clip_get_solitary_path (cairo_clip_t *clip)
     return path;
 }
 
+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_paint (void			*abstract_dst,
-		    cairo_operator_t		 op,
-		    const cairo_pattern_t	*source,
-		    cairo_clip_t		*clip)
+i915_surface_fill_with_alpha (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,
+			      double			 opacity)
+{
+    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 (extents.is_bounded && clip != NULL) {
+	cairo_clip_path_t *clip_path;
+
+	if (((clip_path = _clip_get_solitary_path (clip)) != NULL) &&
+	    _cairo_path_fixed_equal (&clip_path->path, path))
+	{
+	    clip = NULL;
+	}
+    }
+
+    if (clip != NULL) {
+	clip = _cairo_clip_init_copy (&local_clip, clip);
+	have_clip = TRUE;
+    }
+
+    status = _cairo_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,
+						opacity);
+	}
+
+	_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, opacity);
+
+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_paint_with_alpha (void			*abstract_dst,
+			       cairo_operator_t		 op,
+			       const cairo_pattern_t	*source,
+			       cairo_clip_t		*clip,
+			       double			 opacity)
 {
     i915_surface_t *dst = abstract_dst;
     cairo_composite_rectangles_t extents;
@@ -1015,8 +2008,6 @@ i915_surface_paint (void			*abstract_dst,
     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,
@@ -1050,19 +2041,19 @@ i915_surface_paint (void			*abstract_dst,
 	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);
+	status = i915_surface_fill_with_alpha (dst, op, source,
+					       &clip_path->path,
+					       clip_path->fill_rule,
+					       clip_path->tolerance,
+					       clip_path->antialias,
+					       NULL, opacity);
     }
     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);
+					    &extents, clip, opacity);
     }
     if (clip_boxes != boxes.boxes_embedded)
 	free (clip_boxes);
@@ -1074,6 +2065,24 @@ i915_surface_paint (void			*abstract_dst,
 }
 
 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;
+
+    /* XXX unsupported operators? use pixel shader blending, eventually */
+
+    if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) {
+	dst->deferred_clear = TRUE;
+	return CAIRO_STATUS_SUCCESS;
+    }
+
+    return i915_surface_paint_with_alpha (dst, op, source, clip, 1.);
+}
+
+static cairo_int_status_t
 i915_surface_mask (void				*abstract_dst,
 		   cairo_operator_t		 op,
 		   const cairo_pattern_t	*source,
@@ -1090,6 +2099,11 @@ i915_surface_mask (void				*abstract_dst,
     cairo_bool_t have_clip = FALSE;
     cairo_status_t status;
 
+    if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
+	const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) mask;
+	return i915_surface_paint_with_alpha (dst, op, source, clip, solid->color.alpha);
+    }
+
     status = _cairo_composite_rectangles_init_for_mask (&extents,
 							dst->intel.drm.width,
 							dst->intel.drm.height,
@@ -1111,7 +2125,7 @@ i915_surface_mask (void				*abstract_dst,
 	have_clip = TRUE;
     }
 
-    i915_shader_init (&shader, dst, op);
+    i915_shader_init (&shader, dst, op, 1.);
 
     status = i915_shader_acquire_pattern (&shader,
 					  &shader.source,
@@ -1129,10 +2143,38 @@ i915_surface_mask (void				*abstract_dst,
 
     if (clip != NULL) {
 	status = _cairo_clip_get_region (clip, &clip_region);
-	assert (status == CAIRO_STATUS_SUCCESS || CAIRO_INT_STATUS_UNSUPPORTED);
+	if (unlikely (_cairo_status_is_error (status) ||
+		      status == CAIRO_INT_STATUS_NOTHING_TO_DO))
+	{
+	    goto err_shader;
+	}
+
 	need_clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
 	if (need_clip_surface)
 	    i915_shader_set_clip (&shader, clip);
+
+	if (clip_region != NULL) {
+	    cairo_rectangle_int_t rect;
+	    cairo_bool_t is_empty;
+
+	    status = CAIRO_STATUS_SUCCESS;
+	    cairo_region_get_extents (clip_region, &rect);
+	    is_empty = ! _cairo_rectangle_intersect (&extents.unbounded, &rect);
+	    if (unlikely (is_empty))
+		goto err_shader;
+
+	    is_empty = ! _cairo_rectangle_intersect (&extents.bounded, &rect);
+	    if (unlikely (is_empty && extents.is_bounded))
+		goto err_shader;
+
+	    if (cairo_region_num_rectangles (clip_region) == 1)
+		clip_region = NULL;
+	}
+    }
+
+    if (i915_surface_needs_tiling (dst)) {
+	ASSERT_NOT_REACHED;
+	return CAIRO_INT_STATUS_UNSUPPORTED;
     }
 
     device = i915_device (dst);
@@ -1140,6 +2182,12 @@ i915_surface_mask (void				*abstract_dst,
     if (unlikely (status))
 	goto err_shader;
 
+    if (dst->deferred_clear) {
+	status = i915_surface_clear (dst);
+	if (unlikely (status))
+	    goto err_shader;
+    }
+
     status = i915_shader_commit (&shader, device);
     if (unlikely (status))
 	goto err_device;
@@ -1177,38 +2225,6 @@ i915_surface_mask (void				*abstract_dst,
     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,
@@ -1267,7 +2283,7 @@ i915_surface_stroke (void			*abstract_dst,
 	if (likely (status == CAIRO_STATUS_SUCCESS)) {
 	    status = _clip_and_composite_boxes (dst, op, source,
 						&boxes, antialias,
-						&extents, clip);
+						&extents, clip, 1.);
 	}
 
 	_cairo_boxes_fini (&boxes);
@@ -1297,7 +2313,7 @@ i915_surface_stroke (void			*abstract_dst,
 
     if (info.polygon.num_edges == 0) {
 	if (! extents.is_bounded)
-	    status =  i915_fixup_unbounded (dst, &extents, clip);
+	    status = i915_fixup_unbounded (dst, &extents, clip);
 
 	goto CLEANUP_POLYGON;
     }
@@ -1306,7 +2322,7 @@ i915_surface_stroke (void			*abstract_dst,
     info.antialias = antialias;
     status = i915_clip_and_composite_spans (dst, op, source, antialias,
 					    _composite_polygon_spans, &info,
-					    &extents, clip);
+					    &extents, clip, 1.);
 
 CLEANUP_POLYGON:
     _cairo_polygon_fini (&info.polygon);
@@ -1331,116 +2347,13 @@ i915_surface_fill (void			*abstract_dst,
 		   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 (extents.is_bounded && clip != NULL) {
-	cairo_clip_path_t *clip_path;
-
-	if (((clip_path = _clip_get_solitary_path (clip)) != NULL) &&
-	    _cairo_path_fixed_equal (&clip_path->path, path))
-	{
-	    clip = NULL;
-	}
-    }
-
-    if (clip != NULL) {
-	clip = _cairo_clip_init_copy (&local_clip, clip);
-	have_clip = TRUE;
-    }
-
-    status = _cairo_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;
+    return i915_surface_fill_with_alpha (abstract_dst, op, source, path, fill_rule, tolerance, antialias, clip, 1.);
 }
 
 static const cairo_surface_backend_t i915_surface_backend = {
     CAIRO_SURFACE_TYPE_DRM,
 
-    _cairo_drm_surface_create_similar,
+    i915_surface_create_similar,
     i915_surface_finish,
     intel_surface_acquire_source_image,
     intel_surface_release_source_image,
@@ -1472,32 +2385,42 @@ static const cairo_surface_backend_t i915_surface_backend = {
 
 static void
 i915_surface_init (i915_surface_t *surface,
-	           cairo_content_t content,
-		   cairo_drm_device_t *device)
+		   cairo_drm_device_t *device,
+		   cairo_format_t format,
+		   int width, int height)
 {
-    intel_surface_init (&surface->intel, &i915_surface_backend, device, content);
+    intel_surface_init (&surface->intel, &i915_surface_backend, device,
+			format, width, height);
 
-    switch (content) {
+    switch (format) {
     default:
+    case CAIRO_FORMAT_INVALID:
+    case CAIRO_FORMAT_A1:
 	ASSERT_NOT_REACHED;
-    case CAIRO_CONTENT_COLOR_ALPHA:
+    case CAIRO_FORMAT_ARGB32:
 	surface->map0 = MAPSURF_32BIT | MT_32BIT_ARGB8888;
 	surface->colorbuf = COLR_BUF_ARGB8888 | DEPTH_FRMT_24_FIXED_8_OTHER;
 	break;
-    case CAIRO_CONTENT_COLOR:
+    case CAIRO_FORMAT_RGB24:
 	surface->map0 = MAPSURF_32BIT | MT_32BIT_XRGB8888;
 	surface->colorbuf = COLR_BUF_ARGB8888 | DEPTH_FRMT_24_FIXED_8_OTHER;
 	break;
-    case CAIRO_CONTENT_ALPHA:
+    case CAIRO_FORMAT_RGB16_565:
+	surface->map0 = MAPSURF_16BIT | MT_16BIT_RGB565;
+	surface->colorbuf = COLR_BUF_RGB565;
+	break;
+    case CAIRO_FORMAT_A8:
 	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->map0 |= ((height - 1) << MS3_HEIGHT_SHIFT) |
+		     ((width  - 1) << MS3_WIDTH_SHIFT);
     surface->map1 = 0;
 
     surface->is_current_texture = 0;
+    surface->deferred_clear = FALSE;
 
     surface->offset = 0;
 
@@ -1507,7 +2430,7 @@ i915_surface_init (i915_surface_t *surface,
 
 cairo_surface_t *
 i915_surface_create_internal (cairo_drm_device_t *base_dev,
-		              cairo_content_t content,
+		              cairo_format_t format,
 			      int width, int height,
 			      uint32_t tiling,
 			      cairo_bool_t gpu_target)
@@ -1519,48 +2442,58 @@ i915_surface_create_internal (cairo_drm_device_t *base_dev,
     if (unlikely (surface == NULL))
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    i915_surface_init (surface, content, base_dev);
+    i915_surface_init (surface, base_dev, format, width, height);
 
     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);
+	uint32_t size, stride;
+	intel_bo_t *bo;
 
 	width = (width + 3) & -4;
-	surface->intel.drm.stride = cairo_format_stride_for_width (surface->intel.drm.format,
-							      width);
+	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)
+	if (height * stride <= 4096)
+	    tiling = I915_TILING_NONE;
+	if (tiling != I915_TILING_NONE && stride <= 512)
+	    tiling = I915_TILING_NONE;
+	if (tiling != I915_TILING_NONE) {
+	    if (height <= 8)
+		tiling = I915_TILING_NONE;
+	    else if (height <= 16)
+		tiling = I915_TILING_X;
+	}
+	/* large surfaces we need to blt, so force TILING_X */
+	if (height > 2048)
+	    tiling = I915_TILING_X;
+	/* but there is a maximum limit to the tiling pitch */
+	if (tiling != I915_TILING_NONE && stride > 8192)
 	    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));
+	stride = i915_tiling_stride (tiling, stride);
+	assert (stride >= (uint32_t) cairo_format_stride_for_width (surface->intel.drm.format, width));
+	assert (tiling == I915_TILING_NONE || stride <= 8192);
 	height = i915_tiling_height (tiling, height);
-	assert (height <= 2048);
-
-	size = i915_tiling_size (tiling, surface->intel.drm.stride * height);
+	if (height > 64*1024) {
+	    free (surface);
+	    cairo_device_destroy (&base_dev->base);
+	    return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
+	}
 
-	surface->intel.drm.bo = &intel_bo_create (to_intel_device (&base_dev->base),
-					     size, gpu_target)->base;
-	if (surface->intel.drm.bo == NULL) {
+	size = stride * height;
+	bo = intel_bo_create (to_intel_device (&base_dev->base),
+			      i915_tiling_size (tiling, size), size,
+			      gpu_target, tiling, stride);
+	if (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));
 	}
+	assert (bo->base.size >= size);
 
-	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->intel.drm.bo = &bo->base;
+	surface->intel.drm.stride = stride;
 
-	surface->map0 |= MS3_tiling (to_intel_bo (surface->intel.drm.bo)->tiling);
-	surface->map1 = (surface->intel.drm.stride/4 - 1) << MS4_PITCH_SHIFT;
+	surface->map0 |= MS3_tiling (tiling);
+	surface->map1 = (stride/4 - 1) << MS4_PITCH_SHIFT;
     }
 
     return &surface->intel.drm.base;
@@ -1568,21 +2501,32 @@ i915_surface_create_internal (cairo_drm_device_t *base_dev,
 
 static cairo_surface_t *
 i915_surface_create (cairo_drm_device_t *base_dev,
-		      cairo_content_t content,
-		      int width, int height)
+		     cairo_format_t format,
+		     int width, int height)
 {
-    return i915_surface_create_internal (base_dev, content, width, height,
+    switch (format) {
+    case CAIRO_FORMAT_ARGB32:
+    case CAIRO_FORMAT_RGB16_565:
+    case CAIRO_FORMAT_RGB24:
+    case CAIRO_FORMAT_A8:
+	break;
+    case CAIRO_FORMAT_INVALID:
+    default:
+    case CAIRO_FORMAT_A1:
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+    }
+
+    return i915_surface_create_internal (base_dev, format, 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)
+			      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 */
@@ -1598,14 +2542,9 @@ i915_surface_create_for_name (cairo_drm_device_t *base_dev,
     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_RGB16_565:
     case CAIRO_FORMAT_RGB24:
-	content = CAIRO_CONTENT_COLOR;
-	break;
     case CAIRO_FORMAT_A8:
-	content = CAIRO_CONTENT_ALPHA;
 	break;
     }
 
@@ -1613,15 +2552,10 @@ i915_surface_create_for_name (cairo_drm_device_t *base_dev,
     if (unlikely (surface == NULL))
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    i915_surface_init (surface, content, base_dev);
+    i915_surface_init (surface, base_dev, format, width, height);
 
     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 =
@@ -1645,7 +2579,8 @@ i915_buffer_cache_init (intel_buffer_cache_t *cache,
 			cairo_format_t format,
 			int width, int height)
 {
-    const uint32_t tiling = I915_TILING_Y;
+    const uint32_t tiling = I915_TILING_DEFAULT;
+    uint32_t stride, size;
 
     assert ((width & 3) == 0);
     assert ((height & 1) == 0);
@@ -1660,29 +2595,29 @@ i915_buffer_cache_init (intel_buffer_cache_t *cache,
 	ASSERT_NOT_REACHED;
     case CAIRO_FORMAT_ARGB32:
 	cache->buffer.map0 = MAPSURF_32BIT | MT_32BIT_ARGB8888;
-	cache->buffer.stride = width * 4;
+	stride = width * 4;
 	break;
     case CAIRO_FORMAT_A8:
 	cache->buffer.map0 = MAPSURF_8BIT | MT_8BIT_I8;
-	cache->buffer.stride = width;
+	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 ((stride & 7) == 0);
+    assert (i915_tiling_stride (tiling, stride) == stride);
     assert (i915_tiling_height (tiling, height) == height);
 
-    cache->buffer.bo = intel_bo_create (&device->intel,
-					height * cache->buffer.stride,
-					FALSE);
+    size = height * stride;
+    assert (i915_tiling_size (tiling, size) == size);
+    cache->buffer.bo = intel_bo_create (&device->intel, size, size, FALSE, tiling, stride);
     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->buffer.stride = cache->buffer.bo->stride;
+
+    cache->buffer.map0 |= ((height - 1) << MS3_HEIGHT_SHIFT) |
+			  ((width  - 1) << MS3_WIDTH_SHIFT);
+    cache->buffer.map0 |= MS3_tiling (tiling);
+    cache->buffer.map1 = ((stride / 4) - 1) << MS4_PITCH_SHIFT;
 
     cache->ref_count = 0;
     cairo_list_init (&cache->link);
@@ -1702,12 +2637,16 @@ i915_surface_create_from_cacheable_image_internal (i915_device_t *device,
     cairo_format_t format;
     int width, height, bpp;
 
+    format = image->format;
+    if (format == CAIRO_FORMAT_A1)
+	format = CAIRO_FORMAT_A8;
+
     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,
+					  format,
 					  width, height,
 					  I915_TILING_NONE, FALSE);
 	if (unlikely (surface->intel.drm.base.status))
@@ -1715,7 +2654,6 @@ i915_surface_create_from_cacheable_image_internal (i915_device_t *device,
 
 	status = intel_bo_put_image (&device->intel,
 				     to_intel_bo (surface->intel.drm.bo),
-				     surface->intel.drm.stride,
 				     image,
 				     0, 0,
 				     width, height,
@@ -1795,7 +2733,7 @@ i915_surface_create_from_cacheable_image_internal (i915_device_t *device,
     ((i915_image_private_t *) node)->container = cache;
 
     status = intel_bo_put_image (&device->intel,
-				 cache->buffer.bo, cache->buffer.stride,
+				 cache->buffer.bo,
 				 image,
 				 0, 0,
 				 width, height,
@@ -1809,15 +2747,12 @@ i915_surface_create_from_cacheable_image_internal (i915_device_t *device,
 	goto CLEANUP_CACHE;
     }
 
-    i915_surface_init (surface, image->base.content, &device->intel.base);
+    i915_surface_init (surface, &device->intel.base,
+		       format, width, height);
 
-    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->map0 |= MS3_tiling (cache->buffer.bo->tiling);
     surface->map1 = (surface->intel.drm.stride/4 - 1) << MS4_PITCH_SHIFT;
 
     surface->intel.drm.bo = &intel_bo_reference (cache->buffer.bo)->base;
@@ -1879,16 +2814,11 @@ i915_surface_enable_scan_out (void *abstract_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);
-	}
+	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;
 }
@@ -1967,12 +2897,20 @@ _cairo_drm_i915_device_create (int fd, dev_t dev_id, int vendor_id, int chip_id)
 
     device->debug = 0;
     if (getenv ("CAIRO_DEBUG_DRM") != NULL)
-	device->debug = I915_DEBUG_BATCH;
+	device->debug = I915_DEBUG_SYNC;
 
-    device->batch.gtt_size = I915_BATCH_SIZE;
+    n = intel_get (fd, I915_PARAM_NUM_FENCES_AVAIL);
+    if (n == 0)
+	n = 8;
+    device->batch.fences_avail = n - 2; /* conservative */
+
+    device->batch.gtt_avail_size = device->intel.gtt_avail_size / 4;
+    device->batch.est_gtt_size = I915_BATCH_SIZE;
+    device->batch.total_gtt_size = I915_BATCH_SIZE;
     device->batch.exec_count = 0;
     device->batch.reloc_count = 0;
     device->batch.used = 0;
+    device->batch.fences = 0;
 
     memcpy (device->batch_header, i915_batch_setup, sizeof (i915_batch_setup));
     device->vbo = 0;
@@ -1982,13 +2920,6 @@ _cairo_drm_i915_device_create (int fd, dev_t dev_id, int vendor_id, int chip_id)
     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]);
 
@@ -2004,9 +2935,14 @@ _cairo_drm_i915_device_create (int fd, dev_t dev_id, int vendor_id, int chip_id)
     device->intel.base.device.throttle = i915_device_throttle;
     device->intel.base.device.destroy = i915_device_destroy;
 
+    device->floats_per_vertex = 0;
+    device->current_source = NULL;
+    device->current_mask = NULL;
+    device->current_clip = NULL;
+
     i915_device_reset (device);
 
     return _cairo_drm_device_init (&device->intel.base,
 				   fd, dev_id, vendor_id, chip_id,
-				   2048);
+				   16*1024);
 }
diff --git a/src/drm/cairo-drm-i965-glyphs.c b/src/drm/cairo-drm-i965-glyphs.c
index 01c4e39..e1ec95d 100644
--- a/src/drm/cairo-drm-i965-glyphs.c
+++ b/src/drm/cairo-drm-i965-glyphs.c
@@ -71,8 +71,6 @@ i965_glyphs_accumulate_rectangle (i965_glyphs_t *glyphs)
     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! */
@@ -83,7 +81,8 @@ i965_glyphs_accumulate_rectangle (i965_glyphs_t *glyphs)
 
 	vbo->next = NULL;
 	vbo->bo = intel_bo_create (&glyphs->shader.device->intel,
-				   I965_VERTEX_SIZE, FALSE);
+				   I965_VERTEX_SIZE, I965_VERTEX_SIZE,
+				   FALSE, I915_TILING_NONE, 0);
 	vbo->count = 0;
 
 	glyphs->vbo_offset = 0;
@@ -152,8 +151,8 @@ i965_surface_mask_internal (i965_surface_t *dst,
     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);
+				 -extents->bounded.x,
+				 -extents->bounded.y);
     cairo_matrix_scale (&shader.mask.base.matrix,
 			1. / mask->intel.drm.width,
 			1. / mask->intel.drm.height);
@@ -266,15 +265,15 @@ i965_surface_glyphs (void			*abstract_surface,
     }
 
     if (overlap || ! extents.is_bounded) {
-	cairo_content_t content;
+	cairo_format_t format;
 
-	content = CAIRO_CONTENT_ALPHA;
+	format = CAIRO_FORMAT_A8;
 	if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
-	    content |= CAIRO_CONTENT_COLOR;
+	    format = CAIRO_FORMAT_ARGB32;
 
 	mask = (i965_surface_t *)
 	    i965_surface_create_internal (&i965_device (surface)->intel.base,
-					  content,
+					  format,
 					  extents.bounded.width,
 					  extents.bounded.height,
 					  I965_TILING_DEFAULT,
@@ -331,7 +330,8 @@ i965_surface_glyphs (void			*abstract_surface,
     } else {
 	glyphs.get_rectangle = i965_glyphs_accumulate_rectangle;
 	glyphs.head.bo = intel_bo_create (&device->intel,
-					  I965_VERTEX_SIZE, FALSE);
+					  I965_VERTEX_SIZE, I965_VERTEX_SIZE,
+					  FALSE, I915_TILING_NONE, 0);
 	if (unlikely (glyphs.head.bo == NULL))
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
@@ -431,16 +431,19 @@ i965_surface_glyphs (void			*abstract_surface,
 	    last_bo = cache->buffer.bo;
 	}
 
-	x1 += mask_x; x2 += mask_x;
-	y1 += mask_y; y2 += mask_y;
+	x2 = x1 + glyph->width;
+	y2 = y1 + glyph->height;
+
+	if (mask_x)
+	    x1 += mask_x, x2 += mask_x;
+	if (mask_y)
+	    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);
+    if (mask != NULL && clip_region != NULL)
 	i965_clipped_vertices (device, &glyphs.head, clip_region);
-    }
 
     status = CAIRO_STATUS_SUCCESS;
   FINISH:
@@ -449,9 +452,6 @@ i965_surface_glyphs (void			*abstract_surface,
   CLEANUP_GLYPHS:
     i965_shader_fini (&glyphs.shader);
 
-    if (glyphs.tail->bo && glyphs.tail->bo->virtual)
-	intel_bo_unmap (glyphs.tail->bo);
-
     if (glyphs.head.bo != NULL) {
 	struct i965_vbo *vbo, *next;
 
diff --git a/src/drm/cairo-drm-i965-private.h b/src/drm/cairo-drm-i965-private.h
index e13ea78..79568a6 100644
--- a/src/drm/cairo-drm-i965-private.h
+++ b/src/drm/cairo-drm-i965-private.h
@@ -646,7 +646,7 @@ i965_shader_add_rectangle (const i965_shader_t *shader,
 
 cairo_private cairo_surface_t *
 i965_surface_create_internal (cairo_drm_device_t *base_dev,
-		              cairo_content_t content,
+			      cairo_format_t format,
 			      int width, int height,
 			      uint32_t tiling,
 			      cairo_bool_t gpu_target);
diff --git a/src/drm/cairo-drm-i965-shader.c b/src/drm/cairo-drm-i965-shader.c
index 377b478..078fcdd 100644
--- a/src/drm/cairo-drm-i965-shader.c
+++ b/src/drm/cairo-drm-i965-shader.c
@@ -271,7 +271,6 @@ i965_surface_clone (i965_device_t *device,
 
     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,
@@ -317,7 +316,6 @@ i965_surface_clone_subimage (i965_device_t *device,
 
     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,
@@ -668,8 +666,6 @@ i965_shader_acquire_surface (i965_shader_t *shader,
     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);
 
@@ -793,8 +789,7 @@ i965_shader_set_clip (i965_shader_t *shader,
 			     1. / s->intel.drm.height);
 
     cairo_matrix_translate (&shader->clip.base.matrix,
-			    NEAREST_BIAS - clip_x,
-			    NEAREST_BIAS - clip_y);
+			    -clip_x, -clip_y);
 }
 
 static cairo_bool_t
@@ -888,9 +883,6 @@ i965_shader_setup_dst (i965_shader_t *shader)
     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;
 
@@ -2827,7 +2819,6 @@ i965_clipped_vertices (i965_device_t *device,
 	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++) {
diff --git a/src/drm/cairo-drm-i965-spans.c b/src/drm/cairo-drm-i965-spans.c
index 2c06b25..5cba7ce 100644
--- a/src/drm/cairo-drm-i965-spans.c
+++ b/src/drm/cairo-drm-i965-spans.c
@@ -87,8 +87,6 @@ i965_spans_accumulate_rectangle (i965_spans_t *spans)
     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! */
@@ -98,7 +96,9 @@ i965_spans_accumulate_rectangle (i965_spans_t *spans)
 	spans->tail = vbo;
 
 	vbo->next = NULL;
-	vbo->bo = intel_bo_create (&spans->device->intel, I965_VERTEX_SIZE, FALSE);
+	vbo->bo = intel_bo_create (&spans->device->intel,
+				   I965_VERTEX_SIZE, I965_VERTEX_SIZE,
+				   FALSE, I915_TILING_NONE, 0);
 	vbo->count = 0;
 
 	spans->vbo_offset = 0;
@@ -326,7 +326,8 @@ i965_spans_init (i965_spans_t *spans,
     } else {
 	spans->get_rectangle = i965_spans_accumulate_rectangle;
 	spans->head.bo = intel_bo_create (&spans->device->intel,
-					  I965_VERTEX_SIZE, FALSE);
+					  I965_VERTEX_SIZE, I965_VERTEX_SIZE,
+					  FALSE, I915_TILING_NONE, 0);
 	if (unlikely (spans->head.bo == NULL))
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
@@ -344,9 +345,6 @@ i965_spans_fini (i965_spans_t *spans)
 {
     i965_shader_fini (&spans->shader);
 
-    if (spans->tail->bo && spans->tail->bo->virtual)
-	intel_bo_unmap (spans->tail->bo);
-
     if (spans->head.bo != NULL) {
 	struct i965_vbo *vbo, *next;
 
@@ -397,10 +395,8 @@ i965_clip_and_composite_spans (i965_surface_t		*dst,
 	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);
+    if (spans.clip_region != NULL && status == CAIRO_STATUS_SUCCESS)
 	i965_clipped_vertices (device, &spans.head, spans.clip_region);
-    }
 
   CLEANUP_DEVICE:
     cairo_device_release (dst->intel.drm.base.device);
diff --git a/src/drm/cairo-drm-i965-surface.c b/src/drm/cairo-drm-i965-surface.c
index 8164c53..a944fb3 100644
--- a/src/drm/cairo-drm-i965-surface.c
+++ b/src/drm/cairo-drm-i965-surface.c
@@ -168,7 +168,9 @@ i965_stream_commit (i965_device_t *device,
 
     assert (stream->used);
 
-    bo = intel_bo_create (&device->intel, stream->used, FALSE);
+    bo = intel_bo_create (&device->intel,
+			  stream->used, stream->used,
+			  FALSE, I915_TILING_NONE, 0);
 
     /* apply pending relocations */
     for (n = 0; n < stream->num_pending_relocations; n++) {
@@ -373,22 +375,25 @@ i965_exec (i965_device_t *device, uint32_t offset)
 
     /* XXX any write target within the batch should now be in error */
     for (i = 0; i < device->exec.count; i++) {
+	intel_bo_t *bo = device->exec.bo[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;
+	bo->offset = device->exec.exec[i].offset;
+	bo->exec = NULL;
+	bo->batch_read_domains = 0;
+	bo->batch_write_domain = 0;
 
-	if (device->exec.bo[i]->purgeable) {
-	    ret = intel_bo_madvise (&device->intel,
-				    device->exec.bo[i],
-				    I915_MADV_DONTNEED);
+	if (bo->virtual)
+	    intel_bo_unmap (bo);
+	bo->cpu = FALSE;
+
+	if (bo->purgeable)
+	    ret = intel_bo_madvise (&device->intel, bo, 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_del (&bo->cache_list);
+	cairo_list_init (&bo->link);
+	intel_bo_destroy (&device->intel, bo);
     }
     cairo_list_init (&device->flush);
 
@@ -496,7 +501,8 @@ i965_device_flush (i965_device_t *device)
 
 	bo = intel_bo_create (&device->intel,
 			      device->general.used,
-			      FALSE);
+			      device->general.used,
+			      FALSE, I915_TILING_NONE, 0);
 	if (unlikely (bo == NULL))
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
@@ -547,7 +553,9 @@ i965_device_flush (i965_device_t *device)
 	if (aligned <= 8192)
 	    max = aligned;
 
-	bo = intel_bo_create (&device->intel, max, FALSE);
+	bo = intel_bo_create (&device->intel,
+			      max, max,
+			      FALSE, I915_TILING_NONE, 0);
 	if (unlikely (bo == NULL))
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
@@ -615,7 +623,9 @@ i965_device_flush (i965_device_t *device)
 	if (device->surface.used)
 	    i965_stream_commit (device, &device->surface);
 
-	bo = intel_bo_create (&device->intel, device->batch.used, FALSE);
+	bo = intel_bo_create (&device->intel,
+			      device->batch.used, device->batch.used,
+			      FALSE, I915_TILING_NONE, 0);
 	if (unlikely (bo == NULL))
 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
@@ -638,8 +648,6 @@ i965_device_flush (i965_device_t *device)
 	aligned = 0;
     }
 
-    intel_glyph_cache_unmap (&device->intel);
-
     status = i965_exec (device, aligned);
 
     i965_stream_reset (&device->vertex);
@@ -654,6 +662,29 @@ i965_device_flush (i965_device_t *device)
     return status;
 }
 
+static cairo_surface_t *
+i965_surface_create_similar (void *abstract_other,
+			     cairo_content_t content,
+			     int width, int height)
+{
+    i965_surface_t *other;
+    cairo_format_t format;
+
+    if (width > 8192 || height > 8192)
+	return NULL;
+
+    other = abstract_other;
+    if (content == other->intel.drm.base.content)
+	format = other->intel.drm.format;
+    else
+	format = _cairo_format_from_content (content);
+
+    return i965_surface_create_internal ((cairo_drm_device_t *) other->intel.drm.base.device,
+					 format,
+					 width, height,
+					 I965_TILING_DEFAULT, TRUE);
+}
+
 static cairo_status_t
 i965_surface_finish (void *abstract_surface)
 {
@@ -1462,7 +1493,7 @@ CLEANUP_BOXES:
 static const cairo_surface_backend_t i965_surface_backend = {
     CAIRO_SURFACE_TYPE_DRM,
 
-    _cairo_drm_surface_create_similar,
+    i965_surface_create_similar,
     i965_surface_finish,
     intel_surface_acquire_source_image,
     intel_surface_release_source_image,
@@ -1494,10 +1525,12 @@ static const cairo_surface_backend_t i965_surface_backend = {
 
 static void
 i965_surface_init (i965_surface_t *surface,
-	           cairo_content_t content,
-		   cairo_drm_device_t *device)
+		   cairo_drm_device_t *device,
+	           cairo_format_t format,
+		   int width, int height)
 {
-    intel_surface_init (&surface->intel, &i965_surface_backend, device, content);
+    intel_surface_init (&surface->intel, &i965_surface_backend, device,
+			format, width, height);
     surface->stream = 0;
 }
 
@@ -1523,7 +1556,7 @@ i965_tiling_height (uint32_t tiling, int height)
 
 cairo_surface_t *
 i965_surface_create_internal (cairo_drm_device_t *base_dev,
-		              cairo_content_t content,
+		              cairo_format_t format,
 			      int width, int height,
 			      uint32_t tiling,
 			      cairo_bool_t gpu_target)
@@ -1535,47 +1568,36 @@ i965_surface_create_internal (cairo_drm_device_t *base_dev,
     if (unlikely (surface == NULL))
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    i965_surface_init (surface, content, base_dev);
+    i965_surface_init (surface, base_dev, format, width, height);
 
     if (width && height) {
-	uint32_t size;
-
-	surface->intel.drm.width  = width;
-	surface->intel.drm.height = height;
+	uint32_t size, stride;
+	intel_bo_t *bo;
 
 	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);
+	stride = cairo_format_stride_for_width (surface->intel.drm.format, width);
+	stride = (stride + 63) & ~63;
+	stride = i965_tiling_stride (tiling, stride);
+	surface->intel.drm.stride = 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) {
+	size = stride * height;
+	bo = intel_bo_create (to_intel_device (&base_dev->base),
+			      size, size,
+			      gpu_target, tiling, stride);
+	if (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);
+	bo->tiling = tiling;
+	bo->stride = stride;
+	surface->intel.drm.bo = &bo->base;
 
-	assert (surface->intel.drm.bo->size >= (size_t) surface->intel.drm.stride*height);
+	assert (bo->base.size >= (size_t) stride*height);
     }
 
     return &surface->intel.drm.base;
@@ -1583,9 +1605,21 @@ i965_surface_create_internal (cairo_drm_device_t *base_dev,
 
 static cairo_surface_t *
 i965_surface_create (cairo_drm_device_t *device,
-		     cairo_content_t content, int width, int height)
+		     cairo_format_t format, int width, int height)
 {
-    return i965_surface_create_internal (device, content, width, height,
+    switch (format) {
+    case CAIRO_FORMAT_ARGB32:
+    case CAIRO_FORMAT_RGB16_565:
+    case CAIRO_FORMAT_RGB24:
+    case CAIRO_FORMAT_A8:
+	break;
+    case CAIRO_FORMAT_INVALID:
+    default:
+    case CAIRO_FORMAT_A1:
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+    }
+
+    return i965_surface_create_internal (device, format, width, height,
 	                                 I965_TILING_DEFAULT, TRUE);
 }
 
@@ -1597,7 +1631,6 @@ i965_surface_create_for_name (cairo_drm_device_t *base_dev,
 {
     i965_device_t *device;
     i965_surface_t *surface;
-    cairo_content_t content;
     cairo_status_t status_ignored;
     int min_stride;
 
@@ -1610,14 +1643,9 @@ i965_surface_create_for_name (cairo_drm_device_t *base_dev,
 
     switch (format) {
     case CAIRO_FORMAT_ARGB32:
-	content = CAIRO_CONTENT_COLOR_ALPHA;
-	break;
     case CAIRO_FORMAT_RGB16_565:
     case CAIRO_FORMAT_RGB24:
-	content = CAIRO_CONTENT_COLOR;
-	break;
     case CAIRO_FORMAT_A8:
-	content = CAIRO_CONTENT_ALPHA;
 	break;
     case CAIRO_FORMAT_INVALID:
     default:
@@ -1629,7 +1657,7 @@ i965_surface_create_for_name (cairo_drm_device_t *base_dev,
     if (unlikely (surface == NULL))
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    i965_surface_init (surface, content, base_dev);
+    i965_surface_init (surface, base_dev, format, width, height);
 
     device = (i965_device_t *) base_dev;
     surface->intel.drm.bo = &intel_bo_create_for_name (&device->intel, name)->base;
@@ -1639,8 +1667,6 @@ i965_surface_create_for_name (cairo_drm_device_t *base_dev,
 	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;
diff --git a/src/drm/cairo-drm-intel-debug.c b/src/drm/cairo-drm-intel-debug.c
index cc2e47a..7068c93 100644
--- a/src/drm/cairo-drm-intel-debug.c
+++ b/src/drm/cairo-drm-intel-debug.c
@@ -720,6 +720,7 @@ debug_copy_blit (struct debug_stream *stream,
     uint32_t *ptr = (uint32_t *)(stream->ptr + stream->offset);
     uint32_t j = 0;
 
+    fprintf (stderr, "%04x:  ", stream->offset);
     fprintf (stderr, "%s (%d dwords):\n", name, len);
     fprintf (stderr, "\t0x%08x\n",  ptr[j++]);
 
diff --git a/src/drm/cairo-drm-intel-ioctl-private.h b/src/drm/cairo-drm-intel-ioctl-private.h
index d347694..29fe88a 100644
--- a/src/drm/cairo-drm-intel-ioctl-private.h
+++ b/src/drm/cairo-drm-intel-ioctl-private.h
@@ -32,6 +32,22 @@
 
 #include "cairo-drm-intel-command-private.h"
 
+#define I915_PARAM_IRQ_ACTIVE            1
+#define I915_PARAM_ALLOW_BATCHBUFFER     2
+#define I915_PARAM_LAST_DISPATCH         3
+#define I915_PARAM_CHIPSET_ID            4
+#define I915_PARAM_HAS_GEM               5
+#define I915_PARAM_NUM_FENCES_AVAIL      6
+#define I915_PARAM_HAS_OVERLAY           7
+#define I915_PARAM_HAS_PAGEFLIPPING	 8
+#define I915_PARAM_HAS_EXECBUF2          9
+
+struct intel_getparam {
+	int param;
+	int *value;
+};
+
+
 /** @{
  * Intel memory domains
  *
@@ -331,7 +347,9 @@ struct drm_i915_gem_get_aperture {
 	uint64_t aper_available_size;
 };
 
+#define DRM_I915_GETPARAM	0x06
 
+#define DRM_IOCTL_I915_GETPARAM         DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GETPARAM, struct intel_getparam)
 #define DRM_IOCTL_I915_GEM_EXECBUFFER	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER, struct drm_i915_gem_execbuffer)
 #define DRM_IOCTL_I915_GEM_BUSY		DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_BUSY, struct drm_i915_gem_busy)
 #define DRM_IOCTL_I915_GEM_THROTTLE	DRM_IO ( DRM_COMMAND_BASE + DRM_I915_GEM_THROTTLE)
@@ -414,4 +432,11 @@ struct drm_i915_gem_execbuffer2 {
 #define DRM_I915_GEM_EXECBUFFER2	0x29
 #define DRM_IOCTL_I915_GEM_EXECBUFFER2	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_EXECBUFFER2, struct drm_i915_gem_execbuffer2)
 
+struct drm_i915_gem_real_size {
+	uint32_t handle;
+	uint64_t size;
+};
+#define DRM_I915_GEM_REAL_SIZE	0x2a
+#define DRM_IOCTL_I915_GEM_REAL_SIZE	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_REAL_SIZE, struct drm_i915_gem_real_size)
+
 #endif /* CAIRO_DRM_INTEL_IOCTL_PRIVATE_H */
diff --git a/src/drm/cairo-drm-intel-private.h b/src/drm/cairo-drm-intel-private.h
index 738beb9..aaba13d 100644
--- a/src/drm/cairo-drm-intel-private.h
+++ b/src/drm/cairo-drm-intel-private.h
@@ -42,11 +42,8 @@
 
 #include "cairo-drm-intel-ioctl-private.h"
 
-#define NEAREST_BIAS (-.375)
-
 #define INTEL_TILING_DEFAULT I915_TILING_Y
 
-
 #define INTEL_BO_CACHE_BUCKETS 12 /* cache surfaces up to 16 MiB */
 
 #define INTEL_GLYPH_CACHE_WIDTH 1024
@@ -57,24 +54,28 @@
 typedef struct _intel_bo {
     cairo_drm_bo_t base;
 
+    cairo_list_t link;
     cairo_list_t cache_list;
 
     uint32_t offset;
-    void *virtual;
-
-    uint32_t tiling;
-    uint32_t swizzle;
-    uint32_t stride;
-    cairo_bool_t purgeable;
+    uint32_t batch_read_domains;
+    uint32_t batch_write_domain;
 
     uint32_t opaque0;
     uint32_t opaque1;
 
-    struct drm_i915_gem_exec_object2 *exec;
-    uint32_t batch_read_domains;
-    uint32_t batch_write_domain;
+    uint32_t full_size;
+    uint16_t stride;
+    uint16_t _stride;
+    uint32_t bucket :4;
+    uint32_t tiling :4;
+    uint32_t _tiling :4;
+    uint32_t purgeable :1;
+    uint32_t busy :1;
+    uint32_t cpu :1;
 
-    cairo_list_t link;
+    struct drm_i915_gem_exec_object2 *exec;
+    void *virtual;
 } intel_bo_t;
 
 #define INTEL_BATCH_SIZE (64*1024)
@@ -82,11 +83,10 @@ typedef struct _intel_bo {
 #define INTEL_MAX_RELOCS 2048
 
 static inline void
-intel_bo_mark_purgeable (intel_bo_t *bo,
-			 cairo_bool_t purgeable)
+intel_bo_mark_purgeable (intel_bo_t *bo)
 {
     if (bo->base.name == 0)
-	bo->purgeable = purgeable;
+	bo->purgeable = 1;
 }
 
 typedef struct _intel_vertex_buffer intel_vertex_buffer_t;
@@ -168,6 +168,7 @@ typedef struct _intel_glyph {
     intel_buffer_cache_t *cache;
     void **owner;
     float texcoord[3];
+    int width, height;
 } intel_glyph_t;
 
 typedef struct _intel_gradient_cache {
@@ -200,11 +201,11 @@ typedef struct _intel_device {
     size_t bo_cache_size;
     size_t bo_max_cache_size_high;
     size_t bo_max_cache_size_low;
+    cairo_list_t bo_in_flight;
 
     cairo_mutex_t mutex;
     intel_batch_t batch;
 
-    cairo_bool_t glyph_cache_mapped;
     intel_buffer_cache_t glyph_cache[2];
     cairo_list_t fonts;
 
@@ -242,13 +243,23 @@ intel_bo_reference (intel_bo_t *bo)
 cairo_private cairo_bool_t
 intel_bo_madvise (intel_device_t *device, intel_bo_t *bo, int madv);
 
-
 static cairo_always_inline void
 intel_bo_destroy (intel_device_t *device, intel_bo_t *bo)
 {
     cairo_drm_bo_destroy (&device->base.base, &bo->base);
 }
 
+static inline void
+intel_bo_in_flight_add (intel_device_t *device,
+			intel_bo_t *bo)
+{
+    if (bo->base.name == 0 && bo->exec != NULL && cairo_list_is_empty (&bo->cache_list))
+	cairo_list_add (&bo->cache_list, &device->bo_in_flight);
+}
+
+cairo_private int
+intel_get (int fd, int param);
+
 cairo_private cairo_bool_t
 intel_info (int fd, uint64_t *gtt_size);
 
@@ -260,23 +271,24 @@ intel_device_fini (intel_device_t *dev);
 
 cairo_private intel_bo_t *
 intel_bo_create (intel_device_t *dev,
-	         uint32_t size,
-	         cairo_bool_t gpu_target);
+	         uint32_t max_size,
+	         uint32_t real_size,
+	         cairo_bool_t gpu_target,
+		 uint32_t tiling,
+		 uint32_t stride);
 
 cairo_private intel_bo_t *
 intel_bo_create_for_name (intel_device_t *dev, uint32_t name);
 
 cairo_private void
 intel_bo_set_tiling (const intel_device_t *dev,
-	             intel_bo_t *bo,
-		     uint32_t tiling,
-		     uint32_t stride);
+	             intel_bo_t *bo);
 
 cairo_private cairo_bool_t
 intel_bo_is_inactive (const intel_device_t *device,
-		      const intel_bo_t *bo);
+		      intel_bo_t *bo);
 
-cairo_private void
+cairo_private cairo_bool_t
 intel_bo_wait (const intel_device_t *device, const intel_bo_t *bo);
 
 cairo_private void
@@ -318,7 +330,7 @@ intel_bo_get_image (const intel_device_t *device,
 
 cairo_private cairo_status_t
 intel_bo_put_image (intel_device_t *dev,
-		    intel_bo_t *bo, int stride,
+		    intel_bo_t *bo,
 		    cairo_image_surface_t *src,
 		    int src_x, int src_y,
 		    int width, int height,
@@ -328,7 +340,8 @@ cairo_private void
 intel_surface_init (intel_surface_t *surface,
 		    const cairo_surface_backend_t *backend,
 		    cairo_drm_device_t *device,
-		    cairo_content_t content);
+		    cairo_format_t format,
+		    int width, int height);
 
 cairo_private cairo_status_t
 intel_buffer_cache_init (intel_buffer_cache_t *cache,
@@ -354,9 +367,6 @@ cairo_private void
 intel_scaled_font_fini (cairo_scaled_font_t *scaled_font);
 
 cairo_private void
-intel_glyph_cache_unmap (intel_device_t *device);
-
-cairo_private void
 intel_glyph_cache_unpin (intel_device_t *device);
 
 static inline intel_glyph_t *
@@ -404,17 +414,6 @@ intel_dump_batchbuffer (const void *batch,
 			uint32_t length,
 			int devid);
 
-static inline float cairo_const
-texcoord_2d_16 (double x, double y)
-{
-    union {
-	uint32_t ui;
-	float f;
-    } u;
-    u.ui = (_cairo_half_from_float (y) << 16) | _cairo_half_from_float (x);
-    return u.f;
-}
-
 static inline uint32_t cairo_const
 MS3_tiling (uint32_t tiling)
 {
@@ -426,6 +425,17 @@ MS3_tiling (uint32_t tiling)
     }
 }
 
+static inline float cairo_const
+texcoord_2d_16 (double x, double y)
+{
+    union {
+	uint32_t ui;
+	float f;
+    } u;
+    u.ui = (_cairo_half_from_float (y) << 16) | _cairo_half_from_float (x);
+    return u.f;
+}
+
 #define PCI_CHIP_I810			0x7121
 #define PCI_CHIP_I810_DC100		0x7123
 #define PCI_CHIP_I810_E			0x7125
diff --git a/src/drm/cairo-drm-intel-surface.c b/src/drm/cairo-drm-intel-surface.c
index 9b06c22..96d4615 100644
--- a/src/drm/cairo-drm-intel-surface.c
+++ b/src/drm/cairo-drm-intel-surface.c
@@ -53,9 +53,18 @@ intel_surface_finish (void *abstract_surface)
 {
     intel_surface_t *surface = abstract_surface;
 
+    intel_bo_in_flight_add (to_intel_device (surface->drm.base.device),
+			    to_intel_bo (surface->drm.bo));
     return _cairo_drm_surface_finish (&surface->drm);
 }
 
+static void
+surface_finish_and_destroy (cairo_surface_t *surface)
+{
+    cairo_surface_finish (surface);
+    cairo_surface_destroy (surface);
+}
+
 cairo_status_t
 intel_surface_acquire_source_image (void *abstract_surface,
 				    cairo_image_surface_t **image_out,
@@ -64,8 +73,7 @@ intel_surface_acquire_source_image (void *abstract_surface,
     intel_surface_t *surface = abstract_surface;
     cairo_surface_t *image;
     cairo_status_t status;
-
-    /* XXX batch flush */
+    void *ptr;
 
     if (surface->drm.fallback != NULL) {
 	image = surface->drm.fallback;
@@ -83,14 +91,20 @@ intel_surface_acquire_source_image (void *abstract_surface,
 	    return status;
     }
 
-    image = intel_bo_get_image (to_intel_device (surface->drm.base.device),
-				to_intel_bo (surface->drm.bo),
-				&surface->drm);
-    status = image->status;
-    if (unlikely (status))
-	return status;
+    ptr = intel_bo_map (to_intel_device (surface->drm.base.device),
+			to_intel_bo (surface->drm.bo));
+    if (unlikely (ptr == NULL))
+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-     _cairo_surface_attach_snapshot (&surface->drm.base, image, cairo_surface_destroy);
+    image = cairo_image_surface_create_for_data (ptr,
+						 surface->drm.format,
+						 surface->drm.width,
+						 surface->drm.height,
+						 surface->drm.stride);
+    if (unlikely (image->status))
+	return image->status;
+
+    _cairo_surface_attach_snapshot (&surface->drm.base, image, surface_finish_and_destroy);
 
 DONE:
     *image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
@@ -132,10 +146,8 @@ intel_surface_map_to_image (void *abstract_surface)
 						     surface->drm.width,
 						     surface->drm.height,
 						     surface->drm.stride);
-	if (unlikely (image->status)) {
-	    intel_bo_unmap (to_intel_bo (surface->drm.bo));
+	if (unlikely (image->status))
 	    return image;
-	}
 
 	surface->drm.fallback = image;
     }
@@ -159,8 +171,6 @@ intel_surface_flush (void *abstract_surface)
     cairo_surface_destroy (surface->drm.fallback);
     surface->drm.fallback = NULL;
 
-    intel_bo_unmap (to_intel_bo (surface->drm.bo));
-
     return status;
 }
 
@@ -271,34 +281,21 @@ void
 intel_surface_init (intel_surface_t *surface,
 		    const cairo_surface_backend_t *backend,
 		    cairo_drm_device_t *device,
-		    cairo_content_t content)
+		    cairo_format_t format,
+		    int width, int height)
 {
     _cairo_surface_init (&surface->drm.base,
 			 backend,
 			 &device->base,
-			 content);
-    _cairo_drm_surface_init (&surface->drm, device);
-
-    switch (content) {
-    case CAIRO_CONTENT_ALPHA:
-	surface->drm.format = CAIRO_FORMAT_A8;
-	break;
-    case CAIRO_CONTENT_COLOR:
-	surface->drm.format = CAIRO_FORMAT_RGB24;
-	break;
-    default:
-	ASSERT_NOT_REACHED;
-    case CAIRO_CONTENT_COLOR_ALPHA:
-	surface->drm.format = CAIRO_FORMAT_ARGB32;
-	break;
-    }
+			 _cairo_content_from_format (format));
+    _cairo_drm_surface_init (&surface->drm, format, width, height);
 
     surface->snapshot_cache_entry.hash = 0;
 }
 
 static cairo_surface_t *
 intel_surface_create (cairo_drm_device_t *device,
-		      cairo_content_t content,
+		      cairo_format_t format,
 		      int width, int height)
 {
     intel_surface_t *surface;
@@ -308,12 +305,10 @@ intel_surface_create (cairo_drm_device_t *device,
     if (unlikely (surface == NULL))
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    intel_surface_init (surface, &intel_surface_backend, device, content);
+    intel_surface_init (surface, &intel_surface_backend, device,
+			format, width, height);
 
     if (width && height) {
-	surface->drm.width  = width;
-	surface->drm.height = height;
-
 	/* Vol I, p134: size restrictions for textures */
 	width  = (width  + 3) & -4;
 	height = (height + 1) & -2;
@@ -321,7 +316,8 @@ intel_surface_create (cairo_drm_device_t *device,
 	    cairo_format_stride_for_width (surface->drm.format, width);
 	surface->drm.bo = &intel_bo_create (to_intel_device (&device->base),
 					    surface->drm.stride * height,
-					    TRUE)->base;
+					    surface->drm.stride * height,
+					    TRUE, I915_TILING_NONE, surface->drm.stride)->base;
 	if (surface->drm.bo == NULL) {
 	    status = _cairo_drm_surface_finish (&surface->drm);
 	    free (surface);
@@ -339,7 +335,6 @@ intel_surface_create_for_name (cairo_drm_device_t *device,
 			       int width, int height, int stride)
 {
     intel_surface_t *surface;
-    cairo_content_t content;
     cairo_status_t status;
 
     switch (format) {
@@ -348,14 +343,9 @@ intel_surface_create_for_name (cairo_drm_device_t *device,
     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_RGB16_565:
     case CAIRO_FORMAT_RGB24:
-	content = CAIRO_CONTENT_COLOR;
-	break;
     case CAIRO_FORMAT_A8:
-	content = CAIRO_CONTENT_ALPHA;
 	break;
     }
 
@@ -366,11 +356,10 @@ intel_surface_create_for_name (cairo_drm_device_t *device,
     if (unlikely (surface == NULL))
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    intel_surface_init (surface, &intel_surface_backend, device, content);
+    intel_surface_init (surface, &intel_surface_backend,
+			device, format, width, height);
 
     if (width && height) {
-	surface->drm.width  = width;
-	surface->drm.height = height;
 	surface->drm.stride = stride;
 
 	surface->drm.bo = &intel_bo_create_for_name (to_intel_device (&device->base),
@@ -394,14 +383,7 @@ intel_surface_enable_scan_out (void *abstract_surface)
     if (unlikely (surface->drm.bo == NULL))
 	return _cairo_error (CAIRO_STATUS_INVALID_SIZE);
 
-    if (to_intel_bo (surface->drm.bo)->tiling == I915_TILING_Y) {
-	intel_bo_set_tiling (to_intel_device (surface->drm.base.device),
-			     to_intel_bo (surface->drm.bo),
-			     I915_TILING_X, surface->drm.stride);
-    }
-
-    if (unlikely (to_intel_bo (surface->drm.bo)->tiling == I915_TILING_Y))
-	return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); /* XXX */
+    to_intel_bo (surface->drm.bo)->tiling = I915_TILING_X;
 
     return CAIRO_STATUS_SUCCESS;
 }
diff --git a/src/drm/cairo-drm-intel.c b/src/drm/cairo-drm-intel.c
index b5386cd..4d69f8a 100644
--- a/src/drm/cairo-drm-intel.c
+++ b/src/drm/cairo-drm-intel.c
@@ -49,16 +49,38 @@
 #define IMAGE_CACHE_WIDTH 1024
 #define IMAGE_CACHE_HEIGHT 1024
 
+int
+intel_get (int fd, int param)
+{
+    struct intel_getparam gp;
+    int value;
+
+    gp.param = param;
+    gp.value = &value;
+    if (ioctl (fd, DRM_IOCTL_I915_GETPARAM, &gp) < 0)
+	return 0;
+
+    VG (VALGRIND_MAKE_MEM_DEFINED (&value, sizeof (value)));
+
+    return value;
+}
+
 cairo_bool_t
 intel_info (int fd, uint64_t *gtt_size)
 {
     struct drm_i915_gem_get_aperture info;
-    int ret;
 
-    ret = ioctl (fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &info);
-    if (ret == -1)
+    if (! intel_get (fd, I915_PARAM_HAS_GEM))
+	return FALSE;
+
+    if (! intel_get (fd, I915_PARAM_HAS_EXECBUF2))
+	return FALSE;
+
+    if (ioctl (fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &info) < 0)
 	return FALSE;
 
+    VG (VALGRIND_MAKE_MEM_DEFINED (&info, sizeof (info)));
+
     if (gtt_size != NULL)
 	*gtt_size = info.aper_size;
 
@@ -75,6 +97,15 @@ intel_bo_write (const intel_device_t *device,
     struct drm_i915_gem_pwrite pwrite;
     int ret;
 
+    assert (bo->tiling == I915_TILING_NONE);
+    assert (size);
+    assert (offset < bo->base.size);
+    assert (size+offset <= bo->base.size);
+
+    intel_bo_set_tiling (device, bo);
+
+    assert (bo->_tiling == I915_TILING_NONE);
+
     memset (&pwrite, 0, sizeof (pwrite));
     pwrite.handle = bo->base.handle;
     pwrite.offset = offset;
@@ -83,6 +114,9 @@ intel_bo_write (const intel_device_t *device,
     do {
 	ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite);
     } while (ret == -1 && errno == EINTR);
+    assert (ret == 0);
+
+    bo->busy = FALSE;
 }
 
 void
@@ -95,6 +129,15 @@ intel_bo_read (const intel_device_t *device,
     struct drm_i915_gem_pread pread;
     int ret;
 
+    assert (bo->tiling == I915_TILING_NONE);
+    assert (size);
+    assert (offset < bo->base.size);
+    assert (size+offset <= bo->base.size);
+
+    intel_bo_set_tiling (device, bo);
+
+    assert (bo->_tiling == I915_TILING_NONE);
+
     memset (&pread, 0, sizeof (pread));
     pread.handle = bo->base.handle;
     pread.offset = offset;
@@ -103,25 +146,48 @@ intel_bo_read (const intel_device_t *device,
     do {
 	ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_PREAD, &pread);
     } while (ret == -1 && errno == EINTR);
+    assert (ret == 0);
+
+    bo->cpu = TRUE;
+    bo->busy = FALSE;
 }
 
 void *
 intel_bo_map (const intel_device_t *device, intel_bo_t *bo)
 {
     struct drm_i915_gem_set_domain set_domain;
-    int ret;
     uint32_t domain;
+    int ret;
 
-    assert (bo->virtual == NULL);
+    intel_bo_set_tiling (device, bo);
 
-    if (bo->tiling != I915_TILING_NONE) {
-	struct drm_i915_gem_mmap_gtt mmap_arg;
-	void *ptr;
+    if (bo->virtual != NULL)
+	return bo->virtual;
+
+    if (bo->cpu && bo->tiling == I915_TILING_NONE) {
+	struct drm_i915_gem_mmap mmap_arg;
 
 	mmap_arg.handle = bo->base.handle;
 	mmap_arg.offset = 0;
+	mmap_arg.size = bo->base.size;
+	mmap_arg.addr_ptr = 0;
+
+	do {
+	    ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg);
+	} while (ret == -1 && errno == EINTR);
+	if (unlikely (ret != 0)) {
+	    _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+	    return NULL;
+	}
+
+	bo->virtual = (void *) (uintptr_t) mmap_arg.addr_ptr;
+	domain = I915_GEM_DOMAIN_CPU;
+    } else {
+	struct drm_i915_gem_mmap_gtt mmap_arg;
+	void *ptr;
 
 	/* Get the fake offset back... */
+	mmap_arg.handle = bo->base.handle;
 	do {
 	    ret = ioctl (device->base.fd,
 			 DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg);
@@ -141,27 +207,11 @@ intel_bo_map (const intel_device_t *device, intel_bo_t *bo)
 	}
 
 	bo->virtual = ptr;
-    } else {
-	struct drm_i915_gem_mmap mmap_arg;
-
-	mmap_arg.handle = bo->base.handle;
-	mmap_arg.offset = 0;
-	mmap_arg.size = bo->base.size;
-	mmap_arg.addr_ptr = 0;
-
-	do {
-	    ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg);
-	} while (ret == -1 && errno == EINTR);
-	if (unlikely (ret != 0)) {
-	    _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
-	    return NULL;
-	}
-
-	bo->virtual = (void *) (uintptr_t) mmap_arg.addr_ptr;
+	domain = I915_GEM_DOMAIN_GTT;
     }
 
-    domain = bo->tiling == I915_TILING_NONE ?
-	     I915_GEM_DOMAIN_CPU : I915_GEM_DOMAIN_GTT;
+    VG (VALGRIND_MAKE_MEM_DEFINED (bo->virtual, bo->base.size));
+
     set_domain.handle = bo->base.handle;
     set_domain.read_domains = domain;
     set_domain.write_domain = domain;
@@ -178,6 +228,7 @@ intel_bo_map (const intel_device_t *device, intel_bo_t *bo)
 	return NULL;
     }
 
+    bo->busy = FALSE;
     return bo->virtual;
 }
 
@@ -189,19 +240,23 @@ intel_bo_unmap (intel_bo_t *bo)
 }
 
 cairo_bool_t
-intel_bo_is_inactive (const intel_device_t *device, const intel_bo_t *bo)
+intel_bo_is_inactive (const intel_device_t *device, intel_bo_t *bo)
 {
     struct drm_i915_gem_busy busy;
 
+    if (! bo->busy)
+	return TRUE;
+
     /* Is this buffer busy for our intended usage pattern? */
     busy.handle = bo->base.handle;
     busy.busy = 1;
     ioctl (device->base.fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
 
+    bo->busy = busy.busy;
     return ! busy.busy;
 }
 
-void
+cairo_bool_t
 intel_bo_wait (const intel_device_t *device, const intel_bo_t *bo)
 {
     struct drm_i915_gem_set_domain set_domain;
@@ -214,6 +269,8 @@ intel_bo_wait (const intel_device_t *device, const intel_bo_t *bo)
     do {
 	ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_SET_DOMAIN, &set_domain);
     } while (ret == -1 && errno == EINTR);
+
+    return ret == 0;
 }
 
 static inline int
@@ -238,11 +295,8 @@ intel_bo_cache_remove (intel_device_t *device,
 
     cairo_list_del (&bo->cache_list);
 
-    if (device->bo_cache[bucket].num_entries-- >
-	device->bo_cache[bucket].min_entries)
-    {
-	device->bo_cache_size -= bo->base.size;
-    }
+    device->bo_cache[bucket].num_entries--;
+    device->bo_cache_size -= 4096 * (1 << bucket);
 
     _cairo_freepool_free (&device->bo_pool, bo);
 }
@@ -262,6 +316,36 @@ intel_bo_madvise (intel_device_t *device,
 }
 
 static void
+intel_bo_set_real_size (intel_device_t *device,
+			intel_bo_t *bo,
+			size_t size)
+{
+    struct drm_i915_gem_real_size arg;
+    int ret;
+
+    return;
+
+    if (size == bo->base.size)
+	return;
+
+    arg.handle = bo->base.handle;
+    arg.size = size;
+    do {
+	ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_REAL_SIZE, &arg);
+    } while (ret == -1 && errno == EINTR);
+
+    if (ret == 0) {
+	if (size > bo->base.size) {
+	    assert (bo->exec == NULL);
+	    bo->cpu = TRUE;
+	    bo->busy = FALSE;
+	}
+
+	bo->base.size = size;
+    }
+}
+
+static void
 intel_bo_cache_purge (intel_device_t *device)
 {
     int bucket;
@@ -282,89 +366,131 @@ intel_bo_cache_purge (intel_device_t *device)
 
 intel_bo_t *
 intel_bo_create (intel_device_t *device,
-	         uint32_t size,
-	         cairo_bool_t gpu_target)
+	         uint32_t max_size,
+	         uint32_t real_size,
+	         cairo_bool_t gpu_target,
+		 uint32_t tiling,
+		 uint32_t stride)
 {
-    intel_bo_t *bo = NULL;
+    intel_bo_t *bo;
     uint32_t cache_size;
     struct drm_i915_gem_create create;
     int bucket;
     int ret;
 
-    cache_size = pot ((size + 4095) & -4096);
+    max_size = (max_size + 4095) & -4096;
+    real_size = (real_size + 4095) & -4096;
+    cache_size = pot (max_size);
     bucket = ffs (cache_size / 4096) - 1;
+    if (bucket >= INTEL_BO_CACHE_BUCKETS)
+	cache_size = max_size;
+
+    if (gpu_target) {
+	intel_bo_t *first = NULL;
+
+	cairo_list_foreach_entry (bo, intel_bo_t,
+				  &device->bo_in_flight,
+				  cache_list)
+	{
+	    assert (bo->exec != NULL);
+	    if (tiling && bo->_tiling &&
+		(bo->_tiling != tiling || bo->_stride != stride))
+	    {
+		continue;
+	    }
+
+	    if (real_size <= bo->base.size) {
+		if (real_size >= bo->base.size/2) {
+		    cairo_list_del (&bo->cache_list);
+		    bo = intel_bo_reference (bo);
+		    goto DONE;
+		}
+
+		if (first == NULL)
+		    first = bo;
+	    }
+	}
+
+	if (first != NULL) {
+	    cairo_list_del (&first->cache_list);
+	    bo = intel_bo_reference (first);
+	    goto DONE;
+	}
+    }
+
+    bo = NULL;
+
     CAIRO_MUTEX_LOCK (device->bo_mutex);
     if (bucket < INTEL_BO_CACHE_BUCKETS) {
-	size = cache_size;
-
+	int loop = MIN (3, INTEL_BO_CACHE_BUCKETS - bucket);
 	/* Our goal is to avoid clflush which occur on CPU->GPU
 	 * transitions, so we want to minimise reusing CPU
 	 * write buffers. However, by the time a buffer is freed
 	 * it is most likely in the GPU domain anyway (readback is rare!).
 	 */
-  retry:
-	if (gpu_target) {
-	    do {
-		cairo_list_foreach_entry_reverse (bo,
-						  intel_bo_t,
-						  &device->bo_cache[bucket].list,
-						  cache_list)
+	do {
+	    if (gpu_target) {
+		intel_bo_t *next;
+
+		cairo_list_foreach_entry_reverse_safe (bo, next,
+						       intel_bo_t,
+						       &device->bo_cache[bucket].list,
+						       cache_list)
 		{
+		    if (real_size > bo->base.size)
+			continue;
+
 		    /* For a gpu target, by the time our batch fires, the
 		     * GPU will have finished using this buffer. However,
 		     * changing tiling may require a fence deallocation and
 		     * cause serialisation...
 		     */
 
-		    if (device->bo_cache[bucket].num_entries-- >
-			device->bo_cache[bucket].min_entries)
+		    if (tiling && bo->_tiling &&
+			(bo->_tiling != tiling || bo->_stride != stride))
 		    {
-			device->bo_cache_size -= bo->base.size;
+			continue;
 		    }
+
+		    device->bo_cache[bucket].num_entries--;
+		    device->bo_cache_size -= 4096 * (1 << bucket);
 		    cairo_list_del (&bo->cache_list);
 
 		    if (! intel_bo_madvise (device, bo, I915_MADV_WILLNEED)) {
 			_cairo_drm_bo_close (&device->base, &bo->base);
 			_cairo_freepool_free (&device->bo_pool, bo);
-			goto retry;
-		    }
-
-		    goto DONE;
+		    } else
+			goto INIT;
 		}
+	    }
 
-		/* As it is unlikely to trigger clflush, we can use the
-		 * first available buffer into which we fit.
-		 */
-	    } while (++bucket < INTEL_BO_CACHE_BUCKETS);
-	} else {
-	    if (! cairo_list_is_empty (&device->bo_cache[bucket].list)) {
+	    while (! cairo_list_is_empty (&device->bo_cache[bucket].list)) {
 		bo = cairo_list_first_entry (&device->bo_cache[bucket].list,
 					     intel_bo_t, cache_list);
 		if (intel_bo_is_inactive (device, bo)) {
-		    if (device->bo_cache[bucket].num_entries-- >
-			device->bo_cache[bucket].min_entries)
-		    {
-			device->bo_cache_size -= bo->base.size;
-		    }
+		    device->bo_cache[bucket].num_entries--;
+		    device->bo_cache_size -= 4096 * (1 << bucket);
 		    cairo_list_del (&bo->cache_list);
 
 		    if (! intel_bo_madvise (device, bo, I915_MADV_WILLNEED)) {
 			_cairo_drm_bo_close (&device->base, &bo->base);
 			_cairo_freepool_free (&device->bo_pool, bo);
-			goto retry;
-		    }
-
-		    goto DONE;
-		}
+		    } else
+			goto SIZE;
+		} else
+		    break;
 	    }
-	}
+	} while (--loop && ++bucket);
     }
 
     if (device->bo_cache_size > device->bo_max_cache_size_high) {
+	cairo_bool_t not_empty;
+
 	intel_bo_cache_purge (device);
 
 	/* trim caches by discarding the most recent buffer in each bucket */
-	while (device->bo_cache_size > device->bo_max_cache_size_low) {
+	do {
+	    not_empty = FALSE;
 	    for (bucket = INTEL_BO_CACHE_BUCKETS; bucket--; ) {
 		if (device->bo_cache[bucket].num_entries >
 		    device->bo_cache[bucket].min_entries)
@@ -373,30 +499,36 @@ intel_bo_create (intel_device_t *device,
 						intel_bo_t, cache_list);
 
 		    intel_bo_cache_remove (device, bo, bucket);
+		    not_empty = TRUE;
 		}
 	    }
-	}
+	} while (not_empty && device->bo_cache_size > device->bo_max_cache_size_low);
     }
 
     /* no cached buffer available, allocate fresh */
     bo = _cairo_freepool_alloc (&device->bo_pool);
     if (unlikely (bo == NULL)) {
 	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
-	goto UNLOCK;
+	CAIRO_MUTEX_UNLOCK (device->bo_mutex);
+	return bo;
     }
 
     cairo_list_init (&bo->cache_list);
 
     bo->base.name = 0;
-    bo->base.size = size;
 
     bo->offset = 0;
     bo->virtual = NULL;
+    bo->cpu = TRUE;
 
-    bo->tiling = I915_TILING_NONE;
-    bo->stride = 0;
-    bo->swizzle = I915_BIT_6_SWIZZLE_NONE;
+    bucket = ffs (cache_size / 4096) - 1;
+    if (bucket > INTEL_BO_CACHE_BUCKETS)
+	bucket = INTEL_BO_CACHE_BUCKETS;
+    bo->bucket = bucket;
+    bo->_tiling = I915_TILING_NONE;
+    bo->_stride = 0;
     bo->purgeable = 0;
+    bo->busy = FALSE;
 
     bo->opaque0 = 0;
     bo->opaque1 = 0;
@@ -406,23 +538,27 @@ intel_bo_create (intel_device_t *device,
     bo->batch_write_domain = 0;
     cairo_list_init (&bo->link);
 
-    create.size = size;
+    create.size = cache_size;
     create.handle = 0;
     ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_CREATE, &create);
     if (unlikely (ret != 0)) {
 	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
 	_cairo_freepool_free (&device->bo_pool, bo);
-	bo = NULL;
-	goto UNLOCK;
+	CAIRO_MUTEX_UNLOCK (device->bo_mutex);
+	return NULL;
     }
 
     bo->base.handle = create.handle;
+    bo->full_size = bo->base.size = create.size;
 
-DONE:
+SIZE:
+    intel_bo_set_real_size (device, bo, real_size);
+INIT:
     CAIRO_REFERENCE_COUNT_INIT (&bo->base.ref_count, 1);
-UNLOCK:
     CAIRO_MUTEX_UNLOCK (device->bo_mutex);
-
+DONE:
+    bo->tiling = tiling;
+    bo->stride = stride;
     return bo;
 }
 
@@ -449,9 +585,13 @@ intel_bo_create_for_name (intel_device_t *device, uint32_t name)
     CAIRO_REFERENCE_COUNT_INIT (&bo->base.ref_count, 1);
     cairo_list_init (&bo->cache_list);
 
+    bo->full_size = bo->base.size;
     bo->offset = 0;
     bo->virtual = NULL;
     bo->purgeable = 0;
+    bo->busy = TRUE;
+    bo->cpu = FALSE;
+    bo->bucket = INTEL_BO_CACHE_BUCKETS;
 
     bo->opaque0 = 0;
     bo->opaque1 = 0;
@@ -471,8 +611,7 @@ intel_bo_create_for_name (intel_device_t *device, uint32_t name)
 	goto FAIL;
     }
 
-    bo->tiling = get_tiling.tiling_mode;
-    bo->swizzle = get_tiling.swizzle_mode;
+    bo->_tiling = bo->tiling = get_tiling.tiling_mode;
     // bo->stride = get_tiling.stride; /* XXX not available from get_tiling */
 
     return bo;
@@ -491,24 +630,26 @@ intel_bo_release (void *_dev, void *_bo)
     intel_bo_t *bo = _bo;
     int bucket;
 
-    assert (bo->virtual == NULL);
+    if (bo->virtual != NULL)
+	intel_bo_unmap (bo);
+
+    assert (bo->exec == NULL);
+    assert (cairo_list_is_empty (&bo->cache_list));
 
-    bucket = INTEL_BO_CACHE_BUCKETS;
-    if (bo->base.size & -bo->base.size)
-	bucket = ffs (bo->base.size / 4096) - 1;
+    bucket = bo->bucket;
 
     CAIRO_MUTEX_LOCK (device->bo_mutex);
     if (bo->base.name == 0 &&
 	bucket < INTEL_BO_CACHE_BUCKETS &&
 	intel_bo_madvise (device, bo, I915_MADV_DONTNEED))
     {
-	if (++device->bo_cache[bucket].num_entries >
-	    device->bo_cache[bucket].min_entries)
-	{
-	    device->bo_cache_size += bo->base.size;
-	}
+	device->bo_cache[bucket].num_entries++;
+	device->bo_cache_size += 4096 * (1 << bucket);
 
-	cairo_list_add_tail (&bo->cache_list, &device->bo_cache[bucket].list);
+	if (bo->busy)
+	    cairo_list_add_tail (&bo->cache_list, &device->bo_cache[bucket].list);
+	else
+	    cairo_list_add (&bo->cache_list, &device->bo_cache[bucket].list);
     }
     else
     {
@@ -520,36 +661,26 @@ intel_bo_release (void *_dev, void *_bo)
 
 void
 intel_bo_set_tiling (const intel_device_t *device,
-	             intel_bo_t *bo,
-		     uint32_t tiling,
-		     uint32_t stride)
+	             intel_bo_t *bo)
 {
     struct drm_i915_gem_set_tiling set_tiling;
     int ret;
 
-    if (bo->tiling == tiling &&
-	(tiling == I915_TILING_NONE || bo->stride == stride))
-    {
+    if (bo->tiling == bo->_tiling &&
+	(bo->tiling == I915_TILING_NONE || bo->stride == bo->_stride))
 	return;
-    }
-
-    assert (bo->exec == NULL);
-
-    if (bo->virtual)
-	intel_bo_unmap (bo);
 
     do {
 	set_tiling.handle = bo->base.handle;
-	set_tiling.tiling_mode = tiling;
-	set_tiling.stride = stride;
+	set_tiling.tiling_mode = bo->tiling;
+	set_tiling.stride = bo->stride;
 
 	ret = ioctl (device->base.fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling);
     } while (ret == -1 && errno == EINTR);
-    if (ret == 0) {
-	bo->tiling = set_tiling.tiling_mode;
-	bo->swizzle = set_tiling.swizzle_mode;
-	bo->stride = set_tiling.stride;
-    }
+
+    assert (ret == 0);
+    bo->_tiling = bo->tiling;
+    bo->_stride = bo->stride;
 }
 
 cairo_surface_t *
@@ -568,26 +699,11 @@ intel_bo_get_image (const intel_device_t *device,
     if (unlikely (image->base.status))
 	return &image->base;
 
-    if (bo->tiling == I915_TILING_NONE) {
-	if (image->stride == surface->stride) {
-	    size = surface->stride * surface->height;
-	    intel_bo_read (device, bo, 0, size, image->data);
-	} else {
-	    int offset;
-
-	    size = surface->width;
-	    if (surface->format != CAIRO_FORMAT_A8)
-		size *= 4;
-
-	    offset = 0;
-	    row = surface->height;
-	    dst = image->data;
-	    while (row--) {
-		intel_bo_read (device, bo, offset, size, dst);
-		offset += surface->stride;
-		dst += image->stride;
-	    }
-	}
+    intel_bo_set_tiling (device, bo);
+
+    if (bo->tiling == I915_TILING_NONE && image->stride == surface->stride) {
+	size = surface->stride * surface->height;
+	intel_bo_read (device, bo, 0, size, image->data);
     } else {
 	const uint8_t *src;
 
@@ -606,16 +722,14 @@ intel_bo_get_image (const intel_device_t *device,
 	    dst += image->stride;
 	    src += surface->stride;
 	}
-
-	intel_bo_unmap (bo);
     }
 
     return &image->base;
 }
 
 static cairo_status_t
-_intel_bo_put_a1_image (intel_device_t *dev,
-			intel_bo_t *bo, int stride,
+_intel_bo_put_a1_image (intel_device_t *device,
+			intel_bo_t *bo,
 			cairo_image_surface_t *src,
 			int src_x, int src_y,
 			int width, int height,
@@ -628,13 +742,13 @@ _intel_bo_put_a1_image (intel_device_t *dev,
 
     data = src->data + src_y * src->stride;
 
-    if (bo->tiling == I915_TILING_NONE && width == stride) {
+    if (bo->tiling == I915_TILING_NONE && width == bo->stride) {
 	uint8_t *p;
 	int size;
 
-	size = stride * height;
+	size = bo->stride * height;
 	if (size > (int) sizeof (buf)) {
-	    a8 = _cairo_malloc_ab (stride, height);
+	    a8 = _cairo_malloc_ab (bo->stride, height);
 	    if (a8 == NULL)
 		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	}
@@ -649,11 +763,11 @@ _intel_bo_put_a1_image (intel_device_t *dev,
 	    }
 
 	    data += src->stride;
-	    p += stride;
+	    p += bo->stride;
 	}
 
-	intel_bo_write (dev, bo,
-			dst_y * stride + dst_x, /* XXX  bo_offset */
+	intel_bo_write (device, bo,
+			dst_y * bo->stride + dst_x, /* XXX  bo_offset */
 			size, a8);
     } else {
 	uint8_t *dst;
@@ -664,14 +778,14 @@ _intel_bo_put_a1_image (intel_device_t *dev,
 		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 	}
 
-	dst = intel_bo_map (dev, bo);
+	dst = intel_bo_map (device, bo);
 	if (dst == NULL) {
 	    if (a8 != buf)
 		free (a8);
 	    return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
 	}
 
-	dst += dst_y * stride + dst_x; /* XXX  bo_offset */
+	dst += dst_y * bo->stride + dst_x; /* XXX  bo_offset */
 	while (height--) {
 	    for (x = 0; x < width; x++) {
 		int i = src_x + x;
@@ -681,10 +795,9 @@ _intel_bo_put_a1_image (intel_device_t *dev,
 	    }
 
 	    memcpy (dst, a8, width);
-	    dst  += stride;
+	    dst  += bo->stride;
 	    data += src->stride;
 	}
-	intel_bo_unmap (bo);
     }
 
     if (a8 != buf)
@@ -694,8 +807,8 @@ _intel_bo_put_a1_image (intel_device_t *dev,
 }
 
 cairo_status_t
-intel_bo_put_image (intel_device_t *dev,
-		    intel_bo_t *bo, int stride,
+intel_bo_put_image (intel_device_t *device,
+		    intel_bo_t *bo,
 		    cairo_image_surface_t *src,
 		    int src_x, int src_y,
 		    int width, int height,
@@ -705,7 +818,9 @@ intel_bo_put_image (intel_device_t *dev,
     int size;
     int offset;
 
-    offset = dst_y * stride;
+    intel_bo_set_tiling (device, bo);
+
+    offset = dst_y * bo->stride;
     data = src->data + src_y * src->stride;
     switch (src->format) {
     case CAIRO_FORMAT_ARGB32:
@@ -725,8 +840,7 @@ intel_bo_put_image (intel_device_t *dev,
 	size    = width;
 	break;
     case CAIRO_FORMAT_A1:
-	return _intel_bo_put_a1_image (dev,
-				       bo, stride, src,
+	return _intel_bo_put_a1_image (device, bo, src,
 				       src_x, src_y,
 				       width, height,
 				       dst_x, dst_y);
@@ -735,28 +849,21 @@ intel_bo_put_image (intel_device_t *dev,
 	return _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
     }
 
-    if (bo->tiling == I915_TILING_NONE) {
-	if (src->stride == stride) {
-	    intel_bo_write (dev, bo, offset, stride * height, data);
-	} else while (height--) {
-	    intel_bo_write (dev, bo, offset, size, data);
-	    offset += stride;
-	    data += src->stride;
-	}
+    if (bo->tiling == I915_TILING_NONE && src->stride == bo->stride) {
+	intel_bo_write (device, bo, offset, bo->stride * height, data);
     } else {
 	uint8_t *dst;
 
-	dst = intel_bo_map (dev, bo);
+	dst = intel_bo_map (device, bo);
 	if (unlikely (dst == NULL))
 	    return _cairo_error (CAIRO_STATUS_DEVICE_ERROR);
 
 	dst += offset;
 	while (height--) {
 	    memcpy (dst, data, size);
-	    dst  += stride;
+	    dst  += bo->stride;
 	    data += src->stride;
 	}
-	intel_bo_unmap (bo);
     }
 
     return CAIRO_STATUS_SUCCESS;
@@ -771,6 +878,7 @@ _intel_device_init_bo_cache (intel_device_t *device)
     device->bo_cache_size = 0;
     device->bo_max_cache_size_high = device->gtt_max_size / 2;
     device->bo_max_cache_size_low = device->gtt_max_size / 4;
+    cairo_list_init (&device->bo_in_flight);
 
     for (i = 0; i < INTEL_BO_CACHE_BUCKETS; i++) {
 	struct _intel_bo_cache *cache = &device->bo_cache[i];
@@ -805,7 +913,6 @@ _intel_snapshot_cache_entry_destroy (void *closure)
 						   snapshot_cache_entry);
 
     surface->snapshot_cache_entry.hash = 0;
-    cairo_surface_destroy (&surface->drm.base);
 }
 
 cairo_status_t
@@ -839,7 +946,6 @@ intel_device_init (intel_device_t *device, int fd)
     if (unlikely (status))
 	return status;
 
-    device->glyph_cache_mapped = FALSE;
     for (n = 0; n < ARRAY_LENGTH (device->glyph_cache); n++) {
 	device->glyph_cache[n].buffer.bo = NULL;
 	cairo_list_init (&device->glyph_cache[n].rtree.pinned);
@@ -926,25 +1032,6 @@ intel_throttle (intel_device_t *device)
 }
 
 void
-intel_glyph_cache_unmap (intel_device_t *device)
-{
-    int n;
-
-    if (likely (! device->glyph_cache_mapped))
-	return;
-
-    for (n = 0; n < ARRAY_LENGTH (device->glyph_cache); n++) {
-	if (device->glyph_cache[n].buffer.bo != NULL &&
-	    device->glyph_cache[n].buffer.bo->virtual != NULL)
-	{
-	    intel_bo_unmap (device->glyph_cache[n].buffer.bo);
-	}
-    }
-
-    device->glyph_cache_mapped = FALSE;
-}
-
-void
 intel_glyph_cache_unpin (intel_device_t *device)
 {
     int n;
@@ -984,6 +1071,8 @@ intel_glyph_cache_add_glyph (intel_device_t *device,
     if (unlikely (status))
 	return status;
 
+    /* XXX streaming upload? */
+
     height = glyph_surface->height;
     src = glyph_surface->data;
     dst = cache->buffer.bo->virtual;
@@ -1002,10 +1091,8 @@ intel_glyph_cache_add_glyph (intel_device_t *device,
 
 	if (width > (int) sizeof (buf)) {
 	    a8 = malloc (width);
-	    if (unlikely (a8 == NULL)) {
-		intel_bo_unmap (cache->buffer.bo);
+	    if (unlikely (a8 == NULL))
 		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	    }
 	}
 
 	dst += node->x;
@@ -1051,9 +1138,6 @@ intel_glyph_cache_add_glyph (intel_device_t *device,
 	return _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
     }
 
-    /* leave mapped! */
-    device->glyph_cache_mapped = TRUE;
-
     scaled_glyph->surface_private = node;
 
     glyph= (intel_glyph_t *) node;
@@ -1064,14 +1148,17 @@ intel_glyph_cache_add_glyph (intel_device_t *device,
     sf_x = 1. / cache->buffer.width;
     sf_y = 1. / cache->buffer.height;
     glyph->texcoord[0] =
-	texcoord_2d_16 (sf_x * (node->x + glyph_surface->width + NEAREST_BIAS),
-		        sf_y * (node->y + glyph_surface->height + NEAREST_BIAS));
+	texcoord_2d_16 (sf_x * (node->x + glyph_surface->width),
+		        sf_y * (node->y + glyph_surface->height));
     glyph->texcoord[1] =
-	texcoord_2d_16 (sf_x * (node->x + NEAREST_BIAS),
-		        sf_y * (node->y + glyph_surface->height + NEAREST_BIAS));
+	texcoord_2d_16 (sf_x * node->x,
+		        sf_y * (node->y + glyph_surface->height));
     glyph->texcoord[2] =
-	texcoord_2d_16 (sf_x * (node->x + NEAREST_BIAS),
-	                sf_y * (node->y + NEAREST_BIAS));
+	texcoord_2d_16 (sf_x * node->x,
+	                sf_y * node->y);
+
+    glyph->width  = glyph_surface->width;
+    glyph->height = glyph_surface->height;
 
     return CAIRO_STATUS_SUCCESS;
 }
@@ -1190,9 +1277,6 @@ intel_get_glyph (intel_device_t *device,
 
 	assert (cache->buffer.bo->exec != NULL);
 
-	if (cache->buffer.bo->virtual != NULL)
-	    intel_bo_unmap (cache->buffer.bo);
-
 	_cairo_rtree_reset (&cache->rtree);
 	intel_bo_destroy (device, cache->buffer.bo);
 	cache->buffer.bo = NULL;
@@ -1225,6 +1309,7 @@ intel_buffer_cache_init (intel_buffer_cache_t *cache,
 			int width, int height)
 {
     const uint32_t tiling = I915_TILING_Y;
+    uint32_t stride, size;
 
     assert ((width & 3) == 0);
     assert ((height & 1) == 0);
@@ -1233,6 +1318,7 @@ intel_buffer_cache_init (intel_buffer_cache_t *cache,
     cache->buffer.height = height;
 
     switch (format) {
+    default:
     case CAIRO_FORMAT_A1:
     case CAIRO_FORMAT_RGB16_565:
     case CAIRO_FORMAT_RGB24:
@@ -1241,25 +1327,28 @@ intel_buffer_cache_init (intel_buffer_cache_t *cache,
 	return _cairo_error (CAIRO_STATUS_INVALID_FORMAT);
     case CAIRO_FORMAT_ARGB32:
 	cache->buffer.map0 = MAPSURF_32BIT | MT_32BIT_ARGB8888;
-	cache->buffer.stride = width * 4;
+	stride = width * 4;
 	break;
     case CAIRO_FORMAT_A8:
 	cache->buffer.map0 = MAPSURF_8BIT | MT_8BIT_I8;
-	cache->buffer.stride = width;
+	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;
 
+    size = height * stride;
     cache->buffer.bo = intel_bo_create (device,
-					height * cache->buffer.stride, FALSE);
+					size, size,
+					FALSE, tiling, stride);
     if (unlikely (cache->buffer.bo == NULL))
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
 
-    intel_bo_set_tiling (device, cache->buffer.bo, tiling, cache->buffer.stride);
+    cache->buffer.stride = stride;
 
-    cache->buffer.map0 |= MS3_tiling (cache->buffer.bo->tiling);
+    cache->buffer.offset = 0;
+    cache->buffer.map0 |= MS3_tiling (tiling);
+    cache->buffer.map0 |= ((height - 1) << MS3_HEIGHT_SHIFT) |
+	                  ((width - 1)  << MS3_WIDTH_SHIFT);
+    cache->buffer.map1 = ((stride / 4) - 1) << MS4_PITCH_SHIFT;
 
     cache->ref_count = 0;
     cairo_list_init (&cache->link);
@@ -1272,16 +1361,8 @@ intel_snapshot_cache_insert (intel_device_t *device,
 			     intel_surface_t *surface)
 {
     cairo_status_t status;
-    int bpp;
-
-    bpp = 1;
-    if (surface->drm.format != CAIRO_FORMAT_A8)
-	bpp = 4;
-
-    surface->snapshot_cache_entry.hash = (unsigned long) surface;
-    surface->snapshot_cache_entry.size =
-	surface->drm.width * surface->drm.height * bpp;
 
+    surface->snapshot_cache_entry.size = surface->drm.bo->size;
     if (surface->snapshot_cache_entry.size >
 	device->snapshot_cache_max_size)
     {
@@ -1291,6 +1372,7 @@ intel_snapshot_cache_insert (intel_device_t *device,
     if (device->snapshot_cache.freeze_count == 0)
 	_cairo_cache_freeze (&device->snapshot_cache);
 
+    surface->snapshot_cache_entry.hash = (unsigned long) surface;
     status = _cairo_cache_insert (&device->snapshot_cache,
 	                          &surface->snapshot_cache_entry);
     if (unlikely (status)) {
@@ -1298,8 +1380,6 @@ intel_snapshot_cache_insert (intel_device_t *device,
 	return status;
     }
 
-    cairo_surface_reference (&surface->drm.base);
-
     return CAIRO_STATUS_SUCCESS;
 }
 
@@ -1314,7 +1394,7 @@ intel_surface_detach_snapshot (cairo_surface_t *abstract_surface)
 	device = (intel_device_t *) surface->drm.base.device;
 	_cairo_cache_remove (&device->snapshot_cache,
 		             &surface->snapshot_cache_entry);
-	surface->snapshot_cache_entry.hash = 0;
+	assert (surface->snapshot_cache_entry.hash == 0);
     }
 }
 
@@ -1470,12 +1550,13 @@ intel_gradient_render (intel_device_t *device,
 
     pixman_image_unref (gradient);
 
-    buffer->bo = intel_bo_create (device, 4*width, FALSE);
+    buffer->bo = intel_bo_create (device,
+				  4*width, 4*width,
+				  FALSE, I915_TILING_NONE, 4*width);
     if (unlikely (buffer->bo == NULL)) {
 	pixman_image_unref (image);
 	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     }
-    intel_bo_set_tiling (device, buffer->bo, I915_TILING_NONE, 0);
 
     intel_bo_write (device, buffer->bo, 0, 4*width, pixman_image_get_data (image));
     pixman_image_unref (image);
@@ -1486,8 +1567,7 @@ intel_gradient_render (intel_device_t *device,
     buffer->stride = 4*width;
     buffer->format = CAIRO_FORMAT_ARGB32;
     buffer->map0 = MAPSURF_32BIT | MT_32BIT_ARGB8888;
-    buffer->map0 |= MS3_tiling (buffer->bo->tiling);
-    buffer->map0 |= ((width - 1)  << MS3_WIDTH_SHIFT);
+    buffer->map0 |= ((width - 1) << MS3_WIDTH_SHIFT);
     buffer->map1 = (width - 1) << MS4_PITCH_SHIFT;
 
     if (device->gradient_cache.size < GRADIENT_CACHE_SIZE) {
diff --git a/src/drm/cairo-drm-private.h b/src/drm/cairo-drm-private.h
index df24b0a..2db7f38 100644
--- a/src/drm/cairo-drm-private.h
+++ b/src/drm/cairo-drm-private.h
@@ -63,7 +63,7 @@ typedef void
 
 typedef cairo_surface_t *
 (*cairo_drm_surface_create_func_t) (cairo_drm_device_t *device,
-				    cairo_content_t content,
+				    cairo_format_t format,
 				    int width, int height);
 
 typedef cairo_surface_t *
@@ -172,16 +172,12 @@ _cairo_drm_bo_close (const cairo_drm_device_t *dev,
 
 cairo_private void
 _cairo_drm_surface_init (cairo_drm_surface_t *surface,
-			 cairo_drm_device_t *device);
+			 cairo_format_t format,
+			 int width, int height);
 
 cairo_private cairo_status_t
 _cairo_drm_surface_finish (cairo_drm_surface_t *surface);
 
-cairo_private cairo_surface_t *
-_cairo_drm_surface_create_similar (void			*abstract_src,
-				   cairo_content_t	 content,
-				   int			 width,
-				   int			 height);
 cairo_private void
 _cairo_drm_surface_get_font_options (void                  *abstract_surface,
 				     cairo_font_options_t  *options);
diff --git a/src/drm/cairo-drm-radeon-surface.c b/src/drm/cairo-drm-radeon-surface.c
index df95d8c..cbcef2a 100644
--- a/src/drm/cairo-drm-radeon-surface.c
+++ b/src/drm/cairo-drm-radeon-surface.c
@@ -283,34 +283,21 @@ static const cairo_surface_backend_t radeon_surface_backend = {
 
 static void
 radeon_surface_init (radeon_surface_t *surface,
-		     cairo_content_t content,
-		     cairo_drm_device_t *device)
+		     cairo_drm_device_t *device,
+		     cairo_format_t format,
+		     int width, int height)
 {
     _cairo_surface_init (&surface->base.base,
 			 &radeon_surface_backend,
 			 &device->base,
-			 content);
-    _cairo_drm_surface_init (&surface->base, device);
-
-    switch (content) {
-    case CAIRO_CONTENT_ALPHA:
-	surface->base.format = CAIRO_FORMAT_A8;
-	break;
-    case CAIRO_CONTENT_COLOR:
-	surface->base.format = CAIRO_FORMAT_RGB24;
-	break;
-    default:
-	ASSERT_NOT_REACHED;
-    case CAIRO_CONTENT_COLOR_ALPHA:
-	surface->base.format = CAIRO_FORMAT_ARGB32;
-	break;
-    }
+			 _cairo_content_from_format (format));
+    _cairo_drm_surface_init (&surface->base, format, width, height);
 }
 
 static cairo_surface_t *
 radeon_surface_create_internal (cairo_drm_device_t *device,
-		              cairo_content_t content,
-			      int width, int height)
+				cairo_format_t format,
+				int width, int height)
 {
     radeon_surface_t *surface;
     cairo_status_t status;
@@ -319,12 +306,9 @@ radeon_surface_create_internal (cairo_drm_device_t *device,
     if (unlikely (surface == NULL))
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    radeon_surface_init (surface, content, device);
+    radeon_surface_init (surface, device, format, width, height);
 
     if (width && height) {
-	surface->base.width  = width;
-	surface->base.height = height;
-
 	surface->base.stride =
 	    cairo_format_stride_for_width (surface->base.format, width);
 
@@ -344,10 +328,22 @@ radeon_surface_create_internal (cairo_drm_device_t *device,
 
 static cairo_surface_t *
 radeon_surface_create (cairo_drm_device_t *device,
-		     cairo_content_t content,
-		     int width, int height)
+		       cairo_format_t format,
+		       int width, int height)
 {
-    return radeon_surface_create_internal (device, content, width, height);
+    switch (format) {
+    default:
+    case CAIRO_FORMAT_INVALID:
+    case CAIRO_FORMAT_A1:
+    case CAIRO_FORMAT_RGB16_565:
+	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT));
+    case CAIRO_FORMAT_ARGB32:
+    case CAIRO_FORMAT_RGB24:
+    case CAIRO_FORMAT_A8:
+	break;
+    }
+
+    return radeon_surface_create_internal (device, format, width, height);
 }
 
 static cairo_surface_t *
@@ -358,7 +354,6 @@ radeon_surface_create_for_name (cairo_drm_device_t *device,
 {
     radeon_surface_t *surface;
     cairo_status_t status;
-    cairo_content_t content;
 
     switch (format) {
     default:
@@ -367,13 +362,8 @@ radeon_surface_create_for_name (cairo_drm_device_t *device,
     case CAIRO_FORMAT_RGB16_565:
 	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;
     }
 
@@ -384,11 +374,9 @@ radeon_surface_create_for_name (cairo_drm_device_t *device,
     if (unlikely (surface == NULL))
 	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
-    radeon_surface_init (surface, content, device);
+    radeon_surface_init (surface, device, format, width, height);
 
     if (width && height) {
-	surface->base.width  = width;
-	surface->base.height = height;
 	surface->base.stride = stride;
 
 	surface->base.bo = radeon_bo_create_for_name (to_radeon_device (&device->base),
diff --git a/src/drm/cairo-drm-surface.c b/src/drm/cairo-drm-surface.c
index a94150b..a8a8f32 100644
--- a/src/drm/cairo-drm-surface.c
+++ b/src/drm/cairo-drm-surface.c
@@ -36,28 +36,15 @@
 
 #include "cairo-error-private.h"
 
-cairo_surface_t *
-_cairo_drm_surface_create_similar (void			*abstract_surface,
-			           cairo_content_t	 content,
-				   int			 width,
-				   int			 height)
-{
-    cairo_drm_surface_t *surface = abstract_surface;
-    cairo_drm_device_t *device = (cairo_drm_device_t *) surface->base.device;
-
-    if (width > device->max_surface_size || height > device->max_surface_size)
-	return NULL;
-
-    return device->surface.create (device, content, width, height);
-}
-
 void
 _cairo_drm_surface_init (cairo_drm_surface_t *surface,
-			 cairo_drm_device_t *device)
+			 cairo_format_t format,
+			 int width, int height)
 {
     surface->bo = NULL;
-    surface->width  = 0;
-    surface->height = 0;
+    surface->format = format;
+    surface->width  = width;
+    surface->height = height;
     surface->stride = 0;
 
     surface->fallback = NULL;
@@ -100,15 +87,12 @@ _cairo_drm_surface_get_extents (void *abstract_surface,
 
 cairo_surface_t *
 cairo_drm_surface_create (cairo_device_t *abstract_device,
-			  cairo_content_t content,
+			  cairo_format_t format,
 			  int width, int height)
 {
     cairo_drm_device_t *device = (cairo_drm_device_t *) abstract_device;
     cairo_surface_t *surface;
 
-    if (! CAIRO_CONTENT_VALID (content))
-	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT));
-
     if (device != NULL && device->base.status)
     {
 	surface = _cairo_surface_create_in_error (device->base.status);
@@ -118,8 +102,7 @@ cairo_drm_surface_create (cairo_device_t *abstract_device,
 	     width == 0 || width > device->max_surface_size ||
 	     height == 0 || height > device->max_surface_size)
     {
-	surface = cairo_image_surface_create (_cairo_format_from_content (content),
-					      width, height);
+	surface = cairo_image_surface_create (format, width, height);
     }
     else if (device->base.finished)
     {
@@ -127,7 +110,9 @@ cairo_drm_surface_create (cairo_device_t *abstract_device,
     }
     else
     {
-	surface = device->surface.create (device, content, width, height);
+	surface = device->surface.create (device, format, width, height);
+	if (surface->status == CAIRO_STATUS_INVALID_SIZE)
+	    surface = cairo_image_surface_create (format, width, height);
     }
 
     return surface;
@@ -334,7 +319,7 @@ cairo_drm_surface_get_stride (cairo_surface_t *abstract_surface)
 
 /* XXX drm or general surface layer? naming? */
 cairo_surface_t *
-cairo_drm_surface_map (cairo_surface_t *abstract_surface)
+cairo_drm_surface_map_to_image (cairo_surface_t *abstract_surface)
 {
     cairo_drm_surface_t *surface;
     cairo_drm_device_t *device;
diff --git a/src/drm/cairo-drm-xr.c b/src/drm/cairo-drm-xr.c
new file mode 100644
index 0000000..c3b1bbd
--- /dev/null
+++ b/src/drm/cairo-drm-xr.c
@@ -0,0 +1,2377 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2010 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 Intel Corporation
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+/*
+ * Implement an X Acceleration Architecture using the cairo-drm
+ * backends.
+ */
+
+#include "cairoint.h"
+#include "cairo-drm-private.h"
+
+#ifdef HAVE_DIX_CONFIG_H
+#include <dix-config.h>
+#else
+#include <xorg-server.h>
+#endif
+
+#include "xf86.h"
+#include "gcstruct.h"
+#include "scrnintstr.h"
+#include "pixmapstr.h"
+#include "windowstr.h"
+#include "picturestr.h"
+#include "mi.h"
+#include "fb.h"
+#ifdef MITSHM
+#include <X11/extensions/shm.h>
+#endif
+#ifdef RENDER
+#include "fbpict.h"
+#include "glyphstr.h"
+#endif
+
+#include "cairo-drm-xr.h"
+
+struct _xr_screen {
+    cairo_device_t *device;
+
+    CreateGCProcPtr SavedCreateGC;
+    CloseScreenProcPtr SavedCloseScreen;
+    GetImageProcPtr SavedGetImage;
+    GetSpansProcPtr SavedGetSpans;
+    CreatePixmapProcPtr SavedCreatePixmap;
+    DestroyPixmapProcPtr SavedDestroyPixmap;
+    CopyWindowProcPtr SavedCopyWindow;
+    ChangeWindowAttributesProcPtr SavedChangeWindowAttributes;
+    BitmapToRegionProcPtr SavedBitmapToRegion;
+
+#ifdef RENDER
+    CompositeProcPtr SavedComposite;
+    GlyphsProcPtr SavedGlyphs;
+    CompositeRectsProcPtr SavedCompositeRects;
+    TrapezoidsProcPtr SavedTrapezoids;
+    TrianglesProcPtr SavedTriangles;
+    TriStripProcPtr SavedTriStrip;
+    TriFanProcPtr SavedTriFan;
+    AddTrianglesProcPtr SavedAddTriangles;
+    AddTrapsProcPtr SavedAddTraps;
+
+    RealizeGlyphProcPtr SavedRealizeGlyph;
+    UnrealizeGlyphProcPtr SavedUnrealizeGlyph;
+#endif
+};
+
+struct xr_access_gc {
+    cairo_surface_t *stipple;
+    cairo_surface_t *tile;
+};
+
+struct xr_access_window {
+    cairo_surface_t *background;
+    cairo_surface_t *border;
+};
+
+static int xr_screen_index;
+static int xr_pixmap_index;
+
+static inline xr_screen_t *
+xr_get_screen (ScreenPtr screen)
+{
+    return dixLookupPrivate (&screen->devPrivates, &xr_screen_index);
+}
+
+static inline PixmapPtr
+xr_drawable_get_pixmap (DrawablePtr drawable)
+{
+    if (drawable->type == DRAWABLE_WINDOW)
+	return drawable->pScreen->GetWindowPixmap ((WindowPtr) drawable);
+    else
+	return (PixmapPtr) drawable;
+}
+
+static inline cairo_drm_surface_t *
+xr_pixmap_get_drm_surface (PixmapPtr pixmap)
+{
+    return dixLookupPrivate (&pixmap->devPrivates, &xr_pixmap_index);
+}
+
+static cairo_drm_surface_t *
+xr_drawable_get_drm_surface (DrawablePtr drawable)
+{
+    return xr_pixmap_get_drm_surface (xr_drawable_get_pixmap (drawable));
+}
+
+static cairo_format_t
+xr_format_for_depth (int depth)
+{
+    switch (depth) {
+    case 1:
+	return CAIRO_FORMAT_A1;
+    case 8:
+	return CAIRO_FORMAT_A8;
+    case 16:
+	return CAIRO_FORMAT_RGB16_565;
+    case 24:
+	return CAIRO_FORMAT_RGB24;
+    default:
+    case 32:
+	return CAIRO_FORMAT_ARGB32;
+    }
+}
+
+static cairo_surface_t *
+xr_pixmap_get_surface (PixmapPtr pixmap)
+{
+    cairo_drm_surface_t *drm;
+
+    drm = xr_pixmap_get_drm_surface (pixmap);
+    if (drm != NULL)
+	return cairo_surface_reference (&drm->base);
+
+    return cairo_image_surface_create_for_data (pixmap->devPrivate.ptr,
+						xr_format_for_depth (pixmap->drawable.depth),
+						pixmap->drawable.width,
+						pixmap->drawable.height,
+						pixmap->devKind);
+}
+
+static cairo_surface_t *
+xr_drawable_get_surface (DrawablePtr drawable)
+{
+    return xr_pixmap_get_surface (xr_drawable_get_pixmap (drawable));
+}
+
+static cairo_bool_t
+xr_prepare_access (DrawablePtr drawable,
+		   cairo_surface_t **image)
+{
+    PixmapPtr pixmap;
+    cairo_drm_surface_t *drm;
+
+    *image = NULL;
+
+    pixmap = xr_drawable_get_pixmap (drawable);
+    drm = xr_pixmap_get_drm_surface (pixmap);
+    if (drm == NULL)
+	return TRUE;
+
+    *image = cairo_drm_surface_map_to_image (&drm->base);
+    if ((*image)->status)
+	return FALSE;
+
+    pixmap->devPrivate.ptr =
+	((cairo_image_surface_t *) *image)->data;
+
+    return TRUE;
+}
+
+static void
+xr_finish_access (DrawablePtr drawable,
+		  cairo_surface_t *image)
+{
+    if (image != NULL) {
+	cairo_drm_surface_unmap (&xr_drawable_get_drm_surface (drawable)->base,
+				 image);
+    }
+}
+
+static cairo_bool_t
+xr_prepare_access_gc (GCPtr gc,
+		      struct xr_access_gc *local)
+{
+    local->stipple = NULL;
+    local->tile = NULL;
+
+    if (gc->stipple) {
+	if (! xr_prepare_access (&gc->stipple->drawable, &local->stipple))
+	    return FALSE;
+    }
+
+    if (gc->fillStyle == FillTiled) {
+	if (! xr_prepare_access (&gc->tile.pixmap->drawable,
+				  &local->tile))
+	{
+	    if (local->stipple) {
+		xr_finish_access (&gc->stipple->drawable,
+				   local->stipple);
+	    }
+
+	    return FALSE;
+	}
+    }
+
+    return TRUE;
+}
+
+static void
+xr_finish_access_gc (GCPtr gc,
+		     struct xr_access_gc *local)
+{
+    if (local->tile) {
+	xr_finish_access(&gc->tile.pixmap->drawable,
+			  local->tile);
+    }
+
+    if (local->stipple) {
+	xr_finish_access(&gc->stipple->drawable,
+			  local->stipple);
+    }
+}
+
+static void
+xr_fill_spans (DrawablePtr drawable,
+	       GCPtr gc,
+	       int nspans,
+	       DDXPointPtr ppt,
+	       int *pwidth,
+	       int fSorted)
+{
+    cairo_surface_t *image;
+    struct xr_access_gc access_gc;
+
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+    if (xr_prepare_access (drawable, &image)) {
+	if (xr_prepare_access_gc (gc, &access_gc)) {
+	    fbFillSpans (drawable, gc,
+			 nspans, ppt, pwidth,
+			 fSorted);
+	    xr_finish_access_gc(gc, &access_gc);
+	}
+	xr_finish_access (drawable, image);
+    }
+}
+
+static void
+xr_set_spans (DrawablePtr drawable,
+	      GCPtr gc,
+	      char *psrc,
+	      DDXPointPtr ppt,
+	      int *pwidth,
+	      int nspans,
+	      int fSorted)
+{
+    cairo_surface_t *image;
+
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+    if (xr_prepare_access (drawable, &image)) {
+	fbSetSpans (drawable, gc, psrc, ppt, pwidth, nspans, fSorted);
+	xr_finish_access (drawable, image);
+    }
+}
+
+#define XR_PM_IS_SOLID(_pDrawable, _pm) \
+	(((_pm) & FbFullMask((_pDrawable)->depth)) == \
+	 FbFullMask((_pDrawable)->depth))
+
+static cairo_clip_t *
+xr_gc_get_clip (GCPtr gc, int xoff, int yoff)
+{
+    return NULL;
+}
+
+static cairo_bool_t
+xr_do_put_image (DrawablePtr drawable,
+		 GCPtr gc,
+		 int depth,
+		 int x, int y,
+		 int width, int height,
+		 int format,
+		 char *bits, int src_stride)
+{
+    cairo_surface_t *surface;
+    cairo_clip_t *clip;
+    cairo_surface_t *image;
+    cairo_surface_pattern_t pattern;
+    cairo_status_t status;
+    cairo_path_fixed_t path;
+    cairo_fixed_t x1, y1, x2, y2;
+
+    if (format != ZPixmap || drawable->bitsPerPixel < 8)
+	return FALSE;
+
+    if (! XR_PM_IS_SOLID (drawable, gc->planemask) || gc->alu != GXcopy)
+	return FALSE;
+
+    clip = xr_gc_get_clip (gc, drawable->x, drawable->y);
+    x1 = _cairo_fixed_from_int (x + drawable->x);
+    y1 = _cairo_fixed_from_int (y + drawable->y);
+    x2 = x1 + _cairo_fixed_from_int (width);
+    y2 = y1 + _cairo_fixed_from_int (height);
+    _cairo_path_fixed_init (&path);
+    if (_cairo_path_fixed_move_to (&path, x1, y1) ||
+	_cairo_path_fixed_line_to (&path, x2, y1) ||
+	_cairo_path_fixed_line_to (&path, x2, y2) ||
+	_cairo_path_fixed_line_to (&path, x1, y2) ||
+	_cairo_path_fixed_close_path (&path))
+    {
+	goto err_path;
+    }
+
+    image = cairo_image_surface_create_for_data ((uint8_t *) bits,
+						 xr_format_for_depth (depth),
+						 width, height, src_stride);
+    _cairo_pattern_init_for_surface (&pattern, image);
+    cairo_surface_destroy (image);
+    pattern.base.filter = CAIRO_FILTER_NEAREST;
+    cairo_matrix_init_translate (&pattern.base.matrix,
+				 -x - drawable->x,
+				 -y - drawable->x);
+
+    surface = xr_drawable_get_surface (drawable);
+    status = _cairo_surface_fill (surface,
+				  CAIRO_OPERATOR_SOURCE,
+				  &pattern.base,
+				  &path,
+				  CAIRO_FILL_RULE_WINDING,
+				  CAIRO_ANTIALIAS_DEFAULT,
+				  CAIRO_GSTATE_TOLERANCE_DEFAULT,
+				  clip);
+    cairo_surface_destroy (surface);
+    _cairo_pattern_fini (&pattern.base);
+err_path:
+    _cairo_path_fixed_fini (&path);
+
+    (void) status;
+    return TRUE;
+}
+
+static void
+xr_put_image(DrawablePtr drawable,
+	      GCPtr gc, int depth,
+	      int x, int y,
+	      int w, int h,
+	      int leftPad,
+	      int format,
+	      char *bits)
+{
+    if (! xr_do_put_image (drawable,
+			   gc,
+			   depth,
+			   x, y, w, h,
+			   format,
+			   bits,
+			   PixmapBytePad (w, drawable->depth)))
+    {
+	cairo_surface_t *image;
+
+	//ErrorF ("fallback: %s\n", __FUNCTION__);
+	if (xr_prepare_access (drawable, &image)) {
+	    fbPutImage (drawable, gc, depth,
+			x, y, w, h,
+			leftPad, format, bits);
+	    xr_finish_access (drawable, image);
+	}
+    }
+}
+
+static void
+xr_pattern_init_for_drawable (cairo_surface_pattern_t *pattern,
+			      DrawablePtr drawable)
+{
+    cairo_surface_t *surface;
+
+    surface = xr_drawable_get_surface (drawable);
+    _cairo_pattern_init_for_surface (pattern, surface);
+    cairo_surface_destroy (surface);
+
+    pattern->base.filter = CAIRO_FILTER_NEAREST;
+    pattern->base.extend = CAIRO_EXTEND_NONE;
+    cairo_matrix_init_translate (&pattern->base.matrix,
+				 drawable->x,
+				 drawable->y);
+}
+
+static RegionPtr
+xr_copy_area (DrawablePtr src,
+	      DrawablePtr dst,
+	      GCPtr gc,
+	      int src_x, int src_y,
+	      int width, int height,
+	      int dst_x, int dst_y)
+{
+    cairo_surface_pattern_t pattern;
+    cairo_clip_t *clip;
+    cairo_surface_t *surface;
+    cairo_status_t status;
+    cairo_path_fixed_t path;
+    cairo_fixed_t x1, x2, y1, y2;
+
+    xr_pattern_init_for_drawable (&pattern, src);
+    cairo_matrix_translate (&pattern.base.matrix,
+			    src->x + src_x - dst_x - dst->x,
+			    src->y + src_y - dst_y - dst->y);
+
+    clip = xr_gc_get_clip (gc, dst->x, dst->y);
+    surface = xr_drawable_get_surface (dst);
+
+    x1 = _cairo_fixed_from_int (dst_x + dst->x);
+    y1 = _cairo_fixed_from_int (dst_y + dst->y);
+    x2 = x1 + _cairo_fixed_from_int (width);
+    y2 = y1 + _cairo_fixed_from_int (height);
+    _cairo_path_fixed_init (&path);
+    if (_cairo_path_fixed_move_to (&path, x1, y1) ||
+	_cairo_path_fixed_line_to (&path, x2, y1) ||
+	_cairo_path_fixed_line_to (&path, x2, y2) ||
+	_cairo_path_fixed_line_to (&path, x1, y2) ||
+	_cairo_path_fixed_close_path (&path))
+    {
+	goto err_path;
+    }
+
+    status = _cairo_surface_fill (surface,
+				  CAIRO_OPERATOR_SOURCE,
+				  &pattern.base,
+				  &path,
+				  CAIRO_FILL_RULE_WINDING,
+				  CAIRO_ANTIALIAS_DEFAULT,
+				  CAIRO_GSTATE_TOLERANCE_DEFAULT,
+				  clip);
+    (void) status;
+
+err_path:
+    _cairo_path_fixed_fini (&path);
+    _cairo_pattern_fini (&pattern.base);
+    cairo_surface_destroy (surface);
+
+    return miGetCompositeClip (gc);
+}
+
+static RegionPtr
+xr_copy_plane (DrawablePtr src,
+	       DrawablePtr dst,
+	       GCPtr gc,
+	       int src_x, int src_y,
+	       int w, int h,
+	       int dst_x, int dst_y,
+	       unsigned long bitPlane)
+{
+    RegionPtr ret = NULL;
+    cairo_surface_t *src_image, *dst_image;
+
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+    if (xr_prepare_access (dst, &dst_image)) {
+	if (xr_prepare_access (src, &src_image)) {
+	    ret = fbCopyPlane (src, dst, gc,
+			       src_x, src_y,
+			       w, h,
+			       dst_x, dst_y,
+			       bitPlane);
+	    xr_finish_access (src, src_image);
+	}
+	xr_finish_access (dst, dst_image);
+    }
+    return ret;
+}
+
+static void
+xr_poly_point (DrawablePtr drawable,
+	       GCPtr gc,
+	       int mode,
+	       int npt,
+	       DDXPointPtr ppt)
+{
+    cairo_surface_t *image;
+
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+    if (xr_prepare_access (drawable, &image)) {
+	fbPolyPoint (drawable, gc, mode, npt, ppt);
+	xr_finish_access (drawable, image);
+    }
+}
+
+static void
+xr_poly_line (DrawablePtr drawable,
+	      GCPtr gc,
+	      int mode,
+	      int npt,
+	      DDXPointPtr ppt)
+{
+    cairo_surface_t *image;
+
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+    if (xr_prepare_access (drawable, &image)) {
+	fbPolyLine (drawable, gc, mode, npt, ppt);
+	xr_finish_access (drawable, image);
+    }
+}
+
+static void
+xr_poly_segment (DrawablePtr drawable,
+		 GCPtr gc,
+		 int nseg,
+		 xSegment *pSeg)
+{
+    cairo_surface_t *image;
+
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+    if (xr_prepare_access (drawable, &image)) {
+	fbPolySegment (drawable, gc, nseg, pSeg);
+	xr_finish_access (drawable, image);
+    }
+}
+
+static void
+xr_poly_rectangle (DrawablePtr drawable,
+		    GCPtr gc,
+		    int nrect,
+		    xRectangle *pRects)
+{
+    cairo_surface_t *image;
+
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+    if (xr_prepare_access (drawable, &image)) {
+	fbPolyRectangle (drawable, gc, nrect, pRects);
+	xr_finish_access (drawable, image);
+    }
+}
+
+static void
+xr_poly_arc (DrawablePtr drawable,
+	     GCPtr gc,
+	     int narcs,
+	     xArc *pArcs)
+{
+    cairo_surface_t *image;
+
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+    if (xr_prepare_access (drawable, &image)) {
+	fbPolyArc (drawable, gc, narcs, pArcs);
+	xr_finish_access (drawable, image);
+    }
+}
+
+static void
+xr_poly_fill (DrawablePtr drawable,
+	      GCPtr gc,
+	      int shape,
+	      int mode,
+	      int count,
+	      DDXPointPtr pPts)
+{
+    cairo_surface_t *image;
+
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+    if (xr_prepare_access (drawable, &image)) {
+	fbFillPolygon (drawable, gc, shape, mode, count, pPts);
+	xr_finish_access (drawable, image);
+    }
+}
+
+static void
+xr_poly_fill_rect_fallback (DrawablePtr drawable,
+			    GCPtr gc,
+			    int nrect,
+			    xRectangle *prect)
+{
+    cairo_surface_t *image;
+
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+    if (xr_prepare_access (drawable, &image)) {
+	miPolyFillRect (drawable, gc, nrect, prect);
+	xr_finish_access (drawable, image);
+    }
+}
+
+
+static void
+xr_poly_fill_rect (DrawablePtr drawable,
+		   GCPtr gc,
+		   int nrect,
+		   xRectangle *rect)
+{
+    cairo_clip_t *clip;
+    cairo_surface_t *surface;
+    cairo_status_t status;
+    int n;
+
+    if (gc->alu != GXcopy && gc->alu != GXclear) {
+	xr_poly_fill_rect_fallback (drawable, gc, nrect, rect);
+	return;
+    }
+
+    if (gc->fillStyle != FillSolid &&
+	!(gc->tileIsPixel && gc->fillStyle == FillTiled))
+    {
+	xr_poly_fill_rect_fallback (drawable, gc, nrect, rect);
+	return;
+    }
+
+    surface = xr_drawable_get_surface (drawable);
+    clip = xr_gc_get_clip (gc, drawable->x, drawable->y);
+    if (clip == NULL && nrect == 1 &&
+	rect->x <= 0 &&
+	rect->y <= 0 &&
+	rect->width >= drawable->width &&
+	rect->height >= drawable->height &&
+	(gc->alu == GXclear || (gc->fgPixel & 0x00ffffff) == 0))
+    {
+	status = _cairo_surface_paint (surface,
+				       CAIRO_OPERATOR_CLEAR,
+				       &_cairo_pattern_clear.base,
+				       NULL);
+    }
+    else
+    {
+	cairo_path_fixed_t path;
+	cairo_fixed_t x_off, y_off;
+	cairo_solid_pattern_t pattern;
+	cairo_color_t color;
+
+	x_off = _cairo_fixed_from_int (drawable->x);
+	y_off = _cairo_fixed_from_int (drawable->y);
+	_cairo_path_fixed_init (&path);
+	for (n = 0; n < nrect; n++) {
+	    cairo_fixed_t x1 = x_off + _cairo_fixed_from_int (rect[n].x);
+	    cairo_fixed_t x2 = x1 + _cairo_fixed_from_int (rect[n].width);
+	    cairo_fixed_t y1 = y_off + _cairo_fixed_from_int (rect[n].y);
+	    cairo_fixed_t y2 = y1 + _cairo_fixed_from_int (rect[n].height);
+
+	    if (_cairo_path_fixed_move_to (&path, x1, y1) ||
+		_cairo_path_fixed_line_to (&path, x2, y1) ||
+		_cairo_path_fixed_line_to (&path, x2, y2) ||
+		_cairo_path_fixed_line_to (&path, x1, y2) ||
+		_cairo_path_fixed_close_path (&path))
+	    {
+		goto err_path;
+	    }
+	}
+
+	_cairo_color_init_rgb (&color,
+			       ((gc->fgPixel & 0x00ff0000) >> 16) / 255.,
+			       ((gc->fgPixel & 0x0000ff00) >> 8) / 255.,
+			       ((gc->fgPixel & 0x000000ff) >> 0) / 255.);
+	_cairo_pattern_init_solid (&pattern, &color, CAIRO_CONTENT_COLOR);
+
+	status = _cairo_surface_fill (surface,
+				      gc->alu == GXcopy ? CAIRO_OPERATOR_SOURCE : CAIRO_OPERATOR_CLEAR,
+				      &pattern.base,
+				      &path,
+				      CAIRO_FILL_RULE_WINDING,
+				      1.,
+				      CAIRO_ANTIALIAS_DEFAULT,
+				      clip);
+err_path:
+	_cairo_path_fixed_fini (&path);
+    }
+
+    cairo_surface_destroy (surface);
+    (void) status;
+}
+
+static void
+xr_poly_fill_arc (DrawablePtr drawable,
+		  GCPtr gc,
+		  int narc,
+		  xArc *arc)
+{
+    cairo_surface_t *image;
+
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+    if (xr_prepare_access (drawable, &image)) {
+	miPolyFillArc (drawable, gc, narc, arc);
+	xr_finish_access (drawable, image);
+    }
+}
+
+static void
+xr_image_glyph_blt (DrawablePtr drawable, GCPtr gc,
+			  int x, int y, unsigned int nglyph,
+			  CharInfoPtr * ppci, pointer pglyphBase)
+{
+    cairo_surface_t *image;
+    struct xr_access_gc local_gc;
+
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+    if (xr_prepare_access (drawable, &image)) {
+	if (xr_prepare_access_gc (gc, &local_gc)) {
+	    fbImageGlyphBlt (drawable, gc,
+			     x, y,
+			     nglyph,
+			     ppci,
+			     pglyphBase);
+	    xr_finish_access_gc (gc, &local_gc);
+	}
+	xr_finish_access (drawable, image);
+    }
+}
+
+static void
+xr_poly_glyph_blt (DrawablePtr drawable,
+		   GCPtr gc,
+		   int x, int y,
+		   unsigned int nglyph,
+		   CharInfoPtr *ppci,
+		   pointer pglyphBase)
+{
+    cairo_surface_t *image;
+    struct xr_access_gc local_gc;
+
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+    if (xr_prepare_access (drawable, &image)) {
+	if (xr_prepare_access_gc (gc, &local_gc)) {
+	    fbPolyGlyphBlt (drawable, gc,
+			    x, y,
+			    nglyph,
+			    ppci,
+			    pglyphBase);
+	    xr_finish_access_gc (gc, &local_gc);
+	}
+	xr_finish_access (drawable, image);
+    }
+}
+
+static void
+xr_push_pixels (GCPtr gc,
+		PixmapPtr src,
+		DrawablePtr dst,
+		int w, int h, int x, int y)
+{
+    cairo_surface_t *src_image, *dst_image;
+    struct xr_access_gc local_gc;
+
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+    if (xr_prepare_access (dst, &dst_image)) {
+	if (xr_prepare_access (&src->drawable, &src_image)) {
+	    if (xr_prepare_access_gc (gc, &local_gc)) {
+		fbPushPixels (gc, src, dst,
+			     w, h, x, y);
+		xr_finish_access_gc (gc, &local_gc);
+	    }
+	    xr_finish_access (&src->drawable, src_image);
+	}
+	xr_finish_access (dst, dst_image);
+    }
+}
+
+static void
+xr_validate_gc (GCPtr gc,
+		unsigned long changes,
+		DrawablePtr drawable)
+{
+    static const GCOps xr_ops = {
+	xr_fill_spans,
+	xr_set_spans,
+	xr_put_image,
+	xr_copy_area,
+	xr_copy_plane,
+	xr_poly_point,
+	xr_poly_line,
+	xr_poly_segment,
+	xr_poly_rectangle,
+	xr_poly_arc,
+	xr_poly_fill,
+	xr_poly_fill_rect,
+	xr_poly_fill_arc,
+	miPolyText8,
+	miPolyText16,
+	miImageText8,
+	miImageText16,
+	xr_image_glyph_blt,
+	xr_poly_glyph_blt,
+	xr_push_pixels,
+    };
+
+    /* fbValidateGC will do direct access to pixmaps if the tiling has
+     * changed.  Preempt fbValidateGC by doing its work and masking the
+     * change out, so that we can do the prepare/finish access.
+     */
+#ifdef FB_24_32BIT
+    if (changes & GCTile && fbGetRotatedPixmap (gc)) {
+	gc->pScreen->DestroyPixmap (fbGetRotatedPixmap (gc));
+	fbGetRotatedPixmap (gc) = 0;
+    }
+
+    if (gc->fillStyle == FillTiled) {
+	PixmapPtr old;
+
+	old = gc->tile.pixmap;
+	if (old->drawable.bitsPerPixel != drawable->bitsPerPixel) {
+	    PixmapPtr new = fbGetRotatedPixmap (gc);
+	    if (new == NULL ||
+		new->drawable.bitsPerPixel != drawable->bitsPerPixel)
+	    {
+		cairo_surface_t *image;
+
+		if (new)
+		    gc->pScreen->DestroyPixmap (new);
+
+		/* fb24_32ReformatTile will do direct access
+		 * of a newly-allocated pixmap.  This isn't a
+		 * problem yet, since we don't put pixmaps in
+		 * FB until at least one accelerated UXA op.
+		 */
+		if (xr_prepare_access (&old->drawable, &image)) {
+		    new = fb24_32ReformatTile (old,
+					       drawable->bitsPerPixel);
+		    xr_finish_access (&old->drawable, image);
+		}
+	    }
+
+	    if (new) {
+		fbGetRotatedPixmap (gc) = old;
+		gc->tile.pixmap = new;
+		changes |= GCTile;
+	    }
+	}
+    }
+#endif
+
+    if (changes & GCTile) {
+	if (! gc->tileIsPixel &&
+	    FbEvenTile (gc->tile.pixmap->drawable.width *
+			drawable->bitsPerPixel))
+	{
+	    cairo_surface_t *image;
+
+	    if (xr_prepare_access (&gc->tile.pixmap->drawable,
+				    &image))
+	    {
+		fbPadPixmap(gc->tile.pixmap);
+		xr_finish_access(&gc->tile.pixmap->drawable, image);
+	    }
+	}
+
+	/* Mask out the GCTile change notification, now that we've
+	 * done FB's job for it.
+	 */
+	changes &= ~GCTile;
+    }
+
+    if (changes & GCStipple && gc->stipple) {
+	cairo_surface_t *image;
+
+	/* We can't inline stipple handling like we do for GCTile
+	 * because it sets fbgc privates.
+	 */
+	if (xr_prepare_access (&gc->stipple->drawable, &image)) {
+	    fbValidateGC (gc, changes, drawable);
+	    xr_finish_access (&gc->stipple->drawable, image);
+	}
+    } else {
+	fbValidateGC(gc, changes, drawable);
+    }
+
+    gc->ops = (GCOps *) & xr_ops;
+}
+
+static void
+xr_change_gc (GCPtr gc, unsigned long mask)
+{
+}
+
+static void
+xr_copy_gc (GCPtr src, unsigned long changes, GCPtr dst)
+{
+}
+
+static void
+xr_destroy_gc (GCPtr gc)
+{
+    miDestroyGC (gc);
+}
+
+static void
+xr_destroy_clip (GCPtr gc)
+{
+    miDestroyClip (gc);
+}
+
+static void
+xr_change_clip (GCPtr gc, int type, pointer value, int nrects)
+{
+    xr_destroy_clip (gc);
+
+    miChangeClip (gc, type, value, nrects);
+}
+
+static void
+xr_copy_clip (GCPtr dst, GCPtr src)
+{
+    miCopyClip (dst, src);
+}
+
+static int xr_create_gc (GCPtr gc)
+{
+    static GCFuncs funcs = {
+	xr_validate_gc,
+	xr_change_gc,
+	xr_copy_gc,
+	xr_destroy_gc,
+	xr_change_clip,
+	xr_destroy_clip,
+	xr_copy_clip,
+    };
+
+    if (! fbCreateGC (gc))
+	return FALSE;
+
+    gc->funcs = &funcs;
+    return TRUE;
+}
+
+static void
+xr_get_image (DrawablePtr drawable,
+	      int x, int y, int w, int h,
+	      unsigned int format, unsigned long planeMask,
+	      char *d)
+{
+    cairo_surface_t *image;
+
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+    if (xr_prepare_access (drawable, &image)) {
+	fbGetImage (drawable, x, y, w, h, format, planeMask, d);
+	xr_finish_access (drawable, image);
+    }
+}
+
+static void
+xr_get_spans (DrawablePtr drawable,
+	      int wMax,
+	      DDXPointPtr ppt,
+	      int *pwidth,
+	      int nspans,
+	      char *pdstStart)
+{
+    cairo_surface_t *image;
+
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+    if (xr_prepare_access (drawable, &image)) {
+	fbGetSpans (drawable, wMax, ppt, pwidth, nspans, pdstStart);
+	xr_finish_access (drawable, image);
+    }
+}
+
+static void
+xr_copy_window (WindowPtr win,
+		DDXPointRec origin,
+		RegionPtr src_region)
+{
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+#if 0
+    RegionRec dst_region;
+    PixmapPtr pixmap;
+    int dx, dy;
+
+    dx = origin.x - win->drawable.x;
+    dy = origin.y - win->drawable.y;
+    REGION_TRANSLATE (win->drawable.pScreen, src_region, -dx, -dy);
+
+    REGION_INIT (win->drawable.pScreen, &dst_region, NullBox, 0);
+
+    REGION_INTERSECT (win->drawable.pScreen,
+		      &dst_region, &win->borderClip,
+		     src_region);
+    pixmap = win->drawable.pScreen->GetWindowPixmap (win);
+#ifdef COMPOSITE
+    if (pixmap->screen_x || pixmap->screen_y)
+	REGION_TRANSLATE (win->drawable.pScreen, &dst_region,
+			  -pixmap->screen_x, -pixmap->screen_y);
+#endif
+
+    miCopyRegion (&pixmap->drawable, &pixmap->drawable,
+		  NULL, &dst_region, dx, dy,
+		  xr_copy_n_to_n, 0, NULL);
+
+    REGION_UNINIT (win->drawable.pScreen, &dst_region);
+#endif
+}
+
+static cairo_bool_t
+xr_prepare_access_window (WindowPtr win,
+			  struct xr_access_window *local)
+{
+    local->background = NULL;
+    local->border = NULL;
+
+    if (win->backgroundState == BackgroundPixmap) {
+	if (! xr_prepare_access (&win->background.pixmap->drawable,
+				 &local->background))
+	{
+	    return FALSE;
+	}
+    }
+
+    if (win->borderIsPixel == FALSE) {
+	if (! xr_prepare_access (&win->border.pixmap->drawable,
+				 &local->border))
+	{
+	    if (local->background) {
+		xr_finish_access (&win->background.pixmap->drawable,
+				  local->background);
+	    }
+	    return FALSE;
+	}
+    }
+    return TRUE;
+}
+
+static void
+xr_finish_access_window (WindowPtr win,
+			 struct xr_access_window *local)
+{
+    if (local->background) {
+	xr_finish_access (&win->background.pixmap->drawable,
+			  local->background);
+    }
+
+    if (local->border) {
+	xr_finish_access (&win->border.pixmap->drawable,
+			  local->border);
+    }
+}
+
+static Bool
+xr_change_window_attributes (WindowPtr win,
+			     unsigned long mask)
+{
+    Bool ret = FALSE;
+    struct xr_access_window local;
+
+    if (xr_prepare_access_window (win, &local)) {
+	ret = fbChangeWindowAttributes (win, mask);
+	xr_finish_access_window (win, &local);
+    }
+
+    return ret;
+}
+
+static RegionPtr
+xr_bitmap_to_region (PixmapPtr pPix)
+{
+    RegionPtr ret = NULL;
+    cairo_surface_t *image;
+
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+    if (xr_prepare_access (&pPix->drawable, &image)) {
+	ret = fbPixmapToRegion (pPix);
+	xr_finish_access (&pPix->drawable, image);
+    }
+
+    return ret;
+}
+
+static void
+_color_from_pixel (cairo_color_t *color, uint32_t pixel)
+{
+    color->alpha_short = (pixel & 0xff000000 >> 24);
+    color->alpha_short |= color->alpha_short << 8;
+
+    if (color->alpha_short == 0) {
+	color->red_short = color->green_short = color->blue_short = 0;
+	color->alpha = color->red = color->green = color->blue = 0.;
+	return;
+    }
+
+    color->red_short = (pixel & 0x00ff0000 >> 16);
+    color->red_short |= color->red_short << 8;
+
+    color->green_short = (pixel & 0x0000ff00 >> 8);
+    color->green_short |= color->green_short << 8;
+
+    color->blue_short = (pixel & 0x000000ff >> 0);
+    color->blue_short |= color->blue_short << 8;
+
+    color->alpha = color->alpha_short / (double) 0xffff;
+    color->red = color->red_short / (double) 0xffff / color->alpha;
+    color->green = color->green_short / (double) 0xffff / color->alpha;
+    color->blue = color->blue_short / (double) 0xffff / color->alpha;
+}
+
+static uint32_t
+_pixmap_first_pixel (PixmapPtr pixmap)
+{
+    cairo_surface_t *image;
+    uint32_t pixel;
+    void *fb;
+
+    if (! xr_prepare_access (&pixmap->drawable, &image))
+	return 0;
+
+    fb = pixmap->devPrivate.ptr;
+    switch (pixmap->drawable.bitsPerPixel) {
+    case 32:
+	pixel = *(uint32_t *) fb;
+	break;
+    case 16:
+	pixel = *(uint16_t *) fb;
+	break;
+    default:
+	pixel = *(CARD8 *) fb;
+	break;
+    }
+    xr_finish_access (&pixmap->drawable, image);
+
+    return pixel;
+}
+
+static cairo_bool_t
+_rgba_from_pixel (uint32_t pixel,
+		  uint16_t *red,
+		  uint16_t *green,
+		  uint16_t *blue,
+		  uint16_t *alpha,
+		  uint32_t format)
+{
+    int rbits, bbits, gbits, abits;
+    int rshift, bshift, gshift, ashift;
+
+    rbits = PICT_FORMAT_R(format);
+    gbits = PICT_FORMAT_G(format);
+    bbits = PICT_FORMAT_B(format);
+    abits = PICT_FORMAT_A(format);
+
+    if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A) {
+	rshift = gshift = bshift = ashift = 0;
+    } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB) {
+	bshift = 0;
+	gshift = bbits;
+	rshift = gshift + gbits;
+	ashift = rshift + rbits;
+    } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
+	rshift = 0;
+	gshift = rbits;
+	bshift = gshift + gbits;
+	ashift = bshift + bbits;
+    } else {
+	return FALSE;
+    }
+
+    if (rbits) {
+	*red = ((pixel >> rshift) & ((1 << rbits) - 1)) << (16 - rbits);
+	while (rbits < 16) {
+	    *red |= *red >> rbits;
+	    rbits <<= 1;
+	}
+    } else
+	*red = 0;
+
+    if (gbits) {
+	*green = ((pixel >> gshift) & ((1 << gbits) - 1)) << (16 - gbits);
+	while (gbits < 16) {
+	    *green |= *green >> gbits;
+	    gbits <<= 1;
+	}
+    } else
+	*green = 0;
+
+    if (bbits) {
+	*blue = ((pixel >> bshift) & ((1 << bbits) - 1)) << (16 - bbits);
+	while (bbits < 16) {
+	    *blue |= *blue >> bbits;
+	    bbits <<= 1;
+	}
+    } else
+	*blue = 0;
+
+    if (abits) {
+	*alpha =
+	    ((pixel >> ashift) & ((1 << abits) - 1)) << (16 - abits);
+	while (abits < 16) {
+	    *alpha |= *alpha >> abits;
+	    abits <<= 1;
+	}
+    } else
+	*alpha = 0xffff;
+
+    return TRUE;
+}
+
+static cairo_bool_t
+_color_from_pixmap (PixmapPtr	 pixmap,
+		    uint32_t	 src_format,
+		    cairo_color_t  *color)
+{
+    uint32_t pixel = _pixmap_first_pixel(pixmap);
+    if (! _rgba_from_pixel (pixel,
+			    &color->red_short,
+			    &color->green_short,
+			    &color->blue_short,
+			    &color->alpha_short,
+			    src_format))
+    {
+	return FALSE;
+    }
+
+    if (color->alpha_short == 0) {
+	color->red_short = color->green_short = color->blue_short = 0;
+	color->alpha = color->red = color->green = color->blue = 0.;
+	return TRUE;
+    }
+
+    color->alpha = color->alpha_short / (double) 0xffff;
+    color->red = color->red_short / (double) 0xffff / color->alpha;
+    color->green = color->green_short / (double) 0xffff / color->alpha;
+    color->blue = color->blue_short / (double) 0xffff / color->alpha;
+    return TRUE;
+}
+
+static cairo_bool_t
+xr_pattern_init_for_picture (cairo_pattern_union_t *pattern,
+			     PicturePtr picture)
+{
+    cairo_color_t color;
+
+    if (picture->pSourcePict) {
+	SourcePict *source = picture->pSourcePict;
+	switch (source->type) {
+	case SourcePictTypeSolidFill:
+	    _color_from_pixel (&color, source->solidFill.color);
+	    _cairo_pattern_init_solid (&pattern->solid,
+				       &color,
+				       CAIRO_CONTENT_COLOR_ALPHA);
+	    break;
+	default:
+	    return FALSE;
+	}
+    } else if (picture->pDrawable) {
+	cairo_surface_t *surface;
+
+	if (picture->alphaMap)
+	    return FALSE;
+
+	if (picture->pDrawable->width == 1 &&
+	    picture->pDrawable->height == 1 &&
+	    picture->repeat == 1)
+	{
+	    if (! _color_from_pixmap ((PixmapPtr) picture->pDrawable,
+				      picture->format,
+				      &color))
+		goto use_surface;
+
+	    _cairo_pattern_init_solid (&pattern->solid,
+				       &color,
+				       CAIRO_CONTENT_COLOR_ALPHA);
+	}
+	else
+	{
+use_surface:
+	    surface = xr_drawable_get_surface (picture->pDrawable);
+	    _cairo_pattern_init_for_surface (&pattern->surface,
+					     surface);
+	    cairo_surface_destroy (surface);
+	}
+    } else {
+	return FALSE;
+    }
+
+    if (! picture->repeat) {
+	pattern->base.extend = CAIRO_EXTEND_NONE;
+    } else switch (picture->repeatType) {
+    case RepeatNormal:
+	pattern->base.extend = CAIRO_EXTEND_REPEAT;
+	break;
+    case RepeatPad:
+	pattern->base.extend = CAIRO_EXTEND_PAD;
+	break;
+    case RepeatReflect:
+	pattern->base.extend = CAIRO_EXTEND_REFLECT;
+	break;
+    default:
+	goto fail;
+    }
+
+    switch (picture->filter) {
+    case PictFilterNearest:
+	pattern->base.filter = CAIRO_FILTER_NEAREST;
+	break;
+    case PictFilterBilinear:
+	pattern->base.filter = CAIRO_FILTER_BILINEAR;
+	break;
+    case PictFilterFast:
+	pattern->base.filter = CAIRO_FILTER_FAST;
+	break;
+    case PictFilterGood:
+	pattern->base.filter = CAIRO_FILTER_GOOD;
+	break;
+    case PictFilterBest:
+	pattern->base.filter = CAIRO_FILTER_BEST;
+	break;
+    default:
+	goto fail;
+    }
+
+    return TRUE;
+
+fail:
+    _cairo_pattern_fini (&pattern->base);
+    return FALSE;
+}
+
+static cairo_bool_t
+_render_operator (CARD8 render_op, cairo_operator_t *op)
+{
+    switch (render_op) {
+    case PictOpClear: *op = CAIRO_OPERATOR_CLEAR; break;
+    case PictOpSrc: *op = CAIRO_OPERATOR_SOURCE; break;
+    case PictOpOver: *op = CAIRO_OPERATOR_OVER; break;
+    case PictOpIn: *op = CAIRO_OPERATOR_IN; break;
+    case PictOpOut: *op = CAIRO_OPERATOR_OUT; break;
+    case PictOpAtop: *op = CAIRO_OPERATOR_ATOP; break;
+    case PictOpDst: *op = CAIRO_OPERATOR_DEST; break;
+    case PictOpOverReverse: *op = CAIRO_OPERATOR_DEST_OVER; break;
+    case PictOpInReverse: *op = CAIRO_OPERATOR_DEST_IN; break;
+    case PictOpOutReverse: *op = CAIRO_OPERATOR_DEST_OUT; break;
+    case PictOpAtopReverse: *op = CAIRO_OPERATOR_DEST_ATOP; break;
+    case PictOpXor: *op = CAIRO_OPERATOR_XOR; break;
+    case PictOpAdd: *op = CAIRO_OPERATOR_ADD; break;
+    case PictOpSaturate: *op = CAIRO_OPERATOR_SATURATE; break;
+    case PictOpMultiply: *op = CAIRO_OPERATOR_MULTIPLY; break;
+    case PictOpScreen: *op = CAIRO_OPERATOR_SCREEN; break;
+    case PictOpOverlay: *op = CAIRO_OPERATOR_OVERLAY; break;
+    case PictOpDarken: *op = CAIRO_OPERATOR_DARKEN; break;
+    case PictOpLighten: *op = CAIRO_OPERATOR_LIGHTEN; break;
+    case PictOpColorDodge: *op = CAIRO_OPERATOR_COLOR_DODGE; break;
+    case PictOpColorBurn: *op = CAIRO_OPERATOR_COLOR_BURN; break;
+    case PictOpHardLight: *op = CAIRO_OPERATOR_HARD_LIGHT; break;
+    case PictOpSoftLight: *op = CAIRO_OPERATOR_SOFT_LIGHT; break;
+    case PictOpDifference: *op = CAIRO_OPERATOR_DIFFERENCE; break;
+    case PictOpExclusion: *op = CAIRO_OPERATOR_EXCLUSION; break;
+    case PictOpHSLHue: *op = CAIRO_OPERATOR_HSL_HUE; break;
+    case PictOpHSLSaturation: *op = CAIRO_OPERATOR_HSL_SATURATION; break;
+    case PictOpHSLColor: *op = CAIRO_OPERATOR_HSL_COLOR; break;
+    case PictOpHSLLuminosity: *op = CAIRO_OPERATOR_HSL_LUMINOSITY; break;
+
+    default: return FALSE;
+    }
+
+    return TRUE;
+}
+
+static void
+xr_picture_get_clip (PicturePtr picture,
+		     cairo_clip_t *clip)
+{
+    cairo_status_t status;
+
+    _cairo_clip_init (clip);
+
+    if (picture->pCompositeClip) {
+	cairo_path_fixed_t path;
+	BoxPtr pbox;
+	int nbox;
+
+	nbox = REGION_NUM_RECTS (picture->pCompositeClip);
+	pbox = REGION_RECTS (picture->pCompositeClip);
+	_cairo_path_fixed_init (&path);
+	while (nbox--) {
+	    if (_cairo_path_fixed_move_to (&path,
+					   _cairo_fixed_from_int (pbox->x1),
+					   _cairo_fixed_from_int (pbox->y1)) ||
+		_cairo_path_fixed_line_to (&path,
+					   _cairo_fixed_from_int (pbox->x2),
+					   _cairo_fixed_from_int (pbox->y1)) ||
+		_cairo_path_fixed_line_to (&path,
+					   _cairo_fixed_from_int (pbox->x2),
+					   _cairo_fixed_from_int (pbox->y2)) ||
+		_cairo_path_fixed_line_to (&path,
+					   _cairo_fixed_from_int (pbox->x1),
+					   _cairo_fixed_from_int (pbox->y2)) ||
+		_cairo_path_fixed_close_path (&path))
+	    {
+		goto err_path;
+	    }
+	}
+
+	status = _cairo_clip_clip (clip,
+				   &path,
+				   CAIRO_FILL_RULE_WINDING,
+				   1.0,
+				   CAIRO_ANTIALIAS_DEFAULT);
+
+err_path:
+	_cairo_path_fixed_fini (&path);
+    }
+
+    (void) status;
+}
+
+static void
+xr_composite (CARD8 render_op,
+	      PicturePtr pSrc,
+	      PicturePtr pMask,
+	      PicturePtr pDst,
+	      INT16 xSrc, INT16 ySrc,
+	      INT16 xMask, INT16 yMask,
+	      INT16 xDst, INT16 yDst,
+	      CARD16 width, CARD16 height)
+{
+    cairo_pattern_union_t source, mask;
+    cairo_operator_t op;
+    cairo_surface_t *surface;
+    cairo_clip_t clip;
+    cairo_rectangle_int_t rect;
+    cairo_bool_t mask_is_clipped = FALSE, source_is_clipped = FALSE;
+    cairo_status_t status;
+
+    if (! _render_operator (render_op, &op))
+	goto fallback;
+
+    if (! xr_pattern_init_for_picture (&source, pSrc))
+	goto fallback;
+
+    cairo_matrix_translate (&source.base.matrix,
+			    xSrc - xDst, ySrc - yDst);
+
+    if (pMask) {
+	if (! xr_pattern_init_for_picture (&mask, pMask)) {
+	    _cairo_pattern_fini (&source.base);
+	    goto fallback;
+	}
+
+	cairo_matrix_translate (&mask.base.matrix,
+				xMask - xDst, yMask - yDst);
+    }
+
+    xr_picture_get_clip (pDst, &clip);
+    rect.x = xDst;
+    rect.y = yDst;
+    rect.width  = width;
+    rect.height = height;
+    status = _cairo_clip_rectangle (&clip, &rect);
+
+#if 0
+    {
+	cairo_clip_t clip_source;
+
+	xr_picture_get_clip (pSrc, &clip_source);
+	if (clip_source.path != NULL) {
+	    _cairo_clip_apply_clip (&clip, &clip_source);
+	    source_is_clipped = TRUE;
+	}
+	_cairo_clip_fini (&clip_source);
+    }
+    if (pMask) {
+	cairo_clip_t clip_mask;
+
+	xr_picture_get_clip (pMask, &clip_mask);
+	if (clip_mask.path != NULL) {
+	    _cairo_clip_apply_clip (&clip, &clip_mask);
+	    mask_is_clipped = TRUE;
+	}
+	_cairo_clip_fini (&clip_mask);
+    }
+#endif
+
+    surface = xr_drawable_get_surface (pDst->pDrawable);
+    if (! clip.all_clipped) {
+	if (pMask) {
+	    status = _cairo_surface_mask (surface, op,
+					  &source.base,
+					  &mask.base,
+					  &clip);
+	} else {
+	    status = _cairo_surface_paint (surface, op,
+					   &source.base,
+					   &clip);
+	}
+    }
+
+#if 0
+    if (source_is_clipped) {
+	/* clear areas in dst where source was clipped */
+	cairo_surface_t *surface;
+	cairo_clip_t clip_source;
+
+	if (pMask) {
+	    cairo_clip_t clip_mask;
+
+	    xr_picture_get_clip (pMask, &clip_mask);
+	    if (clip_mask.path != NULL) {
+		_cairo_clip_apply_clip (&local_clip, &clip_mask);
+		mask_is_clipped = TRUE;
+	    }
+	    _cairo_clip_fini (&clip_mask);
+	}
+
+	xr_picture_get_inverse_clip (pSrc, &clip_source);
+	_cairo_clip_apply_clip (&clip_source, &clip);
+
+	if (pMask) {
+	    status = _cairo_surface_mask (surface,
+					  CAIRO_OPERATOR_CLEAR,
+					  &_cairo_pattern_clear.base,
+					  &mask.base,
+					  &clip_source);
+	} else {
+	    status = _cairo_surface_paint (surface,
+					  CAIRO_OPERATOR_CLEAR,
+					  &_cairo_pattern_clear.base,
+					  &clip_source);
+	}
+	_cairo_clip_fini (&clip_source);
+    }
+
+    if (mask_is_clipped && ! _cairo_operator_bounded_by_mask (op)) {
+	/* clear areas in dst where mask was clipped */
+	cairo_surface_t *surface;
+	cairo_clip_t clip_mask;
+
+	xr_picture_get_inverse_clip (pMask, &clip_mask);
+	_cairo_clip_apply_clip (&clip, &clip_mask);
+	_cairo_clip_fini (&clip_mask);
+
+	status = _cairo_surface_paint (surface,
+				       CAIRO_OPERATOR_CLEAR,
+				       &_cairo_pattern_clear.base,
+				       &clip);
+    }
+#endif
+
+    cairo_surface_destroy (surface);
+    _cairo_clip_fini (&clip);
+
+    if (pMask)
+	_cairo_pattern_fini (&mask.base);
+    _cairo_pattern_fini (&source.base);
+
+    return;
+
+fallback:
+    {
+	cairo_surface_t *dst_image, *src_image, *mask_image;
+	//ErrorF ("fallback: %s\n", __FUNCTION__);
+	if (xr_prepare_access (pDst->pDrawable, &dst_image)) {
+	    if (pSrc->pDrawable == NULL ||
+		xr_prepare_access (pSrc->pDrawable, &src_image))
+	    {
+		if (pMask == NULL || pMask->pDrawable == NULL ||
+		    xr_prepare_access (pMask->pDrawable, &mask_image))
+		{
+		    fbComposite (op, pSrc, pMask, pDst,
+				 xSrc, ySrc,
+				 xMask, yMask,
+				 xDst, yDst,
+				 width, height);
+		    if (pMask && pMask->pDrawable)
+			xr_finish_access (pMask->pDrawable, mask_image);
+		}
+		if (pSrc->pDrawable)
+		    xr_finish_access (pSrc->pDrawable, src_image);
+	    }
+	    xr_finish_access (pDst->pDrawable, dst_image);
+	}
+    }
+}
+
+static void
+xr_glyphs (CARD8 op,
+	   PicturePtr pSrc,
+	   PicturePtr pDst,
+	   PictFormatPtr maskFormat,
+	   INT16 xSrc, INT16 ySrc,
+	   int nlist,
+	   GlyphListPtr list,
+	   GlyphPtr *glyphs)
+{
+}
+
+static cairo_bool_t
+xr_do_fill (cairo_operator_t op,
+	    PicturePtr pSrc,
+	    PicturePtr pDst,
+	    int		src_x,
+	    int		src_y,
+	    cairo_path_fixed_t *path)
+{
+    cairo_pattern_union_t source;
+    cairo_clip_t clip;
+    cairo_surface_t *surface;
+    cairo_status_t status;
+
+    if (! xr_pattern_init_for_picture (&source, pSrc))
+	return FALSE;
+
+    cairo_matrix_translate (&source.base.matrix, src_x, src_y);
+
+    surface = xr_drawable_get_surface (pDst->pDrawable);
+    xr_picture_get_clip (pDst, &clip);
+    status = _cairo_surface_fill (surface, op, &source.base, path,
+				  CAIRO_FILL_RULE_WINDING,
+				  pDst->polyEdge == PolyEdgeSharp ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT,
+				  CAIRO_GSTATE_TOLERANCE_DEFAULT,
+				  clip.path ? &clip : NULL);
+    _cairo_clip_fini (&clip);
+    cairo_surface_destroy (surface);
+    _cairo_pattern_fini (&source.base);
+
+    return TRUE;
+}
+
+static void
+xr_composite_rects (CARD8		 render_op,
+		    PicturePtr		 picture,
+		    xRenderColor	*xColor,
+		    int			 nrect,
+		    xRectangle		*rect)
+{
+    cairo_operator_t op;
+    cairo_clip_t clip;
+    cairo_surface_t *surface;
+    cairo_status_t status;
+
+    if (! _render_operator (render_op, &op))
+	goto fallback;
+
+    surface = xr_drawable_get_surface (picture->pDrawable);
+    xr_picture_get_clip (picture, &clip);
+    if (clip.path == NULL && nrect == 1 &&
+	rect->x <= 0 &&
+	rect->y <= 0 &&
+	rect->width >= picture->pDrawable->width &&
+	rect->height >= picture->pDrawable->height &&
+	(op == CAIRO_OPERATOR_CLEAR || (op == CAIRO_OPERATOR_SOURCE && xColor->alpha <= 0x00ff)))
+    {
+	status = _cairo_surface_paint (surface,
+				       CAIRO_OPERATOR_CLEAR,
+				       &_cairo_pattern_clear.base,
+				       NULL);
+    }
+    else
+    {
+	cairo_path_fixed_t path;
+	cairo_fixed_t x_off, y_off;
+	cairo_solid_pattern_t pattern;
+	cairo_color_t color;
+	int n;
+
+	x_off = _cairo_fixed_from_int (picture->pDrawable->x);
+	y_off = _cairo_fixed_from_int (picture->pDrawable->y);
+	_cairo_path_fixed_init (&path);
+	for (n = 0; n < nrect; n++) {
+	    cairo_fixed_t x1 = x_off + _cairo_fixed_from_int (rect[n].x);
+	    cairo_fixed_t x2 = x1 + _cairo_fixed_from_int (rect[n].width);
+	    cairo_fixed_t y1 = y_off + _cairo_fixed_from_int (rect[n].y);
+	    cairo_fixed_t y2 = y1 + _cairo_fixed_from_int (rect[n].height);
+
+	    if (_cairo_path_fixed_move_to (&path, x1, y1) ||
+		_cairo_path_fixed_line_to (&path, x2, y1) ||
+		_cairo_path_fixed_line_to (&path, x2, y2) ||
+		_cairo_path_fixed_line_to (&path, x1, y2) ||
+		_cairo_path_fixed_close_path (&path))
+	    {
+		goto err_path;
+	    }
+	}
+
+	color.red_short   = xColor->red;
+	color.green_short = xColor->green;
+	color.blue_short  = xColor->blue;
+	color.alpha_short = xColor->alpha;
+	if (color.alpha_short <= 0x00ff) {
+	    color.red_short = color.green_short = color.blue_short = 0;
+	    color.alpha = color.red = color.green = color.blue = 0.;
+	} else {
+	    color.alpha = color.alpha_short / (double) 0xffff;
+	    color.red   = color.red_short / (double) 0xffff / color.alpha;
+	    color.green = color.green_short / (double) 0xffff / color.alpha;
+	    color.blue  = color.blue_short / (double) 0xffff / color.alpha;
+	}
+	_cairo_pattern_init_solid (&pattern, &color, CAIRO_CONTENT_COLOR);
+
+	status = _cairo_surface_fill (surface, op,
+				      &pattern.base,
+				      &path,
+				      CAIRO_FILL_RULE_WINDING,
+				      1.,
+				      CAIRO_ANTIALIAS_DEFAULT,
+				      clip.path ? &clip : NULL);
+err_path:
+	_cairo_path_fixed_fini (&path);
+    }
+
+    cairo_surface_destroy (surface);
+    _cairo_clip_fini (&clip);
+
+    (void) status;
+    return;
+
+fallback:
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+#if 0
+    {
+	cairo_surface_t *dst_image, *src_image;
+	if (xr_prepare_access (pDst->pDrawable, &dst_image)) {
+	    if (pSrc->pDrawable == NULL ||
+		xr_prepare_access (pSrc->pDrawable, &src_image))
+	    {
+		fbTrapezoids (op, pSrc, pDst,
+			      maskFormat,
+			      xSrc, ySrc,
+			      ntrap, traps);
+		if (pSrc->pDrawable)
+		    xr_finish_access (pSrc->pDrawable, src_image);
+	    }
+	    xr_finish_access (pDst->pDrawable, dst_image);
+	}
+    }
+#endif
+    return;
+}
+
+static void
+xr_trapezoids (CARD8	    render_op,
+	       PicturePtr   pSrc,
+	       PicturePtr   pDst,
+	       PictFormatPtr maskFormat,
+	       INT16	    xSrc,
+	       INT16	    ySrc,
+	       int	    ntrap,
+	       xTrapezoid   *traps)
+{
+    cairo_path_fixed_t path;
+    cairo_operator_t op;
+    int src_x, src_y;
+
+    if (! _render_operator (render_op, &op))
+	goto fallback;
+
+    src_x = xSrc - (traps->left.p1.x >> 16);
+    src_y = ySrc - (traps->left.p1.y >> 16);
+
+    _cairo_path_fixed_init (&path);
+    while (ntrap--) {
+	if (traps->bottom > traps->top) {
+	    cairo_fixed_t x1, x2;
+	    cairo_fixed_t y1, y2;
+
+	    if (traps->left.p1.y != traps->top) {
+		double x;
+
+		x = _cairo_fixed_16_16_to_double (traps->left.p1.x) +
+		    _cairo_fixed_16_16_to_double (traps->left.p1.x - traps->left.p2.x) *
+		    _cairo_fixed_16_16_to_double (traps->top - traps->left.p2.y) /
+		    _cairo_fixed_16_16_to_double (traps->left.p1.y - traps->left.p2.y);
+
+		x1 = _cairo_fixed_from_double (x);
+	    } else {
+		x1 = _cairo_fixed_from_16_16 (traps->left.p1.x);
+	    }
+
+	    if (traps->right.p1.y != traps->top) {
+		double x;
+
+		x = _cairo_fixed_16_16_to_double (traps->right.p1.x) +
+		    _cairo_fixed_16_16_to_double (traps->right.p1.x - traps->right.p2.x) *
+		    _cairo_fixed_16_16_to_double (traps->top - traps->right.p2.y) /
+		    _cairo_fixed_16_16_to_double (traps->right.p1.y - traps->right.p2.y);
+
+		x2 = _cairo_fixed_from_double (x);
+	    } else {
+		x2 = _cairo_fixed_from_16_16 (traps->left.p2.x);
+	    }
+
+	    y1 = _cairo_fixed_from_16_16 (traps->top);
+	    y2 = _cairo_fixed_from_16_16 (traps->bottom);
+
+	    if (_cairo_path_fixed_move_to (&path, x1, y1) ||
+		_cairo_path_fixed_line_to (&path, x2, y1) ||
+		_cairo_path_fixed_line_to (&path, x2, y2) ||
+		_cairo_path_fixed_line_to (&path, x1, y2) ||
+		_cairo_path_fixed_close_path (&path))
+	    {
+		goto err_path;
+	    }
+	}
+
+	traps++;
+    }
+
+    if (! xr_do_fill (op, pSrc, pDst, src_x, src_y, &path)) {
+	_cairo_path_fixed_fini (&path);
+	goto fallback;
+    }
+
+err_path:
+    _cairo_path_fixed_fini (&path);
+
+    return;
+
+fallback:
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+#if 0
+    {
+	cairo_surface_t *dst_image, *src_image;
+	if (xr_prepare_access (pDst->pDrawable, &dst_image)) {
+	    if (pSrc->pDrawable == NULL ||
+		xr_prepare_access (pSrc->pDrawable, &src_image))
+	    {
+		fbTrapezoids (op, pSrc, pDst,
+			      maskFormat,
+			      xSrc, ySrc,
+			      ntrap, traps);
+		if (pSrc->pDrawable)
+		    xr_finish_access (pSrc->pDrawable, src_image);
+	    }
+	    xr_finish_access (pDst->pDrawable, dst_image);
+	}
+    }
+#endif
+    return;
+}
+
+static void
+xr_triangles (CARD8	    render_op,
+	      PicturePtr	    pSrc,
+	      PicturePtr	    pDst,
+	      PictFormatPtr   maskFormat,
+	      INT16	    xSrc,
+	      INT16	    ySrc,
+	      int	     ntriangles,
+	      xTriangle	    *triangles)
+{
+    cairo_path_fixed_t path;
+    cairo_operator_t op;
+    int src_x, src_y;
+
+    if (! _render_operator (render_op, &op))
+	goto fallback;
+
+    src_x = xSrc - (triangles->p1.x >> 16);
+    src_y = ySrc - (triangles->p1.y >> 16);
+
+    _cairo_path_fixed_init (&path);
+    while (ntriangles--) {
+	if (_cairo_path_fixed_move_to (&path,
+				       _cairo_fixed_from_16_16 (triangles->p1.x),
+				       _cairo_fixed_from_16_16 (triangles->p1.y)) ||
+	    _cairo_path_fixed_line_to (&path,
+				       _cairo_fixed_from_16_16 (triangles->p2.x),
+				       _cairo_fixed_from_16_16 (triangles->p2.y)) ||
+	    _cairo_path_fixed_line_to (&path,
+				       _cairo_fixed_from_16_16 (triangles->p3.x),
+				       _cairo_fixed_from_16_16 (triangles->p3.y)) ||
+	    _cairo_path_fixed_close_path (&path))
+	{
+	    goto err_path;
+	}
+
+	triangles++;
+    }
+
+    if (! xr_do_fill (op, pSrc, pDst, src_x, src_y, &path)) {
+	_cairo_path_fixed_fini (&path);
+	goto fallback;
+    }
+
+err_path:
+    _cairo_path_fixed_fini (&path);
+
+    return;
+
+fallback:
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+#if 0
+    {
+	cairo_surface_t *dst_image, *src_image;
+	if (xr_prepare_access (pDst->pDrawable, &dst_image)) {
+	    if (pSrc->pDrawable == NULL ||
+		xr_prepare_access (pSrc->pDrawable, &src_image))
+	    {
+		fbTriangles (op, pSrc, pDst,
+			     maskFormat,
+			     xSrc, ySrc,
+			     ntriangles, triangles);
+		if (pSrc->pDrawable)
+		    xr_finish_access (pSrc->pDrawable, src_image);
+	    }
+	    xr_finish_access (pDst->pDrawable, dst_image);
+	}
+    }
+#endif
+    return;
+}
+
+static void
+xr_tristrip (CARD8	    op,
+	     PicturePtr	    pSrc,
+	     PicturePtr	    pDst,
+	     PictFormatPtr    maskFormat,
+	     INT16	    xSrc,
+	     INT16	    ySrc,
+	     int		    npoints,
+	     xPointFixed	    *points)
+{
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+#if 0
+    {
+	cairo_surface_t *dst_image, *src_image;
+	if (xr_prepare_access (pDst->pDrawable, &dst_image)) {
+	    if (pSrc->pDrawable == NULL ||
+		xr_prepare_access (pSrc->pDrawable, &src_image))
+	    {
+		fbTriStrip (op, pSrc, pDst,
+			     maskFormat,
+			     xSrc, ySrc,
+			     npoints, points);
+		if (pSrc->pDrawable)
+		    xr_finish_access (pSrc->pDrawable, src_image);
+	    }
+	    xr_finish_access (pDst->pDrawable, dst_image);
+	}
+    }
+#endif
+}
+
+static void
+xr_trifan (CARD8		render_op,
+	   PicturePtr	pSrc,
+	   PicturePtr	pDst,
+	   PictFormatPtr	maskFormat,
+	   INT16		xSrc,
+	   INT16		ySrc,
+	   int		npoints,
+	   xPointFixed	*points)
+{
+    cairo_path_fixed_t path;
+    cairo_operator_t op;
+    int src_x, src_y;
+
+    if (! _render_operator (render_op, &op))
+	goto fallback;
+
+    src_x = xSrc - (points->x >> 16);
+    src_y = ySrc - (points->y >> 16);
+
+    _cairo_path_fixed_init (&path);
+    points++;
+    while (--npoints) {
+	if (_cairo_path_fixed_line_to (&path,
+				       _cairo_fixed_from_16_16 (points->x),
+				       _cairo_fixed_from_16_16 (points->y)))
+	{
+	    goto err_path;
+	}
+
+	points++;
+    }
+    if (_cairo_path_fixed_close_path (&path))
+	goto err_path;
+
+    if (! xr_do_fill (op, pSrc, pDst, src_x, src_y, &path)) {
+	_cairo_path_fixed_fini (&path);
+	goto fallback;
+    }
+
+err_path:
+    _cairo_path_fixed_fini (&path);
+
+    return;
+
+fallback:
+    //ErrorF ("fallback: %s\n", __FUNCTION__);
+#if 0
+    {
+	cairo_surface_t *dst_image, *src_image;
+	if (xr_prepare_access (pDst->pDrawable, &dst_image)) {
+	    if (pSrc->pDrawable == NULL ||
+		xr_prepare_access (pSrc->pDrawable, &src_image))
+	    {
+		fbTriFan (op, pSrc, pDst,
+			     maskFormat,
+			     xSrc, ySrc,
+			     npoints, points);
+		if (pSrc->pDrawable)
+		    xr_finish_access (pSrc->pDrawable, src_image);
+	    }
+	    xr_finish_access (pDst->pDrawable, dst_image);
+	}
+    }
+#endif
+    return;
+}
+
+static void
+xr_add_triangles (PicturePtr picture,
+		  INT16 x_off, INT16 y_off,
+		  int ntriangle, xTriangle *triangles)
+{
+    cairo_path_fixed_t path;
+    cairo_clip_t clip;
+    cairo_surface_t *surface;
+    cairo_status_t status;
+    int x, y;
+
+    x = _cairo_fixed_from_int (x_off);
+    y = _cairo_fixed_from_int (y_off);
+
+    _cairo_path_fixed_init (&path);
+    while (ntriangle--) {
+	if (_cairo_path_fixed_move_to (&path,
+				       x + _cairo_fixed_from_16_16 (triangles->p1.x),
+				       y + _cairo_fixed_from_16_16 (triangles->p1.y)) ||
+	    _cairo_path_fixed_line_to (&path,
+				       x + _cairo_fixed_from_16_16 (triangles->p2.x),
+				       y + _cairo_fixed_from_16_16 (triangles->p2.y)) ||
+	    _cairo_path_fixed_line_to (&path,
+				       x + _cairo_fixed_from_16_16 (triangles->p3.x),
+				       y + _cairo_fixed_from_16_16 (triangles->p3.y)) ||
+	    _cairo_path_fixed_close_path (&path))
+	{
+	    goto err_path;
+	}
+
+	triangles++;
+    }
+
+    surface = xr_drawable_get_surface (picture->pDrawable);
+    xr_picture_get_clip (picture, &clip);
+    status = _cairo_surface_fill (surface,
+				  CAIRO_OPERATOR_ADD,
+				  &_cairo_pattern_white.base,
+				  &path,
+				  CAIRO_FILL_RULE_WINDING,
+				  picture->polyEdge == PolyEdgeSharp ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT,
+				  CAIRO_GSTATE_TOLERANCE_DEFAULT,
+				  clip.path ? &clip : NULL);
+    _cairo_clip_fini (&clip);
+    cairo_surface_destroy (surface);
+
+err_path:
+    _cairo_path_fixed_fini (&path);
+}
+
+static void
+xr_add_traps (PicturePtr picture,
+	      INT16 x_off, INT16 y_off,
+	      int ntrap, xTrap * traps)
+{
+    cairo_path_fixed_t path;
+    cairo_clip_t clip;
+    cairo_surface_t *surface;
+    cairo_status_t status;
+    int x, y;
+
+    x = _cairo_fixed_from_int (x_off);
+    y = _cairo_fixed_from_int (y_off);
+
+    _cairo_path_fixed_init (&path);
+    while (ntrap--) {
+	if (_cairo_path_fixed_move_to (&path,
+				       x + _cairo_fixed_from_16_16 (traps->top.l),
+				       y + _cairo_fixed_from_16_16 (traps->top.y)) ||
+	    _cairo_path_fixed_line_to (&path,
+				       x + _cairo_fixed_from_16_16 (traps->top.r),
+				       y + _cairo_fixed_from_16_16 (traps->top.y)) ||
+	    _cairo_path_fixed_line_to (&path,
+				       x + _cairo_fixed_from_16_16 (traps->bot.r),
+				       y + _cairo_fixed_from_16_16 (traps->bot.y)) ||
+	    _cairo_path_fixed_move_to (&path,
+				       x + _cairo_fixed_from_16_16 (traps->bot.l),
+				       y + _cairo_fixed_from_16_16 (traps->bot.y)) ||
+	    _cairo_path_fixed_close_path (&path))
+	{
+	    goto err_path;
+	}
+
+	traps++;
+    }
+
+    surface = xr_drawable_get_surface (picture->pDrawable);
+    xr_picture_get_clip (picture, &clip);
+    status = _cairo_surface_fill (surface,
+				  CAIRO_OPERATOR_ADD,
+				  &_cairo_pattern_white.base,
+				  &path,
+				  CAIRO_FILL_RULE_WINDING,
+				  picture->polyEdge == PolyEdgeSharp ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT,
+				  CAIRO_GSTATE_TOLERANCE_DEFAULT,
+				  clip.path ? &clip : NULL);
+    _cairo_clip_fini (&clip);
+    cairo_surface_destroy (surface);
+
+err_path:
+    _cairo_path_fixed_fini (&path);
+}
+
+static Bool
+xr_realize_glyph (ScreenPtr screen, GlyphPtr glyph)
+{
+    return TRUE;
+}
+
+static void
+xr_unrealize_glyph (ScreenPtr screen, GlyphPtr glyph)
+{
+}
+
+static PixmapPtr
+xr_create_pixmap (ScreenPtr screen,
+		  int w, int h, int depth,
+		  unsigned usage)
+{
+    xr_screen_t *xr = xr_get_screen (screen);
+    PixmapPtr pixmap;
+
+    if (w > 32767 || h > 32767)
+	return NullPixmap;
+
+    if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE)
+	return fbCreatePixmap (screen, w, h, depth, usage);
+
+    if (w && h) {
+	cairo_surface_t *surface;
+	cairo_format_t format;
+
+	format = xr_format_for_depth (depth);
+	surface = cairo_drm_surface_create (xr->device, format, w, h);
+	if (unlikely (surface->status))
+	    goto fallback;
+
+	pixmap = fbCreatePixmap (screen, 0, 0, depth, usage);
+	screen->ModifyPixmapHeader (pixmap, w, h, 0, 0,
+				    cairo_drm_surface_get_stride (surface),
+				    NULL);
+	dixSetPrivate (&pixmap->devPrivates, &xr_pixmap_index, surface);
+    } else {
+fallback:
+	pixmap = fbCreatePixmap (screen, w, h, depth, usage);
+    }
+
+    return pixmap;
+}
+
+static Bool
+xr_destroy_pixmap (PixmapPtr pixmap)
+{
+	if (pixmap->refcnt == 1)
+	    cairo_surface_destroy (&xr_pixmap_get_drm_surface (pixmap)->base);
+
+	fbDestroyPixmap(pixmap);
+	return TRUE;
+}
+
+static Bool
+xr_close_screen (int i, ScreenPtr screen)
+{
+    xr_screen_t *xr = xr_get_screen(screen);
+
+    screen->CreateGC = xr->SavedCreateGC;
+    screen->CloseScreen = xr->SavedCloseScreen;
+    screen->GetImage = xr->SavedGetImage;
+    screen->GetSpans = xr->SavedGetSpans;
+    screen->CreatePixmap = xr->SavedCreatePixmap;
+    screen->DestroyPixmap = xr->SavedDestroyPixmap;
+    screen->CopyWindow = xr->SavedCopyWindow;
+    screen->ChangeWindowAttributes =
+	xr->SavedChangeWindowAttributes;
+    screen->BitmapToRegion = xr->SavedBitmapToRegion;
+#ifdef RENDER
+    {
+	PictureScreenPtr ps = GetPictureScreenIfSet(screen);
+	if (ps) {
+	    ps->Composite = xr->SavedComposite;
+	    ps->Glyphs = xr->SavedGlyphs;
+	    ps->CompositeRects = xr->SavedCompositeRects;
+	    ps->Trapezoids = xr->SavedTrapezoids;
+	    ps->Triangles = xr->SavedTriangles;
+	    ps->TriStrip = xr->SavedTriStrip;
+	    ps->TriFan = xr->SavedTriFan;
+	    ps->AddTriangles = xr->SavedAddTriangles;
+	    ps->AddTraps = xr->SavedAddTraps;
+	    ps->RealizeGlyph = xr->SavedRealizeGlyph;
+	    ps->UnrealizeGlyph = xr->SavedUnrealizeGlyph;
+	}
+    }
+#endif
+
+    cairo_device_destroy (xr->device);
+    xfree (xr);
+
+    return screen->CloseScreen (i, screen);
+}
+
+static void
+xr_block_handler (void *data, OSTimePtr timeout, void *last_select_mask)
+{
+    xr_screen_t *xr = data;
+
+    cairo_device_flush (xr->device);
+    cairo_drm_device_throttle (xr->device);
+}
+
+static void
+xr_wakeup_handler (void *data, int result, void *last_select_mask)
+{
+}
+
+xr_screen_t *
+cairo_drm_xr_enable (ScreenPtr screen, int fd)
+{
+    xr_screen_t *xr;
+    cairo_device_t *device;
+
+    device = cairo_drm_device_get_for_fd (fd);
+    if (device == NULL)
+	return NULL;
+
+    xr = malloc (sizeof (*xr));
+    if (unlikely (xr == NULL))
+	goto cleanup_device;
+
+    xr->device = device;
+    dixSetPrivate (&screen->devPrivates,
+		   &xr_screen_index,
+		   xr);
+
+    if (! dixRequestPrivate(&xr_pixmap_index, 0))
+	goto cleanup_driver;
+
+    if (! RegisterBlockAndWakeupHandlers (xr_block_handler,
+					  xr_wakeup_handler,
+					  xr))
+    {
+	goto cleanup_driver;
+    }
+
+    /* wrap the screen interfaces */
+    xr->SavedCloseScreen = screen->CloseScreen;
+    screen->CloseScreen = xr_close_screen;
+
+    xr->SavedCreateGC = screen->CreateGC;
+    screen->CreateGC = xr_create_gc;
+
+    xr->SavedGetImage = screen->GetImage;
+    screen->GetImage = xr_get_image;
+
+    xr->SavedGetSpans = screen->GetSpans;
+    screen->GetSpans = xr_get_spans;
+
+    xr->SavedCopyWindow = screen->CopyWindow;
+    screen->CopyWindow = xr_copy_window;
+
+    xr->SavedChangeWindowAttributes =
+	screen->ChangeWindowAttributes;
+    screen->ChangeWindowAttributes = xr_change_window_attributes;
+
+    xr->SavedBitmapToRegion = screen->BitmapToRegion;
+    screen->BitmapToRegion = xr_bitmap_to_region;
+
+#ifdef RENDER
+    {
+	PictureScreenPtr ps = GetPictureScreenIfSet(screen);
+	if (ps) {
+	    xr->SavedComposite = ps->Composite;
+	    ps->Composite = xr_composite;
+
+	    xr->SavedGlyphs = ps->Glyphs;
+	    ps->Glyphs = xr_glyphs;
+
+	    xr->SavedCompositeRects = ps->CompositeRects;
+	    ps->CompositeRects = xr_composite_rects;
+
+	    xr->SavedTrapezoids = ps->Trapezoids;
+	    ps->Trapezoids = xr_trapezoids;
+
+	    xr->SavedTriangles = ps->Triangles;
+	    ps->Triangles = xr_triangles;
+
+	    xr->SavedTriStrip = ps->TriStrip;
+	    ps->TriStrip = xr_tristrip;
+
+	    xr->SavedTriFan = ps->TriFan;
+	    ps->TriFan = xr_trifan;
+
+	    xr->SavedAddTriangles = ps->AddTriangles;
+	    ps->AddTriangles = xr_add_triangles;
+
+	    xr->SavedAddTraps = ps->AddTraps;
+	    ps->AddTraps = xr_add_traps;
+
+	    xr->SavedRealizeGlyph = ps->RealizeGlyph;
+	    ps->RealizeGlyph = xr_realize_glyph;
+
+	    xr->SavedUnrealizeGlyph = ps->UnrealizeGlyph;
+	    ps->UnrealizeGlyph = xr_unrealize_glyph;
+	}
+    }
+#endif
+
+#ifdef MITSHM
+#if 0
+    /* Re-register with the MI funcs, which don't allow shared pixmaps.
+     * Shared pixmaps are almost always a performance loss for us, but this
+     * still allows for SHM PutImage.
+     */
+    {
+	static ShmFuncs xr_shm_funcs = { NULL, NULL };
+	ShmRegisterFuncs (screen, &xr_shm_funcs);
+    }
+#endif
+#endif
+
+    screen->CreatePixmap = xr_create_pixmap;
+    screen->DestroyPixmap = xr_destroy_pixmap;
+
+    LogMessage (X_INFO,
+		"XR(%d): Driver registered support.\n", screen->myNum);
+
+    return xr;
+
+cleanup_driver:
+    free (xr);
+cleanup_device:
+    cairo_device_destroy (device);
+    return NULL;
+}
+
+void
+cairo_drm_xr_pixmap_link_bo (xr_screen_t *xr,
+			     PixmapPtr pixmap,
+			     uint32_t name,
+			     cairo_format_t format,
+			     int width,
+			     int height,
+			     int stride)
+{
+    cairo_surface_t *surface;
+
+    cairo_surface_destroy (dixLookupPrivate (&pixmap->devPrivates,
+					     &xr_pixmap_index));
+
+    surface = cairo_drm_surface_create_for_name (xr->device, name, format,
+						 width, height, stride);
+    dixSetPrivate (&pixmap->devPrivates, &xr_pixmap_index, surface);
+}
+
+void
+cairo_drm_xr_pixmap_unlink_bo (xr_screen_t *xr,
+			       PixmapPtr pixmap)
+{
+    cairo_surface_destroy (dixLookupPrivate (&pixmap->devPrivates,
+					     &xr_pixmap_index));
+
+    dixSetPrivate (&pixmap->devPrivates, &xr_pixmap_index, NULL);
+}
commit c8fba4960339797521afbf8068fcbe62d064f5dc
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Apr 3 15:38:04 2010 +0100

    rtree: Remove the unused evict hook.

diff --git a/src/cairo-gl-glyphs.c b/src/cairo-gl-glyphs.c
index fe8fc87..f283f56 100644
--- a/src/cairo-gl-glyphs.c
+++ b/src/cairo-gl-glyphs.c
@@ -905,8 +905,7 @@ _cairo_gl_glyph_cache_init (cairo_gl_glyph_cache_t *cache)
 		       GLYPH_CACHE_WIDTH,
 		       GLYPH_CACHE_HEIGHT,
 		       GLYPH_CACHE_MIN_SIZE,
-		       sizeof (cairo_gl_glyph_private_t),
-		       NULL);
+		       sizeof (cairo_gl_glyph_private_t));
 }
 
 void
diff --git a/src/cairo-rtree-private.h b/src/cairo-rtree-private.h
index 1eda240..e539c0b 100644
--- a/src/cairo-rtree-private.h
+++ b/src/cairo-rtree-private.h
@@ -62,7 +62,6 @@ typedef struct _cairo_rtree_node {
 typedef struct _cairo_rtree {
     cairo_rtree_node_t root;
     int min_size;
-    void (*evict) (void *node);
     cairo_list_t pinned;
     cairo_list_t available;
     cairo_list_t evictable;
@@ -98,8 +97,7 @@ _cairo_rtree_init (cairo_rtree_t	*rtree,
 	           int			 width,
 		   int			 height,
 		   int			 min_size,
-		   int			 node_size,
-		   void			 (*evict) (void *node));
+		   int			 node_size);
 
 cairo_private cairo_int_status_t
 _cairo_rtree_insert (cairo_rtree_t	     *rtree,
diff --git a/src/cairo-rtree.c b/src/cairo-rtree.c
index a26fa85..d6e5791 100644
--- a/src/cairo-rtree.c
+++ b/src/cairo-rtree.c
@@ -80,8 +80,6 @@ _cairo_rtree_node_destroy (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
     if (node->state == CAIRO_RTREE_NODE_OCCUPIED) {
 	if (node->owner != NULL)
 	    *node->owner = NULL;
-	if (rtree->evict != NULL)
-	    rtree->evict (node);
     } else {
 	for (i = 0; i < 4 && node->children[i] != NULL; i++)
 	    _cairo_rtree_node_destroy (rtree, node->children[i]);
@@ -257,8 +255,6 @@ _cairo_rtree_evict_random (cairo_rtree_t	 *rtree,
 	    if (node->state == CAIRO_RTREE_NODE_OCCUPIED) {
 		if (node->owner != NULL)
 		    *node->owner = NULL;
-		if (rtree->evict != NULL)
-		    rtree->evict (node);
 	    } else {
 		for (i = 0; i < 4 && node->children[i] != NULL; i++)
 		    _cairo_rtree_node_destroy (rtree, node->children[i]);
@@ -331,11 +327,8 @@ _cairo_rtree_init (cairo_rtree_t	*rtree,
 	           int			 width,
 		   int			 height,
 		   int			 min_size,
-		   int			 node_size,
-		   void			 (*evict) (void *node))
+		   int			 node_size)
 {
-    rtree->evict = evict;
-
     assert (node_size >= (int) sizeof (cairo_rtree_node_t));
     _cairo_freepool_init (&rtree->node_freepool, node_size);
 
@@ -360,8 +353,6 @@ _cairo_rtree_reset (cairo_rtree_t *rtree)
     if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) {
 	if (rtree->root.owner != NULL)
 	    *rtree->root.owner = NULL;
-	if (rtree->evict != NULL)
-	    rtree->evict (&rtree->root);
     } else {
 	for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++)
 	    _cairo_rtree_node_destroy (rtree, rtree->root.children[i]);
@@ -385,8 +376,6 @@ _cairo_rtree_fini (cairo_rtree_t *rtree)
     if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) {
 	if (rtree->root.owner != NULL)
 	    *rtree->root.owner = NULL;
-	if (rtree->evict != NULL)
-	    rtree->evict (&rtree->root);
     } else {
 	for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++)
 	    _cairo_rtree_node_destroy (rtree, rtree->root.children[i]);
diff --git a/src/drm/cairo-drm-i915-surface.c b/src/drm/cairo-drm-i915-surface.c
index 30d66cf..5e04982 100644
--- a/src/drm/cairo-drm-i915-surface.c
+++ b/src/drm/cairo-drm-i915-surface.c
@@ -1784,8 +1784,7 @@ i915_surface_create_from_cacheable_image_internal (i915_device_t *device,
 			   IMAGE_CACHE_WIDTH,
 			   IMAGE_CACHE_HEIGHT,
 			   4,
-			   sizeof (i915_image_private_t),
-			   NULL);
+			   sizeof (i915_image_private_t));
 
 	status = _cairo_rtree_insert (&cache->rtree, width, height, &node);
 	assert (status == CAIRO_STATUS_SUCCESS);
diff --git a/src/drm/cairo-drm-intel.c b/src/drm/cairo-drm-intel.c
index 954783d..b5386cd 100644
--- a/src/drm/cairo-drm-intel.c
+++ b/src/drm/cairo-drm-intel.c
@@ -1133,7 +1133,7 @@ intel_get_glyph_cache (intel_device_t *device,
 	_cairo_rtree_init (&cache->rtree,
 			   INTEL_GLYPH_CACHE_WIDTH,
 			   INTEL_GLYPH_CACHE_HEIGHT,
-			   0, sizeof (intel_glyph_t), NULL);
+			   0, sizeof (intel_glyph_t));
     }
 
     *out = cache;
commit 2a0726337368462046ef84d9be4cf59734b39806
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Apr 3 15:30:18 2010 +0100

    rtree: defer propagating pinned nodes until eviction.
    
    Only during infrequent eviction do we require absolute knowledge of
    which graph of nodes are in use and thus pinned. So during the common
    use of querying the glyph cache, we just mark the leaf as used. Then we
    need to make space for a new glyph, we move the parents of the left
    nodes from the evictable list to the pinned list.

diff --git a/src/cairo-rtree-private.h b/src/cairo-rtree-private.h
index 70abefe..1eda240 100644
--- a/src/cairo-rtree-private.h
+++ b/src/cairo-rtree-private.h
@@ -113,8 +113,16 @@ _cairo_rtree_evict_random (cairo_rtree_t	 *rtree,
 		           int			  height,
 		           cairo_rtree_node_t	**out);
 
-cairo_private void *
-_cairo_rtree_pin (cairo_rtree_t *rtree, cairo_rtree_node_t *node);
+static inline void *
+_cairo_rtree_pin (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
+{
+    if (node->pinned == FALSE) {
+	cairo_list_move (&node->link, &rtree->pinned);
+	node->pinned = TRUE;
+    }
+
+    return node;
+}
 
 cairo_private void
 _cairo_rtree_unpin (cairo_rtree_t *rtree);
diff --git a/src/cairo-rtree.c b/src/cairo-rtree.c
index 7bba990..a26fa85 100644
--- a/src/cairo-rtree.c
+++ b/src/cairo-rtree.c
@@ -108,9 +108,7 @@ _cairo_rtree_node_collapse (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
 	node->children[0] = NULL;
 	node->state = CAIRO_RTREE_NODE_AVAILABLE;
 	cairo_list_move (&node->link, &rtree->available);
-
-	node = node->parent;
-    } while (node != NULL && ! node->pinned);
+    } while ((node = node->parent) != NULL);
 }
 
 cairo_status_t
@@ -193,8 +191,7 @@ _cairo_rtree_node_remove (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
     node->state = CAIRO_RTREE_NODE_AVAILABLE;
     cairo_list_move (&node->link, &rtree->available);
 
-    if (! node->parent->pinned)
-	_cairo_rtree_node_collapse (rtree, node->parent);
+    _cairo_rtree_node_collapse (rtree, node->parent);
 }
 
 cairo_int_status_t
@@ -230,9 +227,17 @@ _cairo_rtree_evict_random (cairo_rtree_t	 *rtree,
 		           int			  height,
 		           cairo_rtree_node_t		**out)
 {
-    cairo_rtree_node_t *node;
+    cairo_rtree_node_t *node, *next;
     int i, cnt;
 
+    /* propagate pinned from children to root */
+    cairo_list_foreach_entry_safe (node, next, cairo_rtree_node_t,
+				   &rtree->pinned, link)
+    {
+	if (node->parent != NULL)
+	    _cairo_rtree_pin (rtree, node->parent);
+    }
+
     cnt = 0;
     cairo_list_foreach_entry (node, cairo_rtree_node_t,
 			      &rtree->evictable, link)
@@ -271,22 +276,6 @@ _cairo_rtree_evict_random (cairo_rtree_t	 *rtree,
     return CAIRO_INT_STATUS_UNSUPPORTED;
 }
 
-void *
-_cairo_rtree_pin (cairo_rtree_t *rtree, cairo_rtree_node_t *node)
-{
-    void *ptr = node;
-
-    while (node->pinned == FALSE) {
-	cairo_list_move (&node->link, &rtree->pinned);
-	node->pinned = TRUE;
-	node = node->parent;
-	if (node == NULL)
-	    break;
-    }
-
-    return ptr;
-}
-
 void
 _cairo_rtree_unpin (cairo_rtree_t *rtree)
 {
commit cbe8fd0794adaccdf3eb15eef780a030e3d51784
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Apr 3 14:56:25 2010 +0100

    script: Avoid the expensive of the redundant memset.
    
    As we are about to immediately fill the entire image, allocate the
    memory ourselves to avoid the redundant memset performed by pixman.

diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index e583120..7d8297c 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -2821,36 +2821,46 @@ _image_read_raw (csi_file_t *src,
 {
     cairo_surface_t *image;
     uint8_t *bp, *data;
-    int rem, len, ret, x, stride;
+    int rem, len, ret, x, rowlen, stride;
     cairo_status_t status;
 
-    image = cairo_image_surface_create (format, width, height);
-    status = cairo_surface_status (image);
-    if (status)
+    stride = cairo_format_stride_for_width (format, width);
+    data = malloc (stride * height);
+    if (data == NULL)
+	return CAIRO_STATUS_NO_MEMORY;
+
+    image = cairo_image_surface_create_for_data (data, format,
+						 width, height, stride);
+    status = cairo_surface_set_user_data (image,
+					  (const cairo_user_data_key_t *) image,
+					  data, free);
+    if (status) {
+	cairo_surface_destroy (image);
+	free (image);
 	return status;
+    }
 
     switch (format) {
     case CAIRO_FORMAT_A1:
-	len = (width+7)/8 * height;
+	rowlen = (width+7)/8;
 	break;
     case CAIRO_FORMAT_A8:
-	len = width * height;
+	rowlen = width;
 	break;
     case CAIRO_FORMAT_RGB16_565:
-	len = 2 * width * height;
+	rowlen = 2 * width;
 	break;
     case CAIRO_FORMAT_RGB24:
-	len = 3 * width * height;
+	rowlen = 3 * width;
 	break;
     default:
     case CAIRO_FORMAT_INVALID:
     case CAIRO_FORMAT_ARGB32:
-	len = 4 * width * height;
+	rowlen = 4 * width;
 	break;
     }
+    len = rowlen * height;
 
-    stride = cairo_image_surface_get_stride (image);
-    data = cairo_image_surface_get_data (image);
     bp = data;
     rem = len;
     while (rem) {
@@ -2870,7 +2880,7 @@ _image_read_raw (csi_file_t *src,
 	    /* XXX pixel conversion */
 	    switch (format) {
 	    case CAIRO_FORMAT_A1:
-		for (x = (width+7)/8; x--; ) {
+		for (x = rowlen; x--; ) {
 		    uint8_t byte = *--bp;
 		    row[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
 		}
@@ -2910,12 +2920,14 @@ _image_read_raw (csi_file_t *src,
 		/* stride == width */
 		break;
 	    }
+
+	    memset (row + rowlen, 0, stride - rowlen);
 	}
 
 	/* need to treat last row carefully */
 	switch (format) {
 	case CAIRO_FORMAT_A1:
-	    for (x = (width+7)/8; x--; ) {
+	    for (x = rowlen; x--; ) {
 		uint8_t byte = *--bp;
 		data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte);
 	    }
@@ -2996,6 +3008,7 @@ _image_read_raw (csi_file_t *src,
 	    /* stride == width */
 	    break;
 	}
+	memset (data + rowlen, 0, stride - rowlen);
     } else {
 #ifndef WORDS_BIGENDIAN
 	switch (format) {
commit b9f7a4b5261b6d4e7bdbb5cc56d78d50ad1bd4a7
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Apr 3 14:48:36 2010 +0100

    script: Don't hash the entire image.
    
    The reuse hit rate is very small, and most images are quickly
    distinguished in the first few bytes... Though perhaps not for video as
    in the swfdec-youtube case...

diff --git a/util/cairo-script/cairo-script-operators.c b/util/cairo-script/cairo-script-operators.c
index 754a27e..e583120 100644
--- a/util/cairo-script/cairo-script-operators.c
+++ b/util/cairo-script/cairo-script-operators.c
@@ -126,19 +126,17 @@ _csi_proxy_destroy (void *closure)
     cairo_script_interpreter_destroy (ctx);
 }
 
-static unsigned long
-_csi_blob_hash (const uint8_t *bytes, int len)
+static void
+_csi_blob_hash (csi_blob_t *blob, const uint32_t *data, int len)
 {
+    unsigned long hash = blob->hash;
     /* very simple! */
-    unsigned long hash = 5381;
-    unsigned long *data = (unsigned long *) bytes;
-    len /= sizeof (unsigned long);
     while (len--) {
 	unsigned long c = *data++;
 	hash *= 33;
 	hash ^= c;
     }
-    return hash;
+    blob->hash = hash;
 }
 
 static csi_boolean_t
@@ -152,10 +150,6 @@ _csi_blob_equal (const csi_list_t *link, void *data)
     if (A->len != B->len)
 	return FALSE;
 
-    if (A->hash == 0)
-	A->hash = _csi_blob_hash (A->bytes, A->len);
-    if (B->hash == 0)
-	B->hash = _csi_blob_hash (B->bytes, B->len);
     if (A->hash != B->hash)
 	return FALSE;
 
@@ -165,7 +159,7 @@ _csi_blob_equal (const csi_list_t *link, void *data)
 static void
 _csi_blob_init (csi_blob_t *blob, uint8_t *bytes, int len)
 {
-    blob->hash = 0;
+    blob->hash = 5381;
     blob->len = len;
     blob->bytes = bytes;
 }
@@ -1760,6 +1754,7 @@ _ft_create_for_source (csi_t *ctx,
     /* check for an existing FT_Face (kept alive by the font cache) */
     /* XXX index/flags */
     _csi_blob_init (&tmpl, (uint8_t *) source->string, source->len);
+    _csi_blob_hash (&tmpl, (uint32_t *) source->string, source->len / sizeof (uint32_t));
     link = _csi_list_find (ctx->_faces, _csi_blob_equal, &tmpl);
     if (link) {
 	if (--source->base.ref == 0)
@@ -1869,6 +1864,7 @@ _ft_create_for_pattern (csi_t *ctx,
     void *bytes;
 
     _csi_blob_init (&tmpl, (uint8_t *) string->string, string->len);
+    _csi_blob_hash (&tmpl, (uint32_t *) string->string, string->len / sizeof (uint32_t));
     link = _csi_list_find (ctx->_faces, _csi_blob_equal, &tmpl);
     if (link) {
 	if (--string->base.ref == 0)
@@ -3082,6 +3078,22 @@ _image_tag_done (void *closure)
     cairo_script_interpreter_destroy (ctx);
 }
 
+static void
+_image_hash (csi_blob_t *blob,
+	     cairo_surface_t *surface)
+{
+    uint32_t  value;
+
+    value = cairo_image_surface_get_width (surface);
+    _csi_blob_hash (blob, &value, 1);
+
+    value = cairo_image_surface_get_height (surface);
+    _csi_blob_hash (blob, &value, 1);
+
+    value = cairo_image_surface_get_format (surface);
+    _csi_blob_hash (blob, &value, 1);
+}
+
 static cairo_surface_t *
 _image_cached (csi_t *ctx, cairo_surface_t *surface)
 {
@@ -3097,6 +3109,7 @@ _image_cached (csi_t *ctx, cairo_surface_t *surface)
     stride = cairo_image_surface_get_stride (surface);
     height = cairo_image_surface_get_height (surface);
     _csi_blob_init (&tmpl, data, stride * height);
+    _image_hash (&tmpl, surface);
     link = _csi_list_find (ctx->_images, _csi_blob_equal, &tmpl);
     if (link) {
 	cairo_surface_destroy (surface);
commit a85c6c1e36273d534f01ade0714b0592b6bed5ab
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Apr 3 14:09:56 2010 +0100

    gstate: reduce a couple more operators

diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 5a8664a..caed88b 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -993,8 +993,21 @@ _reduce_op (cairo_gstate_t *gstate)
     const cairo_pattern_t *pattern;
 
     op = gstate->op;
-    if (op != CAIRO_OPERATOR_SOURCE)
+    if (op == CAIRO_OPERATOR_IN &&
+	gstate->target->is_clear &&
+	gstate->target->content & CAIRO_CONTENT_ALPHA)
+    {
+	return CAIRO_OPERATOR_CLEAR;
+    }
+
+    if (op != CAIRO_OPERATOR_SOURCE &&
+	! (gstate->target->is_clear &&
+	   (op == CAIRO_OPERATOR_OVER ||
+	    (op == CAIRO_OPERATOR_ADD &&
+	     gstate->target->content & CAIRO_CONTENT_ALPHA))))
+    {
 	return op;
+    }
 
     pattern = gstate->source;
     if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
commit a3cb52e4037db9e565d32f85d69c364b606555e9
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Apr 3 13:36:18 2010 +0100

    simplify pattern extents for translation matrices

diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index e97996b..8504527 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -2445,7 +2445,6 @@ void
 _cairo_pattern_get_extents (const cairo_pattern_t         *pattern,
 			    cairo_rectangle_int_t         *extents)
 {
-    cairo_matrix_t imatrix;
     double x1, y1, x2, y2;
     cairo_status_t status;
 
@@ -2558,14 +2557,21 @@ _cairo_pattern_get_extents (const cairo_pattern_t         *pattern,
 	ASSERT_NOT_REACHED;
     }
 
-    imatrix = pattern->matrix;
-    status = cairo_matrix_invert (&imatrix);
-    /* cairo_pattern_set_matrix ensures the matrix is invertible */
-    assert (status == CAIRO_STATUS_SUCCESS);
+    if (_cairo_matrix_is_translation (&pattern->matrix)) {
+	x1 -= pattern->matrix.x0; x2 -= pattern->matrix.x0;
+	y1 -= pattern->matrix.y0; y2 -= pattern->matrix.y0;
+    } else {
+	cairo_matrix_t imatrix;
+
+	imatrix = pattern->matrix;
+	status = cairo_matrix_invert (&imatrix);
+	/* cairo_pattern_set_matrix ensures the matrix is invertible */
+	assert (status == CAIRO_STATUS_SUCCESS);
 
-    _cairo_matrix_transform_bounding_box (&imatrix,
-					  &x1, &y1, &x2, &y2,
-					  NULL);
+	_cairo_matrix_transform_bounding_box (&imatrix,
+					      &x1, &y1, &x2, &y2,
+					      NULL);
+    }
 
     x1 = floor (x1);
     if (x1 < CAIRO_RECT_INT_MIN)
commit d45c7dc62d6b036bbbe85c3c1951807e055930d9
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Apr 1 17:09:11 2010 +0100

    xcb: discard glyph mask and use dst directly when possible.

diff --git a/boilerplate/cairo-boilerplate-xcb.c b/boilerplate/cairo-boilerplate-xcb.c
index 0a5f5a4..7f06a4e 100644
--- a/boilerplate/cairo-boilerplate-xcb.c
+++ b/boilerplate/cairo-boilerplate-xcb.c
@@ -28,6 +28,8 @@
 
 #include <cairo-xcb.h>
 
+#include <assert.h>
+
 static const cairo_user_data_key_t xcb_closure_key;
 
 typedef struct _xcb_target_closure {
@@ -437,8 +439,9 @@ _cairo_boilerplate_xcb_create_render_0_0 (const char		 *name,
 	return tmp;
     }
 
-    cairo_xcb_device_debug_cap_xrender_version (cairo_surface_get_device (tmp),
-                                                0, 0);
+    xtc->device = cairo_device_reference (cairo_surface_get_device (tmp));
+    cairo_xcb_device_debug_cap_xrender_version (xtc->device, 0, 0);
+
     /* recreate with impaired connection */
     surface = cairo_xcb_surface_create_with_xrender_format (c, root,
 							    xtc->drawable,
@@ -447,7 +450,8 @@ _cairo_boilerplate_xcb_create_render_0_0 (const char		 *name,
     free (formats);
     cairo_surface_destroy (tmp);
 
-    xtc->device = cairo_device_reference (cairo_surface_get_device (surface));
+    assert (cairo_surface_get_device (surface) == xtc->device);
+
     status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL);
     if (status == CAIRO_STATUS_SUCCESS)
 	return surface;
@@ -668,7 +672,7 @@ static const cairo_boilerplate_target_t targets[] = {
 	cairo_surface_write_to_png,
 	_cairo_boilerplate_xcb_cleanup,
 	_cairo_boilerplate_xcb_synchronize,
-	TRUE, FALSE, FALSE
+	FALSE, FALSE, FALSE
     },
     {
 	"xcb-render-0.0", "xlib-fallback", NULL, NULL,
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 20d91ca..5a8664a 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -993,10 +993,11 @@ _reduce_op (cairo_gstate_t *gstate)
     const cairo_pattern_t *pattern;
 
     op = gstate->op;
+    if (op != CAIRO_OPERATOR_SOURCE)
+	return op;
+
     pattern = gstate->source;
-    if (op == CAIRO_OPERATOR_SOURCE &&
-	pattern->type == CAIRO_PATTERN_TYPE_SOLID)
-    {
+    if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
 	const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
 	if (solid->color.alpha_short <= 0x00ff) {
 	    op = CAIRO_OPERATOR_CLEAR;
@@ -1008,6 +1009,17 @@ _reduce_op (cairo_gstate_t *gstate)
 		op = CAIRO_OPERATOR_CLEAR;
 	    }
 	}
+    } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
+	const cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) pattern;
+	if (surface->surface->is_clear &&
+	    surface->surface->content & CAIRO_CONTENT_ALPHA)
+	{
+	    op = CAIRO_OPERATOR_CLEAR;
+	}
+    } else {
+	const cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
+	if (gradient->n_stops == 0)
+	    op = CAIRO_OPERATOR_CLEAR;
     }
 
     return op;
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index d66b17c..e97996b 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -1857,7 +1857,7 @@ _cairo_pattern_is_clear (const cairo_pattern_t *abstract_pattern)
 	ASSERT_NOT_REACHED;
     case CAIRO_PATTERN_TYPE_LINEAR:
     case CAIRO_PATTERN_TYPE_RADIAL:
-	return FALSE;
+	return pattern->gradient.base.n_stops == 0;
     }
 }
 
diff --git a/src/cairo-xcb-surface-render.c b/src/cairo-xcb-surface-render.c
index 9c2d462..a006d96 100644
--- a/src/cairo-xcb-surface-render.c
+++ b/src/cairo-xcb-surface-render.c
@@ -2510,7 +2510,7 @@ _core_boxes (cairo_xcb_surface_t *dst,
 	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))
+	if (dst->base.is_clear || _cairo_pattern_is_opaque (src, &extents->bounded))
 	    op = CAIRO_OPERATOR_SOURCE;
     }
     if (op != CAIRO_OPERATOR_SOURCE)
@@ -2635,7 +2635,8 @@ _upload_image_inplace (cairo_xcb_surface_t *surface,
     cairo_image_surface_t *image;
     xcb_gcontext_t gc;
     cairo_status_t status;
-    int len, tx, ty;
+    int tx, ty;
+    int len, bpp;
 
     if (source->type != CAIRO_PATTERN_TYPE_SURFACE)
 	return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -2698,21 +2699,24 @@ _upload_image_inplace (cairo_xcb_surface_t *surface,
     gc = _cairo_xcb_screen_get_gc (surface->screen, surface->drawable, image->depth);
 
     /* Do we need to trim the image? */
-    len = CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format));
+    bpp = PIXMAN_FORMAT_BPP (image->pixman_format);
+    len = CAIRO_STRIDE_FOR_WIDTH_BPP (extents->width, bpp);
     if (len == image->stride) {
 	_cairo_xcb_connection_put_image (surface->connection,
 					 surface->drawable, gc,
-					 image->width, image->height,
+					 extents->width, extents->height,
 					 extents->x, extents->y,
 					 image->depth,
 					 image->stride,
-					 image->data);
+					 image->data +
+					 (extents->y + ty) * image->stride +
+					 (extents->x + tx) * bpp/8);
     } else {
 	_cairo_xcb_connection_put_subimage (surface->connection,
 					    surface->drawable, gc,
 					    extents->x + tx, extents->y + ty,
-					    image->width, image->height,
-					    PIXMAN_FORMAT_BPP (image->pixman_format) / 8,
+					    extents->width, extents->height,
+					    bpp / 8,
 					    image->stride,
 					    extents->x, extents->y,
 					    image->depth,
@@ -2761,6 +2765,19 @@ _clip_and_composite_boxes (cairo_xcb_surface_t *dst,
 	    return status;
     }
 
+    if (dst->deferred_clear) {
+	_cairo_xcb_surface_clear (dst);
+
+	if (op == CAIRO_OPERATOR_OVER)
+	    op = CAIRO_OPERATOR_SOURCE;
+    }
+
+    if (clip == NULL && op == CAIRO_OPERATOR_SOURCE && boxes->num_boxes == 1) {
+	status = _upload_image_inplace (dst, src, &extents->bounded);
+	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
+	    return status;
+    }
+
     if ((dst->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0)
 	return _core_boxes (dst, op, src, boxes, antialias, clip, extents);
 
@@ -3772,6 +3789,7 @@ typedef struct {
     cairo_scaled_font_t *font;
     cairo_xcb_glyph_t *glyphs;
     int num_glyphs;
+    cairo_bool_t use_mask;
 } composite_glyphs_info_t;
 
 static cairo_status_t
@@ -4312,7 +4330,8 @@ _emit_glyphs_chunk (cairo_xcb_surface_t *dst,
 		    int num_glyphs,
 		    int width,
 		    int estimated_req_size,
-		    cairo_xcb_font_glyphset_info_t *glyphset_info)
+		    cairo_xcb_font_glyphset_info_t *glyphset_info,
+		    xcb_render_pictformat_t mask_format)
 {
     cairo_xcb_render_composite_text_func_t composite_text_func;
     uint8_t stack_buf[CAIRO_STACK_BUFFER_SIZE];
@@ -4368,7 +4387,7 @@ _emit_glyphs_chunk (cairo_xcb_surface_t *dst,
 			 _render_operator (op),
 			 src->picture,
 			 dst->picture,
-			 glyphset_info->xrender_format,
+			 mask_format,
 			 glyphset_info->glyphset,
 			 src->x + glyphs[0].i.x,
 			 src->y + glyphs[0].i.y,
@@ -4382,11 +4401,12 @@ _emit_glyphs_chunk (cairo_xcb_surface_t *dst,
 
 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_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;
@@ -4495,7 +4515,8 @@ _composite_glyphs (void				*closure,
 	    status = _emit_glyphs_chunk (dst, op, src,
 					 info->glyphs, i,
 					 old_width, request_size,
-					 glyphset_info);
+					 glyphset_info,
+					 info->use_mask ? glyphset_info->xrender_format : 0);
 	    if (unlikely (status)) {
 		cairo_surface_destroy (&src->base);
 		return status;
@@ -4539,7 +4560,8 @@ _composite_glyphs (void				*closure,
 	status = _emit_glyphs_chunk (dst, op, src,
 				     info->glyphs, i,
 				     width, request_size,
-				     glyphset_info);
+				     glyphset_info,
+				     info->use_mask ? glyphset_info->xrender_format : 0);
     }
 
     cairo_surface_destroy (&src->base);
@@ -4577,6 +4599,7 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t	*surface,
     cairo_clip_t local_clip;
     cairo_bool_t have_clip = FALSE;
     cairo_status_t status;
+    cairo_bool_t overlap;
 
     if (unlikely (! _operator_is_supported (surface->flags, op)))
 	return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -4590,7 +4613,7 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t	*surface,
 							  op, source,
 							  scaled_font,
 							  glyphs, num_glyphs,
-							  clip, NULL);
+							  clip, &overlap);
     if (unlikely (status))
 	return status;
 
@@ -4600,11 +4623,38 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t	*surface,
     if (clip != NULL) {
 	clip = _cairo_clip_init_copy (&local_clip, clip);
 	if (extents.is_bounded) {
+	    cairo_region_t *clip_region = NULL;
+
 	    status = _cairo_clip_rectangle (clip, &extents.bounded);
 	    if (unlikely (status)) {
 		_cairo_clip_fini (&local_clip);
 		return status;
 	    }
+
+	    status = _cairo_clip_get_region (clip, &clip_region);
+	    if (unlikely (_cairo_status_is_error (status) ||
+			  status == CAIRO_INT_STATUS_NOTHING_TO_DO))
+	    {
+		_cairo_clip_fini (&local_clip);
+		return status;
+	    }
+
+	    if (clip_region != NULL) {
+		cairo_rectangle_int_t rect;
+		cairo_bool_t is_empty;
+
+		cairo_region_get_extents (clip_region, &rect);
+		is_empty = ! _cairo_rectangle_intersect (&extents.unbounded, &rect);
+		if (unlikely (is_empty))
+		    return CAIRO_STATUS_SUCCESS;
+
+		is_empty = ! _cairo_rectangle_intersect (&extents.bounded, &rect);
+		if (unlikely (is_empty && extents.is_bounded))
+		    return CAIRO_STATUS_SUCCESS;
+
+		if (cairo_region_num_rectangles (clip_region) == 1)
+		    clip = NULL;
+	    }
 	}
 	have_clip = TRUE;
     }
@@ -4622,6 +4672,7 @@ _cairo_xcb_surface_render_glyphs (cairo_xcb_surface_t	*surface,
 		info.font = scaled_font;
 		info.glyphs = (cairo_xcb_glyph_t *) glyphs;
 		info.num_glyphs = num_glyphs;
+		info.use_mask = overlap || clip != NULL || ! extents.is_bounded;
 
 		status = _clip_and_composite (surface, op, source,
 					      _composite_glyphs, &info,
commit a8b611ea8eb90f190ee3a9e7999e08e2d865ac43
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Mar 27 08:23:10 2010 +0000

    clip: Fill instead of creating intermediate surfaces.

diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 518b7de..72eecfe 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -1036,7 +1036,9 @@ _cairo_clip_path_get_surface (cairo_clip_path_t *clip_path,
 	{
 	    /* a simple box only affects the extents */
 	}
-	else if (prev->path.is_rectilinear)
+	else if (prev->path.is_rectilinear ||
+		prev->surface == NULL ||
+		prev->surface->backend != target->backend)
 	{
 	    if (need_translate) {
 		_cairo_path_fixed_translate (&prev->path,


More information about the cairo-commit mailing list