xf86-video-intel: 16 commits - configure.ac src/sna/fb src/sna/Makefile.am src/sna/sna_accel.c src/sna/sna_blt.c src/sna/sna_composite.c src/sna/sna_display.c src/sna/sna_dri.c src/sna/sna_driver.c src/sna/sna_glyphs.c src/sna/sna.h src/sna/sna_render.c src/sna/sna_tiling.c src/sna/sna_trapezoids.c test/Makefile.am

Chris Wilson ickle at kemper.freedesktop.org
Sun Jul 8 14:35:55 PDT 2012


 configure.ac             |    1 
 src/sna/Makefile.am      |    4 
 src/sna/fb/Makefile.am   |   37 +
 src/sna/fb/README        |    1 
 src/sna/fb/fb.h          |  557 ++++++++++++++++++++++++++++
 src/sna/fb/fbarc.c       |  122 ++++++
 src/sna/fb/fbarcbits.h   |  204 ++++++++++
 src/sna/fb/fbbitmap.c    |  142 +++++++
 src/sna/fb/fbblt.c       |  322 ++++++++++++++++
 src/sna/fb/fbbltone.c    |  413 +++++++++++++++++++++
 src/sna/fb/fbclip.c      |  113 +++++
 src/sna/fb/fbclip.h      |   80 ++++
 src/sna/fb/fbcopy.c      |  240 ++++++++++++
 src/sna/fb/fbfill.c      |  235 ++++++++++++
 src/sna/fb/fbgc.c        |  192 +++++++++
 src/sna/fb/fbglyph.c     |  277 ++++++++++++++
 src/sna/fb/fbglyphbits.h |  140 +++++++
 src/sna/fb/fbimage.c     |  254 +++++++++++++
 src/sna/fb/fbline.c      |  179 +++++++++
 src/sna/fb/fblinebits.h  |  284 ++++++++++++++
 src/sna/fb/fbpict.c      |  330 +++++++++++++++++
 src/sna/fb/fbpict.h      |   43 ++
 src/sna/fb/fbpoint.c     |  120 ++++++
 src/sna/fb/fbpointbits.h |  110 +++++
 src/sna/fb/fbpush.c      |  177 +++++++++
 src/sna/fb/fbrop.h       |  111 +++++
 src/sna/fb/fbseg.c       |  563 +++++++++++++++++++++++++++++
 src/sna/fb/fbsegbits.h   |  212 +++++++++++
 src/sna/fb/fbspan.c      |  131 ++++++
 src/sna/fb/fbstipple.c   |  223 +++++++++++
 src/sna/fb/fbtile.c      |  152 +++++++
 src/sna/fb/fbutil.c      |  126 ++++++
 src/sna/sna.h            |   41 --
 src/sna/sna_accel.c      |  904 +++++++++++++++++++++++++----------------------
 src/sna/sna_blt.c        |    3 
 src/sna/sna_composite.c  |    2 
 src/sna/sna_display.c    |   35 +
 src/sna/sna_dri.c        |  829 ++++++++++++++++---------------------------
 src/sna/sna_driver.c     |   86 ++--
 src/sna/sna_glyphs.c     |    3 
 src/sna/sna_render.c     |    5 
 src/sna/sna_tiling.c     |    3 
 src/sna/sna_trapezoids.c |   21 -
 test/Makefile.am         |    1 
 44 files changed, 7009 insertions(+), 1019 deletions(-)

New commits:
commit 8be00b6d4767ffc09328d246d02ee75312ad5842
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jul 8 20:48:40 2012 +0100

    sna: Substitute the reduce clip region for fallback ops
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/fb/fbclip.c b/src/sna/fb/fbclip.c
index 9b33e4a..5a8eefa 100644
--- a/src/sna/fb/fbclip.c
+++ b/src/sna/fb/fbclip.c
@@ -98,8 +98,10 @@ fbClipBoxes(const RegionRec *region, const BoxRec *box, const BoxRec **end)
 	c0 = (const BoxRec *)region->data + 1;
 	c1 = c0 + region->data->numRects;
 
-	c0 = find_c0(c0, c1, box->y1);
-	c1 = find_c1(c0, c1, box->y2);
+	if (c0->y2 <= box->y1)
+		c0 = find_c0(c0, c1, box->y1);
+	if (c1[-1].y1 >= box->y2)
+		c1 = find_c1(c0, c1, box->y2);
 
 	DBG(("%s: c0=(%d, %d),(%d, %d); c1=(%d, %d),(%d, %d)\n",
 	     __FUNCTION__,
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 08260af..cd960a1 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -2757,7 +2757,8 @@ static bool must_check sna_gc_move_to_cpu(GCPtr gc,
 	assert(gc->ops == (GCOps *)&sna_gc_ops);
 	assert(gc->funcs == (GCFuncs *)&sna_gc_funcs);
 
-	sgc->priv = region;
+	sgc->priv = gc->pCompositeClip;
+	gc->pCompositeClip = region;
 	gc->ops = (GCOps *)&sna_gc_ops__cpu;
 	gc->funcs = (GCFuncs *)&sna_gc_funcs__cpu;
 
@@ -2815,6 +2816,7 @@ static void sna_gc_move_to_gpu(GCPtr gc)
 
 	gc->ops = (GCOps *)&sna_gc_ops;
 	gc->funcs = (GCFuncs *)&sna_gc_funcs;
+	gc->pCompositeClip = sna_gc(gc)->priv;
 }
 
 static inline bool clip_box(BoxPtr box, GCPtr gc)
@@ -3545,18 +3547,6 @@ sna_put_image(DrawablePtr drawable, GCPtr gc, int depth,
 	if (w == 0 || h == 0)
 		return;
 
-	if (priv == NULL) {
-		DBG(("%s: fbPutImage, unattached(%d, %d, %d, %d)\n",
-		     __FUNCTION__, x, y, w, h));
-		if (sna_gc_move_to_cpu(gc, drawable, NULL)) {
-			fbPutImage(drawable, gc, depth,
-				   x, y, w, h, left,
-				   format, bits);
-			sna_gc_move_to_gpu(gc);
-		}
-		return;
-	}
-
 	get_drawable_deltas(drawable, pixmap, &dx, &dy);
 
 	region.extents.x1 = x + drawable->x;
@@ -3575,6 +3565,12 @@ sna_put_image(DrawablePtr drawable, GCPtr gc, int depth,
 			return;
 	}
 
+	if (priv == NULL) {
+		DBG(("%s: fallback -- unattached(%d, %d, %d, %d)\n",
+		     __FUNCTION__, x, y, w, h));
+		goto fallback;
+	}
+
 	RegionTranslate(&region, dx, dy);
 
 	if (FORCE_FALLBACK)
@@ -4355,6 +4351,9 @@ sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
 				src_y - dst_y - dst->y + src->y);
 		if (!sna_drawable_move_region_to_cpu(src, &region, MOVE_READ))
 			goto out_gc;
+		RegionTranslate(&region,
+				-(src_x - dst_x - dst->x + src->x),
+				-(src_y - dst_y - dst->y + src->y));
 
 		ret = miDoCopy(src, dst, gc,
 			       src_x, src_y,
commit 0457935a70f6c1ae06f61f9ad0dd1bdc825465fa
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jul 8 20:38:03 2012 +0100

    sna: Review placement hints for fallback operations
    
    Look for those operations that maybe better via the GTT and those that
    are preferred to be in CPU cache. The wonders of multiple layers of
    heuristics.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 9ce870d..08260af 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -2044,12 +2044,9 @@ inline static bool drawable_gc_inplace_hint(DrawablePtr draw, GCPtr gc)
 	return true;
 }
 
-inline static unsigned drawable_gc_flags(DrawablePtr draw,
-					 GCPtr gc,
-					 bool read)
+inline static unsigned
+drawable_gc_flags(DrawablePtr draw, GCPtr gc, bool partial)
 {
-	unsigned flags;
-
 	assert(sna_gc(gc)->changes == 0);
 
 	if (gc->fillStyle == FillStippled) {
@@ -2059,7 +2056,7 @@ inline static unsigned drawable_gc_flags(DrawablePtr draw,
 	}
 
 	if (fb_gc(gc)->and) {
-		DBG(("%s: read due to rop %d:%x\n",
+		DBG(("%s: read due to rrop %d:%x\n",
 		     __FUNCTION__, gc->alu, (unsigned)fb_gc(gc)->and));
 		return MOVE_READ | MOVE_WRITE;
 	}
@@ -2067,12 +2064,7 @@ inline static unsigned drawable_gc_flags(DrawablePtr draw,
 	DBG(("%s: try operating on drawable inplace [hint? %d]\n",
 	     __FUNCTION__, drawable_gc_inplace_hint(draw, gc)));
 
-	flags = MOVE_WRITE;
-	if (read) {
-		DBG(("%s: partial write\n", __FUNCTION__));
-		flags |= MOVE_READ;
-	}
-	return flags;
+	return (!partial ?: MOVE_READ) | MOVE_WRITE | MOVE_INPLACE_HINT;
 }
 
 static bool
@@ -3633,8 +3625,7 @@ fallback:
 	if (!sna_gc_move_to_cpu(gc, drawable, &region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &region,
-					     drawable_gc_flags(drawable, gc,
-							       true)))
+					     drawable_gc_flags(drawable, gc, false)))
 		goto out_gc;
 
 	DBG(("%s: fbPutImage(%d, %d, %d, %d)\n",
@@ -5302,8 +5293,7 @@ fallback:
 	if (!sna_gc_move_to_cpu(gc, drawable, &region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &region,
-					     drawable_gc_flags(drawable,
-							       gc, n > 1)))
+					     drawable_gc_flags(drawable, gc, n > 1)))
 		goto out_gc;
 
 	DBG(("%s: fbFillSpans\n", __FUNCTION__));
@@ -5343,8 +5333,7 @@ fallback:
 	if (!sna_gc_move_to_cpu(gc, drawable, &region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &region,
-					     drawable_gc_flags(drawable,
-							       gc, true)))
+					     drawable_gc_flags(drawable, gc, n > 1)))
 		goto out_gc;
 
 	DBG(("%s: fbSetSpans\n", __FUNCTION__));
@@ -6039,8 +6028,7 @@ fallback:
 	if (!sna_gc_move_to_cpu(gc, drawable, &region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &region,
-					     drawable_gc_flags(drawable, gc,
-							       n > 1)))
+					     MOVE_READ | MOVE_WRITE))
 		goto out_gc;
 
 	DBG(("%s: fbPolyPoint\n", __FUNCTION__));
@@ -8510,9 +8498,8 @@ fallback:
 	if (!sna_gc_move_to_cpu(gc, drawable, &region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &region,
-					     drawable_gc_flags(drawable,
-							       gc, true)))
-		goto out;
+					     drawable_gc_flags(drawable, gc, true)))
+		goto out_gc;
 
 	DBG(("%s: miPolyRectangle\n", __FUNCTION__));
 	miPolyRectangle(drawable, gc, n, r);
@@ -8691,8 +8678,7 @@ fallback:
 	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
-					     drawable_gc_flags(drawable,
-							       gc, true)))
+					     MOVE_READ | MOVE_WRITE))
 		goto out_gc;
 
 	DBG(("%s -- fbPolyArc\n", __FUNCTION__));
@@ -9039,8 +9025,7 @@ fallback:
 	if (!sna_gc_move_to_cpu(gc, draw, &data.region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(draw, &data.region,
-					     drawable_gc_flags(draw, gc,
-							       true)))
+					     drawable_gc_flags(draw, gc, true)))
 		goto out_gc;
 
 	DBG(("%s: fallback -- miFillPolygon -> sna_fill_spans__cpu\n",
@@ -10451,8 +10436,7 @@ fallback:
 	if (!sna_gc_move_to_cpu(gc, draw, &region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(draw, &region,
-					     drawable_gc_flags(draw, gc,
-							       n > 1)))
+					     drawable_gc_flags(draw, gc, n > 1)))
 		goto out_gc;
 
 	DBG(("%s: fallback - fbPolyFillRect\n", __FUNCTION__));
@@ -10582,8 +10566,7 @@ fallback:
 	if (!sna_gc_move_to_cpu(gc, draw, &data.region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(draw, &data.region,
-					     drawable_gc_flags(draw, gc,
-							       true)))
+					     drawable_gc_flags(draw, gc, true)))
 		goto out_gc;
 
 	DBG(("%s: fallback -- miPolyFillArc -> sna_fill_spans__cpu\n",
@@ -11044,8 +11027,7 @@ force_fallback:
 		if (!sna_gc_move_to_cpu(gc, drawable, &region))
 			goto out;
 		if (!sna_drawable_move_region_to_cpu(drawable, &region,
-						     drawable_gc_flags(drawable,
-								       gc, true)))
+						     MOVE_READ | MOVE_WRITE))
 			goto out_gc;
 
 		DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
@@ -11139,7 +11121,7 @@ force_fallback:
 		if (!sna_gc_move_to_cpu(gc, drawable, &region))
 			goto out;
 		if (!sna_drawable_move_region_to_cpu(drawable, &region,
-						     drawable_gc_flags(drawable, gc, true)))
+						     MOVE_READ | MOVE_WRITE))
 			goto out_gc;
 
 		DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
@@ -11242,8 +11224,7 @@ force_fallback:
 		if (!sna_gc_move_to_cpu(gc, drawable, &region))
 			goto out;
 		if (!sna_drawable_move_region_to_cpu(drawable, &region,
-						     drawable_gc_flags(drawable,
-								       gc, n > 1)))
+						     MOVE_READ | MOVE_WRITE))
 			goto out_gc;
 
 		DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
@@ -11339,8 +11320,7 @@ force_fallback:
 		if (!sna_gc_move_to_cpu(gc, drawable, &region))
 			goto out;
 		if (!sna_drawable_move_region_to_cpu(drawable, &region,
-						     drawable_gc_flags(drawable,
-								       gc, n > 1)))
+						     MOVE_READ | MOVE_WRITE))
 			goto out_gc;
 
 		DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
@@ -11637,8 +11617,7 @@ fallback:
 	if (!sna_gc_move_to_cpu(gc, drawable, &region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &region,
-					     drawable_gc_flags(drawable,
-							       gc, n > 1)))
+					     MOVE_READ | MOVE_WRITE))
 		goto out_gc;
 
 	DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
@@ -11718,8 +11697,7 @@ fallback:
 	if (!sna_gc_move_to_cpu(gc, drawable, &region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &region,
-					     drawable_gc_flags(drawable,
-							       gc, true)))
+					     MOVE_READ | MOVE_WRITE))
 		goto out_gc;
 
 	DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
@@ -11904,8 +11882,7 @@ sna_push_pixels(GCPtr gc, PixmapPtr bitmap, DrawablePtr drawable,
 	if (!sna_pixmap_move_to_cpu(bitmap, MOVE_READ))
 		goto out_gc;
 	if (!sna_drawable_move_region_to_cpu(drawable, &region,
-					     drawable_gc_flags(drawable,
-							       gc, false)))
+					     drawable_gc_flags(drawable, gc, false)))
 		goto out_gc;
 
 	DBG(("%s: fallback, fbPushPixels(%d, %d, %d %d)\n",
commit b7f0b0e7e3f66165b87c46f897de536cf74a9daf
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jul 8 19:59:34 2012 +0100

    sna: Remove function for force-to-gpu
    
    This is now enitrely done in the core move-to-gpu as a special case.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna.h b/src/sna/sna.h
index 6738400..f62cfbc 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -416,10 +416,6 @@ PixmapPtr sna_pixmap_create_upload(ScreenPtr screen,
 PixmapPtr sna_pixmap_create_unattached(ScreenPtr screen,
 				       int width, int height, int depth);
 
-struct sna_pixmap *sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags);
-struct sna_pixmap *sna_pixmap_force_to_gpu(PixmapPtr pixmap, unsigned flags);
-struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling);
-
 #define MOVE_WRITE 0x1
 #define MOVE_READ 0x2
 #define MOVE_INPLACE_HINT 0x4
@@ -427,6 +423,15 @@ struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling);
 #define MOVE_SOURCE_HINT 0x10
 #define MOVE_WHOLE_HINT 0x20
 #define __MOVE_FORCE 0x40
+
+struct sna_pixmap *sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags);
+static inline struct sna_pixmap *
+sna_pixmap_force_to_gpu(PixmapPtr pixmap, unsigned flags)
+{
+	/* Unlike move-to-gpu, we ignore wedged and always create the GPU bo */
+	DBG(("%s(pixmap=%p, flags=%x)\n", __FUNCTION__, pixmap, flags));
+	return sna_pixmap_move_to_gpu(pixmap, flags | __MOVE_FORCE);
+}
 bool must_check _sna_pixmap_move_to_cpu(PixmapPtr pixmap, unsigned flags);
 static inline bool must_check sna_pixmap_move_to_cpu(PixmapPtr pixmap, unsigned flags)
 {
@@ -450,6 +455,8 @@ sna_drawable_move_to_gpu(DrawablePtr drawable, unsigned flags)
 	return sna_pixmap_move_to_gpu(get_drawable_pixmap(drawable), flags) != NULL;
 }
 
+struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling);
+
 static inline bool
 sna_drawable_is_clear(DrawablePtr d)
 {
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 681b283..9ce870d 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -1218,7 +1218,8 @@ skip_inplace_map:
 	    sna_pixmap_move_to_gpu(pixmap, flags)) {
 		kgem_bo_submit(&sna->kgem, priv->gpu_bo);
 
-		DBG(("%s: operate inplace\n", __FUNCTION__));
+		DBG(("%s: try to operate inplace\n", __FUNCTION__));
+		assert(priv->cpu == false);
 
 		pixmap->devPrivate.ptr =
 			kgem_bo_map(&sna->kgem, priv->gpu_bo);
@@ -1233,10 +1234,10 @@ skip_inplace_map:
 				list_del(&priv->list);
 				priv->undamaged = false;
 				priv->clear = false;
-				priv->cpu = false;
 			}
 
 			assert_pixmap_damage(pixmap);
+			DBG(("%s: operate inplace\n", __FUNCTION__));
 			return true;
 		}
 
@@ -1647,7 +1648,7 @@ sna_drawable_move_region_to_cpu(DrawablePtr drawable,
 	    region_inplace(sna, pixmap, region, priv, (flags & MOVE_READ) == 0)) {
 		kgem_bo_submit(&sna->kgem, priv->gpu_bo);
 
-		DBG(("%s: operate inplace\n", __FUNCTION__));
+		DBG(("%s: try to operate inplace\n", __FUNCTION__));
 
 		pixmap->devPrivate.ptr =
 			kgem_bo_map(&sna->kgem, priv->gpu_bo);
@@ -1674,6 +1675,7 @@ sna_drawable_move_region_to_cpu(DrawablePtr drawable,
 			priv->cpu = false;
 			if (dx | dy)
 				RegionTranslate(region, -dx, -dy);
+			DBG(("%s: operate inplace\n", __FUNCTION__));
 			return true;
 		}
 
@@ -2570,32 +2572,6 @@ sna_pixmap_mark_active(struct sna *sna, struct sna_pixmap *priv)
 }
 
 struct sna_pixmap *
-sna_pixmap_force_to_gpu(PixmapPtr pixmap, unsigned flags)
-{
-	struct sna_pixmap *priv;
-
-	DBG(("%s(pixmap=%p)\n", __FUNCTION__, pixmap));
-
-	priv = sna_pixmap(pixmap);
-	if (priv == NULL)
-		return NULL;
-
-	if (DAMAGE_IS_ALL(priv->gpu_damage)) {
-		DBG(("%s: GPU all-damaged\n", __FUNCTION__));
-		assert(!priv->gpu_bo->proxy || (flags & MOVE_WRITE) == 0);
-		return sna_pixmap_mark_active(to_sna_from_pixmap(pixmap), priv);
-	}
-
-	/* Unlike move-to-gpu, we ignore wedged and always create the GPU bo */
-	if (!sna_pixmap_move_to_gpu(pixmap, flags | __MOVE_FORCE))
-		return NULL;
-
-	assert(!priv->cpu);
-
-	return priv;
-}
-
-struct sna_pixmap *
 sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
 {
 	struct sna *sna = to_sna_from_pixmap(pixmap);
@@ -2679,15 +2655,15 @@ sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
 		}
 	}
 
-	if (priv->cpu_damage == NULL)
-		goto done;
-
 	if (priv->gpu_bo->proxy) {
 		DBG(("%s: reusing cached upload\n", __FUNCTION__));
 		assert((flags & MOVE_WRITE) == 0);
-		goto done;
+		return priv;
 	}
 
+	if (priv->cpu_damage == NULL)
+		goto done;
+
 	if (priv->mapped) {
 		assert(priv->stride);
 		pixmap->devPrivate.ptr = priv->ptr;
@@ -12440,6 +12416,7 @@ static void sna_accel_flush(struct sna *sna)
 	if (priv) {
 		sna_pixmap_force_to_gpu(priv->pixmap, MOVE_READ);
 		kgem_bo_flush(&sna->kgem, priv->gpu_bo);
+		assert(!priv->cpu);
 	}
 
 	sna_mode_redisplay(sna);
commit bb8770158c08394c2de79e0ca1c1b3112e17dd23
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jul 8 18:53:25 2012 +0100

    sna: Apply the clear color when resizing the front buffer
    
    If the existing front buffer is clear, just apply the clear color to
    then new buffer rather than copy the old one across.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 2d8b0f3..12a6bac 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -2159,17 +2159,28 @@ static void copy_front(struct sna *sna, PixmapPtr old, PixmapPtr new)
 	DBG(("%s: copying box (%dx%d) from (%d, %d) to (%d, %d)\n",
 	     __FUNCTION__, box.x2, box.y2, sx, sy, dx, dy));
 
-	if (box.x2 != new->drawable.width || box.y2 != new->drawable.height) {
-		(void)sna->render.fill_one(sna, new, new_priv->gpu_bo, 0,
+	if (old_priv->clear) {
+		(void)sna->render.fill_one(sna, new, new_priv->gpu_bo,
+					   old_priv->clear_color,
 					   0, 0,
 					   new->drawable.width,
 					   new->drawable.height,
-					   GXclear);
+					   GXcopy);
+		new_priv->clear = true;
+		new_priv->clear_color = old_priv->clear_color;
+	} else {
+		if (box.x2 != new->drawable.width || box.y2 != new->drawable.height) {
+			(void)sna->render.fill_one(sna, new, new_priv->gpu_bo, 0,
+						   0, 0,
+						   new->drawable.width,
+						   new->drawable.height,
+						   GXclear);
+		}
+		(void)sna->render.copy_boxes(sna, GXcopy,
+					     old, old_priv->gpu_bo, sx, sy,
+					     new, new_priv->gpu_bo, dx, dy,
+					     &box, 1, 0);
 	}
-	(void)sna->render.copy_boxes(sna, GXcopy,
-				     old, old_priv->gpu_bo, sx, sy,
-				     new, new_priv->gpu_bo, dx, dy,
-				     &box, 1, 0);
 
 	if (!DAMAGE_IS_ALL(new_priv->gpu_damage))
 		sna_damage_all(&new_priv->gpu_damage,
commit 8dd14855d75240501aa2d089bcdfa46e7badbf18
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Jul 8 15:46:41 2012 +0100

    sna/dri: Review stale comments
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index e520394..75c66b7 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -869,10 +869,6 @@ sna_dri_frame_event_info_free(struct sna *sna,
 	free(info);
 }
 
-/*
- * Our internal swap routine takes care of actually exchanging, blitting, or
- * flipping buffers as necessary.
- */
 static Bool
 sna_dri_page_flip(struct sna *sna, struct sna_dri_frame_event *info)
 {
@@ -1402,7 +1398,6 @@ sna_dri_page_flip_handler(struct sna *sna,
 
 	/* Is this the event whose info shall be delivered to higher level? */
 	if (event->user_data & 1) {
-		/* Yes: Cache msc, ust for later delivery. */
 		info->fe_frame = event->sequence;
 		info->fe_tv_sec = event->tv_sec;
 		info->fe_tv_usec = event->tv_usec;
@@ -1433,7 +1428,6 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 
 	VG_CLEAR(vbl);
 
-	/* XXX In theory we can just exchange pixmaps.... */
 	pipe = sna_dri_get_pipe(draw);
 	if (pipe == -1)
 		return FALSE;
@@ -1562,14 +1556,15 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 			vbl.request.sequence = current_msc - current_msc % divisor + remainder;
 
 			/*
-			 * If the calculated deadline vbl.request.sequence is smaller than
-			 * or equal to current_msc, it means we've passed the last point
-			 * when effective onset frame seq could satisfy
-			 * seq % divisor == remainder, so we need to wait for the next time
-			 * this will happen.
+			 * If the calculated deadline vbl.request.sequence is
+			 * smaller than or equal to current_msc, it means
+			 * we've passed the last point when effective onset
+			 * frame seq could satisfy *seq % divisor == remainder,
+			 * so we need to wait for the next time this will
+			 * happen.
 			 *
-			 * This comparison takes the 1 frame swap delay in pageflipping mode
-			 * into account.
+			 * This comparison takes the 1 frame swap delay
+			 * in pageflipping mode into account.
 			 */
 			if (vbl.request.sequence <= current_msc)
 				vbl.request.sequence += divisor;
@@ -1599,7 +1594,8 @@ sna_dri_immediate_xchg(struct sna *sna,
 {
 	drmVBlank vbl;
 
-	DBG(("%s: emitting immediate exchange, throttling client\n", __FUNCTION__));
+	DBG(("%s: emitting immediate exchange, throttling client\n",
+	     __FUNCTION__));
 	VG_CLEAR(vbl);
 
 	if ((sna->flags & SNA_NO_WAIT) == 0) {
@@ -1794,7 +1790,7 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	 * the swap.
 	 */
 	if (current_msc < *target_msc) {
-		DBG(("%s: waiting for swap: current=%d, target=%d,  divisor=%d\n",
+		DBG(("%s: waiting for swap: current=%d, target=%d, divisor=%d\n",
 		     __FUNCTION__,
 		     (int)current_msc,
 		     (int)*target_msc,
@@ -2097,7 +2093,8 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 
 	/*
 	 * If we get here, target_msc has already passed or we don't have one,
-	 * so we queue an event that will satisfy the divisor/remainder equation.
+	 * so we queue an event that will satisfy the divisor/remainder
+	 * equation.
 	 */
 	vbl.request.type =
 		DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | pipe_select(pipe);
commit 3bb7a530e77a5c6e8bae0fb14c570feafe37c2bd
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 7 20:53:27 2012 +0100

    sna/dri: Fix cross-chaining of pageflip vs vblank
    
    And double-check that the drawable is still flippable before completing
    the delay exchange.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index 8346554..e520394 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -1083,9 +1083,17 @@ static void chain_swap(struct sna *sna,
 	int type;
 
 	assert(chain == sna_dri_window_get_chain((WindowPtr)draw));
+	DBG(("%s: chaining type=%d\n", __FUNCTION__, chain->type));
+	switch (chain->type) {
+	case DRI2_XCHG_THROTTLE:
+	case DRI2_SWAP_THROTTLE:
+		break;
+	default:
+		return;
+	}
 
-	/* In theory, it shoudln't be possible for cross-chaining to occur! */
-	if (chain->type == DRI2_XCHG_THROTTLE) {
+	if (chain->type == DRI2_XCHG_THROTTLE &&
+	    can_exchange(sna, draw, chain->front, chain->back)) {
 		DBG(("%s: performing chained exchange\n", __FUNCTION__));
 		sna_dri_exchange_buffers(draw, chain->front, chain->back);
 		type = DRI2_EXCHANGE_COMPLETE;
commit 1454df8caa51fff9810a9b792d17aa82b247a4ae
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 7 19:59:50 2012 +0100

    sna/dri: Use draw ref directly
    
    As we hook into the DestroyWindow notification, we can reliably use the
    original Drawable reference and avoid the secondary object lookups.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index 07c95fb..8346554 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -73,7 +73,7 @@ enum frame_event_type {
 };
 
 struct sna_dri_frame_event {
-	XID drawable_id;
+	DrawablePtr draw;
 	ClientPtr client;
 	enum frame_event_type type;
 	unsigned frame;
@@ -817,7 +817,7 @@ void sna_dri_destroy_window(WindowPtr win)
 
 	DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.serialNumber));
 	while (chain) {
-		chain->drawable_id = None;
+		chain->draw = NULL;
 		chain = chain->chain;
 	}
 }
@@ -849,9 +849,6 @@ sna_dri_frame_event_info_free(struct sna *sna,
 			      DrawablePtr draw,
 			      struct sna_dri_frame_event *info)
 {
-	DBG(("%s: del[%p] (%p, %ld)\n", __FUNCTION__,
-	     info, info->client, (long)info->drawable_id));
-
 	if (draw && draw->type == DRAWABLE_WINDOW)
 		sna_dri_remove_frame_event((WindowPtr)draw, info);
 	_sna_dri_destroy_buffer(sna, info->front);
@@ -1148,19 +1145,12 @@ static bool sna_dri_blit_complete(struct sna *sna,
 void sna_dri_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
 {
 	struct sna_dri_frame_event *info = (void *)(uintptr_t)event->user_data;
-	DrawablePtr draw = NULL;
-	int status;
-
-	DBG(("%s(id=%d, type=%d)\n", __FUNCTION__,
-	     (int)info->drawable_id, info->type));
-
-	status = BadDrawable;
-	if (info->drawable_id)
-		status = dixLookupDrawable(&draw,
-					   info->drawable_id,
-					   serverClient,
-					   M_ANY, DixWriteAccess);
-	if (status != Success)
+	DrawablePtr draw;
+
+	DBG(("%s(type=%d)\n", __FUNCTION__, info->type));
+
+	draw = info->draw;
+	if (draw == NULL)
 		goto done;
 
 	switch (info->type) {
@@ -1268,8 +1258,7 @@ sna_dri_flip_continue(struct sna *sna,
 static void sna_dri_flip_event(struct sna *sna,
 			       struct sna_dri_frame_event *flip)
 {
-	DrawablePtr draw = NULL;
-	int status;
+	DrawablePtr draw;
 
 	DBG(("%s(frame=%d, tv=%d.%06d, type=%d)\n",
 	     __FUNCTION__,
@@ -1281,13 +1270,8 @@ static void sna_dri_flip_event(struct sna *sna,
 	if (sna->dri.flip_pending == flip)
 		sna->dri.flip_pending = NULL;
 
-	status = BadDrawable;
-	if (flip->drawable_id)
-		status = dixLookupDrawable(&draw,
-					   flip->drawable_id,
-					   serverClient,
-					   M_ANY, DixWriteAccess);
-	if (status != Success) {
+	draw = flip->draw;
+	if (draw == NULL) {
 		DBG(("%s: drawable already gone\n", __FUNCTION__));
 		sna_dri_frame_event_info_free(sna, draw, flip);
 		return;
@@ -1457,7 +1441,7 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 
 		info = sna->dri.flip_pending;
 		if (info) {
-			if (info->drawable_id == draw->id) {
+			if (info->draw == draw) {
 				DBG(("%s: chaining flip\n", __FUNCTION__));
 				info->next_front.name = 1;
 				return TRUE;
@@ -1478,7 +1462,7 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 
 		info->type = type;
 
-		info->drawable_id = draw->id;
+		info->draw = draw;
 		info->client = client;
 		info->event_complete = func;
 		info->event_data = data;
@@ -1518,7 +1502,7 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		if (info == NULL)
 			return FALSE;
 
-		info->drawable_id = draw->id;
+		info->draw = draw;
 		info->client = client;
 		info->event_complete = func;
 		info->event_data = data;
@@ -1767,7 +1751,7 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	if (!info)
 		goto blit_fallback;
 
-	info->drawable_id = draw->id;
+	info->draw = draw;
 	info->client = client;
 	info->event_complete = func;
 	info->event_data = data;
@@ -2078,7 +2062,7 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 	if (!info)
 		goto out_complete;
 
-	info->drawable_id = draw->id;
+	info->draw = draw;
 	info->client = client;
 	info->type = DRI2_WAITMSC;
 	sna_dri_add_frame_event(draw, info);
commit 9abb6c09bdb9831db5f0626eed70663a2dc39fc6
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 7 18:43:06 2012 +0100

    sna/dri: Remove dead code for 'old_fb'
    
    The member still exists but is never set and is unused.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna.h b/src/sna/sna.h
index 5f3ca76..6738400 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -308,8 +308,7 @@ extern int sna_output_dpms_status(xf86OutputPtr output);
 extern int sna_page_flip(struct sna *sna,
 			 struct kgem_bo *bo,
 			 void *data,
-			 int ref_crtc_hw_id,
-			 uint32_t *old_fb);
+			 int ref_crtc_hw_id);
 
 constant static inline struct sna *
 to_sna(ScrnInfoPtr scrn)
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 7c1d3bc..2d8b0f3 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -2304,8 +2304,7 @@ int
 sna_page_flip(struct sna *sna,
 	      struct kgem_bo *bo,
 	      void *data,
-	      int ref_crtc_hw_id,
-	      uint32_t *old_fb)
+	      int ref_crtc_hw_id)
 {
 	int count;
 
diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index 50ee087..07c95fb 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -97,7 +97,6 @@ struct sna_dri_frame_event {
 		struct kgem_bo *bo;
 		uint32_t name;
 	} old_front, next_front, cache;
-	uint32_t old_fb;
 
 	int off_delay;
 };
@@ -884,9 +883,7 @@ sna_dri_page_flip(struct sna *sna, struct sna_dri_frame_event *info)
 
 	DBG(("%s()\n", __FUNCTION__));
 
-	info->count = sna_page_flip(sna, bo,
-				    info, info->pipe,
-				    &info->old_fb);
+	info->count = sna_page_flip(sna, bo, info, info->pipe);
 	if (info->count == 0)
 		return FALSE;
 
@@ -1246,7 +1243,7 @@ sna_dri_flip_continue(struct sna *sna,
 	bo = get_private(info->back)->bo;
 	assert(get_drawable_pixmap(draw)->drawable.height * bo->pitch <= kgem_bo_size(bo));
 
-	info->count = sna_page_flip(sna, bo, info, info->pipe, &info->old_fb);
+	info->count = sna_page_flip(sna, bo, info, info->pipe);
 	if (info->count == 0)
 		return FALSE;
 
@@ -1368,8 +1365,7 @@ static void sna_dri_flip_event(struct sna *sna,
 
 			flip->count = sna_page_flip(sna,
 						    get_private(flip->front)->bo,
-						    flip, flip->pipe,
-						    &flip->old_fb);
+						    flip, flip->pipe);
 			if (flip->count == 0)
 				goto finish_async_flip;
 
@@ -1382,8 +1378,7 @@ static void sna_dri_flip_event(struct sna *sna,
 			/* Just queue a no-op flip to trigger another event */
 			flip->count = sna_page_flip(sna,
 						    get_private(flip->front)->bo,
-						    flip, flip->pipe,
-						    &flip->old_fb);
+						    flip, flip->pipe);
 			if (flip->count == 0)
 				goto finish_async_flip;
 		} else {
commit ad877abdc70b842afd202b2f97892d97a0b8d151
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 7 17:48:52 2012 +0100

    sna/dri: Attach the chain of frame events to the Window, not pixmap
    
    So that we can have multiple clients swapping in separate windows
    concurrently.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index 6994fba..50ee087 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -63,6 +63,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 enum frame_event_type {
 	DRI2_SWAP,
+	DRI2_SWAP_WAIT,
 	DRI2_SWAP_THROTTLE,
 	DRI2_XCHG_THROTTLE,
 	DRI2_ASYNC_FLIP,
@@ -79,8 +80,6 @@ struct sna_dri_frame_event {
 	int pipe;
 	int count;
 
-	struct list drawable_events;
-
 	/* for swaps & flips only */
 	DRI2SwapEventPtr event_complete;
 	void *event_data;
@@ -107,7 +106,6 @@ struct sna_dri_private {
 	int refcnt;
 	PixmapPtr pixmap;
 	struct kgem_bo *bo;
-	struct sna_dri_frame_event *chain;
 };
 
 static inline struct sna_dri_frame_event *
@@ -131,30 +129,30 @@ static inline struct kgem_bo *ref(struct kgem_bo *bo)
 /* Prefer to enable TILING_Y if this buffer will never be a
  * candidate for pageflipping
  */
-static uint32_t color_tiling(struct sna *sna, DrawablePtr drawable)
+static uint32_t color_tiling(struct sna *sna, DrawablePtr draw)
 {
 	uint32_t tiling;
 
 	if (COLOR_PREFER_TILING_Y &&
-	    (drawable->width  != sna->front->drawable.width ||
-	     drawable->height != sna->front->drawable.height))
+	    (draw->width  != sna->front->drawable.width ||
+	     draw->height != sna->front->drawable.height))
 		tiling = I915_TILING_Y;
 	else
 		tiling = I915_TILING_X;
 
 	return kgem_choose_tiling(&sna->kgem, -tiling,
-				  drawable->width,
-				  drawable->height,
-				  drawable->bitsPerPixel);
+				  draw->width,
+				  draw->height,
+				  draw->bitsPerPixel);
 }
 
-static uint32_t other_tiling(struct sna *sna, DrawablePtr drawable)
+static uint32_t other_tiling(struct sna *sna, DrawablePtr draw)
 {
 	/* XXX Can mix color X / depth Y? */
 	return kgem_choose_tiling(&sna->kgem, -I915_TILING_Y,
-				  drawable->width,
-				  drawable->height,
-				  drawable->bitsPerPixel);
+				  draw->width,
+				  draw->height,
+				  draw->bitsPerPixel);
 }
 
 static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
@@ -200,11 +198,11 @@ static inline void sna_pixmap_set_buffer(PixmapPtr pixmap, void *ptr)
 }
 
 static DRI2Buffer2Ptr
-sna_dri_create_buffer(DrawablePtr drawable,
+sna_dri_create_buffer(DrawablePtr draw,
 		      unsigned int attachment,
 		      unsigned int format)
 {
-	struct sna *sna = to_sna_from_drawable(drawable);
+	struct sna *sna = to_sna_from_drawable(draw);
 	DRI2Buffer2Ptr buffer;
 	struct sna_dri_private *private;
 	PixmapPtr pixmap;
@@ -212,13 +210,12 @@ sna_dri_create_buffer(DrawablePtr drawable,
 	int bpp;
 
 	DBG(("%s(attachment=%d, format=%d, drawable=%dx%d)\n",
-	     __FUNCTION__, attachment, format,
-	     drawable->width, drawable->height));
+	     __FUNCTION__, attachment, format, draw->width, draw->height));
 
 	pixmap = NULL;
 	switch (attachment) {
 	case DRI2BufferFrontLeft:
-		pixmap = get_drawable_pixmap(drawable);
+		pixmap = get_drawable_pixmap(draw);
 		buffer = sna_pixmap_get_buffer(pixmap);
 		if (buffer) {
 			DBG(("%s: reusing front buffer attachment\n",
@@ -248,12 +245,12 @@ sna_dri_create_buffer(DrawablePtr drawable,
 	case DRI2BufferFrontRight:
 	case DRI2BufferFakeFrontLeft:
 	case DRI2BufferFakeFrontRight:
-		bpp = drawable->bitsPerPixel;
+		bpp = draw->bitsPerPixel;
 		bo = kgem_create_2d(&sna->kgem,
-				    drawable->width,
-				    drawable->height,
-				    drawable->bitsPerPixel,
-				    color_tiling(sna, drawable),
+				    draw->width,
+				    draw->height,
+				    draw->bitsPerPixel,
+				    color_tiling(sna, draw),
 				    CREATE_EXACT);
 		break;
 
@@ -280,11 +277,11 @@ sna_dri_create_buffer(DrawablePtr drawable,
 		 * not understand W tiling and the GTT is incapable of
 		 * W fencing.
 		 */
-		bpp = format ? format : drawable->bitsPerPixel;
+		bpp = format ? format : draw->bitsPerPixel;
 		bpp *= 2;
 		bo = kgem_create_2d(&sna->kgem,
-				    ALIGN(drawable->width, 64),
-				    ALIGN((drawable->height + 1) / 2, 64),
+				    ALIGN(draw->width, 64),
+				    ALIGN((draw->height + 1) / 2, 64),
 				    bpp, I915_TILING_NONE, CREATE_EXACT);
 		break;
 
@@ -292,10 +289,10 @@ sna_dri_create_buffer(DrawablePtr drawable,
 	case DRI2BufferDepthStencil:
 	case DRI2BufferHiz:
 	case DRI2BufferAccum:
-		bpp = format ? format : drawable->bitsPerPixel,
+		bpp = format ? format : draw->bitsPerPixel,
 		bo = kgem_create_2d(&sna->kgem,
-				    drawable->width, drawable->height, bpp,
-				    other_tiling(sna, drawable),
+				    draw->width, draw->height, bpp,
+				    other_tiling(sna, draw),
 				    CREATE_EXACT);
 		break;
 
@@ -373,9 +370,9 @@ static void _sna_dri_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
 	}
 }
 
-static void sna_dri_destroy_buffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
+static void sna_dri_destroy_buffer(DrawablePtr draw, DRI2Buffer2Ptr buffer)
 {
-	_sna_dri_destroy_buffer(to_sna_from_drawable(drawable), buffer);
+	_sna_dri_destroy_buffer(to_sna_from_drawable(draw), buffer);
 }
 
 static void sna_dri_reference_buffer(DRI2Buffer2Ptr buffer)
@@ -773,95 +770,102 @@ sna_dri_get_pipe(DrawablePtr pDraw)
 	return pipe;
 }
 
-static struct list *
-sna_dri_get_window_events(WindowPtr win)
+static struct sna_dri_frame_event *
+sna_dri_window_get_chain(WindowPtr win)
 {
-	struct list *head;
+	return ((void **)win->devPrivates)[1];
+}
 
-	head = ((void **)win->devPrivates)[1];
-	if (head)
-		return head;
+static void
+sna_dri_window_set_chain(WindowPtr win,
+			 struct sna_dri_frame_event *chain)
+{
+	DBG(("%s: head now %p\n", __FUNCTION__, chain));
+	assert(win->drawable.type == DRAWABLE_WINDOW);
+	((void **)win->devPrivates)[1] = chain;
+}
 
-	head = malloc(sizeof(*head));
-	if (head == NULL)
-		return NULL;
+static void
+sna_dri_remove_frame_event(WindowPtr win,
+			    struct sna_dri_frame_event *info)
+{
+	struct sna_dri_frame_event *chain;
+
+	DBG(("%s: remove[%p] from window %ld)\n",
+	     __FUNCTION__, info, (long)win->drawable.id));
+
+	chain = sna_dri_window_get_chain(win);
+	if (chain == NULL)
+		return;
 
-	list_init(head);
-	((void **)win->devPrivates)[1] = head;
-	return head;
+	if (chain == info) {
+		sna_dri_window_set_chain(win, info->chain);
+		return;
+	}
+
+	while (chain->chain != info)
+		chain = chain->chain;
+	chain->chain = info->chain;
 }
 
 void sna_dri_destroy_window(WindowPtr win)
 {
-	struct list *head = ((void **)win->devPrivates)[1];
+	struct sna_dri_frame_event *chain;
 
-	if (head == NULL)
+	chain = sna_dri_window_get_chain(win);
+	if (chain == NULL)
 		return;
 
 	DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.serialNumber));
-
-	while (!list_is_empty(head)) {
-		struct sna_dri_frame_event *info =
-			list_first_entry(head,
-					 struct sna_dri_frame_event,
-					 drawable_events);
-
-		DBG(("%s: marking drawable gone [%p]: %ld\n",
-		     __FUNCTION__, info, (long)info->drawable_id));
-
-		list_del(&info->drawable_events);
-		info->drawable_id = None;
+	while (chain) {
+		chain->drawable_id = None;
+		chain = chain->chain;
 	}
-	free(head);
 }
 
-static bool
+static void
 sna_dri_add_frame_event(DrawablePtr draw, struct sna_dri_frame_event *info)
 {
-	struct list *head;
+	struct sna_dri_frame_event *chain;
 
 	if (draw->type != DRAWABLE_WINDOW)
-		return true;
-
-	head = sna_dri_get_window_events((WindowPtr)draw);
-	if (head == NULL) {
-		DBG(("%s: failed to get drawable events\n", __FUNCTION__));
-		return false;
-	}
-
-	list_add(&info->drawable_events, head);
+		return;
 
 	DBG(("%s: add[%p] to window %ld)\n",
 	     __FUNCTION__, info, (long)draw->id));
-	return true;
-}
 
-static void
-sna_dri_frame_event_release_bo(struct kgem *kgem, struct kgem_bo *bo)
-{
-	kgem_bo_destroy(kgem, bo);
+	chain = sna_dri_window_get_chain((WindowPtr)draw);
+	if (chain == NULL) {
+		sna_dri_window_set_chain((WindowPtr)draw, info);
+		return;
+	}
+
+	while (chain->chain != NULL)
+		chain = chain->chain;
+	chain->chain = info;
 }
 
 static void
 sna_dri_frame_event_info_free(struct sna *sna,
+			      DrawablePtr draw,
 			      struct sna_dri_frame_event *info)
 {
 	DBG(("%s: del[%p] (%p, %ld)\n", __FUNCTION__,
 	     info, info->client, (long)info->drawable_id));
 
-	list_del(&info->drawable_events);
-
+	if (draw && draw->type == DRAWABLE_WINDOW)
+		sna_dri_remove_frame_event((WindowPtr)draw, info);
 	_sna_dri_destroy_buffer(sna, info->front);
 	_sna_dri_destroy_buffer(sna, info->back);
 
 	if (info->old_front.bo)
-		sna_dri_frame_event_release_bo(&sna->kgem, info->old_front.bo);
+		kgem_bo_destroy(&sna->kgem, info->old_front.bo);
 
 	if (info->next_front.bo)
-		sna_dri_frame_event_release_bo(&sna->kgem, info->next_front.bo);
+		kgem_bo_destroy(&sna->kgem, info->next_front.bo);
 
 	if (info->cache.bo)
-		sna_dri_frame_event_release_bo(&sna->kgem, info->cache.bo);
+		kgem_bo_destroy(&sna->kgem, info->cache.bo);
 
 	if (info->bo)
 		kgem_bo_destroy(&sna->kgem, info->bo);
@@ -1084,6 +1088,8 @@ static void chain_swap(struct sna *sna,
 	drmVBlank vbl;
 	int type;
 
+	assert(chain == sna_dri_window_get_chain((WindowPtr)draw));
+
 	/* In theory, it shoudln't be possible for cross-chaining to occur! */
 	if (chain->type == DRI2_XCHG_THROTTLE) {
 		DBG(("%s: performing chained exchange\n", __FUNCTION__));
@@ -1095,7 +1101,7 @@ static void chain_swap(struct sna *sna,
 		chain->bo = sna_dri_copy_to_front(sna, draw, NULL,
 						  get_private(chain->front)->bo,
 						  get_private(chain->back)->bo,
-						 true);
+						  true);
 
 		type = DRI2_BLIT_COMPLETE;
 	}
@@ -1113,13 +1119,39 @@ static void chain_swap(struct sna *sna,
 	vbl.request.sequence = 0;
 	vbl.request.signal = (unsigned long)chain;
 	if (sna_wait_vblank(sna, &vbl))
-		sna_dri_frame_event_info_free(sna, chain);
+		sna_dri_frame_event_info_free(sna, draw, chain);
+}
+
+static bool sna_dri_blit_complete(struct sna *sna,
+				  struct sna_dri_frame_event *info)
+{
+	if (info->bo && kgem_bo_is_busy(info->bo)) {
+		kgem_retire(&sna->kgem);
+		if (kgem_bo_is_busy(info->bo)) {
+			drmVBlank vbl;
+
+			DBG(("%s: vsync'ed blit is still busy, postponing\n",
+			     __FUNCTION__));
+
+			VG_CLEAR(vbl);
+			vbl.request.type =
+				DRM_VBLANK_RELATIVE |
+				DRM_VBLANK_EVENT |
+				pipe_select(info->pipe);
+			vbl.request.sequence = 1;
+			vbl.request.signal = (unsigned long)info;
+			if (!sna_wait_vblank(sna, &vbl))
+				return false;
+		}
+	}
+
+	return true;
 }
 
 void sna_dri_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
 {
 	struct sna_dri_frame_event *info = (void *)(uintptr_t)event->user_data;
-	DrawablePtr draw;
+	DrawablePtr draw = NULL;
 	int status;
 
 	DBG(("%s(id=%d, type=%d)\n", __FUNCTION__,
@@ -1150,81 +1182,38 @@ void sna_dri_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
 						 get_private(info->front)->bo,
 						 get_private(info->back)->bo,
 						 true);
-		info->type = DRI2_SWAP_THROTTLE;
+		info->type = DRI2_SWAP_WAIT;
 		/* fall through to SwapComplete */
+	case DRI2_SWAP_WAIT:
+		if (!sna_dri_blit_complete(sna, info))
+			return;
+
+		DRI2SwapComplete(info->client,
+				 draw, event->sequence,
+				 event->tv_sec, event->tv_usec,
+				 DRI2_BLIT_COMPLETE,
+				 info->client ? info->event_complete : NULL,
+				 info->event_data);
+		break;
+
 	case DRI2_SWAP_THROTTLE:
+		if (!sna_dri_blit_complete(sna, info))
+			return;
+
 		DBG(("%s: %d complete, frame=%d tv=%d.%06d\n",
 		     __FUNCTION__, info->type,
 		     event->sequence, event->tv_sec, event->tv_usec));
-
-		if (info->bo && kgem_bo_is_busy(info->bo)) {
-			kgem_retire(&sna->kgem);
-			if (kgem_bo_is_busy(info->bo)) {
-				drmVBlank vbl;
-
-				DBG(("%s: vsync'ed blit is still busy, postponing\n",
-				     __FUNCTION__));
-
-				VG_CLEAR(vbl);
-				vbl.request.type =
-					DRM_VBLANK_RELATIVE |
-					DRM_VBLANK_EVENT |
-					pipe_select(info->pipe);
-				vbl.request.sequence = 1;
-				vbl.request.signal = (unsigned long)info;
-				if (!sna_wait_vblank(sna, &vbl))
-					return;
-			}
-		}
-
-		if (info->chain) {
-			struct sna_dri_frame_event *chain = info->chain;
-
-			assert(get_private(info->front)->chain == info);
-			get_private(info->front)->chain = chain;
-
-			chain_swap(sna, draw, event, chain);
-
-			info->chain = NULL;
-		} else if (get_private(info->front)->chain == info) {
-			DBG(("%s: chain complete\n", __FUNCTION__));
-			get_private(info->front)->chain = NULL;
-		} else {
-			DBG(("%s: deferred blit complete, unblock client\n",
-			     __FUNCTION__));
-			DRI2SwapComplete(info->client,
-					 draw, event->sequence,
-					 event->tv_sec, event->tv_usec,
-					 DRI2_BLIT_COMPLETE,
-					 info->client ? info->event_complete : NULL,
-					 info->event_data);
-		}
 		break;
 
 	case DRI2_XCHG_THROTTLE:
 		DBG(("%s: xchg throttle\n", __FUNCTION__));
-
-		if (info->chain) {
-			struct sna_dri_frame_event *chain = info->chain;
-
-			assert(get_private(info->front)->chain == info);
-			get_private(info->front)->chain = chain;
-
-			chain_swap(sna, draw, event, chain);
-
-			info->chain = NULL;
-		} else {
-			DBG(("%s: chain complete\n", __FUNCTION__));
-			get_private(info->front)->chain = NULL;
-		}
 		break;
 
 	case DRI2_WAITMSC:
-		if (info->client)
-			DRI2WaitMSCComplete(info->client, draw,
-					    event->sequence,
-					    event->tv_sec,
-					    event->tv_usec);
+		DRI2WaitMSCComplete(info->client, draw,
+				    event->sequence,
+				    event->tv_sec,
+				    event->tv_usec);
 		break;
 	default:
 		xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
@@ -1233,8 +1222,14 @@ void sna_dri_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
 		break;
 	}
 
+	if (info->chain) {
+		sna_dri_remove_frame_event((WindowPtr)draw, info);
+		chain_swap(sna, draw, event, info->chain);
+		draw = NULL;
+	}
+
 done:
-	sna_dri_frame_event_info_free(sna, info);
+	sna_dri_frame_event_info_free(sna, draw, info);
 }
 
 static int
@@ -1276,7 +1271,8 @@ sna_dri_flip_continue(struct sna *sna,
 static void sna_dri_flip_event(struct sna *sna,
 			       struct sna_dri_frame_event *flip)
 {
-	DrawablePtr drawable;
+	DrawablePtr draw = NULL;
+	int status;
 
 	DBG(("%s(frame=%d, tv=%d.%06d, type=%d)\n",
 	     __FUNCTION__,
@@ -1285,80 +1281,74 @@ static void sna_dri_flip_event(struct sna *sna,
 	     flip->fe_tv_usec,
 	     flip->type));
 
+	if (sna->dri.flip_pending == flip)
+		sna->dri.flip_pending = NULL;
+
+	status = BadDrawable;
+	if (flip->drawable_id)
+		status = dixLookupDrawable(&draw,
+					   flip->drawable_id,
+					   serverClient,
+					   M_ANY, DixWriteAccess);
+	if (status != Success) {
+		DBG(("%s: drawable already gone\n", __FUNCTION__));
+		sna_dri_frame_event_info_free(sna, draw, flip);
+		return;
+	}
+
 	/* We assume our flips arrive in order, so we don't check the frame */
 	switch (flip->type) {
 	case DRI2_FLIP:
 		/* Deliver cached msc, ust from reference crtc */
-		/* Check for too small vblank count of pageflip completion, taking wraparound
-		 * into account. This usually means some defective kms pageflip completion,
-		 * causing wrong (msc, ust) return values and possible visual corruption.
+		/* Check for too small vblank count of pageflip completion,
+		 * taking wraparound * into account. This usually means some
+		 * defective kms pageflip completion, causing wrong (msc, ust)
+		 * return values and possible visual corruption.
 		 */
-		if (flip->drawable_id &&
-		    dixLookupDrawable(&drawable,
-				      flip->drawable_id,
-				      serverClient,
-				      M_ANY, DixWriteAccess) == Success) {
-			if ((flip->fe_frame < flip->frame) &&
-			    (flip->frame - flip->fe_frame < 5)) {
-				static int limit = 5;
-
-				/* XXX we are currently hitting this path with older
-				 * kernels, so make it quieter.
-				 */
-				if (limit) {
-					xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
-						   "%s: Pageflip completion has impossible msc %d < target_msc %d\n",
-						   __func__, flip->fe_frame, flip->frame);
-					limit--;
-				}
-
-				/* All-0 values signal timestamping failure. */
-				flip->fe_frame = flip->fe_tv_sec = flip->fe_tv_usec = 0;
-			}
-
-			DBG(("%s: flip complete\n", __FUNCTION__));
-			DRI2SwapComplete(flip->client, drawable,
-					 flip->fe_frame,
-					 flip->fe_tv_sec,
-					 flip->fe_tv_usec,
-					 DRI2_FLIP_COMPLETE,
-					 flip->client ? flip->event_complete : NULL,
-					 flip->event_data);
+		if (flip->fe_frame < flip->frame &&
+		    flip->frame - flip->fe_frame < 5) {
+			/* All-0 values signal timestamping failure. */
+			flip->fe_frame = flip->fe_tv_sec = flip->fe_tv_usec = 0;
 		}
 
-		sna_dri_frame_event_info_free(sna, flip);
+		DBG(("%s: flip complete\n", __FUNCTION__));
+		DRI2SwapComplete(flip->client, draw,
+				 flip->fe_frame,
+				 flip->fe_tv_sec,
+				 flip->fe_tv_usec,
+				 DRI2_FLIP_COMPLETE,
+				 flip->client ? flip->event_complete : NULL,
+				 flip->event_data);
+
+		sna_dri_frame_event_info_free(sna, draw, flip);
 		break;
 
 	case DRI2_FLIP_THROTTLE:
-		assert(sna->dri.flip_pending == flip);
-		sna->dri.flip_pending = NULL;
-
-		if (flip->next_front.name &&
-		    flip->drawable_id &&
-		    dixLookupDrawable(&drawable,
-				      flip->drawable_id,
-				      serverClient,
-				      M_ANY, DixWriteAccess) == Success) {
-			if (can_flip(sna, drawable, flip->front, flip->back) &&
-			    sna_dri_flip_continue(sna, drawable, flip)) {
-				DRI2SwapComplete(flip->client, drawable,
-						0, 0, 0,
-						DRI2_FLIP_COMPLETE,
-						flip->client ? flip->event_complete : NULL,
-						flip->event_data);
-			} else {
-				DBG(("%s: no longer able to flip\n",
-				     __FUNCTION__));
+		if (!flip->next_front.name) {
+			DBG(("%s: flip chain complete\n", __FUNCTION__));
+			sna_dri_frame_event_info_free(sna, draw, flip);
+		} else if (can_flip(sna, draw, flip->front, flip->back) &&
+			   sna_dri_flip_continue(sna, draw, flip)) {
+			DRI2SwapComplete(flip->client, draw,
+					 0, 0, 0,
+					 DRI2_FLIP_COMPLETE,
+					 flip->client ? flip->event_complete : NULL,
+					 flip->event_data);
+		} else {
+			DBG(("%s: no longer able to flip\n", __FUNCTION__));
+
+			flip->bo = sna_dri_copy_to_front(sna, draw, NULL,
+							 get_private(flip->front)->bo,
+							 get_private(flip->back)->bo,
+							 false);
+			DRI2SwapComplete(flip->client, draw,
+					 0, 0, 0,
+					 DRI2_BLIT_COMPLETE,
+					 flip->client ? flip->event_complete : NULL,
+					 flip->event_data);
 
-				DRI2SwapComplete(flip->client, drawable,
-						0, 0, 0,
-						DRI2_EXCHANGE_COMPLETE,
-						flip->client ? flip->event_complete : NULL,
-						flip->event_data);
-				sna_dri_frame_event_info_free(sna, flip);
-			}
-		} else
-			sna_dri_frame_event_info_free(sna, flip);
+			sna_dri_frame_event_info_free(sna, draw, flip);
+		}
 		break;
 
 #if USE_ASYNC_SWAP
@@ -1402,7 +1392,7 @@ finish_async_flip:
 
 			DBG(("%s: async flip completed\n", __FUNCTION__));
 			sna->dri.flip_pending = NULL;
-			sna_dri_frame_event_info_free(sna, flip);
+			sna_dri_frame_event_info_free(sna, draw, flip);
 		}
 		break;
 #endif
@@ -1478,9 +1468,11 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 				return TRUE;
 			} else {
 				/* We need to first wait (one vblank) for the
-				 * async flips to complete before this client can
-				 * take over.
+				 * async flips to complete before this client
+				 * can take over.
 				 */
+				DBG(("%s: queueing flip after pending completion\n",
+				     __FUNCTION__));
 				type = DRI2_FLIP;
 			}
 		}
@@ -1499,36 +1491,33 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		info->back = back;
 		info->pipe = pipe;
 
-		if (!sna_dri_add_frame_event(draw, info)) {
-			DBG(("%s: failed to hook up frame event\n", __FUNCTION__));
-			free(info);
-			return FALSE;
-		}
-
+		sna_dri_add_frame_event(draw, info);
 		sna_dri_reference_buffer(front);
 		sna_dri_reference_buffer(back);
 
 		if (!sna_dri_page_flip(sna, info)) {
 			DBG(("%s: failed to queue page flip\n", __FUNCTION__));
-			sna_dri_frame_event_info_free(sna, info);
+			sna_dri_frame_event_info_free(sna, draw, info);
 			return FALSE;
 		}
 
-		get_private(info->back)->bo =
-			kgem_create_2d(&sna->kgem,
-				       draw->width,
-				       draw->height,
-				       draw->bitsPerPixel,
-				       get_private(info->front)->bo->tiling,
-				       CREATE_EXACT);
-		info->back->name = kgem_bo_flink(&sna->kgem,
-						 get_private(info->back)->bo);
-		sna->dri.flip_pending = info;
+		if (type != DRI2_FLIP) {
+			get_private(info->back)->bo =
+				kgem_create_2d(&sna->kgem,
+					       draw->width,
+					       draw->height,
+					       draw->bitsPerPixel,
+					       get_private(info->front)->bo->tiling,
+					       CREATE_EXACT);
+			info->back->name = kgem_bo_flink(&sna->kgem,
+							 get_private(info->back)->bo);
+			sna->dri.flip_pending = info;
 
-		DRI2SwapComplete(info->client, draw, 0, 0, 0,
-				 DRI2_EXCHANGE_COMPLETE,
-				 info->event_complete,
-				 info->event_data);
+			DRI2SwapComplete(info->client, draw, 0, 0, 0,
+					 DRI2_EXCHANGE_COMPLETE,
+					 info->event_complete,
+					 info->event_data);
+		}
 	} else {
 		info = calloc(1, sizeof(struct sna_dri_frame_event));
 		if (info == NULL)
@@ -1543,12 +1532,7 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		info->pipe = pipe;
 		info->type = DRI2_FLIP;
 
-		if (!sna_dri_add_frame_event(draw, info)) {
-			DBG(("%s: failed to hook up frame event\n", __FUNCTION__));
-			free(info);
-			return FALSE;
-		}
-
+		sna_dri_add_frame_event(draw, info);
 		sna_dri_reference_buffer(front);
 		sna_dri_reference_buffer(back);
 
@@ -1556,7 +1540,7 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe);
 		vbl.request.sequence = 0;
 		if (sna_wait_vblank(sna, &vbl)) {
-			sna_dri_frame_event_info_free(sna, info);
+			sna_dri_frame_event_info_free(sna, draw, info);
 			return FALSE;
 		}
 
@@ -1611,7 +1595,7 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		vbl.request.sequence -= 1;
 		vbl.request.signal = (unsigned long)info;
 		if (sna_wait_vblank(sna, &vbl)) {
-			sna_dri_frame_event_info_free(sna, info);
+			sna_dri_frame_event_info_free(sna, draw, info);
 			return FALSE;
 		}
 
@@ -1626,7 +1610,6 @@ sna_dri_immediate_xchg(struct sna *sna,
 		       DrawablePtr draw,
 		       struct sna_dri_frame_event *info)
 {
-	struct sna_dri_private *priv = get_private(info->front);
 	drmVBlank vbl;
 
 	DBG(("%s: emitting immediate exchange, throttling client\n", __FUNCTION__));
@@ -1634,7 +1617,7 @@ sna_dri_immediate_xchg(struct sna *sna,
 
 	if ((sna->flags & SNA_NO_WAIT) == 0) {
 		info->type = DRI2_XCHG_THROTTLE;
-		if (priv->chain == NULL) {
+		if (sna_dri_window_get_chain((WindowPtr)draw) == info) {
 			DBG(("%s: no pending xchg, starting chain\n",
 			     __FUNCTION__));
 
@@ -1650,15 +1633,8 @@ sna_dri_immediate_xchg(struct sna *sna,
 				pipe_select(info->pipe);
 			vbl.request.sequence = 0;
 			vbl.request.signal = (unsigned long)info;
-			if (sna_wait_vblank(sna, &vbl) == 0)
-				priv->chain = info;
-			else
-				sna_dri_frame_event_info_free(sna, info);
-		} else {
-			DBG(("%s: attaching to vsync chain\n",
-			     __FUNCTION__));
-			assert(priv->chain->chain == NULL);
-			priv->chain->chain = info;
+			if (sna_wait_vblank(sna, &vbl))
+				sna_dri_frame_event_info_free(sna, draw, info);
 		}
 	} else {
 		sna_dri_exchange_buffers(draw, info->front, info->back);
@@ -1666,7 +1642,7 @@ sna_dri_immediate_xchg(struct sna *sna,
 				 DRI2_EXCHANGE_COMPLETE,
 				 info->event_complete,
 				 info->event_data);
-		sna_dri_frame_event_info_free(sna, info);
+		sna_dri_frame_event_info_free(sna, draw, info);
 	}
 }
 
@@ -1675,7 +1651,6 @@ sna_dri_immediate_blit(struct sna *sna,
 		       DrawablePtr draw,
 		       struct sna_dri_frame_event *info)
 {
-	struct sna_dri_private *priv = get_private(info->front);
 	drmVBlank vbl;
 
 	DBG(("%s: emitting immediate blit, throttling client\n", __FUNCTION__));
@@ -1683,7 +1658,7 @@ sna_dri_immediate_blit(struct sna *sna,
 
 	if ((sna->flags & SNA_NO_WAIT) == 0) {
 		info->type = DRI2_SWAP_THROTTLE;
-		if (priv->chain == NULL) {
+		if (sna_dri_window_get_chain((WindowPtr)draw) == info) {
 			DBG(("%s: no pending blit, starting chain\n",
 			     __FUNCTION__));
 
@@ -1703,26 +1678,19 @@ sna_dri_immediate_blit(struct sna *sna,
 				pipe_select(info->pipe);
 			vbl.request.sequence = 0;
 			vbl.request.signal = (unsigned long)info;
-			if (sna_wait_vblank(sna, &vbl) == 0)
-				priv->chain = info;
-			else
-				sna_dri_frame_event_info_free(sna, info);
-		} else {
-			DBG(("%s: attaching to vsync chain\n",
-			     __FUNCTION__));
-			assert(priv->chain->chain == NULL);
-			priv->chain->chain = info;
+			if (sna_wait_vblank(sna, &vbl))
+				sna_dri_frame_event_info_free(sna, draw, info);
 		}
 	} else {
 		info->bo = sna_dri_copy_to_front(sna, draw, NULL,
 						 get_private(info->front)->bo,
 						 get_private(info->back)->bo,
-						 true);
+						 false);
 		DRI2SwapComplete(info->client, draw, 0, 0, 0,
 				 DRI2_BLIT_COMPLETE,
 				 info->event_complete,
 				 info->event_data);
-		sna_dri_frame_event_info_free(sna, info);
+		sna_dri_frame_event_info_free(sna, draw, info);
 	}
 }
 
@@ -1748,8 +1716,8 @@ sna_dri_immediate_blit(struct sna *sna,
  */
 static int
 sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
-		       DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor,
-		       CARD64 remainder, DRI2SwapEventPtr func, void *data)
+		      DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor,
+		      CARD64 remainder, DRI2SwapEventPtr func, void *data)
 {
 	ScreenPtr screen = draw->pScreen;
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
@@ -1812,13 +1780,7 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	info->back = back;
 	info->pipe = pipe;
 
-	if (!sna_dri_add_frame_event(draw, info)) {
-		DBG(("%s: failed to hook up frame event\n", __FUNCTION__));
-		free(info);
-		info = NULL;
-		goto blit_fallback;
-	}
-
+	sna_dri_add_frame_event(draw, info);
 	sna_dri_reference_buffer(front);
 	sna_dri_reference_buffer(back);
 
@@ -1854,16 +1816,16 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		info->frame = *target_msc;
 		info->type = DRI2_SWAP;
 
-		 vbl.request.type =
-			 DRM_VBLANK_ABSOLUTE |
-			 DRM_VBLANK_EVENT |
-			 pipe_select(pipe);
-		 vbl.request.sequence = *target_msc;
-		 vbl.request.signal = (unsigned long)info;
-		 if (sna_wait_vblank(sna, &vbl))
-			 goto blit_fallback;
+		vbl.request.type =
+			DRM_VBLANK_ABSOLUTE |
+			DRM_VBLANK_EVENT |
+			pipe_select(pipe);
+		vbl.request.sequence = *target_msc;
+		vbl.request.signal = (unsigned long)info;
+		if (sna_wait_vblank(sna, &vbl))
+			goto blit_fallback;
 
-		 return TRUE;
+		return TRUE;
 	}
 
 	/*
@@ -1872,10 +1834,10 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	 * equation.
 	 */
 	DBG(("%s: missed target, queueing event for next: current=%d, target=%d,  divisor=%d\n",
-		     __FUNCTION__,
-		     (int)current_msc,
-		     (int)*target_msc,
-		     (int)divisor));
+	     __FUNCTION__,
+	     (int)current_msc,
+	     (int)*target_msc,
+	     (int)divisor));
 
 	vbl.request.type =
 		DRM_VBLANK_ABSOLUTE |
@@ -1917,7 +1879,7 @@ blit_fallback:
 		pipe = DRI2_BLIT_COMPLETE;
 	}
 	if (info)
-		sna_dri_frame_event_info_free(sna, info);
+		sna_dri_frame_event_info_free(sna, draw, info);
 	DRI2SwapComplete(client, draw, 0, 0, 0, pipe, func, data);
 	*target_msc = 0; /* offscreen, so zero out target vblank count */
 	return TRUE;
@@ -1977,21 +1939,12 @@ blit:
 		info->front = front;
 		info->back = back;
 
-		if (!sna_dri_add_frame_event(draw, info)) {
-			DBG(("%s: failed to hook up frame event\n", __FUNCTION__));
-			free(info);
-			goto blit;
-		}
-
-		DBG(("%s: referencing (%p:%d, %p:%d)\n",
-		     __FUNCTION__,
-		     front, get_private(front)->refcnt,
-		     back, get_private(back)->refcnt));
+		sna_dri_add_frame_event(draw, info);
 		sna_dri_reference_buffer(front);
 		sna_dri_reference_buffer(back);
 
 		if (!sna_dri_page_flip(sna, info)) {
-			sna_dri_frame_event_info_free(sna, info);
+			sna_dri_frame_event_info_free(sna, draw, info);
 			goto blit;
 		}
 
@@ -2081,7 +2034,7 @@ sna_dri_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
  */
 static int
 sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
-			   CARD64 divisor, CARD64 remainder)
+			  CARD64 divisor, CARD64 remainder)
 {
 	struct sna *sna = to_sna_from_drawable(draw);
 	struct sna_dri_frame_event *info = NULL;
@@ -2133,11 +2086,7 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 	info->drawable_id = draw->id;
 	info->client = client;
 	info->type = DRI2_WAITMSC;
-	if (!sna_dri_add_frame_event(draw, info)) {
-		DBG(("%s: failed to hook up frame event\n", __FUNCTION__));
-		free(info);
-		goto out_complete;
-	}
+	sna_dri_add_frame_event(draw, info);
 
 	/*
 	 * If divisor is zero, or current_msc is smaller than target_msc,
@@ -2186,7 +2135,7 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 	return TRUE;
 
 out_free_info:
-	sna_dri_frame_event_info_free(sna, info);
+	sna_dri_frame_event_info_free(sna, draw, info);
 out_complete:
 	DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
 	return TRUE;
commit 81cd9aa80091b9bb08b50062f117d678a3bc7a91
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 7 16:12:49 2012 +0100

    sna: Tweak start/stop of the deferred flush
    
    As we now emit work whenever we wakeup and find the GPU idle, we rarely
    actually have pending work in the deferred flush queue, so try to avoid
    installing a timer if we are not accumulating work.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 60595f5..681b283 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -12254,15 +12254,14 @@ static bool has_shadow(struct sna *sna)
 	return !sna->mode.shadow_flip;
 }
 
-static bool need_flush(struct sna *sna, struct sna_pixmap *scanout)
+static bool start_flush(struct sna *sna, struct sna_pixmap *scanout)
 {
-	DBG(("%s: scanout=%d shadow?=%d, (cpu?=%d || gpu?=%d), busy=%d)\n",
+	DBG(("%s: scanout=%d shadow?=%d, (cpu?=%d || gpu?=%d))\n",
 	     __FUNCTION__,
 	     scanout && scanout->gpu_bo ? scanout->gpu_bo->handle : 0,
 	     has_shadow(sna),
 	     scanout && scanout->cpu_damage != NULL,
-	     scanout && scanout->gpu_bo && scanout->gpu_bo->exec != NULL,
-	     scanout && scanout->gpu_bo && __kgem_flush(&sna->kgem, scanout->gpu_bo)));
+	     scanout && scanout->gpu_bo && scanout->gpu_bo->exec != NULL));
 
 	if (has_shadow(sna))
 		return true;
@@ -12270,10 +12269,25 @@ static bool need_flush(struct sna *sna, struct sna_pixmap *scanout)
 	if (!scanout)
 		return false;
 
-	if (scanout->cpu_damage || scanout->gpu_bo->exec)
+	return scanout->cpu_damage || scanout->gpu_bo->exec;
+}
+
+static bool stop_flush(struct sna *sna, struct sna_pixmap *scanout)
+{
+	DBG(("%s: scanout=%d shadow?=%d, (cpu?=%d || gpu?=%d))\n",
+	     __FUNCTION__,
+	     scanout && scanout->gpu_bo ? scanout->gpu_bo->handle : 0,
+	     has_shadow(sna),
+	     scanout && scanout->cpu_damage != NULL,
+	     scanout && scanout->gpu_bo && scanout->gpu_bo->rq != NULL));
+
+	if (has_shadow(sna))
 		return true;
 
-	return __kgem_flush(&sna->kgem, scanout->gpu_bo);
+	if (!scanout)
+		return false;
+
+	return scanout->cpu_damage || scanout->gpu_bo->needs_flush;
 }
 
 static bool sna_accel_do_flush(struct sna *sna)
@@ -12301,8 +12315,9 @@ static bool sna_accel_do_flush(struct sna *sna)
 			return true;
 		}
 	} else {
-		if (!need_flush(sna, priv)) {
+		if (!start_flush(sna, priv)) {
 			DBG(("%s -- no pending write to scanout\n", __FUNCTION__));
+			kgem_bo_flush(&sna->kgem, priv->gpu_bo);
 		} else {
 			sna->timer_active |= 1 << FLUSH_TIMER;
 			sna->timer_expire[FLUSH_TIMER] =
@@ -12417,7 +12432,7 @@ static void sna_accel_flush(struct sna *sna)
 	     sna->kgem.nbatch,
 	     sna->kgem.busy));
 
-	busy = need_flush(sna, priv);
+	busy = stop_flush(sna, priv);
 	if (!sna->kgem.busy && !busy)
 		sna_accel_disarm_timer(sna, FLUSH_TIMER);
 	sna->kgem.busy = busy;
commit 6cb0c631e4eafc09f1677c73906de9108d735de4
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 7 15:10:18 2012 +0100

    sna/dri: Clarify the message for one failure case
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index 6627847..6994fba 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -2058,12 +2058,11 @@ sna_dri_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
 	}
 
 	VG_CLEAR(vbl);
-
 	vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(pipe);
 	vbl.request.sequence = 0;
-
 	if (sna_wait_vblank(sna, &vbl)) {
-		DBG(("%s: failed on pipe %d\n", __FUNCTION__, pipe));
+		DBG(("%s: query failed on pipe %d, ret=%d\n",
+		     __FUNCTION__, pipe, errno));
 		return FALSE;
 	}
 
commit 9a314d18cef1e08b23f9dca861ad2ba396bb1080
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 7 14:56:05 2012 +0100

    sna/dri: Add a couple of missing VG_CLEAR on vblanks
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index beadf57..6627847 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -1630,6 +1630,7 @@ sna_dri_immediate_xchg(struct sna *sna,
 	drmVBlank vbl;
 
 	DBG(("%s: emitting immediate exchange, throttling client\n", __FUNCTION__));
+	VG_CLEAR(vbl);
 
 	if ((sna->flags & SNA_NO_WAIT) == 0) {
 		info->type = DRI2_XCHG_THROTTLE;
@@ -1678,6 +1679,7 @@ sna_dri_immediate_blit(struct sna *sna,
 	drmVBlank vbl;
 
 	DBG(("%s: emitting immediate blit, throttling client\n", __FUNCTION__));
+	VG_CLEAR(vbl);
 
 	if ((sna->flags & SNA_NO_WAIT) == 0) {
 		info->type = DRI2_SWAP_THROTTLE;
commit 66a53c15cb5ee729fb43ea9713fd8538a3f982ad
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 7 14:46:08 2012 +0100

    sna/dri: Couple the frame events into DestroyWindow
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna.h b/src/sna/sna.h
index 7f4c0bf..5f3ca76 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -358,6 +358,7 @@ extern bool sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
 Bool sna_dri_open(struct sna *sna, ScreenPtr pScreen);
 void sna_dri_page_flip_handler(struct sna *sna, struct drm_event_vblank *event);
 void sna_dri_vblank_handler(struct sna *sna, struct drm_event_vblank *event);
+void sna_dri_destroy_window(WindowPtr win);
 void sna_dri_close(struct sna *sna, ScreenPtr pScreen);
 
 extern bool sna_crtc_on(xf86CrtcPtr crtc);
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 099075b..60595f5 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -12618,6 +12618,7 @@ sna_unmap_window(WindowPtr win)
 static Bool
 sna_destroy_window(WindowPtr win)
 {
+	sna_dri_destroy_window(win);
 	return TRUE;
 }
 
diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index fd965bc..beadf57 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -79,8 +79,7 @@ struct sna_dri_frame_event {
 	int pipe;
 	int count;
 
-	struct list drawable_resource;
-	struct list client_resource;
+	struct list drawable_events;
 
 	/* for swaps & flips only */
 	DRI2SwapEventPtr event_complete;
@@ -111,11 +110,6 @@ struct sna_dri_private {
 	struct sna_dri_frame_event *chain;
 };
 
-static DevPrivateKeyRec sna_client_key;
-
-static RESTYPE frame_event_client_type;
-static RESTYPE frame_event_drawable_type;
-
 static inline struct sna_dri_frame_event *
 to_frame_event(uintptr_t  data)
 {
@@ -195,12 +189,12 @@ static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
 	return priv->gpu_bo;
 }
 
-constant static inline void *sna_pixmap_get_dri(PixmapPtr pixmap)
+constant static inline void *sna_pixmap_get_buffer(PixmapPtr pixmap)
 {
 	return ((void **)pixmap->devPrivates)[2];
 }
 
-static inline void *sna_pixmap_set_dri(PixmapPtr pixmap, void *ptr)
+static inline void sna_pixmap_set_buffer(PixmapPtr pixmap, void *ptr)
 {
 	((void **)pixmap->devPrivates)[2] = ptr;
 }
@@ -225,7 +219,7 @@ sna_dri_create_buffer(DrawablePtr drawable,
 	switch (attachment) {
 	case DRI2BufferFrontLeft:
 		pixmap = get_drawable_pixmap(drawable);
-		buffer = sna_pixmap_get_dri(pixmap);
+		buffer = sna_pixmap_get_buffer(pixmap);
 		if (buffer) {
 			DBG(("%s: reusing front buffer attachment\n",
 			     __FUNCTION__));
@@ -332,8 +326,8 @@ sna_dri_create_buffer(DrawablePtr drawable,
 
 	if (pixmap) {
 		assert(attachment == DRI2BufferFrontLeft);
-		sna_pixmap_set_dri(pixmap, buffer);
-		assert(sna_pixmap_get_dri(pixmap) == buffer);
+		sna_pixmap_set_buffer(pixmap, buffer);
+		assert(sna_pixmap_get_buffer(pixmap) == buffer);
 		pixmap->refcnt++;
 	}
 
@@ -368,7 +362,7 @@ static void _sna_dri_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
 				priv->pinned = pixmap == sna->front;
 			}
 
-			sna_pixmap_set_dri(pixmap, NULL);
+			sna_pixmap_set_buffer(pixmap, NULL);
 			pixmap->drawable.pScreen->DestroyPixmap(pixmap);
 		}
 
@@ -780,147 +774,66 @@ sna_dri_get_pipe(DrawablePtr pDraw)
 }
 
 static struct list *
-get_resource(XID id, RESTYPE type)
+sna_dri_get_window_events(WindowPtr win)
 {
-	struct list *resource;
-	void *ptr;
+	struct list *head;
 
-	ptr = NULL;
-	dixLookupResourceByType(&ptr, id, type, NULL, DixWriteAccess);
-	if (ptr)
-		return ptr;
+	head = ((void **)win->devPrivates)[1];
+	if (head)
+		return head;
 
-	resource = malloc(sizeof(*resource));
-	if (resource == NULL)
+	head = malloc(sizeof(*head));
+	if (head == NULL)
 		return NULL;
 
-	if (!AddResource(id, type, resource)) {
-		DBG(("%s: failed to add resource (%ld, %ld)\n",
-		     __FUNCTION__, (long)id, (long)type));
-		free(resource);
-		return NULL;
-	}
-
-	DBG(("%s(%ld): new(%ld)=%p\n", __FUNCTION__,
-	     (long)id, (long)type, resource));
-
-	list_init(resource);
-	return resource;
+	list_init(head);
+	((void **)win->devPrivates)[1] = head;
+	return head;
 }
 
-static int
-sna_dri_frame_event_client_gone(void *data, XID id)
+void sna_dri_destroy_window(WindowPtr win)
 {
-	struct list *resource = data;
-
-	DBG(("%s(%ld): %p\n", __FUNCTION__, (long)id, data));
-
-	while (!list_is_empty(resource)) {
-		struct sna_dri_frame_event *info =
-			list_first_entry(resource,
-					 struct sna_dri_frame_event,
-					 client_resource);
-
-		DBG(("%s: marking client gone [%p]: %p\n",
-		     __FUNCTION__, info, info->client));
-
-		list_del(&info->client_resource);
-		info->client = NULL;
-	}
-	free(resource);
-
-	return Success;
-}
+	struct list *head = ((void **)win->devPrivates)[1];
 
-static int
-sna_dri_frame_event_drawable_gone(void *data, XID id)
-{
-	struct list *resource = data;
+	if (head == NULL)
+		return;
 
-	DBG(("%s(%ld): resource=%p\n", __FUNCTION__, (long)id, resource));
+	DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.serialNumber));
 
-	while (!list_is_empty(resource)) {
+	while (!list_is_empty(head)) {
 		struct sna_dri_frame_event *info =
-			list_first_entry(resource,
+			list_first_entry(head,
 					 struct sna_dri_frame_event,
-					 drawable_resource);
+					 drawable_events);
 
 		DBG(("%s: marking drawable gone [%p]: %ld\n",
 		     __FUNCTION__, info, (long)info->drawable_id));
 
-		list_del(&info->drawable_resource);
+		list_del(&info->drawable_events);
 		info->drawable_id = None;
 	}
-	free(resource);
-
-	return Success;
+	free(head);
 }
 
-static Bool
-sna_dri_register_frame_event_resource_types(void)
+static bool
+sna_dri_add_frame_event(DrawablePtr draw, struct sna_dri_frame_event *info)
 {
-	frame_event_client_type =
-		CreateNewResourceType(sna_dri_frame_event_client_gone,
-				      "Frame Event Client");
-	if (!frame_event_client_type)
-		return FALSE;
-
-	DBG(("%s: frame_event_client_type=%d\n",
-	     __FUNCTION__, frame_event_client_type));
+	struct list *head;
 
-	frame_event_drawable_type =
-		CreateNewResourceType(sna_dri_frame_event_drawable_gone,
-				      "Frame Event Drawable");
-	if (!frame_event_drawable_type)
-		return FALSE;
-
-	DBG(("%s: frame_event_drawable_type=%d\n",
-	     __FUNCTION__, frame_event_drawable_type));
+	if (draw->type != DRAWABLE_WINDOW)
+		return true;
 
-	return TRUE;
-}
-
-static XID
-get_client_id(ClientPtr client)
-{
-	XID *ptr = dixGetPrivateAddr(&client->devPrivates, &sna_client_key);
-	if (*ptr == 0)
-		*ptr = FakeClientID(client->index);
-	return *ptr;
-}
-
-/*
- * Hook this frame event into the server resource
- * database so we can clean it up if the drawable or
- * client exits while the swap is pending
- */
-static Bool
-sna_dri_add_frame_event(struct sna_dri_frame_event *info)
-{
-	struct list *resource;
-
-	resource = get_resource(get_client_id(info->client),
-				frame_event_client_type);
-	if (resource == NULL) {
-		DBG(("%s: failed to get client resource\n", __FUNCTION__));
-		return FALSE;
+	head = sna_dri_get_window_events((WindowPtr)draw);
+	if (head == NULL) {
+		DBG(("%s: failed to get drawable events\n", __FUNCTION__));
+		return false;
 	}
 
-	list_add(&info->client_resource, resource);
+	list_add(&info->drawable_events, head);
 
-	resource = get_resource(info->drawable_id, frame_event_drawable_type);
-	if (resource == NULL) {
-		DBG(("%s: failed to get drawable resource\n", __FUNCTION__));
-		list_del(&info->client_resource);
-		return FALSE;
-	}
-
-	list_add(&info->drawable_resource, resource);
-
-	DBG(("%s: add[%p] (%p, %ld)\n", __FUNCTION__,
-	     info, info->client, (long)info->drawable_id));
-
-	return TRUE;
+	DBG(("%s: add[%p] to window %ld)\n",
+	     __FUNCTION__, info, (long)draw->id));
+	return true;
 }
 
 static void
@@ -936,8 +849,7 @@ sna_dri_frame_event_info_free(struct sna *sna,
 	DBG(("%s: del[%p] (%p, %ld)\n", __FUNCTION__,
 	     info, info->client, (long)info->drawable_id));
 
-	list_del(&info->client_resource);
-	list_del(&info->drawable_resource);
+	list_del(&info->drawable_events);
 
 	_sna_dri_destroy_buffer(sna, info->front);
 	_sna_dri_destroy_buffer(sna, info->back);
@@ -1587,7 +1499,7 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		info->back = back;
 		info->pipe = pipe;
 
-		if (!sna_dri_add_frame_event(info)) {
+		if (!sna_dri_add_frame_event(draw, info)) {
 			DBG(("%s: failed to hook up frame event\n", __FUNCTION__));
 			free(info);
 			return FALSE;
@@ -1631,7 +1543,7 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 		info->pipe = pipe;
 		info->type = DRI2_FLIP;
 
-		if (!sna_dri_add_frame_event(info)) {
+		if (!sna_dri_add_frame_event(draw, info)) {
 			DBG(("%s: failed to hook up frame event\n", __FUNCTION__));
 			free(info);
 			return FALSE;
@@ -1898,7 +1810,7 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
 	info->back = back;
 	info->pipe = pipe;
 
-	if (!sna_dri_add_frame_event(info)) {
+	if (!sna_dri_add_frame_event(draw, info)) {
 		DBG(("%s: failed to hook up frame event\n", __FUNCTION__));
 		free(info);
 		info = NULL;
@@ -2063,7 +1975,7 @@ blit:
 		info->front = front;
 		info->back = back;
 
-		if (!sna_dri_add_frame_event(info)) {
+		if (!sna_dri_add_frame_event(draw, info)) {
 			DBG(("%s: failed to hook up frame event\n", __FUNCTION__));
 			free(info);
 			goto blit;
@@ -2220,7 +2132,7 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
 	info->drawable_id = draw->id;
 	info->client = client;
 	info->type = DRI2_WAITMSC;
-	if (!sna_dri_add_frame_event(info)) {
+	if (!sna_dri_add_frame_event(draw, info)) {
 		DBG(("%s: failed to hook up frame event\n", __FUNCTION__));
 		free(info);
 		goto out_complete;
@@ -2280,8 +2192,6 @@ out_complete:
 }
 #endif
 
-static unsigned int dri2_server_generation;
-
 Bool sna_dri_open(struct sna *sna, ScreenPtr screen)
 {
 	DRI2InfoRec info;
@@ -2307,18 +2217,6 @@ Bool sna_dri_open(struct sna *sna, ScreenPtr screen)
 		return FALSE;
 	}
 
-	if (serverGeneration != dri2_server_generation) {
-	    dri2_server_generation = serverGeneration;
-	    if (!sna_dri_register_frame_event_resource_types()) {
-		xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
-			   "Cannot register DRI2 frame event resources\n");
-		return FALSE;
-	    }
-	}
-
-	if (!dixRegisterPrivateKey(&sna_client_key, PRIVATE_CLIENT, sizeof(XID)))
-		return FALSE;
-
 	sna->deviceName = drmGetDeviceNameFromFd(sna->kgem.fd);
 	memset(&info, '\0', sizeof(info));
 	info.fd = sna->kgem.fd;
diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c
index e242b2f..bbbcb63 100644
--- a/src/sna/sna_driver.c
+++ b/src/sna/sna_driver.c
@@ -80,10 +80,8 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #define DBG(x) ErrorF x
 #endif
 
-static DevPrivateKeyRec sna_private_index;
-static DevPrivateKeyRec sna_pixmap_index;
-static DevPrivateKeyRec sna_dri_index;
-static DevPrivateKeyRec sna_gc_index;
+static DevPrivateKeyRec sna_pixmap_key;
+static DevPrivateKeyRec sna_gc_key;
 static DevPrivateKeyRec sna_glyph_key;
 static DevPrivateKeyRec sna_window_key;
 
@@ -803,30 +801,23 @@ static void sna_mode_set(ScrnInfoPtr scrn)
 static Bool
 sna_register_all_privates(void)
 {
-	if (!dixRegisterPrivateKey(&sna_private_index, PRIVATE_PIXMAP, 0))
+	if (!dixRegisterPrivateKey(&sna_pixmap_key, PRIVATE_PIXMAP,
+				   3*sizeof(void *)))
 		return FALSE;
-	assert(sna_private_index.offset == 0);
+	assert(sna_pixmap_key.offset == 0);
 
-	if (!dixRegisterPrivateKey(&sna_pixmap_index, PRIVATE_PIXMAP, 0))
-		return FALSE;
-	assert(sna_pixmap_index.offset == sizeof(void*));
-
-	if (!dixRegisterPrivateKey(&sna_dri_index, PRIVATE_PIXMAP, 0))
-		return FALSE;
-	assert(sna_dri_index.offset == 2*sizeof(void*));
-
-	if (!dixRegisterPrivateKey(&sna_gc_index, PRIVATE_GC,
+	if (!dixRegisterPrivateKey(&sna_gc_key, PRIVATE_GC,
 				   sizeof(FbGCPrivate)))
 		return FALSE;
-	assert(sna_gc_index.offset == 0);
+	assert(sna_gc_key.offset == 0);
 
 	if (!dixRegisterPrivateKey(&sna_glyph_key, PRIVATE_GLYPH,
 				   sizeof(struct sna_glyph)))
 		return FALSE;
 	assert(sna_glyph_key.offset == 0);
 
-	if (!dixRegisterPrivateKey(&sna_window_key,
-				   PRIVATE_WINDOW, 0))
+	if (!dixRegisterPrivateKey(&sna_window_key, PRIVATE_WINDOW,
+				   2*sizeof(void *)))
 		return FALSE;
 	assert(sna_window_key.offset == 0);
 
commit 975a566bed72ddc79853b329307ed72a82df24b0
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 7 14:12:51 2012 +0100

    sna/dri: Replace the DRI2 drawable type with a devPrivate
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index e1b5de6..fd965bc 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -107,7 +107,6 @@ struct sna_dri_frame_event {
 struct sna_dri_private {
 	int refcnt;
 	PixmapPtr pixmap;
-	int width, height;
 	struct kgem_bo *bo;
 	struct sna_dri_frame_event *chain;
 };
@@ -116,7 +115,6 @@ static DevPrivateKeyRec sna_client_key;
 
 static RESTYPE frame_event_client_type;
 static RESTYPE frame_event_drawable_type;
-static RESTYPE dri_drawable_type;
 
 static inline struct sna_dri_frame_event *
 to_frame_event(uintptr_t  data)
@@ -197,6 +195,16 @@ static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
 	return priv->gpu_bo;
 }
 
+constant static inline void *sna_pixmap_get_dri(PixmapPtr pixmap)
+{
+	return ((void **)pixmap->devPrivates)[2];
+}
+
+static inline void *sna_pixmap_set_dri(PixmapPtr pixmap, void *ptr)
+{
+	((void **)pixmap->devPrivates)[2] = ptr;
+}
+
 static DRI2Buffer2Ptr
 sna_dri_create_buffer(DrawablePtr drawable,
 		      unsigned int attachment,
@@ -217,23 +225,16 @@ sna_dri_create_buffer(DrawablePtr drawable,
 	switch (attachment) {
 	case DRI2BufferFrontLeft:
 		pixmap = get_drawable_pixmap(drawable);
-
-		buffer = NULL;
-		dixLookupResourceByType((void **)&buffer, drawable->id,
-					dri_drawable_type, NULL, DixWriteAccess);
+		buffer = sna_pixmap_get_dri(pixmap);
 		if (buffer) {
+			DBG(("%s: reusing front buffer attachment\n",
+			     __FUNCTION__));
+
 			private = get_private(buffer);
-			if (private->pixmap == pixmap) {
-				DBG(("%s: reusing front buffer attachment\n",
-				     __FUNCTION__));
-				assert(private->width  == pixmap->drawable.width);
-				assert(private->height == pixmap->drawable.height);
-				private->refcnt++;
-				return buffer;
-			}
-			FreeResourceByType(drawable->id,
-					   dri_drawable_type,
-					   FALSE);
+			assert(private->pixmap == pixmap);
+
+			private->refcnt++;
+			return buffer;
 		}
 
 		bo = sna_pixmap_set_dri(sna, pixmap);
@@ -323,22 +324,18 @@ sna_dri_create_buffer(DrawablePtr drawable,
 	buffer->flags = 0;
 	buffer->name = kgem_bo_flink(&sna->kgem, bo);
 	private->refcnt = 1;
-	private->pixmap = pixmap;
-	if (pixmap) {
-		private->width  = pixmap->drawable.width;
-		private->height = pixmap->drawable.height;
-	}
 	private->bo = bo;
+	private->pixmap = pixmap;
 
 	if (buffer->name == 0)
 		goto err;
 
-	if (pixmap)
+	if (pixmap) {
+		assert(attachment == DRI2BufferFrontLeft);
+		sna_pixmap_set_dri(pixmap, buffer);
+		assert(sna_pixmap_get_dri(pixmap) == buffer);
 		pixmap->refcnt++;
-
-	if (attachment == DRI2BufferFrontLeft &&
-	    AddResource(drawable->id, dri_drawable_type, buffer))
-		private->refcnt++;
+	}
 
 	return buffer;
 
@@ -361,17 +358,18 @@ static void _sna_dri_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
 
 	if (--private->refcnt == 0) {
 		if (private->pixmap) {
-			ScreenPtr screen = private->pixmap->drawable.pScreen;
-			struct sna_pixmap *priv = sna_pixmap(private->pixmap);
+			PixmapPtr pixmap = private->pixmap;
+			struct sna_pixmap *priv = sna_pixmap(pixmap);
 
 			/* Undo the DRI markings on this pixmap */
 			if (priv->flush && --priv->flush == 0) {
 				list_del(&priv->list);
 				sna_accel_watch_flush(sna, -1);
-				priv->pinned = private->pixmap == sna->front;
+				priv->pinned = pixmap == sna->front;
 			}
 
-			screen->DestroyPixmap(private->pixmap);
+			sna_pixmap_set_dri(pixmap, NULL);
+			pixmap->drawable.pScreen->DestroyPixmap(pixmap);
 		}
 
 		private->bo->flush = 0;
@@ -858,17 +856,6 @@ sna_dri_frame_event_drawable_gone(void *data, XID id)
 	return Success;
 }
 
-static int
-sna_dri_drawable_gone(void *data, XID id)
-{
-	DBG(("%s(%ld)\n", __FUNCTION__, (long)id));
-
-	_sna_dri_destroy_buffer(to_sna_from_pixmap(get_private(data)->pixmap),
-				data);
-
-	return Success;
-}
-
 static Bool
 sna_dri_register_frame_event_resource_types(void)
 {
@@ -890,14 +877,6 @@ sna_dri_register_frame_event_resource_types(void)
 	DBG(("%s: frame_event_drawable_type=%d\n",
 	     __FUNCTION__, frame_event_drawable_type));
 
-	dri_drawable_type =
-		CreateNewResourceType(sna_dri_drawable_gone,
-				      "DRI2 Drawable");
-	if (!dri_drawable_type)
-		return FALSE;
-
-	DBG(("%s: dri_drawable_type=%d\n", __FUNCTION__, dri_drawable_type));
-
 	return TRUE;
 }
 
diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c
index d12c2b0..e242b2f 100644
--- a/src/sna/sna_driver.c
+++ b/src/sna/sna_driver.c
@@ -82,6 +82,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 static DevPrivateKeyRec sna_private_index;
 static DevPrivateKeyRec sna_pixmap_index;
+static DevPrivateKeyRec sna_dri_index;
 static DevPrivateKeyRec sna_gc_index;
 static DevPrivateKeyRec sna_glyph_key;
 static DevPrivateKeyRec sna_window_key;
@@ -810,6 +811,10 @@ sna_register_all_privates(void)
 		return FALSE;
 	assert(sna_pixmap_index.offset == sizeof(void*));
 
+	if (!dixRegisterPrivateKey(&sna_dri_index, PRIVATE_PIXMAP, 0))
+		return FALSE;
+	assert(sna_dri_index.offset == 2*sizeof(void*));
+
 	if (!dixRegisterPrivateKey(&sna_gc_index, PRIVATE_GC,
 				   sizeof(FbGCPrivate)))
 		return FALSE;
commit 0da1c98f660269806408af5fd08c1ab5e538082e
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jul 7 12:15:28 2012 +0100

    test: Add missing header for distcheck
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/test/Makefile.am b/test/Makefile.am
index ba4966c..96c87f8 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -32,6 +32,7 @@ libtest_la_SOURCES = \
 	test_log.c \
 	test_render.c \
 	dri2.c \
+	dri2.h \
 	$(NULL)
 
 EXTRA_DIST = README
commit e3e58123d36924c760ab6f58a7155a040422e91d
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jul 6 15:22:26 2012 +0100

    sna: Fixup fb wrapper
    
    To accommodate changes in the Xserver and avoid breakage; would have been
    much easier had the fb been exported in the first place.

diff --git a/configure.ac b/configure.ac
index d1ddf95..720a0ba 100644
--- a/configure.ac
+++ b/configure.ac
@@ -354,6 +354,7 @@ AC_CONFIG_FILES([
                 src/legacy/i810/Makefile
                 src/legacy/i810/xvmc/Makefile
                 src/sna/Makefile
+                src/sna/fb/Makefile
                 man/Makefile
                 src/render_program/Makefile
 		test/Makefile
diff --git a/src/sna/Makefile.am b/src/sna/Makefile.am
index 911a857..8cd3c45 100644
--- a/src/sna/Makefile.am
+++ b/src/sna/Makefile.am
@@ -18,6 +18,8 @@
 #  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 #  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
+SUBDIRS = fb
+
 AM_CFLAGS = \
 	@CWARNFLAGS@ \
 	-I$(top_srcdir)/src \
@@ -29,7 +31,7 @@ AM_CFLAGS = \
 	$(NULL)
 
 noinst_LTLIBRARIES = libsna.la
-libsna_la_LIBADD = @UDEV_LIBS@ -lm @DRM_LIBS@
+libsna_la_LIBADD = @UDEV_LIBS@ -lm @DRM_LIBS@ fb/libfb.la
 
 libsna_la_SOURCES = \
 	blt.c \
diff --git a/src/sna/fb/Makefile.am b/src/sna/fb/Makefile.am
new file mode 100644
index 0000000..16f9b28
--- /dev/null
+++ b/src/sna/fb/Makefile.am
@@ -0,0 +1,37 @@
+noinst_LTLIBRARIES = libfb.la
+
+libfb_la_CFLAGS = @CWARNFLAGS@ @XORG_CFLAGS@
+libfb_la_LIBADD = $(PIXMAN_LIBS)
+
+libfb_la_SOURCES = 	\
+	fb.h		\
+	fbarc.c		\
+	fbarcbits.h	\
+	fbbitmap.c	\
+	fbblt.c		\
+	fbbltone.c	\
+	fbclip.c	\
+	fbclip.h	\
+	fbcopy.c	\
+	fbfill.c	\
+	fbgc.c		\
+	fbglyph.c	\
+	fbglyphbits.h	\
+	fbimage.c	\
+	fbline.c	\
+	fblinebits.h	\
+	fbpict.c	\
+	fbpict.h	\
+	fbpoint.c	\
+	fbpointbits.h	\
+	fbpush.c	\
+	fbrop.h		\
+	fbseg.c		\
+	fbsegbits.h	\
+	fbspan.c	\
+	fbstipple.c	\
+	fbtile.c	\
+	fbutil.c	\
+	$(NULL)
+
+EXTRA_DIST = README
diff --git a/src/sna/fb/README b/src/sna/fb/README
new file mode 100644
index 0000000..1542124
--- /dev/null
+++ b/src/sna/fb/README
@@ -0,0 +1 @@
+Note this code is intended to live inside pixman in the long term.
diff --git a/src/sna/fb/fb.h b/src/sna/fb/fb.h
new file mode 100644
index 0000000..7847951
--- /dev/null
+++ b/src/sna/fb/fb.h
@@ -0,0 +1,557 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef FB_H
+#define FB_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdbool.h>
+#include <pixman.h>
+
+#include <xorg-server.h>
+#include <servermd.h>
+#include <gcstruct.h>
+#include <colormap.h>
+#include <windowstr.h>
+
+#if HAS_DEBUG_FULL
+#define DBG(x) ErrorF x
+#else
+#define DBG(x)
+#endif
+
+#define WRITE(ptr, val) (*(ptr) = (val))
+#define READ(ptr) (*(ptr))
+
+/*
+ * This single define controls the basic size of data manipulated
+ * by this software; it must be log2(sizeof (FbBits) * 8)
+ */
+#define FB_SHIFT    LOG2_BITMAP_PAD
+
+#define FB_UNIT	    (1 << FB_SHIFT)
+#define FB_HALFUNIT (1 << (FB_SHIFT-1))
+#define FB_MASK	    (FB_UNIT - 1)
+#define FB_ALLONES  ((FbBits) -1)
+
+#if IMAGE_BYTE_ORDER != LSBFirst
+#error "IMAGE_BYTE_ORDER must be LSBFirst"
+#endif
+
+#if GLYPHPADBYTES != 4
+#error "GLYPHPADBYTES must be 4"
+#endif
+
+#if FB_SHIFT != 5
+#error "FB_SHIFT ala LOG2_BITMAP_PAD must be 5"
+#endif
+
+#define FB_STIP_SHIFT	LOG2_BITMAP_PAD
+#define FB_STIP_UNIT	(1 << FB_STIP_SHIFT)
+#define FB_STIP_MASK	(FB_STIP_UNIT - 1)
+#define FB_STIP_ALLONES	((FbStip) -1)
+#define FbFullMask(n)   ((n) == FB_UNIT ? FB_ALLONES : ((((FbBits) 1) << n) - 1))
+
+typedef uint32_t FbBits;
+typedef FbBits FbStip;
+typedef int FbStride;
+
+#include "fbrop.h"
+
+#define FbScrLeft(x,n)	((x) >> (n))
+#define FbScrRight(x,n)	((x) << (n))
+/* #define FbLeftBits(x,n)	((x) & ((((FbBits) 1) << (n)) - 1)) */
+#define FbLeftStipBits(x,n) ((x) & ((((FbStip) 1) << (n)) - 1))
+#define FbStipMoveLsb(x,s,n)	(FbStipRight (x,(s)-(n)))
+#define FbPatternOffsetBits	0
+
+#define FbStipLeft(x,n)	FbScrLeft(x,n)
+#define FbStipRight(x,n) FbScrRight(x,n)
+
+#define FbRotLeft(x,n)	FbScrLeft(x,n) | (n ? FbScrRight(x,FB_UNIT-n) : 0)
+#define FbRotRight(x,n)	FbScrRight(x,n) | (n ? FbScrLeft(x,FB_UNIT-n) : 0)
+
+#define FbRotStipLeft(x,n)  FbStipLeft(x,n) | (n ? FbStipRight(x,FB_STIP_UNIT-n) : 0)
+#define FbRotStipRight(x,n)  FbStipRight(x,n) | (n ? FbStipLeft(x,FB_STIP_UNIT-n) : 0)
+
+#define FbLeftMask(x)	    ( ((x) & FB_MASK) ? \
+			     FbScrRight(FB_ALLONES,(x) & FB_MASK) : 0)
+#define FbRightMask(x)	    ( ((FB_UNIT - (x)) & FB_MASK) ? \
+			     FbScrLeft(FB_ALLONES,(FB_UNIT - (x)) & FB_MASK) : 0)
+
+#define FbLeftStipMask(x)   ( ((x) & FB_STIP_MASK) ? \
+			     FbStipRight(FB_STIP_ALLONES,(x) & FB_STIP_MASK) : 0)
+#define FbRightStipMask(x)  ( ((FB_STIP_UNIT - (x)) & FB_STIP_MASK) ? \
+			     FbScrLeft(FB_STIP_ALLONES,(FB_STIP_UNIT - (x)) & FB_STIP_MASK) : 0)
+
+#define FbBitsMask(x,w)	(FbScrRight(FB_ALLONES,(x) & FB_MASK) & \
+			 FbScrLeft(FB_ALLONES,(FB_UNIT - ((x) + (w))) & FB_MASK))
+
+#define FbStipMask(x,w)	(FbStipRight(FB_STIP_ALLONES,(x) & FB_STIP_MASK) & \
+			 FbStipLeft(FB_STIP_ALLONES,(FB_STIP_UNIT - ((x)+(w))) & FB_STIP_MASK))
+
+#define FbMaskBits(x,w,l,n,r) { \
+    n = (w); \
+    r = FbRightMask((x)+n); \
+    l = FbLeftMask(x); \
+    if (l) { \
+	n -= FB_UNIT - ((x) & FB_MASK); \
+	if (n < 0) { \
+	    n = 0; \
+	    l &= r; \
+	    r = 0; \
+	} \
+    } \
+    n >>= FB_SHIFT; \
+}
+
+#define FbByteMaskInvalid   0x10
+
+#define FbPatternOffset(o,t)  ((o) ^ (FbPatternOffsetBits & ~(sizeof (t) - 1)))
+
+#define FbPtrOffset(p,o,t)		((t *) ((CARD8 *) (p) + (o)))
+#define FbSelectPatternPart(xor,o,t)	((xor) >> (FbPatternOffset (o,t) << 3))
+#define FbStorePart(dst,off,t,xor)	(WRITE(FbPtrOffset(dst,off,t), \
+					 FbSelectPart(xor,off,t)))
+#ifndef FbSelectPart
+#define FbSelectPart(x,o,t) FbSelectPatternPart(x,o,t)
+#endif
+
+#define FbMaskBitsBytes(x,w,copy,l,lb,n,r,rb) { \
+    n = (w); \
+    lb = 0; \
+    rb = 0; \
+    r = FbRightMask((x)+n); \
+    if (r) { \
+	/* compute right byte length */ \
+	if ((copy) && (((x) + n) & 7) == 0) { \
+	    rb = (((x) + n) & FB_MASK) >> 3; \
+	} else { \
+	    rb = FbByteMaskInvalid; \
+	} \
+    } \
+    l = FbLeftMask(x); \
+    if (l) { \
+	/* compute left byte length */ \
+	if ((copy) && ((x) & 7) == 0) { \
+	    lb = ((x) & FB_MASK) >> 3; \
+	} else { \
+	    lb = FbByteMaskInvalid; \
+	} \
+	/* subtract out the portion painted by leftMask */ \
+	n -= FB_UNIT - ((x) & FB_MASK); \
+	if (n < 0) { \
+	    if (lb != FbByteMaskInvalid) { \
+		if (rb == FbByteMaskInvalid) { \
+		    lb = FbByteMaskInvalid; \
+		} else if (rb) { \
+		    lb |= (rb - lb) << (FB_SHIFT - 3); \
+		    rb = 0; \
+		} \
+	    } \
+	    n = 0; \
+	    l &= r; \
+	    r = 0; \
+	}\
+    } \
+    n >>= FB_SHIFT; \
+}
+
+#define FbDoLeftMaskByteRRop(dst,lb,l,and,xor) { \
+    switch (lb) { \
+    case (sizeof (FbBits) - 3) | (1 << (FB_SHIFT - 3)): \
+	FbStorePart(dst,sizeof (FbBits) - 3,CARD8,xor); \
+	break; \
+    case (sizeof (FbBits) - 3) | (2 << (FB_SHIFT - 3)): \
+	FbStorePart(dst,sizeof (FbBits) - 3,CARD8,xor); \
+	FbStorePart(dst,sizeof (FbBits) - 2,CARD8,xor); \
+	break; \
+    case (sizeof (FbBits) - 2) | (1 << (FB_SHIFT - 3)): \
+	FbStorePart(dst,sizeof (FbBits) - 2,CARD8,xor); \
+	break; \
+    case sizeof (FbBits) - 3: \
+	FbStorePart(dst,sizeof (FbBits) - 3,CARD8,xor); \
+    case sizeof (FbBits) - 2: \
+	FbStorePart(dst,sizeof (FbBits) - 2,CARD16,xor); \
+	break; \
+    case sizeof (FbBits) - 1: \
+	FbStorePart(dst,sizeof (FbBits) - 1,CARD8,xor); \
+	break; \
+    default: \
+	WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, l)); \
+	break; \
+    } \
+}
+
+#define FbDoRightMaskByteRRop(dst,rb,r,and,xor) { \
+    switch (rb) { \
+    case 1: \
+	FbStorePart(dst,0,CARD8,xor); \
+	break; \
+    case 2: \
+	FbStorePart(dst,0,CARD16,xor); \
+	break; \
+    case 3: \
+	FbStorePart(dst,0,CARD16,xor); \
+	FbStorePart(dst,2,CARD8,xor); \
+	break; \
+    default: \
+	WRITE(dst, FbDoMaskRRop (READ(dst), and, xor, r)); \
+    } \
+}
+
+#define FbMaskStip(x,w,l,n,r) { \
+    n = (w); \
+    r = FbRightStipMask((x)+n); \
+    l = FbLeftStipMask(x); \
+    if (l) { \
+	n -= FB_STIP_UNIT - ((x) & FB_STIP_MASK); \
+	if (n < 0) { \
+	    n = 0; \
+	    l &= r; \
+	    r = 0; \
+	} \
+    } \
+    n >>= FB_STIP_SHIFT; \
+}
+
+/*
+ * These macros are used to transparently stipple
+ * in copy mode; the expected usage is with 'n' constant
+ * so all of the conditional parts collapse into a minimal
+ * sequence of partial word writes
+ *
+ * 'n' is the bytemask of which bytes to store, 'a' is the address
+ * of the FbBits base unit, 'o' is the offset within that unit
+ *
+ * The term "lane" comes from the hardware term "byte-lane" which
+ */
+
+#define FbLaneCase1(n,a,o)						\
+    if ((n) == 0x01) {							\
+	WRITE((CARD8 *) ((a)+FbPatternOffset(o,CARD8)), fgxor);		\
+    }
+
+#define FbLaneCase2(n,a,o)						\
+    if ((n) == 0x03) {							\
+	WRITE((CARD16 *) ((a)+FbPatternOffset(o,CARD16)), fgxor);	\
+    } else {								\
+	FbLaneCase1((n)&1,a,o)						\
+	FbLaneCase1((n)>>1,a,(o)+1)					\
+    }
+
+#define FbLaneCase4(n,a,o)						\
+    if ((n) == 0x0f) {							\
+	WRITE((CARD32 *) ((a)+FbPatternOffset(o,CARD32)), fgxor);	\
+    } else {								\
+	FbLaneCase2((n)&3,a,o)						\
+	FbLaneCase2((n)>>2,a,(o)+2)					\
+    }
+
+#define FbLaneCase(n,a)   FbLaneCase4(n,(CARD8 *) (a),0)
+
+typedef struct {
+	long changes;
+	long serial;
+	void *priv;
+
+	FbBits and, xor;            /* reduced rop values */
+	FbBits bgand, bgxor;        /* for stipples */
+	FbBits fg, bg, pm;          /* expanded and filled */
+	unsigned int dashLength;    /* total of all dash elements */
+	unsigned char evenStipple;  /* stipple is even */
+	unsigned char bpp;          /* current drawable bpp */
+} FbGCPrivate, *FbGCPrivPtr;
+
+static inline FbGCPrivate *fb_gc(GCPtr gc)
+{
+	return (FbGCPrivate *)gc->devPrivates;
+}
+static inline PixmapPtr fbGetWindowPixmap(WindowPtr window)
+{
+	return *(void **)window->devPrivates;
+}
+
+#ifdef ROOTLESS
+#define __fbPixDrawableX(p)	((p)->drawable.x)
+#define __fbPixDrawableY(p)	((p)->drawable.y)
+#else
+#define __fbPixDrawableX(p)	0
+#define __fbPixDrawableY(p)	0
+#endif
+
+#ifdef COMPOSITE
+#define __fbPixOffXWin(p)	(__fbPixDrawableX(p) - (p)->screen_x)
+#define __fbPixOffYWin(p)	(__fbPixDrawableY(p) - (p)->screen_y)
+#else
+#define __fbPixOffXWin(p)	(__fbPixDrawableX(p))
+#define __fbPixOffYWin(p)	(__fbPixDrawableY(p))
+#endif
+#define __fbPixOffXPix(p)	(__fbPixDrawableX(p))
+#define __fbPixOffYPix(p)	(__fbPixDrawableY(p))
+
+#define fbGetDrawablePixmap(drawable, pixmap, xoff, yoff) {		\
+    if ((drawable)->type != DRAWABLE_PIXMAP) {				\
+	(pixmap) = fbGetWindowPixmap((WindowPtr)drawable);		\
+	(xoff) = __fbPixOffXWin(pixmap);				\
+	(yoff) = __fbPixOffYWin(pixmap);				\
+    } else {								\
+	(pixmap) = (PixmapPtr) (drawable);				\
+	(xoff) = __fbPixOffXPix(pixmap);				\
+	(yoff) = __fbPixOffYPix(pixmap);				\
+    }									\
+}
+
+#define fbGetPixmapBitsData(pixmap, pointer, stride, bpp) {		\
+    (pointer) = (FbBits *) (pixmap)->devPrivate.ptr;			\
+    (stride) = ((int) (pixmap)->devKind) / sizeof (FbBits); (void)(stride);\
+    (bpp) = (pixmap)->drawable.bitsPerPixel;  (void)(bpp);		\
+}
+
+#define fbGetPixmapStipData(pixmap, pointer, stride, bpp) {		\
+    (pointer) = (FbStip *) (pixmap)->devPrivate.ptr;			\
+    (stride) = ((int) (pixmap)->devKind) / sizeof (FbStip); (void)(stride);\
+    (bpp) = (pixmap)->drawable.bitsPerPixel;  (void)(bpp);		\
+}
+
+#define fbGetDrawable(drawable, pointer, stride, bpp, xoff, yoff) {	\
+    PixmapPtr   _pPix;							\
+    fbGetDrawablePixmap(drawable, _pPix, xoff, yoff);			\
+    fbGetPixmapBitsData(_pPix, pointer, stride, bpp);			\
+}
+
+#define fbGetStipDrawable(drawable, pointer, stride, bpp, xoff, yoff) {	\
+    PixmapPtr   _pPix;							\
+    fbGetDrawablePixmap(drawable, _pPix, xoff, yoff);			\
+    fbGetPixmapStipData(_pPix, pointer, stride, bpp);			\
+}
+
+/*
+ * XFree86 empties the root BorderClip when the VT is inactive,
+ * here's a macro which uses that to disable GetImage and GetSpans
+ */
+#define fbWindowEnabled(pWin) \
+    RegionNotEmpty(&(pWin)->drawable.pScreen->root->borderClip)
+#define fbDrawableEnabled(drawable) \
+    ((drawable)->type == DRAWABLE_PIXMAP ? \
+     TRUE : fbWindowEnabled((WindowPtr) drawable))
+
+#define FbPowerOfTwo(w)	    (((w) & ((w) - 1)) == 0)
+/*
+ * Accelerated tiles are power of 2 width <= FB_UNIT
+ */
+#define FbEvenTile(w)	    ((w) <= FB_UNIT && FbPowerOfTwo(w))
+/*
+ * Accelerated stipples are power of 2 width and <= FB_UNIT/dstBpp
+ * with dstBpp a power of 2 as well
+ */
+#define FbEvenStip(w,bpp)   ((w) * (bpp) <= FB_UNIT && FbPowerOfTwo(w) && FbPowerOfTwo(bpp))
+
+inline static int16_t fbBound(int16_t a, uint16_t b)
+{
+	int v = (int)a + (int)b;
+	if (v > MAXSHORT)
+		return MAXSHORT;
+	return v;
+}
+
+extern void
+fbPolyArc(DrawablePtr drawable, GCPtr gc, int narcs, xArc * parcs);
+
+extern void
+fbBlt(FbBits *src, FbStride srcStride, int srcX,
+      FbBits *dst, FbStride dstStride, int dstX,
+      int width, int height,
+      int alu, FbBits pm, int bpp,
+      Bool reverse, Bool upsidedown);
+
+#if FB_STIP_SHIFT == FB_SHIFT
+static inline void
+fbBltStip(FbStip *src, FbStride srcStride, int srcX,
+	  FbStip *dst, FbStride dstStride, int dstX,
+	  int width, int height, int alu, FbBits pm, int bpp)
+{
+	fbBlt((FbBits *)src, srcStride, srcX,
+	      (FbBits *)dst, dstStride, dstX,
+	      width, height, alu, pm, bpp,
+	      FALSE, FALSE);
+}
+#else
+#error FB_STIP_SHIFT must equal FB_SHIFT
+#endif
+
+extern void
+fbBltOne(FbStip *src, FbStride srcStride, int srcX,
+         FbBits *dst, FbStride dstStride, int dstX,
+         int dstBpp, int width, int height,
+	 FbBits fgand, FbBits fbxor, FbBits bgand, FbBits bgxor);
+
+extern void
+fbBltPlane(FbBits *src, FbStride srcStride, int srcX, int srcBpp,
+           FbStip *dst, FbStride dstStride, int dstX,
+           int width, int height,
+           FbStip fgand, FbStip fgxor, FbStip bgand, FbStip bgxor,
+	   Pixel planeMask);
+
+extern void
+fbCopyNtoN(DrawablePtr src, DrawablePtr dst, GCPtr gc,
+           BoxPtr pbox, int nbox,
+           int dx, int dy,
+           Bool reverse, Bool upsidedown, Pixel bitplane, void *closure);
+
+extern void
+fbCopy1toN(DrawablePtr src, DrawablePtr dst, GCPtr gc,
+           BoxPtr pbox, int nbox,
+           int dx, int dy,
+           Bool reverse, Bool upsidedown, Pixel bitplane, void *closure);
+
+extern void
+fbCopyNto1(DrawablePtr src, DrawablePtr dst, GCPtr gc,
+           BoxPtr pbox, int nbox,
+           int dx, int dy,
+           Bool reverse, Bool upsidedown, Pixel bitplane, void *closure);
+
+extern RegionPtr
+fbCopyArea(DrawablePtr src, DrawablePtr dst, GCPtr gc,
+	   int sx, int sy,
+	   int width, int height,
+	   int dx, int dy);
+
+extern RegionPtr
+fbCopyPlane(DrawablePtr src, DrawablePtr dst, GCPtr gc,
+	    int sx, int sy,
+	    int width, int height,
+	    int dx, int dy,
+	    unsigned long bitplane);
+
+extern void
+fbFill(DrawablePtr drawable, GCPtr gc, int x, int y, int width, int height);
+
+extern void
+fbSolidBoxClipped(DrawablePtr drawable, GCPtr gc,
+                  int x1, int y1, int x2, int y2);
+
+extern void
+fbPolyFillRect(DrawablePtr drawable, GCPtr gc, int n, xRectangle *rec);
+
+extern void
+fbFillSpans(DrawablePtr drawable, GCPtr gc,
+            int n, DDXPointPtr pt, int *width, int fSorted);
+
+extern void
+fbPadPixmap(PixmapPtr pPixmap);
+
+extern void
+fbValidateGC(GCPtr gc, unsigned long changes, DrawablePtr drawable);
+
+extern void
+fbGetSpans(DrawablePtr drawable, int wMax,
+           DDXPointPtr pt, int *width, int n, char *dst);
+
+extern void
+fbPolyGlyphBlt(DrawablePtr drawable, GCPtr gc, int x, int y,
+               unsigned int n, CharInfoPtr *info, pointer glyphs);
+
+extern void
+fbImageGlyphBlt(DrawablePtr drawable, GCPtr gc, int x, int y,
+                unsigned int n, CharInfoPtr *info, pointer glyphs);
+
+extern void
+fbPutImage(DrawablePtr drawable, GCPtr gc, int depth,
+           int x, int y, int w, int h,
+	   int leftPad, int format, char *image);
+
+extern void
+fbPutXYImage(DrawablePtr drawable, GCPtr gc,
+             FbBits fg, FbBits bg, FbBits pm,
+             int alu, Bool opaque,
+             int x, int y, int width, int height,
+	     FbStip * src, FbStride srcStride, int srcX);
+
+extern void
+fbGetImage(DrawablePtr drawable,
+           int x, int y, int w, int h,
+	   unsigned int format, unsigned long planeMask, char *d);
+
+extern void
+fbPolyLine(DrawablePtr drawable, GCPtr gc, int mode, int n, DDXPointPtr pt);
+
+extern void
+fbFixCoordModePrevious(int n, DDXPointPtr pt);
+
+extern void
+fbPolySegment(DrawablePtr drawable, GCPtr gc, int n, xSegment *seg);
+
+extern RegionPtr
+fbBitmapToRegion(PixmapPtr pixmap);
+
+extern void
+fbPolyPoint(DrawablePtr drawable, GCPtr gc, int mode, int n, xPoint *pt);
+
+extern void
+fbPushImage(DrawablePtr drawable, GCPtr gc,
+            FbStip *src, FbStride srcStride, int srcX,
+	    int x, int y, int width, int height);
+
+extern void
+fbPushPixels(GCPtr gc, PixmapPtr pBitmap, DrawablePtr drawable,
+	     int dx, int dy, int xOrg, int yOrg);
+
+extern void
+fbSetSpans(DrawablePtr drawable, GCPtr gc,
+           char *src, DDXPointPtr pt, int *width, int n, int fSorted);
+
+extern void
+fbSegment(DrawablePtr drawable, GCPtr gc,
+          int xa, int ya, int xb, int yb,
+	  bool drawLast, int *dashOffset);
+
+extern void
+fbSegment1(DrawablePtr drawable, GCPtr gc, const BoxRec *clip,
+          int xa, int ya, int xb, int yb,
+	  bool drawLast, int *dashOffset);
+
+extern void
+fbTransparentSpan(FbBits * dst, FbBits stip, FbBits fgxor, int n);
+
+extern void
+fbStipple(FbBits *dst, FbStride dstStride, int dstX, int dstBpp,
+          int width, int height,
+          FbStip *stip, FbStride stipStride,
+          int stipWidth, int stipHeight,
+          Bool even,
+          FbBits fgand, FbBits fgxor, FbBits bgand, FbBits bgxor,
+	  int xRot, int yRot);
+
+extern void
+fbTile(FbBits *dst, FbStride dstStride, int dstX, int width, int height,
+       FbBits *tile, FbStride tileStride, int tileWidth, int tileHeight,
+       int alu, FbBits pm, int bpp,
+       int xRot, int yRot);
+
+extern FbBits fbReplicatePixel(Pixel p, int bpp);
+
+#endif  /* FB_H */
diff --git a/src/sna/fb/fbarc.c b/src/sna/fb/fbarc.c
new file mode 100644
index 0000000..2222d0b
--- /dev/null
+++ b/src/sna/fb/fbarc.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fb.h"
+#include <mi.h>
+#include <mizerarc.h>
+#include <limits.h>
+
+#define ARC	    fbArc8
+#define BITS	    BYTE
+#define BITS2	    CARD16
+#define BITS4	    CARD32
+#include "fbarcbits.h"
+#undef BITS
+#undef BITS2
+#undef BITS4
+#undef ARC
+
+#define ARC	    fbArc16
+#define BITS	    CARD16
+#define BITS2	    CARD32
+#include "fbarcbits.h"
+#undef BITS
+#undef BITS2
+#undef ARC
+
+#define ARC	    fbArc32
+#define BITS	    CARD32
+#include "fbarcbits.h"
+#undef BITS
+#undef ARC
+
+void
+fbPolyArc(DrawablePtr drawable, GCPtr gc, int n, xArc *arc)
+{
+	DBG(("%s x %d, width=%d, fill=%d, line=%d\n",
+	     __FUNCTION__, n, gc->lineWidth, gc->lineStyle, gc->fillStyle));
+
+	if (gc->lineWidth == 0) {
+		void (*raster)(FbBits *dst, FbStride dstStride, int dstBpp,
+			       xArc *arc, int dx, int dy,
+			       FbBits and, FbBits xor);
+
+		raster = 0;
+		if (gc->lineStyle == LineSolid && gc->fillStyle == FillSolid) {
+			switch (drawable->bitsPerPixel) {
+			case 8:
+				raster = fbArc8;
+				break;
+			case 16:
+				raster = fbArc16;
+				break;
+			case 32:
+				raster = fbArc32;
+				break;
+			}
+		}
+		if (raster) {
+			FbGCPrivPtr pgc = fb_gc(gc);
+			FbBits *dst;
+			FbStride dstStride;
+			int dstBpp;
+			int dstXoff, dstYoff;
+			BoxRec box;
+			int x2, y2;
+
+			fbGetDrawable(drawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
+			while (n--) {
+				if (miCanZeroArc(arc)) {
+					box.x1 = arc->x + drawable->x;
+					box.y1 = arc->y + drawable->y;
+					/*
+					 * Because box.x2 and box.y2 get truncated to 16 bits, and the
+					 * RECT_IN_REGION test treats the resulting number as a signed
+					 * integer, the RECT_IN_REGION test alone can go the wrong way.
+					 * This can result in a server crash because the rendering
+					 * routines in this file deal directly with cpu addresses
+					 * of pixels to be stored, and do not clip or otherwise check
+					 * that all such addresses are within their respective pixmaps.
+					 * So we only allow the RECT_IN_REGION test to be used for
+					 * values that can be expressed correctly in a signed short.
+					 */
+					x2 = box.x1 + (int) arc->width + 1;
+					box.x2 = x2;
+					y2 = box.y1 + (int) arc->height + 1;
+					box.y2 = y2;
+					if ((x2 <= SHRT_MAX) && (y2 <= SHRT_MAX) &&
+					    (RegionContainsRect(gc->pCompositeClip, &box) == rgnIN)) {
+						raster(dst, dstStride, dstBpp,
+						       arc, drawable->x + dstXoff,
+							drawable->y + dstYoff, pgc->and, pgc->xor);
+					} else
+						miZeroPolyArc(drawable, gc, 1, arc);
+				} else
+					miPolyArc(drawable, gc, 1, arc);
+				arc++;
+			}
+		} else
+			miZeroPolyArc(drawable, gc, n, arc);
+	} else
+		miPolyArc(drawable, gc, n, arc);
+}
diff --git a/src/sna/fb/fbarcbits.h b/src/sna/fb/fbarcbits.h
new file mode 100644
index 0000000..a37206c
--- /dev/null
+++ b/src/sna/fb/fbarcbits.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define isClipped(c,ul,lr)  (((c) | ((c) - (ul)) | ((lr) - (c))) & 0x80008000)
+#define RROP(b,a,x)	WRITE((b), FbDoRRop (READ(b), (a), (x)))
+
+#define ARCCOPY(d)  WRITE(d,xorBits)
+#define ARCRROP(d)  RROP(d,andBits,xorBits)
+
+static void
+ARC(FbBits * dst,
+    FbStride dstStride,
+    int dstBpp, xArc * arc, int drawX, int drawY, FbBits and, FbBits xor)
+{
+	BITS *bits;
+	FbStride bitsStride;
+	miZeroArcRec info;
+	Bool do360;
+	int x;
+	BITS *yorgp, *yorgop;
+	BITS andBits, xorBits;
+	int yoffset, dyoffset;
+	int y, a, b, d, mask;
+	int k1, k3, dx, dy;
+
+	bits = (BITS *) dst;
+	bitsStride = dstStride * (sizeof(FbBits) / sizeof(BITS));
+	andBits = (BITS) and;
+	xorBits = (BITS) xor;
+	do360 = miZeroArcSetup(arc, &info, TRUE);
+	yorgp = bits + ((info.yorg + drawY) * bitsStride);
+	yorgop = bits + ((info.yorgo + drawY) * bitsStride);
+	info.xorg = (info.xorg + drawX);
+	info.xorgo = (info.xorgo + drawX);
+	MIARCSETUP();
+	yoffset = y ? bitsStride : 0;
+	dyoffset = 0;
+	mask = info.initialMask;
+
+	if (!(arc->width & 1)) {
+		if (andBits == 0) {
+			if (mask & 2)
+				ARCCOPY(yorgp + info.xorgo);
+			if (mask & 8)
+				ARCCOPY(yorgop + info.xorgo);
+		} else {
+			if (mask & 2)
+				ARCRROP(yorgp + info.xorgo);
+			if (mask & 8)
+				ARCRROP(yorgop + info.xorgo);
+		}
+	}
+	if (!info.end.x || !info.end.y) {
+		mask = info.end.mask;
+		info.end = info.altend;
+	}
+	if (do360 && (arc->width == arc->height) && !(arc->width & 1)) {
+		int xoffset = bitsStride;
+		BITS *yorghb = yorgp + (info.h * bitsStride) + info.xorg;
+		BITS *yorgohb = yorghb - info.h;
+
+		yorgp += info.xorg;
+		yorgop += info.xorg;
+		yorghb += info.h;
+		while (1) {
+			if (andBits == 0) {
+				ARCCOPY(yorgp + yoffset + x);
+				ARCCOPY(yorgp + yoffset - x);
+				ARCCOPY(yorgop - yoffset - x);
+				ARCCOPY(yorgop - yoffset + x);
+			} else {
+				ARCRROP(yorgp + yoffset + x);
+				ARCRROP(yorgp + yoffset - x);
+				ARCRROP(yorgop - yoffset - x);
+				ARCRROP(yorgop - yoffset + x);
+			}
+			if (a < 0)
+				break;
+			if (andBits == 0) {
+				ARCCOPY(yorghb - xoffset - y);
+				ARCCOPY(yorgohb - xoffset + y);
+				ARCCOPY(yorgohb + xoffset + y);
+				ARCCOPY(yorghb + xoffset - y);
+			} else {
+				ARCRROP(yorghb - xoffset - y);
+				ARCRROP(yorgohb - xoffset + y);
+				ARCRROP(yorgohb + xoffset + y);
+				ARCRROP(yorghb + xoffset - y);
+			}
+			xoffset += bitsStride;
+			MIARCCIRCLESTEP(yoffset += bitsStride;
+				       );
+		}
+		yorgp -= info.xorg;
+		yorgop -= info.xorg;
+		x = info.w;
+		yoffset = info.h * bitsStride;
+	} else if (do360) {
+		while (y < info.h || x < info.w) {
+			MIARCOCTANTSHIFT(dyoffset = bitsStride;
+					);
+			if (andBits == 0) {
+				ARCCOPY(yorgp + yoffset + info.xorg + x);
+				ARCCOPY(yorgp + yoffset + info.xorgo - x);
+				ARCCOPY(yorgop - yoffset + info.xorgo - x);
+				ARCCOPY(yorgop - yoffset + info.xorg + x);
+			} else {
+				ARCRROP(yorgp + yoffset + info.xorg + x);
+				ARCRROP(yorgp + yoffset + info.xorgo - x);
+				ARCRROP(yorgop - yoffset + info.xorgo - x);
+				ARCRROP(yorgop - yoffset + info.xorg + x);
+			}
+			MIARCSTEP(yoffset += dyoffset;
+				  , yoffset += bitsStride;
+				 );
+		}
+	} else {
+		while (y < info.h || x < info.w) {
+			MIARCOCTANTSHIFT(dyoffset = bitsStride;
+					);
+			if ((x == info.start.x) || (y == info.start.y)) {
+				mask = info.start.mask;
+				info.start = info.altstart;
+			}
+			if (andBits == 0) {
+				if (mask & 1)
+					ARCCOPY(yorgp + yoffset + info.xorg + x);
+				if (mask & 2)
+					ARCCOPY(yorgp + yoffset + info.xorgo - x);
+				if (mask & 4)
+					ARCCOPY(yorgop - yoffset + info.xorgo - x);
+				if (mask & 8)
+					ARCCOPY(yorgop - yoffset + info.xorg + x);
+			} else {
+				if (mask & 1)
+					ARCRROP(yorgp + yoffset + info.xorg + x);
+				if (mask & 2)
+					ARCRROP(yorgp + yoffset + info.xorgo - x);
+				if (mask & 4)
+					ARCRROP(yorgop - yoffset + info.xorgo - x);
+				if (mask & 8)
+					ARCRROP(yorgop - yoffset + info.xorg + x);
+			}
+			if ((x == info.end.x) || (y == info.end.y)) {
+				mask = info.end.mask;
+				info.end = info.altend;
+			}
+			MIARCSTEP(yoffset += dyoffset;
+				  , yoffset += bitsStride;
+				 );
+		}
+	}
+	if ((x == info.start.x) || (y == info.start.y))
+		mask = info.start.mask;
+	if (andBits == 0) {
+		if (mask & 1)
+			ARCCOPY(yorgp + yoffset + info.xorg + x);
+		if (mask & 4)
+			ARCCOPY(yorgop - yoffset + info.xorgo - x);
+		if (arc->height & 1) {
+			if (mask & 2)
+				ARCCOPY(yorgp + yoffset + info.xorgo - x);
+			if (mask & 8)
+				ARCCOPY(yorgop - yoffset + info.xorg + x);
+		}
+	} else {
+		if (mask & 1)
+			ARCRROP(yorgp + yoffset + info.xorg + x);
+		if (mask & 4)
+			ARCRROP(yorgop - yoffset + info.xorgo - x);
+		if (arc->height & 1) {
+			if (mask & 2)
+				ARCRROP(yorgp + yoffset + info.xorgo - x);
+			if (mask & 8)
+				ARCRROP(yorgop - yoffset + info.xorg + x);
+		}
+	}
+}
+
+#undef ARCCOPY
+#undef ARCRROP
+
+#undef RROP
+#undef isClipped
diff --git a/src/sna/fb/fbbitmap.c b/src/sna/fb/fbbitmap.c
new file mode 100644
index 0000000..075d6cc
--- /dev/null
+++ b/src/sna/fb/fbbitmap.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+
+#include "fb.h"
+
+static inline void add(RegionPtr region,
+		       int16_t x1, int16_t y1, int16_t x2, int16_t y2)
+{
+	BoxPtr r;
+
+	if (region->data->numRects == region->data->size)
+		RegionRectAlloc(region, 1);
+
+	r = RegionBoxptr(region) + region->data->numRects++;
+	r->x1 = x1; r->y1 = y1;
+	r->x2 = x2; r->y2 = y2;
+
+	if (x1 < region->extents.x1)
+		region->extents.x1 = x1;
+	if (x2 > region->extents.x2)
+		region->extents.x2 = x2;
+}
+
+/* Convert bitmap clip mask into clipping region.
+ * First, goes through each line and makes boxes by noting the transitions
+ * from 0 to 1 and 1 to 0.
+ * Then it coalesces the current line with the previous if they have boxes
+ * at the same X coordinates.
+ */
+RegionPtr
+fbBitmapToRegion(PixmapPtr pixmap)
+{
+	const register FbBits mask0 = FB_ALLONES & ~FbScrRight(FB_ALLONES, 1);
+	register RegionPtr region;
+	const FbBits *bits, *line, *end;
+	int width, y1, y2, base, x1;
+	int stride, i;
+
+	DBG(("%s bitmap=%dx%d\n", __FUNCTION__,
+	     pixmap->drawable.width, pixmap->drawable.height));
+
+	region = RegionCreate(NULL, 1);
+	if (!region)
+		return NullRegion;
+
+	line = (FbBits *) pixmap->devPrivate.ptr;
+	stride = pixmap->devKind >> (FB_SHIFT - 3);
+
+	width = pixmap->drawable.width;
+	region->extents.x1 = width;
+	region->extents.x2 = 0;
+	y2 = 0;
+	while (y2 < pixmap->drawable.height) {
+		y1 = y2++;
+		bits = line;
+		line += stride;
+		while (y2 < pixmap->drawable.height &&
+		       memcmp(bits, line, (width+7)>>3) == 0)
+			line += stride, y2++;
+
+		if (READ(bits) & mask0)
+			x1 = 0;
+		else
+			x1 =-1;
+
+		/* Process all words which are fully in the pixmap */
+		end = bits + (width >> FB_SHIFT);
+		for (base = 0; bits < end; base += FB_UNIT) {
+			FbBits w = READ(bits++);
+			if (x1 < 0) {
+				if (!~w)
+					continue;
+			} else {
+				if (!w)
+					continue;
+			}
+			for (i = 0; i < FB_UNIT; i++) {
+				if (w & mask0) {
+					if (x1 < 0)
+						x1 = base + i;
+				} else {
+					if (x1 >= 0) {
+						add(region, x1, y1, base + i, y2);
+						x1 = -1;
+					}
+				}
+				w = FbScrLeft(w, 1);
+			}
+		}
+		if (width & FB_MASK) {
+			FbBits w = READ(bits++);
+			for (i = 0; i < (width & FB_MASK); i++) {
+				if (w & mask0) {
+					if (x1 < 0)
+						x1 = base + i;
+				} else {
+					if (x1 >= 0) {
+						add(region, x1, y1, base + i, y2);
+						x1 = -1;
+					}
+				}
+				w = FbScrLeft(w, 1);
+			}
+		}
+		if (x1 >= 0)
+			add(region, x1, y1, width, y2);
+	}
+
+	if (region->data->numRects) {
+		region->extents.y1 = RegionBoxptr(region)->y1;
+		region->extents.y2 = RegionEnd(region)->y2;
+		if (region->data->numRects == 1) {
+			free(region->data);
+			region->data = NULL;
+		}
+	} else
+		region->extents.x1 = region->extents.x2 = 0;
+
+	return region;
+}
diff --git a/src/sna/fb/fbblt.c b/src/sna/fb/fbblt.c
new file mode 100644
index 0000000..247a331
--- /dev/null
+++ b/src/sna/fb/fbblt.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+#include "fb.h"
+
+typedef struct _mergeRopBits {
+    FbBits ca1, cx1, ca2, cx2;
+} FbMergeRopRec, *FbMergeRopPtr;
+
+#define O 0
+#define I FB_ALLONES
+
+static const FbMergeRopRec FbMergeRopBits[16] = {
+	{O, O, O, O},               /* clear         0x0         0 */
+	{I, O, O, O},               /* and           0x1         src AND dst */
+	{I, O, I, O},               /* andReverse    0x2         src AND NOT dst */
+	{O, O, I, O},               /* copy          0x3         src */
+	{I, I, O, O},               /* andInverted   0x4         NOT src AND dst */
+	{O, I, O, O},               /* noop          0x5         dst */
+	{O, I, I, O},               /* xor           0x6         src XOR dst */
+	{I, I, I, O},               /* or            0x7         src OR dst */
+	{I, I, I, I},               /* nor           0x8         NOT src AND NOT dst */
+	{O, I, I, I},               /* equiv         0x9         NOT src XOR dst */
+	{O, I, O, I},               /* invert        0xa         NOT dst */
+	{I, I, O, I},               /* orReverse     0xb         src OR NOT dst */
+	{O, O, I, I},               /* copyInverted  0xc         NOT src */
+	{I, O, I, I},               /* orInverted    0xd         NOT src OR dst */
+	{I, O, O, I},               /* nand          0xe         NOT src OR NOT dst */
+	{O, O, O, I},               /* set           0xf         1 */
+};
+
+#undef O
+#undef I
+
+#define FbDeclareMergeRop() FbBits   _ca1, _cx1, _ca2, _cx2;
+#define FbDeclarePrebuiltMergeRop()	FbBits	_cca, _ccx;
+
+#define FbInitializeMergeRop(alu,pm) {\
+    const FbMergeRopRec  *_bits; \
+    _bits = &FbMergeRopBits[alu]; \
+    _ca1 = _bits->ca1 &  pm; \
+    _cx1 = _bits->cx1 | ~pm; \
+    _ca2 = _bits->ca2 &  pm; \
+    _cx2 = _bits->cx2 &  pm; \
+}
+
+#define InitializeShifts(sx,dx,ls,rs) { \
+    if (sx != dx) { \
+	if (sx > dx) { \
+	    ls = sx - dx; \
+	    rs = FB_UNIT - ls; \
+	} else { \
+	    rs = dx - sx; \
+	    ls = FB_UNIT - rs; \
+	} \
+    } \
+}
+
+static void
+fbBlt__rop(FbBits *srcLine, FbStride srcStride, int srcX,
+	   FbBits *dstLine, FbStride dstStride, int dstX,
+	   int width, int height,
+	   int alu, FbBits pm, int bpp,
+	   Bool reverse, Bool upsidedown)
+{
+	FbBits *src, *dst;
+	int leftShift, rightShift;
+	FbBits startmask, endmask;
+	FbBits bits, bits1;
+	int n, nmiddle;
+	Bool destInvarient;
+	int startbyte, endbyte;
+
+	FbDeclareMergeRop();
+
+	FbInitializeMergeRop(alu, pm);
+	destInvarient = FbDestInvarientMergeRop();
+	if (upsidedown) {
+		srcLine += (height - 1) * (srcStride);
+		dstLine += (height - 1) * (dstStride);
+		srcStride = -srcStride;
+		dstStride = -dstStride;
+	}
+	FbMaskBitsBytes(dstX, width, destInvarient, startmask, startbyte,
+			nmiddle, endmask, endbyte);
+	if (reverse) {
+		srcLine += ((srcX + width - 1) >> FB_SHIFT) + 1;
+		dstLine += ((dstX + width - 1) >> FB_SHIFT) + 1;
+		srcX = (srcX + width - 1) & FB_MASK;
+		dstX = (dstX + width - 1) & FB_MASK;
+	} else {
+		srcLine += srcX >> FB_SHIFT;
+		dstLine += dstX >> FB_SHIFT;
+		srcX &= FB_MASK;
+		dstX &= FB_MASK;
+	}
+	if (srcX == dstX) {
+		while (height--) {
+			src = srcLine;
+			srcLine += srcStride;
+			dst = dstLine;
+			dstLine += dstStride;
+			if (reverse) {
+				if (endmask) {
+					bits = READ(--src);
+					--dst;
+					FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
+				}
+				n = nmiddle;
+				if (destInvarient) {
+					while (n--)
+						WRITE(--dst, FbDoDestInvarientMergeRop(READ(--src)));
+				} else {
+					while (n--) {
+						bits = READ(--src);
+						--dst;
+						WRITE(dst, FbDoMergeRop(bits, READ(dst)));
+					}
+				}
+				if (startmask) {
+					bits = READ(--src);
+					--dst;
+					FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
+				}
+			} else {
+				if (startmask) {
+					bits = READ(src++);
+					FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
+					dst++;
+				}
+				n = nmiddle;
+				if (destInvarient) {
+					while (n--)
+						WRITE(dst++, FbDoDestInvarientMergeRop(READ(src++)));
+				} else {
+					while (n--) {
+						bits = READ(src++);
+						WRITE(dst, FbDoMergeRop(bits, READ(dst)));
+						dst++;
+					}
+				}
+				if (endmask) {
+					bits = READ(src);
+					FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
+				}
+			}
+		}
+	} else {
+		if (srcX > dstX) {
+			leftShift = srcX - dstX;
+			rightShift = FB_UNIT - leftShift;
+		} else {
+			rightShift = dstX - srcX;
+			leftShift = FB_UNIT - rightShift;
+		}
+		while (height--) {
+			src = srcLine;
+			srcLine += srcStride;
+			dst = dstLine;
+			dstLine += dstStride;
+
+			bits1 = 0;
+			if (reverse) {
+				if (srcX < dstX)
+					bits1 = READ(--src);
+				if (endmask) {
+					bits = FbScrRight(bits1, rightShift);
+					if (FbScrRight(endmask, leftShift)) {
+						bits1 = READ(--src);
+						bits |= FbScrLeft(bits1, leftShift);
+					}
+					--dst;
+					FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
+				}
+				n = nmiddle;
+				if (destInvarient) {
+					while (n--) {
+						bits = FbScrRight(bits1, rightShift);
+						bits1 = READ(--src);
+						bits |= FbScrLeft(bits1, leftShift);
+						--dst;
+						WRITE(dst, FbDoDestInvarientMergeRop(bits));
+					}
+				} else {
+					while (n--) {
+						bits = FbScrRight(bits1, rightShift);
+						bits1 = READ(--src);
+						bits |= FbScrLeft(bits1, leftShift);
+						--dst;
+						WRITE(dst, FbDoMergeRop(bits, READ(dst)));
+					}
+				}
+				if (startmask) {
+					bits = FbScrRight(bits1, rightShift);
+					if (FbScrRight(startmask, leftShift)) {
+						bits1 = READ(--src);
+						bits |= FbScrLeft(bits1, leftShift);
+					}
+					--dst;
+					FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
+				}
+			} else {
+				if (srcX > dstX)
+					bits1 = READ(src++);
+				if (startmask) {
+					bits = FbScrLeft(bits1, leftShift);
+					if (FbScrLeft(startmask, rightShift)) {
+						bits1 = READ(src++);
+						bits |= FbScrRight(bits1, rightShift);
+					}
+					FbDoLeftMaskByteMergeRop(dst, bits, startbyte, startmask);
+					dst++;
+				}
+				n = nmiddle;
+				if (destInvarient) {
+					while (n--) {
+						bits = FbScrLeft(bits1, leftShift);
+						bits1 = READ(src++);
+						bits |= FbScrRight(bits1, rightShift);
+						WRITE(dst, FbDoDestInvarientMergeRop(bits));
+						dst++;
+					}
+				} else {
+					while (n--) {
+						bits = FbScrLeft(bits1, leftShift);
+						bits1 = READ(src++);
+						bits |= FbScrRight(bits1, rightShift);
+						WRITE(dst, FbDoMergeRop(bits, READ(dst)));
+						dst++;
+					}
+				}
+				if (endmask) {
+					bits = FbScrLeft(bits1, leftShift);
+					if (FbScrLeft(endmask, rightShift)) {
+						bits1 = READ(src);
+						bits |= FbScrRight(bits1, rightShift);
+					}
+					FbDoRightMaskByteMergeRop(dst, bits, endbyte, endmask);
+				}
+			}
+		}
+	}
+}
+
+void
+fbBlt(FbBits *srcLine, FbStride srcStride, int srcX,
+      FbBits *dstLine, FbStride dstStride, int dstX,
+      int width, int height,
+      int alu, FbBits pm, int bpp,
+      Bool reverse, Bool upsidedown)
+{
+	DBG(("%s %dx%d, alu=%d, pm=%d, bpp=%d\n",
+	     __FUNCTION__, width, height, alu, pm, bpp));
+
+	if (alu == GXcopy && pm == FB_ALLONES && ((srcX|dstX|width) & 7) == 0) {
+		CARD8 *s = (CARD8 *) srcLine;
+		CARD8 *d = (CARD8 *) dstLine;
+		int i;
+
+		srcStride *= sizeof(FbBits);
+		dstStride *= sizeof(FbBits);
+		width >>= 3;
+		s += srcX >> 3;
+		d += dstX >> 3;
+
+		DBG(("%s fast blt\n", __FUNCTION__));
+
+		if ((srcLine < dstLine && srcLine + width > dstLine) ||
+		    (dstLine < srcLine && dstLine + width > srcLine)) {
+			if (!upsidedown)
+				for (i = 0; i < height; i++)
+					memmove(d + i * dstStride,
+						s + i * srcStride,
+						width);
+			else
+				for (i = height - 1; i >= 0; i--)
+					memmove(d + i * dstStride,
+						s + i * srcStride,
+						width);
+		} else {
+			if (!upsidedown)
+				for (i = 0; i < height; i++)
+					memcpy(d + i * dstStride,
+					       s + i * srcStride,
+					       width);
+			else
+				for (i = height - 1; i >= 0; i--)
+					memcpy(d + i * dstStride,
+					       s + i * srcStride,
+					       width);
+		}
+
+		return;
+	}
+
+	fbBlt__rop(srcLine, srcStride, srcX,
+		   dstLine, dstStride, dstX,
+		   width, height,
+		   alu, pm, bpp,
+		   reverse, upsidedown);
+}
diff --git a/src/sna/fb/fbbltone.c b/src/sna/fb/fbbltone.c
new file mode 100644
index 0000000..697d20b
--- /dev/null
+++ b/src/sna/fb/fbbltone.c
@@ -0,0 +1,413 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fb.h"
+
+#ifdef __clang__
+/* shift overflow is intentional */
+#pragma clang diagnostic ignored "-Wshift-overflow"
+#endif
+
+/*
+ *  Example: srcX = 13 dstX = 8	(FB unit 32 dstBpp 8)
+ *
+ *	**** **** **** **** **** **** **** ****
+ *			^
+ *	********  ********  ********  ********
+ *		  ^
+ *  leftShift = 12
+ *  rightShift = 20
+ *
+ *  Example: srcX = 0 dstX = 8 (FB unit 32 dstBpp 8)
+ *
+ *	**** **** **** **** **** **** **** ****
+ *	^		
+ *	********  ********  ********  ********
+ *		  ^
+ *
+ *  leftShift = 24
+ *  rightShift = 8
+ */
+
+#define LoadBits {\
+    if (leftShift) { \
+	bitsRight = (src < srcEnd ? READ(src++) : 0); \
+	bits = (FbStipLeft (bitsLeft, leftShift) | \
+		FbStipRight(bitsRight, rightShift)); \
+	bitsLeft = bitsRight; \
+    } else \
+	bits = (src < srcEnd ? READ(src++) : 0); \
+}
+
+#define LaneCases1(n,a)	    case n: FbLaneCase(n,a); break
+#define LaneCases2(n,a)	    LaneCases1(n,a); LaneCases1(n+1,a)
+#define LaneCases4(n,a)	    LaneCases2(n,a); LaneCases2(n+2,a)
+#define LaneCases8(n,a)	    LaneCases4(n,a); LaneCases4(n+4,a)
+#define LaneCases16(n,a)    LaneCases8(n,a); LaneCases8(n+8,a)
+#define LaneCases32(n,a)    LaneCases16(n,a); LaneCases16(n+16,a)
+#define LaneCases64(n,a)    LaneCases32(n,a); LaneCases32(n+32,a)
+#define LaneCases128(n,a)   LaneCases64(n,a); LaneCases64(n+64,a)
+#define LaneCases256(n,a)   LaneCases128(n,a); LaneCases128(n+128,a)
+
+#define LaneCases(a)	    LaneCases16(0,a)
+
+static const CARD8 fb8Lane[16] = {
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+static const CARD8 fb16Lane[16] = {
+    0, 3, 12, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static const CARD8 fb32Lane[16] = {
+    0, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static const CARD8 * const fbLaneTable[33] = {
+    0, 0, 0, 0, 0, 0, 0, 0,
+    fb8Lane, 0, 0, 0, 0, 0, 0, 0,
+    fb16Lane, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    fb32Lane
+};
+
+void
+fbBltOne(FbStip * src, FbStride srcStride,      /* FbStip units per scanline */
+         int srcX,              /* bit position of source */
+         FbBits * dst, FbStride dstStride,      /* FbBits units per scanline */
+         int dstX,              /* bit position of dest */
+         int dstBpp,            /* bits per destination unit */
+         int width,             /* width in bits of destination */
+         int height,            /* height in scanlines */
+         FbBits fgand,          /* rrop values */
+         FbBits fgxor, FbBits bgand, FbBits bgxor)
+{
+	const FbBits *fbBits;
+	FbBits *srcEnd;
+	int pixelsPerDst;           /* dst pixels per FbBits */
+	int unitsPerSrc;            /* src patterns per FbStip */
+	int leftShift, rightShift;  /* align source with dest */
+	FbBits startmask, endmask;  /* dest scanline masks */
+	FbStip bits = 0, bitsLeft, bitsRight;       /* source bits */
+	FbStip left;
+	FbBits mask;
+	int nDst;                   /* dest longwords (w.o. end) */
+	int w;
+	int n, nmiddle;
+	int dstS;                   /* stipple-relative dst X coordinate */
+	Bool copy;                  /* accelerate dest-invariant */
+	Bool transparent;           /* accelerate 0 nop */
+	int srcinc;                 /* source units consumed */
+	Bool endNeedsLoad = FALSE;  /* need load for endmask */
+	const CARD8 *fbLane;
+	int startbyte, endbyte;
+
+	/*
+	 * Do not read past the end of the buffer!
+	 */
+	srcEnd = src + height * srcStride;
+
+	/*
+	 * Number of destination units in FbBits == number of stipple pixels
+	 * used each time
+	 */
+	pixelsPerDst = FB_UNIT / dstBpp;
+
+	/*
+	 * Number of source stipple patterns in FbStip 
+	 */
+	unitsPerSrc = FB_STIP_UNIT / pixelsPerDst;
+
+	copy = FALSE;
+	transparent = FALSE;
+	if (bgand == 0 && fgand == 0)
+		copy = TRUE;
+	else if (bgand == FB_ALLONES && bgxor == 0)
+		transparent = TRUE;
+
+	/*
+	 * Adjust source and dest to nearest FbBits boundary
+	 */
+	src += srcX >> FB_STIP_SHIFT;
+	dst += dstX >> FB_SHIFT;
+	srcX &= FB_STIP_MASK;
+	dstX &= FB_MASK;
+
+	FbMaskBitsBytes(dstX, width, copy,
+			startmask, startbyte, nmiddle, endmask, endbyte);
+
+	/*
+	 * Compute effective dest alignment requirement for
+	 * source -- must align source to dest unit boundary
+	 */
+	dstS = dstX / dstBpp;
+	/*
+	 * Compute shift constants for effective alignement
+	 */
+	if (srcX >= dstS) {
+		leftShift = srcX - dstS;
+		rightShift = FB_STIP_UNIT - leftShift;
+	} else {
+		rightShift = dstS - srcX;
+		leftShift = FB_STIP_UNIT - rightShift;
+	}
+	/*
+	 * Get pointer to stipple mask array for this depth
+	 */
+	fbBits = 0;                 /* unused */
+	if (pixelsPerDst <= 8)
+		fbBits = fbStippleTable[pixelsPerDst];
+	fbLane = 0;
+	if (transparent && fgand == 0 && dstBpp >= 8)
+		fbLane = fbLaneTable[dstBpp];
+
+	/*
+	 * Compute total number of destination words written, but 
+	 * don't count endmask 
+	 */
+	nDst = nmiddle;
+	if (startmask)
+		nDst++;
+
+	dstStride -= nDst;
+
+	/*
+	 * Compute total number of source words consumed
+	 */
+
+	srcinc = (nDst + unitsPerSrc - 1) / unitsPerSrc;
+
+	if (srcX > dstS)
+		srcinc++;
+	if (endmask) {
+		endNeedsLoad = nDst % unitsPerSrc == 0;
+		if (endNeedsLoad)
+			srcinc++;
+	}
+
+	srcStride -= srcinc;
+
+	/*
+	 * Copy rectangle
+	 */
+	while (height--) {
+		w = nDst;               /* total units across scanline */
+		n = unitsPerSrc;        /* units avail in single stipple */
+		if (n > w)
+			n = w;
+
+		bitsLeft = 0;
+		if (srcX > dstS)
+			bitsLeft = READ(src++);
+		if (n) {
+			/*
+			 * Load first set of stipple bits
+			 */
+			LoadBits;
+
+			/*
+			 * Consume stipple bits for startmask
+			 */
+			if (startmask) {
+				mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
+				if (fbLane) {
+					fbTransparentSpan(dst, mask & startmask, fgxor, 1);
+				} else {
+					if (mask || !transparent)
+						FbDoLeftMaskByteStippleRRop(dst, mask,
+									    fgand, fgxor, bgand, bgxor,
+									    startbyte, startmask);
+				}
+				bits = FbStipLeft(bits, pixelsPerDst);
+				dst++;
+				n--;
+				w--;
+			}
+			/*
+			 * Consume stipple bits across scanline
+			 */
+			for (;;) {
+				w -= n;
+				if (copy) {
+					while (n--) {
+#if FB_UNIT > 32
+						if (pixelsPerDst == 16)
+							mask = FbStipple16Bits(FbLeftStipBits(bits, 16));
+						else
+#endif
+							mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
+						WRITE(dst, FbOpaqueStipple(mask, fgxor, bgxor));
+						dst++;
+						bits = FbStipLeft(bits, pixelsPerDst);
+					}
+				}
+				else {
+					if (fbLane) {
+						while (bits && n) {
+							switch (fbLane[FbLeftStipBits(bits, pixelsPerDst)]) {
+								LaneCases((CARD8 *) dst);
+							}
+							bits = FbStipLeft(bits, pixelsPerDst);
+							dst++;
+							n--;
+						}
+						dst += n;
+					} else {
+						while (n--) {
+							left = FbLeftStipBits(bits, pixelsPerDst);
+							if (left || !transparent) {
+								mask = fbBits[left];
+								WRITE(dst, FbStippleRRop(READ(dst), mask,
+											 fgand, fgxor, bgand,
+											 bgxor));
+							}
+							dst++;
+							bits = FbStipLeft(bits, pixelsPerDst);
+						}
+					}
+				}
+				if (!w)
+					break;
+				/*
+				 * Load another set and reset number of available units
+				 */
+				LoadBits;
+				n = unitsPerSrc;
+				if (n > w)
+					n = w;
+			}
+		}
+		/*
+		 * Consume stipple bits for endmask
+		 */
+		if (endmask) {
+			if (endNeedsLoad) {
+				LoadBits;
+			}
+			mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
+			if (fbLane) {
+				fbTransparentSpan(dst, mask & endmask, fgxor, 1);
+			} else {
+				if (mask || !transparent)
+					FbDoRightMaskByteStippleRRop(dst, mask,
+								     fgand, fgxor, bgand, bgxor,
+								     endbyte, endmask);
+			}
+		}
+		dst += dstStride;
+		src += srcStride;
+	}
+}
+
+/*
+ * Not very efficient, but simple -- copy a single plane
+ * from an N bit image to a 1 bit image
+ */
+
+void
+fbBltPlane(FbBits * src,
+           FbStride srcStride,
+           int srcX,
+           int srcBpp,
+           FbStip * dst,
+           FbStride dstStride,
+           int dstX,
+           int width,
+           int height,
+           FbStip fgand,
+           FbStip fgxor, FbStip bgand, FbStip bgxor, Pixel planeMask)
+{
+	FbBits *s;
+	FbBits pm;
+	FbBits srcMask;
+	FbBits srcMaskFirst;
+	FbBits srcMask0 = 0;
+	FbBits srcBits;
+
+	FbStip dstBits;
+	FbStip *d;
+	FbStip dstMask;
+	FbStip dstMaskFirst;
+	FbStip dstUnion;
+	int w;
+	int wt;
+
+	if (!width)
+		return;
+
+	src += srcX >> FB_SHIFT;
+	srcX &= FB_MASK;
+
+	dst += dstX >> FB_STIP_SHIFT;
+	dstX &= FB_STIP_MASK;
+
+	w = width / srcBpp;
+
+	pm = fbReplicatePixel(planeMask, srcBpp);
+	srcMaskFirst = pm & FbBitsMask(srcX, srcBpp);
+	srcMask0 = pm & FbBitsMask(0, srcBpp);
+
+	dstMaskFirst = FbStipMask(dstX, 1);
+	while (height--) {
+		d = dst;
+		dst += dstStride;
+		s = src;
+		src += srcStride;
+
+		srcMask = srcMaskFirst;
+		srcBits = READ(s++);
+
+		dstMask = dstMaskFirst;
+		dstUnion = 0;
+		dstBits = 0;
+
+		wt = w;
+
+		while (wt--) {
+			if (!srcMask) {
+				srcBits = READ(s++);
+				srcMask = srcMask0;
+			}
+			if (!dstMask) {
+				WRITE(d, FbStippleRRopMask(READ(d), dstBits,
+							   fgand, fgxor, bgand, bgxor,
+							   dstUnion));
+				d++;
+				dstMask = FbStipMask(0, 1);
+				dstUnion = 0;
+				dstBits = 0;
+			}
+			if (srcBits & srcMask)
+				dstBits |= dstMask;
+			dstUnion |= dstMask;
+			if (srcBpp == FB_UNIT)
+				srcMask = 0;
+			else
+				srcMask = FbScrRight(srcMask, srcBpp);
+			dstMask = FbStipRight(dstMask, 1);
+		}
+		if (dstUnion)
+			WRITE(d, FbStippleRRopMask(READ(d), dstBits,
+						   fgand, fgxor, bgand, bgxor, dstUnion));
+	}
+}
diff --git a/src/sna/fb/fbclip.c b/src/sna/fb/fbclip.c
new file mode 100644
index 0000000..9b33e4a
--- /dev/null
+++ b/src/sna/fb/fbclip.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Chris Wilson <chris at chris-wilson.co.uk>
+ *
+ */
+
+#include "fb.h"
+#include "fbclip.h"
+
+static const BoxRec *
+find_c0(const BoxRec *begin, const BoxRec *end, int16_t y)
+{
+	const BoxRec *mid;
+
+	if (end == begin)
+		return end;
+
+	if (end - begin == 1) {
+		if (begin->y2 > y)
+			return begin;
+		else
+			return end;
+	}
+
+	mid = begin + (end - begin) / 2;
+	if (mid->y2 > y)
+		return find_c0(begin, mid, y);
+	else
+		return find_c0(mid, end, y);
+}
+
+static const BoxRec *
+find_c1(const BoxRec *begin, const BoxRec *end, int16_t y)
+{
+	const BoxRec *mid;
+
+	if (end == begin)
+		return end;
+
+	if (end - begin == 1) {
+		if (begin->y1 > y)
+			return begin;
+		else
+			return end;
+	}
+
+	mid = begin + (end - begin) / 2;
+	if (mid->y1 > y)
+		return find_c1(begin, mid, y);
+	else
+		return find_c1(mid, end, y);
+}
+
+const BoxRec *
+fbClipBoxes(const RegionRec *region, const BoxRec *box, const BoxRec **end)
+{
+	const BoxRec *c0, *c1;
+
+	DBG(("%s: box=(%d, %d),(%d, %d); region=(%d, %d),(%d, %d) x %ld\n",
+	     __FUNCTION__,
+	     box->x1, box->y1, box->x2, box->y2,
+	     region->extents.x1, region->extents.y1,
+	     region->extents.x2, region->extents.y2,
+	     region->data ? region->data->numRects : 1));
+
+	if (box->x1 >= region->extents.x2 || box->x2 <= region->extents.x1 ||
+	    box->y1 >= region->extents.y2 || box->y2 <= region->extents.y1) {
+		DBG(("%s: no intersection\n", __FUNCTION__));
+		return *end = box;
+	}
+
+	if (region->data == NULL) {
+		*end = &region->extents + 1;
+		return &region->extents;
+	}
+
+	c0 = (const BoxRec *)region->data + 1;
+	c1 = c0 + region->data->numRects;
+
+	c0 = find_c0(c0, c1, box->y1);
+	c1 = find_c1(c0, c1, box->y2);
+
+	DBG(("%s: c0=(%d, %d),(%d, %d); c1=(%d, %d),(%d, %d)\n",
+	     __FUNCTION__,
+	     c0->x1, c0->y1, c0->x2, c0->y2,
+	     c1[-1].x1, c1[-1].y1, c1[-1].x2, c1[-1].y2));
+
+	*end = c1;
+	return c0;
+}
diff --git a/src/sna/fb/fbclip.h b/src/sna/fb/fbclip.h
new file mode 100644
index 0000000..0436c40
--- /dev/null
+++ b/src/sna/fb/fbclip.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Chris Wilson <chris at chris-wilson.co.uk>
+ *
+ */
+
+#ifndef FBCLIP_H
+#define FBCLIP_H
+
+extern const BoxRec *
+fbClipBoxes(const RegionRec *region, const BoxRec *box, const BoxRec **end);
+
+inline static bool
+box_intersect(BoxPtr a, const BoxRec *b)
+{
+	if (a->x1 < b->x1)
+		a->x1 = b->x1;
+	if (a->x2 > b->x2)
+		a->x2 = b->x2;
+	if (a->y1 < b->y1)
+		a->y1 = b->y1;
+	if (a->y2 > b->y2)
+		a->y2 = b->y2;
+
+	return a->x1 < a->x2 && a->y1 < a->y2;
+}
+
+static inline void
+fbDrawableRun(DrawablePtr d, GCPtr gc, const BoxRec *box,
+	      void (*func)(DrawablePtr, GCPtr, const BoxRec *b, void *data),
+	      void *data)
+{
+	const BoxRec *c, *end;
+	for (c = fbClipBoxes(gc->pCompositeClip, box, &end); c != end; c++) {
+		BoxRec b;
+
+		if (box->x2 <= c->x1 || box->x1 >= c->x2)
+			continue;
+
+		b = *box;
+		if (box_intersect(&b, c))
+			func(d, gc, &b, data);
+	}
+}
+
+static inline void
+fbDrawableRunUnclipped(DrawablePtr d, GCPtr gc, const BoxRec *box,
+		       void (*func)(DrawablePtr, GCPtr, const BoxRec *b, void *data),
+		       void *data)
+{
+	const BoxRec *c, *end;
+	for (c = fbClipBoxes(gc->pCompositeClip, box, &end); c != end; c++) {
+		if (box->x2 <= c->x1 || box->x1 >= c->x2)
+			continue;
+		func(d, gc, c, data);
+	}
+}
+
+#endif /* FBCLIP_H */
diff --git a/src/sna/fb/fbcopy.c b/src/sna/fb/fbcopy.c
new file mode 100644
index 0000000..a2b1ded
--- /dev/null
+++ b/src/sna/fb/fbcopy.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+
+#include "fb.h"
+#include <mi.h>
+
+void
+fbCopyNtoN(DrawablePtr src_drawable, DrawablePtr dst_drawable, GCPtr gc,
+           BoxPtr box, int nbox,
+           int dx, int dy,
+	   Bool reverse, Bool upsidedown, Pixel bitplane,
+	   void *closure)
+{
+	CARD8 alu = gc ? gc->alu : GXcopy;
+	FbBits pm = gc ? fb_gc(gc)->pm : FB_ALLONES;
+	FbBits *src;
+	FbStride srcStride;
+	int srcBpp;
+	int srcXoff, srcYoff;
+	FbBits *dst;
+	FbStride dstStride;
+	int dstBpp;
+	int dstXoff, dstYoff;
+
+	fbGetDrawable(src_drawable, src, srcStride, srcBpp, srcXoff, srcYoff);
+	fbGetDrawable(dst_drawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
+
+	while (nbox--) {
+		if (pm == FB_ALLONES && alu == GXcopy && !reverse && !upsidedown) {
+			if (!pixman_blt
+			    ((uint32_t *) src, (uint32_t *) dst, srcStride, dstStride,
+			     srcBpp, dstBpp, (box->x1 + dx + srcXoff),
+			     (box->y1 + dy + srcYoff), (box->x1 + dstXoff),
+			     (box->y1 + dstYoff), (box->x2 - box->x1),
+			     (box->y2 - box->y1)))
+				goto fallback;
+			else
+				goto next;
+		}
+fallback:
+		fbBlt(src + (box->y1 + dy + srcYoff) * srcStride,
+		      srcStride,
+		      (box->x1 + dx + srcXoff) * srcBpp,
+		      dst + (box->y1 + dstYoff) * dstStride,
+		      dstStride,
+		      (box->x1 + dstXoff) * dstBpp,
+		      (box->x2 - box->x1) * dstBpp,
+		      (box->y2 - box->y1), alu, pm, dstBpp, reverse, upsidedown);
+next:
+		box++;
+	}
+}
+
+void
+fbCopy1toN(DrawablePtr src_drawable, DrawablePtr dst_drawable, GCPtr gc,
+           BoxPtr box, int nbox,
+           int dx, int dy,
+	   Bool reverse, Bool upsidedown, Pixel bitplane,
+	   void *closure)
+{
+	FbGCPrivPtr pgc = fb_gc(gc);
+	FbBits *src;
+	FbStride srcStride;
+	int srcBpp;
+	int srcXoff, srcYoff;
+	FbBits *dst;
+	FbStride dstStride;
+	int dstBpp;
+	int dstXoff, dstYoff;
+
+	fbGetDrawable(src_drawable, src, srcStride, srcBpp, srcXoff, srcYoff);
+	fbGetDrawable(dst_drawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
+
+	while (nbox--) {
+		if (dstBpp == 1) {
+			fbBlt(src + (box->y1 + dy + srcYoff) * srcStride,
+			      srcStride,
+			      (box->x1 + dx + srcXoff) * srcBpp,
+			      dst + (box->y1 + dstYoff) * dstStride,
+			      dstStride,
+			      (box->x1 + dstXoff) * dstBpp,
+			      (box->x2 - box->x1) * dstBpp,
+			      (box->y2 - box->y1),
+			      FbOpaqueStipple1Rop(gc->alu,
+						  gc->fgPixel, gc->bgPixel),
+			      pgc->pm, dstBpp, reverse, upsidedown);
+		} else {
+			fbBltOne((FbStip *) (src + (box->y1 + dy + srcYoff) * srcStride),
+				 srcStride * (FB_UNIT / FB_STIP_UNIT),
+				 (box->x1 + dx + srcXoff),
+				 dst + (box->y1 + dstYoff) * dstStride,
+				 dstStride,
+				 (box->x1 + dstXoff) * dstBpp,
+				 dstBpp,
+				 (box->x2 - box->x1) * dstBpp,
+				 (box->y2 - box->y1),
+				 pgc->and, pgc->xor, pgc->bgand, pgc->bgxor);
+		}
+		box++;
+	}
+}
+
+void
+fbCopyNto1(DrawablePtr src_drawable, DrawablePtr dst_drawable, GCPtr gc,
+           BoxPtr box, int nbox,
+           int dx, int dy,
+	   Bool reverse, Bool upsidedown, Pixel bitplane, void *closure)
+{
+	FbGCPrivPtr pgc = fb_gc(gc);
+
+	while (nbox--) {
+		if (dst_drawable->bitsPerPixel == 1) {
+			FbBits *src;
+			FbStride srcStride;
+			int srcBpp;
+			int srcXoff, srcYoff;
+
+			FbStip *dst;
+			FbStride dstStride;
+			int dstBpp;
+			int dstXoff, dstYoff;
+
+			fbGetDrawable(src_drawable, src,
+				      srcStride, srcBpp, srcXoff, srcYoff);
+			fbGetStipDrawable(dst_drawable,
+					  dst, dstStride, dstBpp, dstXoff, dstYoff);
+			fbBltPlane(src + (box->y1 + dy + srcYoff) * srcStride, srcStride,
+				   (box->x1 + dx + srcXoff) * srcBpp, srcBpp,
+				   dst + (box->y1 + dstYoff) * dstStride, dstStride,
+				   (box->x1 + dstXoff) * dstBpp,
+				   (box->x2 - box->x1) * srcBpp, (box->y2 - box->y1),
+				   (FbStip) pgc->and, (FbStip) pgc->xor,
+				   (FbStip) pgc->bgand, (FbStip) pgc->bgxor, bitplane);
+		} else {
+			FbBits *src;
+			FbStride srcStride;
+			int srcBpp;
+			int srcXoff, srcYoff;
+
+			FbBits *dst;
+			FbStride dstStride;
+			int dstBpp;
+			int dstXoff, dstYoff;
+
+			FbStip *tmp;
+			FbStride tmpStride;
+			int width, height;
+
+			width = box->x2 - box->x1;
+			height = box->y2 - box->y1;
+
+			tmpStride = ((width + FB_STIP_MASK) >> FB_STIP_SHIFT);
+			tmp = malloc(tmpStride * height * sizeof(FbStip));
+			if (!tmp)
+				return;
+
+			fbGetDrawable(src_drawable, src,
+				      srcStride, srcBpp, srcXoff, srcYoff);
+			fbGetDrawable(dst_drawable, dst,
+				      dstStride, dstBpp, dstXoff, dstYoff);
+
+			fbBltPlane(src + (box->y1 + dy + srcYoff) * srcStride,
+				   srcStride,
+				   (box->x1 + dx + srcXoff) * srcBpp,
+				   srcBpp,
+				   tmp,
+				   tmpStride,
+				   0,
+				   width * srcBpp,
+				   height,
+				   fbAndStip(GXcopy, FB_ALLONES, FB_ALLONES),
+				   fbXorStip(GXcopy, FB_ALLONES, FB_ALLONES),
+				   fbAndStip(GXcopy, 0, FB_ALLONES),
+				   fbXorStip(GXcopy, 0, FB_ALLONES), bitplane);
+			fbBltOne(tmp,
+				 tmpStride,
+				 0,
+				 dst + (box->y1 + dstYoff) * dstStride,
+				 dstStride,
+				 (box->x1 + dstXoff) * dstBpp,
+				 dstBpp,
+				 width * dstBpp,
+				 height,
+				 pgc->and, pgc->xor, pgc->bgand, pgc->bgxor);
+			free(tmp);
+		}
+		box++;
+	}
+}
+
+RegionPtr
+fbCopyArea(DrawablePtr src, DrawablePtr dst, GCPtr gc,
+	   int sx, int sy,
+	   int width, int height,
+	   int dx, int dy)
+{
+	return miDoCopy(src, dst, gc, sx, sy, width, height, dx, dy,
+			fbCopyNtoN, 0, 0);
+}
+
+RegionPtr
+fbCopyPlane(DrawablePtr src, DrawablePtr dst, GCPtr gc,
+	    int sx, int sy,
+	    int width, int height,
+	    int dx, int dy,
+	    unsigned long bitplane)
+{
+	if (src->bitsPerPixel > 1)
+		return miDoCopy(src, dst, gc, sx, sy, width, height, dx, dy,
+				fbCopyNto1, (Pixel) bitplane, 0);
+	else if (bitplane & 1)
+		return miDoCopy(src, dst, gc, sx, sy, width, height, dx, dy,
+				fbCopy1toN, (Pixel) bitplane, 0);
+	else
+		return miHandleExposures(src, dst, gc,
+					 sx, sy, width, height, dx, dy,
+					 bitplane);
+}
diff --git a/src/sna/fb/fbfill.c b/src/sna/fb/fbfill.c
new file mode 100644
index 0000000..3df1f9c
--- /dev/null
+++ b/src/sna/fb/fbfill.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fb.h"
+#include "fbclip.h"
+
+static void
+fbSolid(FbBits * dst,
+        FbStride dstStride,
+        int dstX, int bpp, int width, int height, FbBits and, FbBits xor)
+{
+	FbBits startmask, endmask;
+	int n, nmiddle;
+	int startbyte, endbyte;
+
+	dst += dstX >> FB_SHIFT;
+	dstX &= FB_MASK;
+	FbMaskBitsBytes(dstX, width, and == 0, startmask, startbyte,
+			nmiddle, endmask, endbyte);
+	if (startmask)
+		dstStride--;
+	dstStride -= nmiddle;
+	while (height--) {
+		if (startmask) {
+			FbDoLeftMaskByteRRop(dst, startbyte, startmask, and, xor);
+			dst++;
+		}
+		n = nmiddle;
+		if (!and)
+			while (n--)
+				WRITE(dst++, xor);
+		else
+			while (n--) {
+				WRITE(dst, FbDoRRop(READ(dst), and, xor));
+				dst++;
+			}
+		if (endmask)
+			FbDoRightMaskByteRRop(dst, endbyte, endmask, and, xor);
+		dst += dstStride;
+	}
+}
+
+void
+fbFill(DrawablePtr drawable, GCPtr gc, int x, int y, int width, int height)
+{
+	FbBits *dst;
+	FbStride dstStride;
+	int dstBpp;
+	int dstXoff, dstYoff;
+	FbGCPrivPtr pgc = fb_gc(gc);
+
+	DBG(("%s (%d, %d)x(%d, %d), style=%d\n",
+	     __FUNCTION__, x, y, width, height, gc->fillStyle));
+
+	fbGetDrawable(drawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
+
+	switch (gc->fillStyle) {
+	case FillSolid:
+		if (pgc->and ||
+		    !pixman_fill((uint32_t *) dst, dstStride, dstBpp,
+				 x + dstXoff, y + dstYoff,
+				 width, height, pgc->xor))
+			fbSolid(dst + (y + dstYoff) * dstStride,
+				dstStride,
+				(x + dstXoff) * dstBpp,
+				dstBpp, width * dstBpp, height, pgc->and, pgc->xor);
+		break;
+
+	case FillStippled:
+	case FillOpaqueStippled:
+		{
+			PixmapPtr pStip = gc->stipple;
+			int stipWidth = pStip->drawable.width;
+			int stipHeight = pStip->drawable.height;
+
+			if (dstBpp == 1) {
+				int alu;
+				FbBits *stip;
+				FbStride stipStride;
+				int stipBpp;
+				_X_UNUSED int stipXoff, stipYoff;
+
+				if (gc->fillStyle == FillStippled)
+					alu = FbStipple1Rop(gc->alu, gc->fgPixel);
+				else
+					alu = FbOpaqueStipple1Rop(gc->alu, gc->fgPixel, gc->bgPixel);
+				fbGetDrawable(&pStip->drawable, stip, stipStride, stipBpp, stipXoff,
+					      stipYoff);
+				fbTile(dst + (y + dstYoff) * dstStride, dstStride, x + dstXoff,
+				       width, height, stip, stipStride, stipWidth, stipHeight, alu,
+				       pgc->pm, dstBpp, (gc->patOrg.x + drawable->x + dstXoff),
+				       gc->patOrg.y + drawable->y - y);
+			} else {
+				FbStip *stip;
+				FbStride stipStride;
+				int stipBpp;
+				_X_UNUSED int stipXoff, stipYoff;
+				FbBits fgand, fgxor, bgand, bgxor;
+
+				fgand = pgc->and;
+				fgxor = pgc->xor;
+				if (gc->fillStyle == FillStippled) {
+					bgand = fbAnd(GXnoop, (FbBits) 0, FB_ALLONES);
+					bgxor = fbXor(GXnoop, (FbBits) 0, FB_ALLONES);
+				} else {
+					bgand = pgc->bgand;
+					bgxor = pgc->bgxor;
+				}
+
+				fbGetStipDrawable(&pStip->drawable, stip, stipStride, stipBpp,
+						  stipXoff, stipYoff);
+				fbStipple(dst + (y + dstYoff) * dstStride, dstStride,
+					  (x + dstXoff) * dstBpp, dstBpp, width * dstBpp, height,
+					  stip, stipStride, stipWidth, stipHeight,
+					  pgc->evenStipple, fgand, fgxor, bgand, bgxor,
+					  gc->patOrg.x + drawable->x + dstXoff,
+					  gc->patOrg.y + drawable->y - y);
+			}
+			break;
+		}
+
+	case FillTiled:
+		{
+			PixmapPtr pTile = gc->tile.pixmap;
+			FbBits *tile;
+			FbStride tileStride;
+			int tileBpp;
+			int tileWidth;
+			int tileHeight;
+			_X_UNUSED int tileXoff, tileYoff;
+
+			fbGetDrawable(&pTile->drawable, tile,
+				      tileStride, tileBpp, tileXoff, tileYoff);
+			tileWidth = pTile->drawable.width;
+			tileHeight = pTile->drawable.height;
+			fbTile(dst + (y + dstYoff) * dstStride,
+			       dstStride,
+			       (x + dstXoff) * dstBpp,
+			       width * dstBpp, height,
+			       tile,
+			       tileStride,
+			       tileWidth * tileBpp,
+			       tileHeight,
+			       gc->alu, pgc->pm,
+			       dstBpp,
+			       (gc->patOrg.x + drawable->x + dstXoff) * dstBpp,
+			       gc->patOrg.y + drawable->y - y);
+			break;
+		}
+	}
+}
+
+static void
+_fbSolidBox(DrawablePtr drawable, GCPtr gc, const BoxRec *b, void *_data)
+{
+	FbBits *dst;
+	FbStride stride;
+	int dx, dy, bpp;
+	FbBits and = fbAnd(GXcopy, fb_gc(gc)->bg, fb_gc(gc)->pm);
+	FbBits xor = fbXor(GXcopy, fb_gc(gc)->bg, fb_gc(gc)->pm);
+
+	fbGetDrawable(drawable, dst, stride, bpp, dx, dy);
+
+	if (and ||
+	    !pixman_fill((uint32_t *) dst, stride, bpp,
+			 b->x1 + dx, b->y1 + dy,
+			 (b->x2 - b->x1), (b->y2 - b->y1), xor))
+		fbSolid(dst + (b->y1 + dy) * stride, stride,
+			(b->x1 + dx) * bpp, bpp,
+			(b->x2 - b->x1) * bpp, (b->y2 - b->y1),
+			and, xor);
+}
+
+void
+fbSolidBoxClipped(DrawablePtr drawable, GCPtr gc,
+                  int x1, int y1, int x2, int y2)
+{
+	BoxRec box;
+
+	box.x1 = x1;
+	box.y1 = y1;
+	box.x2 = x2;
+	box.y2 = y2;
+
+	fbDrawableRun(drawable, gc, &box, _fbSolidBox, NULL);
+}
+
+inline static void
+fbFillBox(DrawablePtr drawable, GCPtr gc, const BoxRec *box, void *data)
+{
+	DBG(("%s box=(%d, %d), (%d, %d)\n", __FUNCTION__,
+	     box->x1, box->y1, box->x2, box->y2));
+	fbFill(drawable, gc,
+	       box->x1, box->y1,
+	       box->x2 - box->x1, box->y2 - box->y1);
+}
+
+void
+fbPolyFillRect(DrawablePtr drawable, GCPtr gc, int n, xRectangle *r)
+{
+	DBG(("%s x %d\n", __FUNCTION__, n));
+	while (n--) {
+		BoxRec b;
+
+		b.x1 = r->x + drawable->x;
+		b.y1 = r->y + drawable->y;
+		b.x2 = fbBound(b.x1, r->width);
+		b.y2 = fbBound(b.y1, r->height);
+		r++;
+
+		DBG(("%s: rectangle (%d, %d), (%d, %d)\n",
+		     __FUNCTION__, b.x1, b.y1, b.x2, b.y2));
+		fbDrawableRun(drawable, gc, &b, fbFillBox, NULL);
+	}
+}
diff --git a/src/sna/fb/fbgc.c b/src/sna/fb/fbgc.c
new file mode 100644
index 0000000..0969040
--- /dev/null
+++ b/src/sna/fb/fbgc.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fb.h"
+#include <gcstruct.h>
+#include <migc.h>
+#include <scrnintstr.h>
+
+/*
+ * Pad pixmap to FB_UNIT bits wide
+ */
+void
+fbPadPixmap(PixmapPtr pPixmap)
+{
+	int width;
+	FbBits *bits;
+	FbBits b;
+	FbBits mask;
+	int height;
+	int w;
+	int stride;
+	int bpp;
+	_X_UNUSED int xOff, yOff;
+
+	fbGetDrawable(&pPixmap->drawable, bits, stride, bpp, xOff, yOff);
+
+	width = pPixmap->drawable.width * pPixmap->drawable.bitsPerPixel;
+	height = pPixmap->drawable.height;
+	mask = FbBitsMask(0, width);
+	while (height--) {
+		b = READ(bits) & mask;
+		w = width;
+		while (w < FB_UNIT) {
+			b = b | FbScrRight(b, w);
+			w <<= 1;
+		}
+		WRITE(bits, b);
+		bits += stride;
+	}
+}
+
+/*
+ * Verify that 'bits' repeats every 'len' bits
+ */
+static Bool
+fbBitsRepeat(FbBits bits, int len, int width)
+{
+	FbBits mask = FbBitsMask(0, len);
+	FbBits orig = bits & mask;
+	int i;
+
+	if (width > FB_UNIT)
+		width = FB_UNIT;
+	for (i = 0; i < width / len; i++) {
+		if ((bits & mask) != orig)
+			return FALSE;
+		bits = FbScrLeft(bits, len);
+	}
+	return TRUE;
+}
+
+/*
+ * Check whether an entire bitmap line is a repetition of
+ * the first 'len' bits
+ */
+static Bool
+fbLineRepeat(FbBits * bits, int len, int width)
+{
+	FbBits first = bits[0];
+
+	if (!fbBitsRepeat(first, len, width))
+		return FALSE;
+	width = (width + FB_UNIT - 1) >> FB_SHIFT;
+	bits++;
+	while (--width)
+		if (READ(bits) != first)
+			return FALSE;
+	return TRUE;
+}
+
+/*
+ * The even stipple code wants the first FB_UNIT/bpp bits on
+ * each scanline to represent the entire stipple
+ */
+static Bool
+fbCanEvenStipple(PixmapPtr pStipple, int bpp)
+{
+	int len = FB_UNIT / bpp;
+	FbBits *bits;
+	int stride;
+	int stip_bpp;
+	_X_UNUSED int stipXoff, stipYoff;
+	int h;
+
+	/* make sure the stipple width is a multiple of the even stipple width */
+	if (pStipple->drawable.width % len != 0)
+		return FALSE;
+
+	fbGetDrawable(&pStipple->drawable, bits, stride, stip_bpp, stipXoff,
+		      stipYoff);
+	h = pStipple->drawable.height;
+	/* check to see that the stipple repeats horizontally */
+	while (h--) {
+		if (!fbLineRepeat(bits, len, pStipple->drawable.width))
+			return FALSE;
+
+		bits += stride;
+	}
+	return TRUE;
+}
+
+void
+fbValidateGC(GCPtr gc, unsigned long changes, DrawablePtr drawable)
+{
+	FbGCPrivPtr pgc = fb_gc(gc);
+	FbBits mask;
+
+	DBG(("%s changes=%lx\n", __FUNCTION__, changes));
+
+	if (changes & GCStipple) {
+		pgc->evenStipple = FALSE;
+
+		if (gc->stipple) {
+			/* can we do an even stipple ?? */
+			if (FbEvenStip(gc->stipple->drawable.width,
+				       drawable->bitsPerPixel) &&
+			    (fbCanEvenStipple(gc->stipple, drawable->bitsPerPixel)))
+				pgc->evenStipple = TRUE;
+		}
+	}
+
+	/*
+	 * Recompute reduced rop values
+	 */
+	if (changes & (GCForeground | GCBackground | GCPlaneMask | GCFunction)) {
+		int s;
+		FbBits depthMask;
+
+		mask = FbFullMask(drawable->bitsPerPixel);
+		depthMask = FbFullMask(drawable->depth);
+
+		pgc->fg = gc->fgPixel & mask;
+		pgc->bg = gc->bgPixel & mask;
+
+		if ((gc->planemask & depthMask) == depthMask)
+			pgc->pm = mask;
+		else
+			pgc->pm = gc->planemask & mask;
+
+		s = drawable->bitsPerPixel;
+		while (s < FB_UNIT) {
+			pgc->fg |= pgc->fg << s;
+			pgc->bg |= pgc->bg << s;
+			pgc->pm |= pgc->pm << s;
+			s <<= 1;
+		}
+		pgc->and = fbAnd(gc->alu, pgc->fg, pgc->pm);
+		pgc->xor = fbXor(gc->alu, pgc->fg, pgc->pm);
+		pgc->bgand = fbAnd(gc->alu, pgc->bg, pgc->pm);
+		pgc->bgxor = fbXor(gc->alu, pgc->bg, pgc->pm);
+	}
+
+	if (changes & GCDashList) {
+		unsigned short n = gc->numInDashList;
+		unsigned char *dash = gc->dash;
+		unsigned int dashLength = 0;
+
+		while (n--)
+			dashLength += (unsigned int) *dash++;
+		pgc->dashLength = dashLength;
+	}
+}
diff --git a/src/sna/fb/fbglyph.c b/src/sna/fb/fbglyph.c
new file mode 100644
index 0000000..789e5b8
--- /dev/null
+++ b/src/sna/fb/fbglyph.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fb.h"
+#include <X11/fonts/fontstruct.h>
+#include <dixfontstr.h>
+
+#define GLYPH	    fbGlyph8
+#define BITS	    BYTE
+#define BITS2	    CARD16
+#define BITS4	    CARD32
+#include "fbglyphbits.h"
+#undef BITS
+#undef BITS2
+#undef BITS4
+#undef GLYPH
+
+#define GLYPH	    fbGlyph16
+#define BITS	    CARD16
+#define BITS2	    CARD32
+#include "fbglyphbits.h"
+#undef BITS
+#undef BITS2
+#undef GLYPH
+
+#define GLYPH	    fbGlyph32
+#define BITS	    CARD32
+#include "fbglyphbits.h"
+#undef BITS
+#undef GLYPH
+
+static bool
+fbGlyphIn(GCPtr gc, int x, int y, int width, int height)
+{
+	BoxRec box;
+	BoxPtr extents = RegionExtents(gc->pCompositeClip);
+
+	/*
+	 * Check extents by hand to avoid 16 bit overflows
+	 */
+	if (x < (int) extents->x1 || (int) extents->x2 < x + width)
+		return FALSE;
+	if (y < (int) extents->y1 || (int) extents->y2 < y + height)
+		return FALSE;
+
+	box.x1 = x;
+	box.x2 = x + width;
+	box.y1 = y;
+	box.y2 = y + height;
+	return RegionContainsRect(gc->pCompositeClip, &box) == rgnIN;
+}
+
+#define WRITE1(d,n,fg)	WRITE((d) + (n), (CARD8) fg)
+#define WRITE2(d,n,fg)	WRITE((CARD16 *) &(d[n]), (CARD16) fg)
+#define WRITE4(d,n,fg)	WRITE((CARD32 *) &(d[n]), (CARD32) fg)
+
+/*
+ * This is a bit tricky, but it's brief.  Write 12 bytes worth
+ * of dest, which is four pixels, at a time.  This gives constant
+ * code for each pattern as they're always aligned the same
+ *
+ *  a b c d  a b c d  a b c d	bytes
+ *  A B C A  B C A B  C A B C	pixels
+ * 
+ *    f0        f1       f2
+ *  A B C A  B C A B  C A B C	pixels LSB
+ *  C A B C  A B C A  B C A B	pixels MSB
+ *
+ *		LSB	MSB
+ *  A		f0	f1
+ *  B		f1	f2
+ *  C		f2	f0
+ *  A B		f0	f2
+ *  B C		f1	f0
+ *  C A		f2	f1
+ *  A B C A	f0	f1
+ *  B C A B	f1    	f2
+ *  C A B C	f2	f0
+ */
+
+#undef _A
+#undef _B
+#undef _C
+#undef _AB
+#undef _BC
+#undef _CA
+#undef _ABCA
+#undef _BCAB
+#undef _CABC
+
+#define _A	f0
+#define _B	f1
+#define _C	f2
+#define _AB	f0
+#define _BC	f1
+#define _CA	f2
+#define _ABCA	f0
+#define _BCAB	f1
+#define _CABC	f2
+#define CASE(a,b,c,d)	(a | (b << 1) | (c << 2) | (d << 3))
+
+void
+fbPolyGlyphBlt(DrawablePtr drawable, GCPtr gc,
+               int x, int y,
+               unsigned int nglyph, CharInfoPtr * ppci, pointer glyphs)
+{
+	FbGCPrivPtr pgc = fb_gc(gc);
+	CharInfoPtr pci;
+	unsigned char *pglyph;      /* pointer bits in glyph */
+	int gx, gy;
+	int gWidth, gHeight;        /* width and height of glyph */
+	FbStride gStride;           /* stride of glyph */
+	void (*raster) (FbBits *, FbStride, int, FbStip *, FbBits, int, int);
+	FbBits *dst = 0;
+	FbStride dstStride = 0;
+	int dstBpp = 0;
+	int dstXoff = 0, dstYoff = 0;
+
+	DBG(("%s x %d\n", __FUNCTION__, nglyph));
+
+	raster = 0;
+	if (gc->fillStyle == FillSolid && pgc->and == 0) {
+		dstBpp = drawable->bitsPerPixel;
+		switch (dstBpp) {
+		case 8:
+			raster = fbGlyph8;
+			break;
+		case 16:
+			raster = fbGlyph16;
+			break;
+		case 32:
+			raster = fbGlyph32;
+			break;
+		}
+	}
+	x += drawable->x;
+	y += drawable->y;
+
+	while (nglyph--) {
+		pci = *ppci++;
+		pglyph = FONTGLYPHBITS(glyphs, pci);
+		gWidth = GLYPHWIDTHPIXELS(pci);
+		gHeight = GLYPHHEIGHTPIXELS(pci);
+		if (gWidth && gHeight) {
+			gx = x + pci->metrics.leftSideBearing;
+			gy = y - pci->metrics.ascent;
+			if (raster && gWidth <= sizeof(FbStip) * 8 &&
+			    fbGlyphIn(gc, gx, gy, gWidth, gHeight)) {
+				fbGetDrawable(drawable, dst, dstStride, dstBpp, dstXoff,
+					      dstYoff);
+				raster(dst + (gy + dstYoff) * dstStride, dstStride, dstBpp,
+					  (FbStip *) pglyph, pgc->xor, gx + dstXoff, gHeight);
+			} else {
+				gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof(FbStip);
+				fbPushImage(drawable, gc,
+					    (FbStip *)pglyph,
+					    gStride, 0, gx, gy, gWidth, gHeight);
+			}
+		}
+		x += pci->metrics.characterWidth;
+	}
+}
+
+void
+fbImageGlyphBlt(DrawablePtr drawable, GCPtr gc,
+                int x, int y,
+                unsigned int nglyph, CharInfoPtr * ppciInit, pointer glyphs)
+{
+	FbGCPrivPtr pgc = fb_gc(gc);
+	CharInfoPtr *ppci;
+	CharInfoPtr pci;
+	unsigned char *pglyph;      /* pointer bits in glyph */
+	int gWidth, gHeight;        /* width and height of glyph */
+	FbStride gStride;           /* stride of glyph */
+	bool opaque;
+	int n;
+	int gx, gy;
+	void (*raster)(FbBits *, FbStride, int, FbStip *, FbBits, int, int);
+	FbBits *dst = 0;
+	FbStride dstStride = 0;
+	int dstBpp = 0;
+	int dstXoff = 0, dstYoff = 0;
+
+	DBG(("%s x %d\n", __FUNCTION__, nglyph));
+
+	raster = 0;
+	if (pgc->and == 0) {
+		dstBpp = drawable->bitsPerPixel;
+		switch (dstBpp) {
+		case 8:
+			raster = fbGlyph8;
+			break;
+		case 16:
+			raster = fbGlyph16;
+			break;
+		case 32:
+			raster = fbGlyph32;
+			break;
+		}
+	}
+
+	x += drawable->x;
+	y += drawable->y;
+
+	if (TERMINALFONT(gc->font) && !raster) {
+		opaque = TRUE;
+	} else {
+		int xBack, widthBack;
+		int yBack, heightBack;
+
+		ppci = ppciInit;
+		n = nglyph;
+		widthBack = 0;
+		while (n--)
+			widthBack += (*ppci++)->metrics.characterWidth;
+
+		xBack = x;
+		if (widthBack < 0) {
+			xBack += widthBack;
+			widthBack = -widthBack;
+		}
+		yBack = y - FONTASCENT(gc->font);
+		heightBack = FONTASCENT(gc->font) + FONTDESCENT(gc->font);
+		fbSolidBoxClipped(drawable, gc,
+				  xBack, yBack,
+				  xBack + widthBack,
+				  yBack + heightBack);
+		opaque = FALSE;
+	}
+
+	ppci = ppciInit;
+	while (nglyph--) {
+		pci = *ppci++;
+		pglyph = FONTGLYPHBITS(glyphs, pci);
+		gWidth = GLYPHWIDTHPIXELS(pci);
+		gHeight = GLYPHHEIGHTPIXELS(pci);
+		if (gWidth && gHeight) {
+			gx = x + pci->metrics.leftSideBearing;
+			gy = y - pci->metrics.ascent;
+			if (raster && gWidth <= sizeof(FbStip) * 8 &&
+			    fbGlyphIn(gc, gx, gy, gWidth, gHeight)) {
+				fbGetDrawable(drawable, dst, dstStride, dstBpp, dstXoff,
+					      dstYoff);
+				raster(dst + (gy + dstYoff) * dstStride, dstStride, dstBpp,
+				       (FbStip *) pglyph, pgc->fg, gx + dstXoff, gHeight);
+			} else {
+				gStride = GLYPHWIDTHBYTESPADDED(pci) / sizeof(FbStip);
+				fbPutXYImage(drawable, gc,
+					     pgc->fg, pgc->bg, pgc->pm,
+					     GXcopy, opaque,
+					     gx, gy, gWidth, gHeight,
+					     (FbStip *) pglyph, gStride, 0);
+			}
+		}
+		x += pci->metrics.characterWidth;
+	}
+}
diff --git a/src/sna/fb/fbglyphbits.h b/src/sna/fb/fbglyphbits.h
new file mode 100644
index 0000000..af0f00f
--- /dev/null
+++ b/src/sna/fb/fbglyphbits.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define isClipped(c,ul,lr)  (((c) | ((c) - (ul)) | ((lr) - (c))) & 0x80008000)
+#define RROP(b,a,x)	WRITE((b), FbDoRRop (READ(b), (a), (x)))
+
+#define WRITE_ADDR1(n)	    (n)
+#define WRITE_ADDR2(n)	    (n)
+#define WRITE_ADDR4(n)	    (n)
+
+#define WRITE1(d,n,fg)	    WRITE(d + WRITE_ADDR1(n), (BITS) (fg))
+
+#ifdef BITS2
+#define WRITE2(d,n,fg)	    WRITE((BITS2 *) &((d)[WRITE_ADDR2(n)]), (BITS2) (fg))
+#else
+#define WRITE2(d,n,fg)	    (WRITE1(d,n,fg), WRITE1(d,(n)+1,fg))
+#endif
+
+#ifdef BITS4
+#define WRITE4(d,n,fg)	    WRITE((BITS4 *) &((d)[WRITE_ADDR4(n)]), (BITS4) (fg))
+#else
+#define WRITE4(d,n,fg)	    (WRITE2(d,n,fg), WRITE2(d,(n)+2,fg))
+#endif
+
+static void
+GLYPH(FbBits * dstBits,
+      FbStride dstStride,
+      int dstBpp, FbStip * stipple, FbBits fg, int x, int height)
+{
+	int lshift;
+	FbStip bits;
+	BITS *dstLine;
+	BITS *dst;
+	int n;
+	int shift;
+
+	dstLine = (BITS *) dstBits;
+	dstLine += x & ~3;
+	dstStride *= (sizeof(FbBits) / sizeof(BITS));
+	shift = x & 3;
+	lshift = 4 - shift;
+	while (height--) {
+		bits = *stipple++;
+		dst = (BITS *) dstLine;
+		n = lshift;
+		while (bits) {
+			switch (FbStipMoveLsb(FbLeftStipBits(bits, n), 4, n)) {
+			case 0:
+				break;
+			case 1:
+				WRITE1(dst, 0, fg);
+				break;
+			case 2:
+				WRITE1(dst, 1, fg);
+				break;
+			case 3:
+				WRITE2(dst, 0, fg);
+				break;
+			case 4:
+				WRITE1(dst, 2, fg);
+				break;
+			case 5:
+				WRITE1(dst, 0, fg);
+				WRITE1(dst, 2, fg);
+				break;
+			case 6:
+				WRITE1(dst, 1, fg);
+				WRITE1(dst, 2, fg);
+				break;
+			case 7:
+				WRITE2(dst, 0, fg);
+				WRITE1(dst, 2, fg);
+				break;
+			case 8:
+				WRITE1(dst, 3, fg);
+				break;
+			case 9:
+				WRITE1(dst, 0, fg);
+				WRITE1(dst, 3, fg);
+				break;
+			case 10:
+				WRITE1(dst, 1, fg);
+				WRITE1(dst, 3, fg);
+				break;
+			case 11:
+				WRITE2(dst, 0, fg);
+				WRITE1(dst, 3, fg);
+				break;
+			case 12:
+				WRITE2(dst, 2, fg);
+				break;
+			case 13:
+				WRITE1(dst, 0, fg);
+				WRITE2(dst, 2, fg);
+				break;
+			case 14:
+				WRITE1(dst, 1, fg);
+				WRITE2(dst, 2, fg);
+				break;
+			case 15:
+				WRITE4(dst, 0, fg);
+				break;
+			}
+			bits = FbStipLeft(bits, n);
+			n = 4;
+			dst += 4;
+		}
+		dstLine += dstStride;
+	}
+}
+
+#undef WRITE_ADDR1
+#undef WRITE_ADDR2
+#undef WRITE_ADDR4
+#undef WRITE1
+#undef WRITE2
+#undef WRITE4
+
+#undef RROP
+#undef isClipped
diff --git a/src/sna/fb/fbimage.c b/src/sna/fb/fbimage.c
new file mode 100644
index 0000000..5af2389
--- /dev/null
+++ b/src/sna/fb/fbimage.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "fb.h"
+#include "fbclip.h"
+
+struct fbPutZImage {
+	FbStip *src, *dst;
+	FbStride src_stride, dst_stride;
+
+	int dst_x, dst_y;
+	int x0, y0;
+};
+
+inline static void
+_fbPutZImage(DrawablePtr drawable, GCPtr gc, const BoxRec *b, void *_data)
+{
+	struct fbPutZImage *data = _data;
+	int bpp = drawable->bitsPerPixel;
+
+	fbBltStip(data->src + (b->y1 - data->y0) * data->src_stride, data->src_stride,
+		  (b->x1 - data->x0) * bpp,
+		  data->dst + (b->y1 + data->dst_y) * data->dst_stride,
+		  data->dst_stride,
+		  (b->x1 + data->dst_x) * bpp,
+		  (b->x2 - b->x1) * bpp, (b->y2 - b->y1),
+		  gc->alu, fb_gc(gc)->pm, bpp);
+}
+
+static void
+fbPutZImage(DrawablePtr drawable, GCPtr gc,
+            int x, int y, int width, int height,
+	    FbStip *src, FbStride srcStride)
+{
+	PixmapPtr pixmap;
+	struct fbPutZImage data;
+	BoxRec box;
+
+	box.x1 = data.x0 = x;
+	box.y1 = data.y0 = y;
+	box.x2 = x + width;
+	box.y2 = y + height;
+	data.src = src;
+	data.src_stride = srcStride;
+
+	fbGetDrawablePixmap(drawable, pixmap, data.dst_x, data.dst_y);
+	data.dst = pixmap->devPrivate.ptr;
+	data.dst_stride = pixmap->devKind / sizeof(FbStip);
+
+	fbDrawableRun(drawable, gc, &box, _fbPutZImage, &data);
+}
+
+struct fbPutXYImage {
+	FbStip *src, *dst;
+	FbStride src_stride, dst_stride;
+
+	int dst_x, dst_y, src_x;
+	int x0, y0;
+
+	int alu, pm;
+	FbBits fgand, fgxor, bgand, bgxor;
+};
+
+inline static void
+_fbPutXYImage1(DrawablePtr drawable, GCPtr gc, const BoxRec *b, void *_data)
+{
+	struct fbPutXYImage *data = _data;
+	int bpp = drawable->bitsPerPixel;
+
+	fbBltStip(data->src + (b->y1 - data->y0) * data->src_stride, data->src_stride,
+		  (b->x1 - data->x0) + data->src_x,
+		  (FbStip *) (data->dst + (b->y1 + data->dst_y) * data->dst_stride),
+		  data->dst_stride,
+		  (b->x1 + data->dst_x) * bpp,
+		  (b->x2 - b->x1) * bpp, (b->y2 - b->y1),
+		  data->alu, data->pm, bpp);
+}
+
+inline static void
+_fbPutXYImageN(DrawablePtr drawable, GCPtr gc, const BoxRec *b, void *_data)
+{
+	struct fbPutXYImage *data = _data;
+	int bpp = drawable->bitsPerPixel;
+
+	fbBltOne(data->src + (b->y1 - data->y0) * data->src_stride,
+		 data->src_stride,
+		 (b->x1 - data->x0) + data->src_x,
+		 data->dst + (b->y1 + data->dst_y) * data->dst_stride,
+		 data->dst_stride,
+		 (b->x1 + data->dst_x) * bpp, bpp,
+		 (b->x2 - b->x1) * bpp, (b->y2 - b->y1),
+		 data->fgand, data->fgxor,
+		 data->bgand, data->bgxor);
+}
+
+void
+fbPutXYImage(DrawablePtr drawable, GCPtr gc,
+             FbBits fg, FbBits bg, FbBits pm, int alu, Bool opaque,
+             int x, int y, int width, int height,
+	     FbStip *src, FbStride srcStride, int srcX)
+{
+	PixmapPtr pixmap;
+	struct fbPutXYImage data;
+	BoxRec box;
+
+	box.x1 = data.x0 = x;
+	box.y1 = data.y0 = y;
+	box.x2 = x + width;
+	box.y2 = y + height;
+	data.src = src;
+	data.src_stride = srcStride;
+	data.src_x = srcX;
+
+	fbGetDrawablePixmap(drawable, pixmap, data.dst_x, data.dst_y);
+	data.dst = pixmap->devPrivate.ptr;
+	data.dst_stride = pixmap->devKind / sizeof(FbStip);
+
+	if (drawable->bitsPerPixel == 1) {
+		if (opaque)
+			data.alu = FbOpaqueStipple1Rop(alu, fg, bg);
+		else
+			data.alu = FbStipple1Rop(alu, fg);
+		data.pm = pm;
+
+		fbDrawableRun(drawable, gc, &box, _fbPutXYImage1, &data);
+	} else {
+		data.fgand = fbAnd(alu, fg, pm);
+		data.fgxor = fbXor(alu, fg, pm);
+		if (opaque) {
+			data.bgand = fbAnd(alu, bg, pm);
+			data.bgxor = fbXor(alu, bg, pm);
+		} else {
+			data.bgand = fbAnd(GXnoop, (FbBits) 0, FB_ALLONES);
+			data.bgxor = fbXor(GXnoop, (FbBits) 0, FB_ALLONES);
+		}
+
+		fbDrawableRun(drawable, gc, &box, _fbPutXYImageN, &data);
+	}
+}
+
+void
+fbPutImage(DrawablePtr drawable, GCPtr gc, int depth,
+           int x, int y, int w, int h,
+	   int leftPad, int format, char *image)
+{
+	FbGCPrivPtr pgc = fb_gc(gc);
+	unsigned long i;
+	FbStride srcStride;
+	FbStip *src = (FbStip *)image;
+
+	DBG(("%s (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
+
+	x += drawable->x;
+	y += drawable->y;
+
+	switch (format) {
+	case XYBitmap:
+		srcStride = BitmapBytePad(w + leftPad) / sizeof(FbStip);
+		fbPutXYImage(drawable, gc,
+			     pgc->fg, pgc->bg, pgc->pm,
+			     gc->alu, TRUE,
+			     x, y, w, h,
+			     src, srcStride, leftPad);
+		break;
+	case XYPixmap:
+		srcStride = BitmapBytePad(w + leftPad) / sizeof(FbStip);
+		for (i = (unsigned long) 1 << (drawable->depth - 1); i; i >>= 1) {
+			if (i & gc->planemask) {
+				fbPutXYImage(drawable, gc,
+					     FB_ALLONES,
+					     0,
+					     fbReplicatePixel(i, drawable->bitsPerPixel),
+					     gc->alu,
+					     TRUE, x, y, w, h, src, srcStride, leftPad);
+				src += srcStride * h;
+			}
+		}
+		break;
+	case ZPixmap:
+		srcStride = PixmapBytePad(w, drawable->depth) / sizeof(FbStip);
+		fbPutZImage(drawable, gc,
+			    x, y, w, h, src, srcStride);
+	}
+}
+
+void
+fbGetImage(DrawablePtr drawable,
+           int x, int y, int w, int h,
+	   unsigned int format, unsigned long planeMask, char *d)
+{
+	FbBits *src;
+	FbStride srcStride;
+	int srcBpp;
+	int srcXoff, srcYoff;
+	FbStip *dst;
+	FbStride dstStride;
+
+	DBG(("%s (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
+
+	fbGetDrawable(drawable, src, srcStride, srcBpp, srcXoff, srcYoff);
+
+	x += drawable->x;
+	y += drawable->y;
+
+	dst = (FbStip *) d;
+	if (format == ZPixmap || srcBpp == 1) {
+		FbBits pm;
+
+		pm = fbReplicatePixel(planeMask, srcBpp);
+		dstStride = PixmapBytePad(w, drawable->depth);
+		if (pm != FB_ALLONES)
+			memset(d, 0, dstStride * h);
+		dstStride /= sizeof(FbStip);
+		fbBltStip((FbStip *)(src + (y + srcYoff) * srcStride), srcStride,
+			  (x + srcXoff) * srcBpp,
+			  dst, dstStride, 0, w * srcBpp, h, GXcopy, pm, srcBpp);
+	} else {
+		dstStride = BitmapBytePad(w) / sizeof(FbStip);
+		fbBltPlane(src + (y + srcYoff) * srcStride,
+			   srcStride,
+			   (x + srcXoff) * srcBpp,
+			   srcBpp,
+			   dst,
+			   dstStride,
+			   0,
+			   w * srcBpp, h,
+			   fbAndStip(GXcopy, FB_STIP_ALLONES, FB_STIP_ALLONES),
+			   fbXorStip(GXcopy, FB_STIP_ALLONES, FB_STIP_ALLONES),
+			   fbAndStip(GXcopy, 0, FB_STIP_ALLONES),
+			   fbXorStip(GXcopy, 0, FB_STIP_ALLONES), planeMask);
+	}
+}
diff --git a/src/sna/fb/fbline.c b/src/sna/fb/fbline.c
new file mode 100644
index 0000000..04d5343
--- /dev/null
+++ b/src/sna/fb/fbline.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fb.h"
+#include <mi.h>
+#include <micoord.h>
+#include <miline.h>
+#include <scrnintstr.h>
+
+#define POLYLINE    fbPolyline8
+#define POLYSEGMENT fbPolySegment8
+#define BITS	    BYTE
+#define BITS2	    CARD16
+#define BITS4	    CARD32
+#include "fblinebits.h"
+#undef BITS
+#undef BITS2
+#undef BITS4
+#undef POLYSEGMENT
+#undef POLYLINE
+
+#define POLYLINE    fbPolyline16
+#define POLYSEGMENT fbPolySegment16
+#define BITS	    CARD16
+#define BITS2	    CARD32
+#include "fblinebits.h"
+#undef BITS
+#undef BITS2
+#undef POLYSEGMENT
+#undef POLYLINE
+
+#define POLYLINE    fbPolyline32
+#define POLYSEGMENT fbPolySegment32
+#define BITS	    CARD32
+#include "fblinebits.h"
+#undef BITS
+#undef POLYSEGMENT
+#undef POLYLINE
+
+static void
+fbZeroLine(DrawablePtr drawable, GCPtr gc, int mode, int n, DDXPointPtr pt)
+{
+	int x1, y1, x2, y2;
+	int x, y;
+	int dashOffset;
+
+	x = drawable->x;
+	y = drawable->y;
+	x1 = pt->x;
+	y1 = pt->y;
+	dashOffset = gc->dashOffset;
+	while (--n) {
+		++pt;
+		x2 = pt->x;
+		y2 = pt->y;
+		if (mode == CoordModePrevious) {
+			x2 += x1;
+			y2 += y1;
+		}
+		fbSegment(drawable, gc,
+			  x1 + x, y1 + y,
+			  x2 + x, y2 + y,
+			  n == 1 && gc->capStyle != CapNotLast, &dashOffset);
+		x1 = x2;
+		y1 = y2;
+	}
+}
+
+static void
+fbZeroSegment(DrawablePtr drawable, GCPtr gc, int n, xSegment *seg)
+{
+	int dashOffset;
+	int16_t x, y;
+	Bool drawLast = gc->capStyle != CapNotLast;
+
+	x = drawable->x;
+	y = drawable->y;
+	while (n--) {
+		dashOffset = gc->dashOffset;
+		fbSegment(drawable, gc,
+			  seg->x1 + x, seg->y1 + y,
+			  seg->x2 + x, seg->y2 + y,
+			  drawLast, &dashOffset);
+		seg++;
+	}
+}
+
+void
+fbFixCoordModePrevious(int n, DDXPointPtr pt)
+{
+	int16_t x = pt->x;
+	int16_t y = pt->y;
+	while (--n) {
+		pt++;
+		x = (pt->x += x);
+		y = (pt->y += y);
+	}
+}
+
+void
+fbPolyLine(DrawablePtr drawable, GCPtr gc, int mode, int n, DDXPointPtr pt)
+{
+	void (*raster)(DrawablePtr, GCPtr, int mode, int n, DDXPointPtr pt);
+
+	DBG(("%s x %d, width=%d, fill=%d, line=%d\n",
+	     __FUNCTION__, n, gc->lineWidth, gc->fillStyle, gc->lineStyle));
+
+	if (gc->lineWidth == 0) {
+		raster = fbZeroLine;
+		if (gc->fillStyle == FillSolid && gc->lineStyle == LineSolid) {
+			switch (drawable->bitsPerPixel) {
+			case 8:
+				raster = fbPolyline8;
+				break;
+			case 16:
+				raster = fbPolyline16;
+				break;
+			case 32:
+				raster = fbPolyline32;
+				break;
+			}
+		}
+	} else {
+		if (gc->lineStyle != LineSolid)
+			raster = miWideDash;
+		else
+			raster = miWideLine;
+	}
+	raster(drawable, gc, mode, n, pt);
+}
+
+void
+fbPolySegment(DrawablePtr drawable, GCPtr gc, int n, xSegment *seg)
+{
+	void (*raster)(DrawablePtr drawable, GCPtr gc, int n, xSegment * seg);
+
+	DBG(("%s x %d, width=%d, fill=%d, line=%d\n",
+	     __FUNCTION__, n, gc->lineWidth, gc->fillStyle, gc->lineStyle));
+
+	if (gc->lineWidth == 0) {
+		raster = fbZeroSegment;
+		if (gc->fillStyle == FillSolid && gc->lineStyle == LineSolid) {
+			switch (drawable->bitsPerPixel) {
+			case 8:
+				raster = fbPolySegment8;
+				break;
+			case 16:
+				raster = fbPolySegment16;
+				break;
+			case 32:
+				raster = fbPolySegment32;
+				break;
+			}
+		}
+	} else
+		raster = miPolySegment;
+
+	raster(drawable, gc, n, seg);
+}
diff --git a/src/sna/fb/fblinebits.h b/src/sna/fb/fblinebits.h
new file mode 100644
index 0000000..db315d8
--- /dev/null
+++ b/src/sna/fb/fblinebits.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define isClipped(c,ul,lr)  (((c) | ((c) - (ul)) | ((lr) - (c))) & 0x80008000)
+#define RROP(b,a,x)	WRITE((b), FbDoRRop (READ(b), (a), (x)))
+
+static void
+POLYLINE(DrawablePtr drawable, GCPtr gc, int mode, int n_0, DDXPointPtr pt_0)
+{
+	int xoff = drawable->x;
+	int yoff = drawable->y;
+	unsigned int bias = miGetZeroLineBias(drawable->pScreen);
+	const BoxRec *clip = RegionRects(gc->pCompositeClip);
+	const BoxRec *const last_clip = clip + RegionNumRects(gc->pCompositeClip);
+
+	FbBits *dst;
+	int dstStride;
+	int dstBpp;
+	int dstXoff, dstYoff;
+
+	BITS *bits, *bitsBase;
+	FbStride bitsStride;
+	BITS xor = fb_gc(gc)->xor;
+	BITS and = fb_gc(gc)->and;
+
+
+	int e, e1, e3, len;
+	int stepmajor, stepminor;
+	int octant;
+
+	if (mode == CoordModePrevious)
+		fbFixCoordModePrevious(n_0, pt_0);
+
+	fbGetDrawable(drawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
+	bitsStride = dstStride * (sizeof(FbBits) / sizeof(BITS));
+	bitsBase =
+		((BITS *) dst) + (yoff + dstYoff) * bitsStride + (xoff + dstXoff);
+	do {
+		INT32 *pt = (INT32 *)pt_0;
+		int n = n_0;
+		INT32 pt1, pt2;
+
+		INT32 ul = coordToInt(clip->x1 - xoff, clip->y1 - yoff);
+		INT32 lr = coordToInt(clip->x2 - xoff - 1, clip->y2 - yoff - 1);
+
+		pt1 = *pt++; n--;
+		pt2 = *pt++; n--;
+		for (;;) {
+			if (isClipped(pt1, ul, lr) | isClipped(pt2, ul, lr)) {
+				int dashoffset = 0;
+				fbSegment1(drawable, gc, clip,
+					  intToX(pt1) + xoff, intToY(pt1) + yoff,
+					  intToX(pt2) + xoff, intToY(pt2) + yoff,
+					  n == 0 && gc->capStyle != CapNotLast, &dashoffset);
+				if (!n)
+					return;
+
+				pt1 = pt2;
+				pt2 = *pt++;
+				n--;
+			} else {
+				bits = bitsBase + intToY(pt1) * bitsStride + intToX(pt1);
+				for (;;) {
+					CalcLineDeltas(intToX(pt1), intToY(pt1),
+						       intToX(pt2), intToY(pt2),
+						       len, e1, stepmajor, stepminor, 1, bitsStride,
+						       octant);
+					if (len < e1) {
+						e3 = len;
+						len = e1;
+						e1 = e3;
+
+						e3 = stepminor;
+						stepminor = stepmajor;
+						stepmajor = e3;
+						SetYMajorOctant(octant);
+					}
+					e = -len;
+					e1 <<= 1;
+					e3 = e << 1;
+					FIXUP_ERROR(e, octant, bias);
+					if (and == 0) {
+						while (len--) {
+							WRITE(bits, xor);
+							bits += stepmajor;
+							e += e1;
+							if (e >= 0) {
+								bits += stepminor;
+								e += e3;
+							}
+						}
+					} else {
+						while (len--) {
+							RROP(bits, and, xor);
+							bits += stepmajor;
+							e += e1;
+							if (e >= 0) {
+								bits += stepminor;
+								e += e3;
+							}
+						}
+					}
+					if (!n) {
+						if (gc->capStyle != CapNotLast &&
+						    pt2 != *((INT32 *)pt_0)) {
+							RROP(bits, and, xor);
+						}
+						return;
+					}
+					pt1 = pt2;
+					pt2 = *pt++;
+					--n;
+					if (isClipped(pt2, ul, lr))
+						break;
+				}
+			}
+		}
+	} while (++clip != last_clip);
+}
+
+static void
+POLYSEGMENT(DrawablePtr drawable, GCPtr gc, int n_0, xSegment *seg_0)
+{
+	int xoff = drawable->x;
+	int yoff = drawable->y;
+	unsigned int bias = miGetZeroLineBias(drawable->pScreen);
+	const BoxRec *clip = RegionRects(gc->pCompositeClip);
+	const BoxRec *const last_clip = clip + RegionNumRects(gc->pCompositeClip);
+
+	FbBits *dst;
+	int dstStride;
+	int dstBpp;
+	int dstXoff, dstYoff;
+
+	BITS *bits, *bitsBase;
+	FbStride bitsStride;
+	FbBits xor = fb_gc(gc)->xor;
+	FbBits and = fb_gc(gc)->and;
+
+	int e, e1, e3, len;
+	int stepmajor, stepminor;
+	int octant;
+	bool capNotLast = gc->capStyle == CapNotLast;
+
+	fbGetDrawable(drawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
+	bitsStride = dstStride * (sizeof(FbBits) / sizeof(BITS));
+	bitsBase =
+		((BITS *) dst) + (yoff + dstYoff) * bitsStride + (xoff + dstXoff);
+
+	do {
+		INT32 ul = coordToInt(clip->x1 - xoff, clip->y1 - yoff);
+		INT32 lr = coordToInt(clip->x2 - xoff - 1, clip->y2 - yoff - 1);
+		uint64_t *pt = (uint64_t *)seg_0;
+		int n = n_0;
+
+		while (n--) {
+			union {
+				int32_t pt32[2];
+				uint64_t pt64;
+			} u;
+
+			u.pt64 = *pt++;
+			if (isClipped(u.pt32[0], ul, lr) | isClipped(u.pt32[1], ul, lr)) {
+				int dashoffset = 0;
+				fbSegment1(drawable, gc, clip,
+					  intToX(u.pt32[0]) + xoff, intToY(u.pt32[0]) + yoff,
+					  intToX(u.pt32[1]) + xoff, intToY(u.pt32[1]) + yoff,
+					  !capNotLast, &dashoffset);
+			} else {
+				CalcLineDeltas(intToX(u.pt32[0]), intToY(u.pt32[0]),
+					       intToX(u.pt32[1]), intToY(u.pt32[1]),
+					       len, e1, stepmajor, stepminor, 1, bitsStride,
+					       octant);
+				if (e1 == 0 && len > 3) {
+					int x1, x2;
+					FbBits *dstLine;
+					int dstX, width;
+					FbBits startmask, endmask;
+					int nmiddle;
+
+					if (stepmajor < 0) {
+						x1 = intToX(u.pt32[1]);
+						x2 = intToX(u.pt32[0]) + 1;
+						if (capNotLast)
+							x1++;
+					} else {
+						x1 = intToX(u.pt32[0]);
+						x2 = intToX(u.pt32[1]);
+						if (!capNotLast)
+							x2++;
+					}
+					dstX = (x1 + xoff + dstXoff) * (sizeof(BITS) * 8);
+					width = (x2 - x1) * (sizeof(BITS) * 8);
+
+					dstLine = dst + (intToY(u.pt32[0]) + yoff + dstYoff) * dstStride;
+					dstLine += dstX >> FB_SHIFT;
+					dstX &= FB_MASK;
+					FbMaskBits(dstX, width, startmask, nmiddle, endmask);
+					if (startmask) {
+						WRITE(dstLine,
+						      FbDoMaskRRop(READ(dstLine), and, xor,
+								   startmask));
+						dstLine++;
+					}
+					if (!and)
+						while (nmiddle--)
+							WRITE(dstLine++, xor);
+					else
+						while (nmiddle--) {
+							WRITE(dstLine,
+							      FbDoRRop(READ(dstLine), and, xor));
+							dstLine++;
+						}
+					if (endmask)
+						WRITE(dstLine,
+						      FbDoMaskRRop(READ(dstLine), and, xor,
+								   endmask));
+				} else {
+					bits = bitsBase + intToY(u.pt32[0]) * bitsStride + intToX(u.pt32[0]);
+					if (len < e1) {
+						e3 = len;
+						len = e1;
+						e1 = e3;
+
+						e3 = stepminor;
+						stepminor = stepmajor;
+						stepmajor = e3;
+						SetYMajorOctant(octant);
+					}
+					e = -len;
+					e1 <<= 1;
+					e3 = e << 1;
+					FIXUP_ERROR(e, octant, bias);
+					if (!capNotLast)
+						len++;
+					if (and == 0) {
+						while (len--) {
+							WRITE(bits, xor);
+							bits += stepmajor;
+							e += e1;
+							if (e >= 0) {
+								bits += stepminor;
+								e += e3;
+							}
+						}
+					} else {
+						while (len--) {
+							RROP(bits, and, xor);
+							bits += stepmajor;
+							e += e1;
+							if (e >= 0) {
+								bits += stepminor;
+								e += e3;
+							}
+						}
+					}
+				}
+			}
+		}
+	} while (++clip != last_clip);
+}
+
+#undef RROP
+#undef isClipped
diff --git a/src/sna/fb/fbpict.c b/src/sna/fb/fbpict.c
new file mode 100644
index 0000000..f6bcb64
--- /dev/null
+++ b/src/sna/fb/fbpict.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright © 2000 SuSE, Inc.
+ * Copyright © 2007 Red Hat, Inc.
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of SuSE not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  SuSE makes no representations about the
+ * suitability of this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ *
+ * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author:  Keith Packard, SuSE, Inc.
+ */
+
+#include <string.h>
+
+#include "fb.h"
+
+#include <picturestr.h>
+#include <mipict.h>
+#include "fbpict.h"
+
+void
+fbComposite(CARD8 op,
+            PicturePtr pSrc,
+            PicturePtr pMask,
+            PicturePtr pDst,
+            INT16 xSrc,
+            INT16 ySrc,
+            INT16 xMask,
+            INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height)
+{
+	pixman_image_t *src, *mask, *dest;
+	int src_xoff, src_yoff;
+	int msk_xoff, msk_yoff;
+	int dst_xoff, dst_yoff;
+
+	miCompositeSourceValidate(pSrc);
+	if (pMask)
+		miCompositeSourceValidate(pMask);
+
+	src = image_from_pict(pSrc, FALSE, &src_xoff, &src_yoff);
+	mask = image_from_pict(pMask, FALSE, &msk_xoff, &msk_yoff);
+	dest = image_from_pict(pDst, TRUE, &dst_xoff, &dst_yoff);
+
+	if (src && dest && !(pMask && !mask)) {
+		pixman_image_composite(op, src, mask, dest,
+				       xSrc + src_xoff, ySrc + src_yoff,
+				       xMask + msk_xoff, yMask + msk_yoff,
+				       xDst + dst_xoff, yDst + dst_yoff, width, height);
+	}
+
+	free_pixman_pict(pSrc, src);
+	free_pixman_pict(pMask, mask);
+	free_pixman_pict(pDst, dest);
+}
+
+static pixman_image_t *
+create_solid_fill_image(PicturePtr pict)
+{
+	PictSolidFill *solid = &pict->pSourcePict->solidFill;
+	pixman_color_t color;
+	CARD32 a, r, g, b;
+
+	a = (solid->color & 0xff000000) >> 24;
+	r = (solid->color & 0x00ff0000) >> 16;
+	g = (solid->color & 0x0000ff00) >> 8;
+	b = (solid->color & 0x000000ff) >> 0;
+
+	color.alpha = (a << 8) | a;
+	color.red = (r << 8) | r;
+	color.green = (g << 8) | g;
+	color.blue = (b << 8) | b;
+
+	return pixman_image_create_solid_fill(&color);
+}
+
+static pixman_image_t *
+create_linear_gradient_image(PictGradient * gradient)
+{
+	PictLinearGradient *linear = (PictLinearGradient *) gradient;
+	pixman_point_fixed_t p1;
+	pixman_point_fixed_t p2;
+
+	p1.x = linear->p1.x;
+	p1.y = linear->p1.y;
+	p2.x = linear->p2.x;
+	p2.y = linear->p2.y;
+
+	return pixman_image_create_linear_gradient(&p1, &p2,
+						   (pixman_gradient_stop_t *)
+						   gradient->stops,
+						   gradient->nstops);
+}
+
+static pixman_image_t *
+create_radial_gradient_image(PictGradient * gradient)
+{
+	PictRadialGradient *radial = (PictRadialGradient *) gradient;
+	pixman_point_fixed_t c1;
+	pixman_point_fixed_t c2;
+
+	c1.x = radial->c1.x;
+	c1.y = radial->c1.y;
+	c2.x = radial->c2.x;
+	c2.y = radial->c2.y;
+
+	return pixman_image_create_radial_gradient(&c1, &c2, radial->c1.radius,
+						   radial->c2.radius,
+						   (pixman_gradient_stop_t *)
+						   gradient->stops,
+						   gradient->nstops);
+}
+
+static pixman_image_t *
+create_conical_gradient_image(PictGradient * gradient)
+{
+	PictConicalGradient *conical = (PictConicalGradient *) gradient;
+	pixman_point_fixed_t center;
+
+	center.x = conical->center.x;
+	center.y = conical->center.y;
+
+	return pixman_image_create_conical_gradient(&center, conical->angle,
+						    (pixman_gradient_stop_t *)
+						    gradient->stops,
+						    gradient->nstops);
+}
+
+static pixman_image_t *
+create_bits_picture(PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
+{
+	PixmapPtr pixmap;
+	FbBits *bits;
+	FbStride stride;
+	int bpp;
+	pixman_image_t *image;
+
+	fbGetDrawablePixmap(pict->pDrawable, pixmap, *xoff, *yoff);
+	fbGetPixmapBitsData(pixmap, bits, stride, bpp);
+
+	image = pixman_image_create_bits((pixman_format_code_t) pict->format,
+					 pixmap->drawable.width,
+					 pixmap->drawable.height, (uint32_t *) bits,
+					 stride * sizeof(FbStride));
+
+	if (!image)
+		return NULL;
+
+	/* pCompositeClip is undefined for source pictures, so
+	 * only set the clip region for pictures with drawables
+	 */
+	if (has_clip) {
+		if (pict->clientClipType != CT_NONE)
+			pixman_image_set_has_client_clip(image, TRUE);
+
+		if (*xoff || *yoff)
+			pixman_region_translate(pict->pCompositeClip, *xoff, *yoff);
+
+		pixman_image_set_clip_region(image, pict->pCompositeClip);
+
+		if (*xoff || *yoff)
+			pixman_region_translate(pict->pCompositeClip, -*xoff, -*yoff);
+	}
+
+	/* Indexed table */
+	if (pict->pFormat->index.devPrivate)
+		pixman_image_set_indexed(image, pict->pFormat->index.devPrivate);
+
+	/* Add in drawable origin to position within the image */
+	*xoff += pict->pDrawable->x;
+	*yoff += pict->pDrawable->y;
+
+	return image;
+}
+
+static pixman_image_t *image_from_pict_internal(PicturePtr pict, Bool has_clip,
+                                                int *xoff, int *yoff,
+                                                Bool is_alpha_map);
+
+static void
+set_image_properties(pixman_image_t * image, PicturePtr pict, Bool has_clip,
+                     int *xoff, int *yoff, Bool is_alpha_map)
+{
+	pixman_repeat_t repeat;
+	pixman_filter_t filter;
+
+	if (pict->transform) {
+		/* For source images, adjust the transform to account
+		 * for the drawable offset within the pixman image,
+		 * then set the offset to 0 as it will be used
+		 * to compute positions within the transformed image.
+		 */
+		if (!has_clip) {
+			struct pixman_transform adjusted;
+
+			adjusted = *pict->transform;
+			pixman_transform_translate(&adjusted,
+						   NULL,
+						   pixman_int_to_fixed(*xoff),
+						   pixman_int_to_fixed(*yoff));
+			pixman_image_set_transform(image, &adjusted);
+			*xoff = 0;
+			*yoff = 0;
+		}
+		else
+			pixman_image_set_transform(image, pict->transform);
+	}
+
+	switch (pict->repeatType) {
+	default:
+	case RepeatNone:
+		repeat = PIXMAN_REPEAT_NONE;
+		break;
+
+	case RepeatPad:
+		repeat = PIXMAN_REPEAT_PAD;
+		break;
+
+	case RepeatNormal:
+		repeat = PIXMAN_REPEAT_NORMAL;
+		break;
+
+	case RepeatReflect:
+		repeat = PIXMAN_REPEAT_REFLECT;
+		break;
+	}
+
+	pixman_image_set_repeat(image, repeat);
+
+	/* Fetch alpha map unless 'pict' is being used
+	 * as the alpha map for this operation
+	 */
+	if (pict->alphaMap && !is_alpha_map) {
+		int alpha_xoff, alpha_yoff;
+		pixman_image_t *alpha_map =
+			image_from_pict_internal(pict->alphaMap, FALSE, &alpha_xoff,
+						 &alpha_yoff, TRUE);
+
+		pixman_image_set_alpha_map(image, alpha_map, pict->alphaOrigin.x,
+					   pict->alphaOrigin.y);
+
+		free_pixman_pict(pict->alphaMap, alpha_map);
+	}
+
+	pixman_image_set_component_alpha(image, pict->componentAlpha);
+
+	switch (pict->filter) {
+	default:
+	case PictFilterNearest:
+	case PictFilterFast:
+		filter = PIXMAN_FILTER_NEAREST;
+		break;
+
+	case PictFilterBilinear:
+	case PictFilterGood:
+		filter = PIXMAN_FILTER_BILINEAR;
+		break;
+
+	case PictFilterConvolution:
+		filter = PIXMAN_FILTER_CONVOLUTION;
+		break;
+	}
+
+	pixman_image_set_filter(image, filter,
+				(pixman_fixed_t *) pict->filter_params,
+				pict->filter_nparams);
+	pixman_image_set_source_clipping(image, TRUE);
+}
+
+static pixman_image_t *
+image_from_pict_internal(PicturePtr pict, Bool has_clip, int *xoff, int *yoff,
+                         Bool is_alpha_map)
+{
+	pixman_image_t *image = NULL;
+
+	if (!pict)
+		return NULL;
+
+	if (pict->pDrawable) {
+		image = create_bits_picture(pict, has_clip, xoff, yoff);
+	}
+	else if (pict->pSourcePict) {
+		SourcePict *sp = pict->pSourcePict;
+
+		if (sp->type == SourcePictTypeSolidFill) {
+			image = create_solid_fill_image(pict);
+		}
+		else {
+			PictGradient *gradient = &pict->pSourcePict->gradient;
+
+			if (sp->type == SourcePictTypeLinear)
+				image = create_linear_gradient_image(gradient);
+			else if (sp->type == SourcePictTypeRadial)
+				image = create_radial_gradient_image(gradient);
+			else if (sp->type == SourcePictTypeConical)
+				image = create_conical_gradient_image(gradient);
+		}
+		*xoff = *yoff = 0;
+	}
+
+	if (image)
+		set_image_properties(image, pict, has_clip, xoff, yoff, is_alpha_map);
+
+	return image;
+}
+
+pixman_image_t *
+image_from_pict(PicturePtr pict, Bool has_clip, int *xoff, int *yoff)
+{
+	return image_from_pict_internal(pict, has_clip, xoff, yoff, FALSE);
+}
+
+void
+free_pixman_pict(PicturePtr pict, pixman_image_t * image)
+{
+	if (image)
+                pixman_image_unref(image);
+}
diff --git a/src/sna/fb/fbpict.h b/src/sna/fb/fbpict.h
new file mode 100644
index 0000000..6bcee34
--- /dev/null
+++ b/src/sna/fb/fbpict.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef FBPICT_H
+#define FBPICT_H
+
+extern void
+fbComposite(CARD8 op,
+            PicturePtr pSrc,
+            PicturePtr pMask,
+            PicturePtr pDst,
+            INT16 xSrc,
+            INT16 ySrc,
+            INT16 xMask,
+            INT16 yMask, INT16 xDst, INT16 yDst, CARD16 width, CARD16 height);
+
+extern pixman_image_t *image_from_pict(PicturePtr pict,
+				       Bool has_clip,
+				       int *xoff, int *yoff);
+
+extern void free_pixman_pict(PicturePtr, pixman_image_t *);
+
+#endif  /* FBPICT_H */
diff --git a/src/sna/fb/fbpoint.c b/src/sna/fb/fbpoint.c
new file mode 100644
index 0000000..d3f796e
--- /dev/null
+++ b/src/sna/fb/fbpoint.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fb.h"
+#include <micoord.h>
+
+#define DOTS	    fbDots8
+#define BITS	    BYTE
+#define BITS2	    CARD16
+#define BITS4	    CARD32
+#include "fbpointbits.h"
+#undef BITS
+#undef BITS2
+#undef BITS4
+#undef DOTS
+
+#define DOTS	    fbDots16
+#define BITS	    CARD16
+#define BITS2	    CARD32
+#include "fbpointbits.h"
+#undef BITS
+#undef BITS2
+#undef DOTS
+
+#define DOTS	    fbDots32
+#define BITS	    CARD32
+#include "fbpointbits.h"
+#undef ARC
+#undef BITS
+#undef DOTS
+
+static void
+fbDots(FbBits *dstOrig, FbStride dstStride, int dstBpp,
+       RegionPtr clip,
+       xPoint *pts, int n,
+       int xorg, int yorg,
+       int xoff, int yoff,
+       FbBits andOrig, FbBits xorOrig)
+{
+	FbStip *dst = (FbStip *) dstOrig;
+	FbStip and = andOrig;
+	FbStip xor = xorOrig;
+
+	while (n--) {
+		int x = pts->x + xorg;
+		int y = pts->y + yorg;
+		pts++;
+		if (RegionContainsPoint(clip, x, y, NULL)) {
+			FbStip mask;
+			FbStip *d;
+
+			x = (x + xoff) * dstBpp;
+			d = dst + ((y + yoff) * dstStride) + (x >> FB_STIP_SHIFT);
+			x &= FB_STIP_MASK;
+
+			mask = FbStipMask(x, dstBpp);
+			WRITE(d, FbDoMaskRRop(READ(d), and, xor, mask));
+		}
+	}
+}
+
+void
+fbPolyPoint(DrawablePtr drawable, GCPtr gc,
+	    int mode, int n, xPoint *pt)
+{
+	FbBits *dst;
+	FbStride dstStride;
+	int dstBpp;
+	int dstXoff, dstYoff;
+	void (*dots)(FbBits *dst, FbStride dstStride, int dstBpp,
+		     RegionPtr clip,
+		     xPoint *pts, int n,
+		     int xorg, int yorg,
+		     int xoff, int yoff,
+		     FbBits and, FbBits xor);
+	FbBits and, xor;
+
+	DBG(("%s x %d\n", __FUNCTION__, n));
+
+	if (mode == CoordModePrevious)
+		fbFixCoordModePrevious(n, pt);
+
+	fbGetDrawable(drawable, dst, dstStride, dstBpp, dstXoff, dstYoff);
+	and = fb_gc(gc)->and;
+	xor = fb_gc(gc)->xor;
+	dots = fbDots;
+	switch (dstBpp) {
+	case 8:
+		dots = fbDots8;
+		break;
+	case 16:
+		dots = fbDots16;
+		break;
+	case 32:
+		dots = fbDots32;
+		break;
+	}
+	dots(dst, dstStride, dstBpp, gc->pCompositeClip, pt, n,
+	     drawable->x, drawable->y, dstXoff, dstYoff, and, xor);
+}
diff --git a/src/sna/fb/fbpointbits.h b/src/sna/fb/fbpointbits.h
new file mode 100644
index 0000000..40a25c6
--- /dev/null
+++ b/src/sna/fb/fbpointbits.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define RROP(b,a,x) WRITE((b), FbDoRRop (READ(b), (a), (x)))
+#define isClipped(c,ul,lr)  (((c) | ((c) - (ul)) | ((lr) - (c))) & 0x80008000)
+
+static void
+DOTS(FbBits * dst,
+     FbStride dstStride,
+     int dstBpp,
+     RegionPtr region,
+     xPoint * ptsOrig,
+     int npt, int xorg, int yorg, int xoff, int yoff, FbBits and, FbBits xor)
+{
+	uint32_t *pts = (uint32_t *) ptsOrig;
+	BITS *bits = (BITS *) dst;
+	BITS bxor = (BITS) xor;
+	BITS band = (BITS) and;
+	FbStride bitsStride = dstStride * (sizeof(FbBits) / sizeof(BITS));
+
+	bits += bitsStride * (yorg + yoff) + (xorg + xoff);
+
+	if (region->data == NULL) {
+		INT32 ul = coordToInt(region->extents.x1 - xorg,
+				      region->extents.y1 - yorg);
+		INT32 lr = coordToInt(region->extents.x2 - xorg - 1,
+				      region->extents.y2 - yorg - 1);
+
+		if (and == 0) {
+			while (npt >= 2) {
+				union {
+					uint32_t pt32[2];
+					uint64_t pt64;
+				} pt;
+				pt.pt64 = *(uint64_t *)pts;
+				if (!isClipped(pt.pt32[0], ul, lr)) {
+					BITS *point = bits + intToY(pt.pt32[0]) * bitsStride + intToX(pt.pt32[0]);
+					WRITE(point, bxor);
+				}
+				if (!isClipped(pt.pt32[1], ul, lr)) {
+					BITS *point = bits + intToY(pt.pt32[1]) * bitsStride + intToX(pt.pt32[1]);
+					WRITE(point, bxor);
+				}
+
+				pts += 2;
+				npt -= 2;
+			}
+			if (npt) {
+				uint32_t pt = *pts;
+				if (!isClipped(pt, ul, lr)) {
+					BITS *point = bits + intToY(pt) * bitsStride + intToX(pt);
+					WRITE(point, bxor);
+				}
+			}
+		} else {
+			while (npt--) {
+				uint32_t pt = *pts++;
+				if (!isClipped(pt, ul, lr)) {
+					BITS *point = bits + intToY(pt) * bitsStride + intToX(pt);
+					RROP(point, band, bxor);
+				}
+			}
+		}
+	} else {
+		if (and == 0) {
+			while (npt--) {
+				uint32_t pt = *pts++;
+				if (RegionContainsPoint(region,
+							intToX(pt), intToY(pt),
+							NULL)) {
+					BITS *point = bits + intToY(pt) * bitsStride + intToX(pt);
+					WRITE(point, bxor);
+				}
+			}
+		} else {
+			while (npt--) {
+				uint32_t pt = *pts++;
+				if (RegionContainsPoint(region,
+							intToX(pt), intToY(pt),
+							NULL)) {
+					BITS *point = bits + intToY(pt) * bitsStride + intToX(pt);
+					RROP(point, band, bxor);
+				}
+			}
+		}
+	}
+}
+
+#undef RROP
+#undef isClipped
diff --git a/src/sna/fb/fbpush.c b/src/sna/fb/fbpush.c
new file mode 100644
index 0000000..c53f0ad
--- /dev/null
+++ b/src/sna/fb/fbpush.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fb.h"
+#include "fbclip.h"
+
+static void
+fbPushPattern(DrawablePtr drawable, GCPtr gc,
+              FbStip *src, FbStride srcStride, int srcX,
+	      int x, int y, int width, int height)
+{
+	FbStip *s, bitsMask, bitsMask0, bits;
+	int xspan;
+	int w;
+	int lenspan;
+
+	src += srcX >> FB_STIP_SHIFT;
+	srcX &= FB_STIP_MASK;
+
+	bitsMask0 = FbStipMask(srcX, 1);
+
+	while (height--) {
+		bitsMask = bitsMask0;
+		w = width;
+		s = src;
+		src += srcStride;
+		bits = READ(s++);
+		xspan = x;
+		while (w) {
+			if (bits & bitsMask) {
+				lenspan = 0;
+				do {
+					if (++lenspan == w)
+						break;
+
+					bitsMask = FbStipRight(bitsMask, 1);
+					if (!bitsMask) {
+						bits = READ(s++);
+						bitsMask = FbBitsMask(0, 1);
+					}
+				} while (bits & bitsMask);
+				fbFill(drawable, gc, xspan, y, lenspan, 1);
+				xspan += lenspan;
+				w -= lenspan;
+			} else {
+				do {
+					xspan++;
+					if (!--w)
+						break;
+
+					bitsMask = FbStipRight(bitsMask, 1);
+					if (!bitsMask) {
+						bits = READ(s++);
+						bitsMask = FbBitsMask(0, 1);
+					}
+				} while (!(bits & bitsMask));
+			}
+		}
+		y++;
+	}
+}
+
+static void
+fbPushFill(DrawablePtr drawable, GCPtr gc,
+           FbStip *src, FbStride srcStride, int srcX,
+	   int x, int y, int width, int height)
+{
+	FbGCPrivPtr pgc = fb_gc(gc);
+
+	if (gc->fillStyle == FillSolid) {
+		FbBits *dst;
+		FbStride dstStride;
+		int dstBpp;
+		int dstXoff, dstYoff;
+		int dstX;
+		int dstWidth;
+
+		fbGetDrawable(drawable, dst,
+			      dstStride, dstBpp, dstXoff, dstYoff);
+		dst = dst + (y + dstYoff) * dstStride;
+		dstX = (x + dstXoff) * dstBpp;
+		dstWidth = width * dstBpp;
+		if (dstBpp == 1) {
+			fbBltStip(src, srcStride, srcX,
+				  (FbStip *)dst, dstStride, dstX,
+				  dstWidth, height,
+				  FbStipple1Rop(gc->alu, gc->fgPixel), pgc->pm, dstBpp);
+		} else {
+			fbBltOne(src, srcStride, srcX,
+				 dst, dstStride, dstX, dstBpp,
+				 dstWidth, height,
+				 pgc->and, pgc->xor,
+				 fbAnd(GXnoop, (FbBits) 0, FB_ALLONES),
+				 fbXor(GXnoop, (FbBits) 0, FB_ALLONES));
+		}
+	} else
+		fbPushPattern(drawable, gc, src, srcStride, srcX,
+			      x, y, width, height);
+}
+
+struct fbPushImage {
+	FbStip *src;
+	FbStride stride;
+	int x0, y0;
+};
+
+inline static void
+_fbPushImage(DrawablePtr drawable, GCPtr gc, const BoxRec *b, void *_data)
+{
+	struct fbPushImage *data = _data;
+
+	fbPushFill(drawable, gc,
+		   data->src + (b->y1 - data->y0) * data->stride, data->stride,
+		   b->x1 - data->x0,
+		   b->x1, b->y1,
+		   b->x2 - b->x1, b->y2 - b->y1);
+}
+
+void
+fbPushImage(DrawablePtr drawable, GCPtr gc,
+            FbStip *src, FbStride stride, int dx,
+	    int x, int y, int width, int height)
+{
+	struct fbPushImage data;
+	BoxRec box;
+
+	DBG(("%s (%d, %d)x(%d, %d)", __FUNCTION__, x, y, width, height));
+
+	data.src = src;
+	data.stride = stride;
+	data.y0 = y;
+	data.x0 = x - dx;
+
+	box.x1 = x;
+	box.y1 = y;
+	box.x2 = x + width;
+	box.y2 = y + height;
+	fbDrawableRun(drawable, gc, &box, _fbPushImage, &data);
+}
+
+void
+fbPushPixels(GCPtr gc, PixmapPtr bitmap, DrawablePtr drawable,
+	     int dx, int dy, int xOrg, int yOrg)
+{
+	FbStip *stip;
+	FbStride stipStride;
+	int stipBpp;
+	_X_UNUSED int stipXoff, stipYoff;
+
+	DBG(("%s bitmap=%x%d\n", __FUNCTION__,
+	     bitmap->drawable.width, bitmap->drawable.height));
+
+	fbGetStipDrawable(&bitmap->drawable, stip,
+			  stipStride, stipBpp, stipXoff, stipYoff);
+
+	fbPushImage(drawable, gc, stip, stipStride, 0, xOrg, yOrg, dx, dy);
+}
diff --git a/src/sna/fb/fbrop.h b/src/sna/fb/fbrop.h
new file mode 100644
index 0000000..9eb1fc3
--- /dev/null
+++ b/src/sna/fb/fbrop.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FBROP_H_
+#define _FBROP_H_
+
+#define FbDestInvarientRop(alu,pm)  ((pm) == FB_ALLONES && \
+				     (((alu) >> 1 & 5) == ((alu) & 5)))
+
+#define FbDestInvarientMergeRop()   (_ca1 == 0 && _cx1 == 0)
+
+/* AND has higher precedence than XOR */
+
+#define FbDoMergeRop(src, dst) \
+    (((dst) & (((src) & _ca1) ^ _cx1)) ^ (((src) & _ca2) ^ _cx2))
+
+#define FbDoDestInvarientMergeRop(src)	(((src) & _ca2) ^ _cx2)
+
+#define FbDoMaskMergeRop(src, dst, mask) \
+    (((dst) & ((((src) & _ca1) ^ _cx1) | ~(mask))) ^ ((((src) & _ca2) ^ _cx2) & (mask)))
+
+#define FbDoLeftMaskByteMergeRop(dst, src, lb, l) { \
+    FbBits  __xor = ((src) & _ca2) ^ _cx2; \
+    FbDoLeftMaskByteRRop(dst,lb,l,((src) & _ca1) ^ _cx1,__xor); \
+}
+
+#define FbDoRightMaskByteMergeRop(dst, src, rb, r) { \
+    FbBits  __xor = ((src) & _ca2) ^ _cx2; \
+    FbDoRightMaskByteRRop(dst,rb,r,((src) & _ca1) ^ _cx1,__xor); \
+}
+
+#define FbDoRRop(dst, and, xor)	(((dst) & (and)) ^ (xor))
+
+#define FbDoMaskRRop(dst, and, xor, mask) \
+    (((dst) & ((and) | ~(mask))) ^ (xor & mask))
+
+/*
+ * Take a single bit (0 or 1) and generate a full mask
+ */
+#define fbFillFromBit(b,t)	(~((t) ((b) & 1)-1))
+
+#define fbXorT(rop,fg,pm,t) ((((fg) & fbFillFromBit((rop) >> 1,t)) | \
+			      (~(fg) & fbFillFromBit((rop) >> 3,t))) & (pm))
+
+#define fbAndT(rop,fg,pm,t) ((((fg) & fbFillFromBit (rop ^ (rop>>1),t)) | \
+			      (~(fg) & fbFillFromBit((rop>>2) ^ (rop>>3),t))) | \
+			     ~(pm))
+
+#define fbXor(rop,fg,pm)	fbXorT(rop,fg,pm,FbBits)
+
+#define fbAnd(rop,fg,pm)	fbAndT(rop,fg,pm,FbBits)
+
+#define fbXorStip(rop,fg,pm)    fbXorT(rop,fg,pm,FbStip)
+
+#define fbAndStip(rop,fg,pm)	fbAndT(rop,fg,pm,FbStip)
+
+/*
+ * Stippling operations; 
+ */
+extern const FbBits *const fbStippleTable[];
+
+#define FbStippleRRop(dst, b, fa, fx, ba, bx) \
+    (FbDoRRop(dst, fa, fx) & b) | (FbDoRRop(dst, ba, bx) & ~b)
+
+#define FbStippleRRopMask(dst, b, fa, fx, ba, bx, m) \
+    (FbDoMaskRRop(dst, fa, fx, m) & (b)) | (FbDoMaskRRop(dst, ba, bx, m) & ~(b))
+
+#define FbDoLeftMaskByteStippleRRop(dst, b, fa, fx, ba, bx, lb, l) { \
+    FbBits  __xor = ((fx) & (b)) | ((bx) & ~(b)); \
+    FbDoLeftMaskByteRRop(dst, lb, l, ((fa) & (b)) | ((ba) & ~(b)), __xor); \
+}
+
+#define FbDoRightMaskByteStippleRRop(dst, b, fa, fx, ba, bx, rb, r) { \
+    FbBits  __xor = ((fx) & (b)) | ((bx) & ~(b)); \
+    FbDoRightMaskByteRRop(dst, rb, r, ((fa) & (b)) | ((ba) & ~(b)), __xor); \
+}
+
+#define FbOpaqueStipple(b, fg, bg) (((fg) & (b)) | ((bg) & ~(b)))
+
+/*
+ * Compute rop for using tile code for 1-bit dest stipples; modifies
+ * existing rop to flip depending on pixel values
+ */
+#define FbStipple1RopPick(alu,b)    (((alu) >> (2 - (((b) & 1) << 1))) & 3)
+
+#define FbOpaqueStipple1Rop(alu,fg,bg)    (FbStipple1RopPick(alu,fg) | \
+					   (FbStipple1RopPick(alu,bg) << 2))
+
+#define FbStipple1Rop(alu,fg)	    (FbStipple1RopPick(alu,fg) | 4)
+
+#endif
diff --git a/src/sna/fb/fbseg.c b/src/sna/fb/fbseg.c
new file mode 100644
index 0000000..5b8173f
--- /dev/null
+++ b/src/sna/fb/fbseg.c
@@ -0,0 +1,563 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+
+#include "fb.h"
+#include "fbclip.h"
+#include <mi.h>
+#include <miline.h>
+#include <scrnintstr.h>
+
+#define FbDashDeclare	\
+    unsigned char	*__dash, *__firstDash, *__lastDash
+
+#define FbDashInit(gc,pgc,dashOffset,dashlen,even) {	    \
+    (even) = TRUE;					    \
+    __firstDash = (gc)->dash;				    \
+    __lastDash = __firstDash + (gc)->numInDashList;	    \
+    (dashOffset) %= (pgc)->dashLength;		    \
+							    \
+    __dash = __firstDash;				    \
+    while ((dashOffset) >= ((dashlen) = *__dash)) {	    \
+	(dashOffset) -= (dashlen);			    \
+	(even) = 1-(even);				    \
+	if (++__dash == __lastDash)			    \
+	    __dash = __firstDash;			    \
+    }							    \
+    (dashlen) -= (dashOffset);				    \
+}
+
+#define FbDashNext(dashlen) {				    \
+    if (++__dash == __lastDash)				    \
+	__dash = __firstDash;				    \
+    (dashlen) = *__dash;				    \
+}
+
+/* as numInDashList is always even, this case can skip a test */
+
+#define FbDashNextEven(dashlen) {			    \
+    (dashlen) = *++__dash;				    \
+}
+
+#define FbDashNextOdd(dashlen)	FbDashNext(dashlen)
+
+#define FbDashStep(dashlen,even) {			    \
+    if (!--(dashlen)) {					    \
+	FbDashNext(dashlen);				    \
+	(even) = 1-(even);				    \
+    }							    \
+}
+
+#define fbBresShiftMask(mask,dir,bpp) ((bpp == FB_STIP_UNIT) ? 0 : \
+					((dir < 0) ? FbStipLeft(mask,bpp) : \
+					 FbStipRight(mask,bpp)))
+
+typedef void FbBres(DrawablePtr drawable,
+                    GCPtr gc,
+                    int dashOffset,
+                    int sdx,
+                    int sdy,
+                    int axis, int x, int y, int e, int e1, int e3, int len);
+
+#define BRESSOLID   fbBresSolid8
+#define BRESSOLIDR  fbBresSolidR8
+#define BRESDASH    fbBresDash8
+#define BITS	    BYTE
+#define BITS2	    CARD16
+#define BITS4	    CARD32
+#include "fbsegbits.h"
+#undef BRESSOLID
+#undef BRESSOLIDR
+#undef BRESDASH
+#undef BITS
+#undef BITS2
+#undef BITS4
+
+#define BRESSOLID   fbBresSolid16
+#define BRESSOLIDR  fbBresSolidR16
+#define BRESDASH    fbBresDash16
+#define BITS	    CARD16
+#define BITS2	    CARD32
+#include "fbsegbits.h"
+#undef BRESSOLID
+#undef BRESSOLIDR
+#undef BRESDASH
+#undef BITS
+#undef BITS2
+
+#define BRESSOLID   fbBresSolid32
+#define BRESSOLIDR  fbBresSolidR32
+#define BRESDASH    fbBresDash32
+#define BITS	    CARD32
+#include "fbsegbits.h"
+#undef BRESSOLID
+#undef BRESSOLIDR
+#undef BRESDASH
+#undef BITS
+
+static void
+fbBresSolid(DrawablePtr drawable, GCPtr gc, int dashOffset,
+            int sdx, int sdy, int axis,
+	    int x1, int y1,
+	    int e, int e1, int e3, int len)
+{
+	FbStip *dst;
+	FbStride stride;
+	int bpp;
+	int dx, dy;
+	FbGCPrivPtr pgc = fb_gc(gc);
+	FbStip and = (FbStip) pgc->and;
+	FbStip xor = (FbStip) pgc->xor;
+	FbStip mask, mask0;
+	FbStip bits;
+
+	fbGetStipDrawable(drawable, dst, stride, bpp, dx, dy);
+	dst += ((y1 + dy) * stride);
+	x1 = (x1 + dx) * bpp;
+	dst += x1 >> FB_STIP_SHIFT;
+	x1 &= FB_STIP_MASK;
+	mask0 = FbStipMask(0, bpp);
+	mask = FbStipRight(mask0, x1);
+	if (sdx < 0)
+		mask0 = FbStipRight(mask0, FB_STIP_UNIT - bpp);
+	if (sdy < 0)
+		stride = -stride;
+	if (axis == X_AXIS) {
+		bits = 0;
+		while (len--) {
+			bits |= mask;
+			mask = fbBresShiftMask(mask, sdx, bpp);
+			if (!mask) {
+				WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, bits));
+				bits = 0;
+				dst += sdx;
+				mask = mask0;
+			}
+			e += e1;
+			if (e >= 0) {
+				WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, bits));
+				bits = 0;
+				dst += stride;
+				e += e3;
+			}
+		}
+		if (bits)
+			WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, bits));
+	} else {
+		while (len--) {
+			WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, mask));
+			dst += stride;
+			e += e1;
+			if (e >= 0) {
+				e += e3;
+				mask = fbBresShiftMask(mask, sdx, bpp);
+				if (!mask) {
+					dst += sdx;
+					mask = mask0;
+				}
+			}
+		}
+	}
+}
+
+static void
+fbBresDash(DrawablePtr drawable, GCPtr gc, int dashOffset,
+           int sdx, int sdy, int axis,
+	   int x1, int y1,
+	   int e, int e1, int e3, int len)
+{
+	FbStip *dst;
+	FbStride stride;
+	int bpp;
+	int dx, dy;
+	FbGCPrivPtr pgc = fb_gc(gc);
+	FbStip and = (FbStip) pgc->and;
+	FbStip xor = (FbStip) pgc->xor;
+	FbStip bgand = (FbStip) pgc->bgand;
+	FbStip bgxor = (FbStip) pgc->bgxor;
+	FbStip mask, mask0;
+
+	FbDashDeclare;
+	int dashlen;
+	bool even;
+	bool doOdd;
+
+	fbGetStipDrawable(drawable, dst, stride, bpp, dx, dy);
+	doOdd = gc->lineStyle == LineDoubleDash;
+
+	FbDashInit(gc, pgc, dashOffset, dashlen, even);
+
+	dst += ((y1 + dy) * stride);
+	x1 = (x1 + dx) * bpp;
+	dst += x1 >> FB_STIP_SHIFT;
+	x1 &= FB_STIP_MASK;
+	mask0 = FbStipMask(0, bpp);
+	mask = FbStipRight(mask0, x1);
+	if (sdx < 0)
+		mask0 = FbStipRight(mask0, FB_STIP_UNIT - bpp);
+	if (sdy < 0)
+		stride = -stride;
+	while (len--) {
+		if (even)
+			WRITE(dst, FbDoMaskRRop(READ(dst), and, xor, mask));
+		else if (doOdd)
+			WRITE(dst, FbDoMaskRRop(READ(dst), bgand, bgxor, mask));
+		if (axis == X_AXIS) {
+			mask = fbBresShiftMask(mask, sdx, bpp);
+			if (!mask) {
+				dst += sdx;
+				mask = mask0;
+			}
+			e += e1;
+			if (e >= 0) {
+				dst += stride;
+				e += e3;
+			}
+		} else {
+			dst += stride;
+			e += e1;
+			if (e >= 0) {
+				e += e3;
+				mask = fbBresShiftMask(mask, sdx, bpp);
+				if (!mask) {
+					dst += sdx;
+					mask = mask0;
+				}
+			}
+		}
+		FbDashStep(dashlen, even);
+	}
+}
+
+static void
+fbBresFill(DrawablePtr drawable, GCPtr gc, int dashOffset,
+           int sdx, int sdy, int axis,
+	   int x1, int y1,
+	   int e, int e1, int e3, int len)
+{
+	while (len--) {
+		fbFill(drawable, gc, x1, y1, 1, 1);
+		if (axis == X_AXIS) {
+			x1 += sdx;
+			e += e1;
+			if (e >= 0) {
+				e += e3;
+				y1 += sdy;
+			}
+		} else {
+			y1 += sdy;
+			e += e1;
+			if (e >= 0) {
+				e += e3;
+				x1 += sdx;
+			}
+		}
+	}
+}
+
+static void
+fbSetFg(DrawablePtr drawable, GCPtr gc, Pixel fg)
+{
+	if (fg != gc->fgPixel) {
+		gc->fgPixel = fg;
+		fbValidateGC(gc, GCForeground, drawable);
+	}
+}
+
+static void
+fbBresFillDash(DrawablePtr drawable,
+               GCPtr gc,
+               int dashOffset,
+               int sdx,
+               int sdy,
+               int axis, int x1, int y1, int e, int e1, int e3, int len)
+{
+	FbGCPrivPtr pgc = fb_gc(gc);
+
+	FbDashDeclare;
+	int dashlen;
+	bool even;
+	bool doOdd;
+	bool doBg;
+	Pixel fg, bg;
+
+	fg = gc->fgPixel;
+	bg = gc->bgPixel;
+
+	/* whether to fill the odd dashes */
+	doOdd = gc->lineStyle == LineDoubleDash;
+	/* whether to switch fg to bg when filling odd dashes */
+	doBg = doOdd && (gc->fillStyle == FillSolid ||
+			 gc->fillStyle == FillStippled);
+
+	/* compute current dash position */
+	FbDashInit(gc, pgc, dashOffset, dashlen, even);
+
+	while (len--) {
+		if (even || doOdd) {
+			if (doBg) {
+				if (even)
+					fbSetFg(drawable, gc, fg);
+				else
+					fbSetFg(drawable, gc, bg);
+			}
+			fbFill(drawable, gc, x1, y1, 1, 1);
+		}
+		if (axis == X_AXIS) {
+			x1 += sdx;
+			e += e1;
+			if (e >= 0) {
+				e += e3;
+				y1 += sdy;
+			}
+		} else {
+			y1 += sdy;
+			e += e1;
+			if (e >= 0) {
+				e += e3;
+				x1 += sdx;
+			}
+		}
+		FbDashStep(dashlen, even);
+	}
+	if (doBg)
+		fbSetFg(drawable, gc, fg);
+}
+
+static FbBres *
+fbSelectBres(DrawablePtr drawable, GCPtr gc)
+{
+	FbGCPrivPtr pgc = fb_gc(gc);
+	int bpp = drawable->bitsPerPixel;
+	FbBres *bres;
+
+	DBG(("%s: line=%d, fill=%d, and=%lx, bgand=%lx\n",
+	     __FUNCTION__, gc->lineStyle, gc->fillStyle, pgc->and, pgc->bgand));
+	assert(gc->lineWidth == 0);
+
+	if (gc->lineStyle == LineSolid) {
+		bres = fbBresFill;
+		if (gc->fillStyle == FillSolid) {
+			bres = fbBresSolid;
+			if (pgc->and == 0) {
+				switch (bpp) {
+				case 8:
+					bres = fbBresSolid8;
+					break;
+				case 16:
+					bres = fbBresSolid16;
+					break;
+				case 32:
+					bres = fbBresSolid32;
+					break;
+				}
+			} else {
+				switch (bpp) {
+				case 8:
+					bres = fbBresSolidR8;
+					break;
+				case 16:
+					bres = fbBresSolidR16;
+					break;
+				case 32:
+					bres = fbBresSolidR32;
+					break;
+				}
+			}
+		}
+	} else {
+		bres = fbBresFillDash;
+		if (gc->fillStyle == FillSolid) {
+			bres = fbBresDash;
+			if (pgc->and == 0 &&
+			    (gc->lineStyle == LineOnOffDash || pgc->bgand == 0)) {
+				switch (bpp) {
+				case 8:
+					bres = fbBresDash8;
+					break;
+				case 16:
+					bres = fbBresDash16;
+					break;
+				case 32:
+					bres = fbBresDash32;
+					break;
+				}
+			}
+		}
+	}
+	return bres;
+}
+
+struct fbSegment {
+	FbBres *bres;
+	bool drawLast;
+	int *dashOffset;
+	int x1, y1, x2, y2;
+};
+
+static void
+_fbSegment(DrawablePtr drawable, GCPtr gc, const BoxRec *b, void *_data)
+{
+	struct fbSegment *data = _data;
+	const unsigned int bias = miGetZeroLineBias(drawable->pScreen);
+	int adx, ady;               /* abs values of dx and dy */
+	int sdx, sdy;               /* sign of dx and dy */
+	int e, e1, e2, e3;          /* bresenham error and increments */
+	int len, axis, octant;
+	int dashoff, doff;
+	unsigned int oc1, oc2;
+
+	DBG(("%s box=(%d, %d),(%d, %d)\n",
+	     __FUNCTION__, b->x1, b->y1, b->x2, b->y2));
+
+	CalcLineDeltas(data->x1, data->y1, data->x2, data->y2,
+		       adx, ady, sdx, sdy, 1, 1, octant);
+
+	if (adx > ady) {
+		axis = X_AXIS;
+		e1 = ady << 1;
+		e2 = e1 - (adx << 1);
+		e = e1 - adx;
+		len = adx;
+	} else {
+		axis = Y_AXIS;
+		e1 = adx << 1;
+		e2 = e1 - (ady << 1);
+		e = e1 - ady;
+		SetYMajorOctant(octant);
+		len = ady;
+	}
+
+	FIXUP_ERROR(e, octant, bias);
+
+	/*
+	 * Adjust error terms to compare against zero
+	 */
+	e3 = e2 - e1;
+	e = e - e1;
+
+	if (data->drawLast)
+		len++;
+	dashoff = *data->dashOffset;
+	*data->dashOffset = dashoff + len;
+
+	oc1 = 0;
+	oc2 = 0;
+	OUTCODES(oc1, data->x1, data->y1, b);
+	OUTCODES(oc2, data->x2, data->y2, b);
+	if ((oc1 | oc2) == 0) {
+		data->bres(drawable, gc, dashoff,
+			   sdx, sdy, axis, data->x1, data->y1, e, e1, e3, len);
+	} else if (oc1 & oc2) {
+	} else {
+		int new_x1 = data->x1, new_y1 = data->y1;
+		int new_x2 = data->x2, new_y2 = data->y2;
+		int clip1 = 0, clip2 = 0;
+		int clipdx, clipdy;
+		int err;
+
+		if (miZeroClipLine(b->x1, b->y1, b->x2-1, b->y2-1,
+				   &new_x1, &new_y1, &new_x2, &new_y2,
+				   adx, ady, &clip1, &clip2,
+				   octant, bias, oc1, oc2) == -1)
+			return;
+
+		if (axis == X_AXIS)
+			len = abs(new_x2 - new_x1);
+		else
+			len = abs(new_y2 - new_y1);
+		if (clip2 != 0 || data->drawLast)
+			len++;
+		if (len) {
+			/* unwind bresenham error term to first point */
+			doff = dashoff;
+			err = e;
+			if (clip1) {
+				clipdx = abs(new_x1 - data->x1);
+				clipdy = abs(new_y1 - data->y1);
+				if (axis == X_AXIS) {
+					doff += clipdx;
+					err += e3 * clipdy + e1 * clipdx;
+				} else {
+					doff += clipdy;
+					err += e3 * clipdx + e1 * clipdy;
+				}
+			}
+			data->bres(drawable, gc, doff,
+				   sdx, sdy, axis, new_x1, new_y1,
+				   err, e1, e3, len);
+		}
+	}
+}
+
+void
+fbSegment(DrawablePtr drawable, GCPtr gc,
+          int x1, int y1, int x2, int y2,
+	  bool drawLast, int *dashOffset)
+{
+	struct fbSegment data;
+	BoxRec box;
+
+	DBG(("%s (%d, %d), (%d, %d), drawLast?=%d\n",
+	     __FUNCTION__, x1, y1, x2, y2, drawLast));
+
+	/* simple overestimate of line extents for clipping */
+	box.x1 = x1 - 1;
+	box.y1 = y1 - 1;
+	box.x2 = x2 + 1;
+	box.y2 = y2 + 1;
+
+	data.x1 = x1;
+	data.y1 = y1;
+	data.x2 = x2;
+	data.y2 = y2;
+
+	data.dashOffset = dashOffset;
+	data.drawLast = drawLast;
+	data.bres = fbSelectBres(drawable, gc);
+
+	fbDrawableRunUnclipped(drawable, gc, &box, _fbSegment, &data);
+}
+
+void
+fbSegment1(DrawablePtr drawable, GCPtr gc, const BoxRec *b,
+	   int x1, int y1, int x2, int y2,
+	   bool drawLast, int *dashOffset)
+{
+	struct fbSegment data;
+
+	DBG(("%s (%d, %d), (%d, %d), drawLast?=%d\n",
+	     __FUNCTION__, x1, y1, x2, y2, drawLast));
+
+	data.x1 = x1;
+	data.y1 = y1;
+	data.x2 = x2;
+	data.y2 = y2;
+
+	data.dashOffset = dashOffset;
+	data.drawLast = drawLast;
+	data.bres = fbSelectBres(drawable, gc);
+
+	_fbSegment(drawable, gc, b, &data);
+}
diff --git a/src/sna/fb/fbsegbits.h b/src/sna/fb/fbsegbits.h
new file mode 100644
index 0000000..590ad30
--- /dev/null
+++ b/src/sna/fb/fbsegbits.h
@@ -0,0 +1,212 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define isClipped(c,ul,lr)  (((c) | ((c) - (ul)) | ((lr) - (c))) & 0x80008000)
+#define RROP(b,a,x)	WRITE((b), FbDoRRop (READ(b), (a), (x)))
+
+static void
+BRESSOLID(DrawablePtr drawable, GCPtr gc, int dashOffset,
+	  int sdx, int sdy, int axis,
+	  int x1, int y1, int e, int e1, int e3, int len)
+{
+	FbBits *dst;
+	FbStride stride;
+	int bpp, dx, dy;
+	BITS *bits;
+	FbStride major, minor;
+	BITS xor = fb_gc(gc)->xor;
+
+	fbGetDrawable(drawable, dst, stride, bpp, dx, dy);
+	bits = (BITS *)(dst + (y1 + dy) * stride) + (x1 + dx);
+	stride = stride * (sizeof(FbBits) / sizeof(BITS));
+	if (sdy < 0)
+		stride = -stride;
+	if (axis == X_AXIS) {
+		major = sdx;
+		minor = stride;
+	} else {
+		major = stride;
+		minor = sdx;
+	}
+	while (len--) {
+		WRITE(bits, xor);
+		bits += major;
+		e += e1;
+		if (e >= 0) {
+			bits += minor;
+			e += e3;
+		}
+	}
+}
+
+static void
+BRESSOLIDR(DrawablePtr drawable, GCPtr gc, int dashOffset,
+	   int sdx, int sdy, int axis,
+	   int x1, int y1, int e, int e1, int e3, int len)
+{
+	FbBits *dst;
+	FbStride stride;
+	int bpp, dx, dy;
+	BITS *bits;
+	FbStride major, minor;
+	BITS and = fb_gc(gc)->and;
+	BITS xor = fb_gc(gc)->xor;
+
+	fbGetDrawable(drawable, dst, stride, bpp, dx, dy);
+	bits = (BITS *)(dst + (y1 + dy) * stride) + (x1 + dx);
+	stride = stride * (sizeof(FbBits) / sizeof(BITS));
+	if (sdy < 0)
+		stride = -stride;
+	if (axis == X_AXIS) {
+		major = sdx;
+		minor = stride;
+	} else {
+		major = stride;
+		minor = sdx;
+	}
+	while (len--) {
+		RROP(bits, and, xor);
+		bits += major;
+		e += e1;
+		if (e >= 0) {
+			bits += minor;
+			e += e3;
+		}
+	}
+}
+
+static void
+BRESDASH(DrawablePtr drawable, GCPtr gc, int dashOffset,
+	 int sdx, int sdy, int axis,
+	 int x1, int y1, int e, int e1, int e3, int len)
+{
+	FbBits *dst;
+	FbStride stride;
+	int bpp, dx, dy;
+	BITS *bits;
+	FbStride major, minor;
+
+	FbDashDeclare;
+	int dashlen;
+	bool even;
+	bool doOdd = gc->lineStyle == LineDoubleDash;
+	BITS xorfg = fb_gc(gc)->xor;
+	BITS xorbg = fb_gc(gc)->bgxor;
+
+	fbGetDrawable(drawable, dst, stride, bpp, dx, dy);
+
+	FbDashInit(gc, fb_gc(gc), dashOffset, dashlen, even);
+
+	bits = ((BITS *) (dst + ((y1 + dy) * stride))) + (x1 + dx);
+	stride = stride * (sizeof(FbBits) / sizeof(BITS));
+	if (sdy < 0)
+		stride = -stride;
+	if (axis == X_AXIS) {
+		major = sdx;
+		minor = stride;
+	} else {
+		major = stride;
+		minor = sdx;
+	}
+	if (dashlen >= len)
+		dashlen = len;
+	if (doOdd) {
+		if (!even)
+			goto doubleOdd;
+		for (;;) {
+			len -= dashlen;
+			while (dashlen--) {
+				WRITE(bits, xorfg);
+				bits += major;
+				if ((e += e1) >= 0) {
+					e += e3;
+					bits += minor;
+				}
+			}
+			if (!len)
+				break;
+
+			FbDashNextEven(dashlen);
+
+			if (dashlen >= len)
+				dashlen = len;
+doubleOdd:
+			len -= dashlen;
+			while (dashlen--) {
+				WRITE(bits, xorbg);
+				bits += major;
+				if ((e += e1) >= 0) {
+					e += e3;
+					bits += minor;
+				}
+			}
+			if (!len)
+				break;
+
+			FbDashNextOdd(dashlen);
+
+			if (dashlen >= len)
+				dashlen = len;
+		}
+	} else {
+		if (!even)
+			goto onOffOdd;
+		for (;;) {
+			len -= dashlen;
+			while (dashlen--) {
+				WRITE(bits, xorfg);
+				bits += major;
+				if ((e += e1) >= 0) {
+					e += e3;
+					bits += minor;
+				}
+			}
+			if (!len)
+				break;
+
+			FbDashNextEven(dashlen);
+
+			if (dashlen >= len)
+				dashlen = len;
+onOffOdd:
+			len -= dashlen;
+			while (dashlen--) {
+				bits += major;
+				if ((e += e1) >= 0) {
+					e += e3;
+					bits += minor;
+				}
+			}
+			if (!len)
+				break;
+
+			FbDashNextOdd(dashlen);
+
+			if (dashlen >= len)
+				dashlen = len;
+		}
+	}
+}
+
+#undef RROP
+#undef isClipped
diff --git a/src/sna/fb/fbspan.c b/src/sna/fb/fbspan.c
new file mode 100644
index 0000000..45cb7cc
--- /dev/null
+++ b/src/sna/fb/fbspan.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fb.h"
+#include "fbclip.h"
+
+inline static void
+fbFillSpan(DrawablePtr drawable, GCPtr gc, const BoxRec *b, void *data)
+{
+	DBG(("%s (%d,%d)+%d\n", __FUNCTION__, b->x1, b->y1, b->x2-b->x1));
+	fbFill(drawable, gc, b->x1, b->y1, b->x2 - b->x1, 1);
+}
+
+void
+fbFillSpans(DrawablePtr drawable, GCPtr gc,
+	    int n, DDXPointPtr pt, int *width, int fSorted)
+{
+	DBG(("%s x %d\n", __FUNCTION__, n));
+	while (n--) {
+		BoxRec box;
+
+		*(DDXPointPtr)&box = *pt++;
+		box.x2 = box.x1 + *width++;
+		box.y2 = box.y1 + 1;
+
+		/* XXX fSorted */
+		fbDrawableRun(drawable, gc, &box, fbFillSpan, NULL);
+	}
+}
+
+struct fbSetSpan {
+	char *src;
+	DDXPointRec pt;
+	FbStride stride;
+	FbBits *dst;
+	int dx, dy;
+};
+
+inline static void
+fbSetSpan(DrawablePtr drawable, GCPtr gc, const BoxRec *b, void *_data)
+{
+	struct fbSetSpan *data = _data;
+	int xoff, bpp;
+
+	xoff = (int) (((long)data->src) & (FB_MASK >> 3));
+	bpp = drawable->bitsPerPixel;
+
+	fbBlt((FbBits *)(data->src - xoff), 0,
+	      (b->x1 - data->pt.x) * bpp + (xoff << 3),
+	      data->dst + (b->y1 + data->dy) * data->stride, data->stride,
+	      (b->x1 + data->dx) * bpp,
+	      (b->x2 - b->x1) * bpp, 1,
+	      gc->alu, fb_gc(gc)->pm, bpp,
+	      FALSE, FALSE);
+}
+
+void
+fbSetSpans(DrawablePtr drawable, GCPtr gc,
+           char *src, DDXPointPtr pt, int *width, int n, int fSorted)
+{
+	struct fbSetSpan data;
+	PixmapPtr pixmap;
+
+	DBG(("%s x %d\n", __FUNCTION__, n));
+
+	fbGetDrawablePixmap(drawable, pixmap, data.dx, data.dy);
+	data.dst = pixmap->devPrivate.ptr;
+	data.stride = pixmap->devKind / sizeof(FbStip);
+
+	data.src = src;
+	while (n--) {
+		BoxRec box;
+
+		*(DDXPointPtr)&box = data.pt = *pt;
+		box.x2 = box.x1 + *width;
+		box.y2 = box.y1 + 1;
+
+		fbDrawableRun(drawable, gc, &box, fbSetSpan, &data);
+
+		data.src += PixmapBytePad(*width, drawable->depth);
+		width++;
+		pt++;
+	}
+}
+
+void
+fbGetSpans(DrawablePtr drawable, int wMax,
+           DDXPointPtr pt, int *width, int n, char *dst)
+{
+	FbBits *src, *d;
+	FbStride srcStride;
+	int srcBpp;
+	int srcXoff, srcYoff;
+	int xoff;
+
+	fbGetDrawable(drawable, src, srcStride, srcBpp, srcXoff, srcYoff);
+
+	DBG(("%s x %d\n", __FUNCTION__, n));
+	while (n--) {
+		xoff = (int) (((long) dst) & (FB_MASK >> 3));
+		d = (FbBits *) (dst - xoff);
+		fbBlt(src + (pt->y + srcYoff) * srcStride, srcStride,
+		      (pt->x + srcXoff) * srcBpp,
+		      d, 1, xoff << 3, *width * srcBpp,
+		      1, GXcopy, FB_ALLONES, srcBpp,
+		      FALSE, FALSE);
+		dst += PixmapBytePad(*width, drawable->depth);
+		pt++;
+		width++;
+	}
+}
diff --git a/src/sna/fb/fbstipple.c b/src/sna/fb/fbstipple.c
new file mode 100644
index 0000000..d02970a
--- /dev/null
+++ b/src/sna/fb/fbstipple.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fb.h"
+
+/*
+ * This is a slight abuse of the preprocessor to generate repetitive
+ * code, the idea is to generate code for each case of a copy-mode
+ * transparent stipple
+ */
+#define LaneCases1(c,a) \
+	case c: while (n--) { FbLaneCase(c,a); a++; } break
+#define LaneCases2(c,a)	    LaneCases1(c,a); LaneCases1(c+1,a)
+#define LaneCases4(c,a)	    LaneCases2(c,a); LaneCases2(c+2,a)
+#define LaneCases8(c,a)	    LaneCases4(c,a); LaneCases4(c+4,a)
+#define LaneCases16(c,a)    LaneCases8(c,a); LaneCases8(c+8,a)
+
+#define LaneCases(a)	    LaneCases16(0,a)
+
+/*
+ * Repeat a transparent stipple across a scanline n times
+ */
+
+void
+fbTransparentSpan(FbBits * dst, FbBits stip, FbBits fgxor, int n)
+{
+	FbStip s;
+
+	s = ((FbStip) (stip) & 0x01);
+	s |= ((FbStip) (stip >> 8) & 0x02);
+	s |= ((FbStip) (stip >> 16) & 0x04);
+	s |= ((FbStip) (stip >> 24) & 0x08);
+	switch (s) {
+		LaneCases(dst);
+	}
+}
+
+static void
+fbEvenStipple(FbBits *dst, FbStride dstStride, int dstX, int dstBpp,
+              int width, int height,
+              FbStip *stip, FbStride stipStride,
+              int stipHeight,
+              FbBits fgand, FbBits fgxor, FbBits bgand, FbBits bgxor,
+	      int xRot, int yRot)
+{
+	FbBits startmask, endmask;
+	FbBits mask, and, xor;
+	int nmiddle, n;
+	FbStip *s, *stipEnd, bits;
+	int rot, stipX, stipY;
+	int pixelsPerDst;
+	const FbBits *fbBits;
+	Bool transparent;
+	int startbyte, endbyte;
+
+	/*
+	 * Check for a transparent stipple (stencil)
+	 */
+	transparent = FALSE;
+	if (dstBpp >= 8 && fgand == 0 && bgand == FB_ALLONES && bgxor == 0)
+		transparent = TRUE;
+
+	pixelsPerDst = FB_UNIT / dstBpp;
+	/*
+	 * Adjust dest pointers
+	 */
+	dst += dstX >> FB_SHIFT;
+	dstX &= FB_MASK;
+	FbMaskBitsBytes(dstX, width, fgand == 0 && bgand == 0,
+			startmask, startbyte, nmiddle, endmask, endbyte);
+
+	if (startmask)
+		dstStride--;
+	dstStride -= nmiddle;
+
+	xRot *= dstBpp;
+	/*
+	 * Compute stip start scanline and rotation parameters
+	 */
+	stipEnd = stip + stipStride * stipHeight;
+	modulus(-yRot, stipHeight, stipY);
+	s = stip + stipStride * stipY;
+	modulus(-xRot, FB_UNIT, stipX);
+	rot = stipX;
+
+	/*
+	 * Get pointer to stipple mask array for this depth
+	 */
+	/* fbStippleTable covers all valid bpp (4,8,16,32) */
+	fbBits = fbStippleTable[pixelsPerDst];
+
+	while (height--) {
+		/*
+		 * Extract stipple bits for this scanline;
+		 */
+		bits = READ(s);
+		s += stipStride;
+		if (s == stipEnd)
+			s = stip;
+		mask = fbBits[FbLeftStipBits(bits, pixelsPerDst)];
+		/*
+		 * Rotate into position and compute reduced rop values
+		 */
+		mask = FbRotLeft(mask, rot);
+		and = (fgand & mask) | (bgand & ~mask);
+		xor = (fgxor & mask) | (bgxor & ~mask);
+
+		if (transparent) {
+			if (startmask) {
+				fbTransparentSpan(dst, mask & startmask, fgxor, 1);
+				dst++;
+			}
+			fbTransparentSpan(dst, mask, fgxor, nmiddle);
+			dst += nmiddle;
+			if (endmask)
+				fbTransparentSpan(dst, mask & endmask, fgxor, 1);
+		} else {
+			/*
+			 * Fill scanline
+			 */
+			if (startmask) {
+				FbDoLeftMaskByteRRop(dst, startbyte, startmask, and, xor);
+				dst++;
+			}
+			n = nmiddle;
+			if (!and)
+				while (n--)
+					WRITE(dst++, xor);
+			else {
+				while (n--) {
+					WRITE(dst, FbDoRRop(READ(dst), and, xor));
+					dst++;
+				}
+			}
+			if (endmask)
+				FbDoRightMaskByteRRop(dst, endbyte, endmask, and, xor);
+		}
+		dst += dstStride;
+	}
+}
+
+static void
+fbOddStipple(FbBits *dst, FbStride dstStride, int dstX, int dstBpp,
+             int width, int height,
+             FbStip *stip, FbStride stipStride,
+             int stipWidth, int stipHeight,
+             FbBits fgand, FbBits fgxor, FbBits bgand, FbBits bgxor,
+	     int xRot, int yRot)
+{
+	int stipX, stipY, sx;
+	int widthTmp;
+	int h, w;
+	int x, y;
+
+	modulus(-yRot, stipHeight, stipY);
+	modulus(dstX / dstBpp - xRot, stipWidth, stipX);
+	y = 0;
+	while (height) {
+		h = stipHeight - stipY;
+		if (h > height)
+			h = height;
+		height -= h;
+		widthTmp = width;
+		x = dstX;
+		sx = stipX;
+		while (widthTmp) {
+			w = (stipWidth - sx) * dstBpp;
+			if (w > widthTmp)
+				w = widthTmp;
+			widthTmp -= w;
+			fbBltOne(stip + stipY * stipStride,
+				 stipStride,
+				 sx,
+				 dst + y * dstStride,
+				 dstStride, x, dstBpp, w, h, fgand, fgxor, bgand, bgxor);
+			x += w;
+			sx = 0;
+		}
+		y += h;
+		stipY = 0;
+	}
+}
+
+void
+fbStipple(FbBits *dst, FbStride dstStride, int dstX, int dstBpp,
+          int width, int height,
+          FbStip *stip, FbStride stipStride,
+          int stipWidth, int stipHeight, Bool even,
+          FbBits fgand, FbBits fgxor, FbBits bgand, FbBits bgxor,
+	  int xRot, int yRot)
+{
+	DBG(("%s stipple=%dx%d, size=%dx%d\n",
+	     __FUNCTION__, stipWidth, stipHeight, width, height));
+
+	if (even)
+		fbEvenStipple(dst, dstStride, dstX, dstBpp, width, height,
+			      stip, stipStride, stipHeight,
+			      fgand, fgxor, bgand, bgxor, xRot, yRot);
+	else
+		fbOddStipple(dst, dstStride, dstX, dstBpp, width, height,
+			     stip, stipStride, stipWidth, stipHeight,
+			     fgand, fgxor, bgand, bgxor, xRot, yRot);
+}
diff --git a/src/sna/fb/fbtile.c b/src/sna/fb/fbtile.c
new file mode 100644
index 0000000..5586553
--- /dev/null
+++ b/src/sna/fb/fbtile.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fb.h"
+
+/*
+ * Accelerated tile fill -- tile width is a power of two not greater
+ * than FB_UNIT
+ */
+
+static void
+fbEvenTile(FbBits *dst, FbStride dstStride, int dstX, int width, int height,
+           FbBits *tile, FbStride tileStride, int tileHeight,
+	   int alu, FbBits pm,
+	   int xRot, int yRot)
+{
+	FbBits *t, *tileEnd, bits;
+	FbBits startmask, endmask;
+	FbBits and, xor;
+	int n, nmiddle;
+	int tileX, tileY;
+	int rot;
+	int startbyte, endbyte;
+
+	dst += dstX >> FB_SHIFT;
+	dstX &= FB_MASK;
+	FbMaskBitsBytes(dstX, width, FbDestInvarientRop(alu, pm),
+			startmask, startbyte, nmiddle, endmask, endbyte);
+	if (startmask)
+		dstStride--;
+	dstStride -= nmiddle;
+
+	/*
+	 * Compute tile start scanline and rotation parameters
+	 */
+	tileEnd = tile + tileHeight * tileStride;
+	modulus(-yRot, tileHeight, tileY);
+	t = tile + tileY * tileStride;
+	modulus(-xRot, FB_UNIT, tileX);
+	rot = tileX;
+
+	while (height--) {
+		/*
+		 * Pick up bits for this scanline
+		 */
+		bits = READ(t);
+		t += tileStride;
+		if (t >= tileEnd)
+			t = tile;
+		bits = FbRotLeft(bits, rot);
+		and = fbAnd(alu, bits, pm);
+		xor = fbXor(alu, bits, pm);
+
+		if (startmask) {
+			FbDoLeftMaskByteRRop(dst, startbyte, startmask, and, xor);
+			dst++;
+		}
+		n = nmiddle;
+		if (!and)
+			while (n--)
+				WRITE(dst++, xor);
+		else
+			while (n--) {
+				WRITE(dst, FbDoRRop(READ(dst), and, xor));
+				dst++;
+			}
+		if (endmask)
+			FbDoRightMaskByteRRop(dst, endbyte, endmask, and, xor);
+		dst += dstStride;
+	}
+}
+
+static void
+fbOddTile(FbBits *dst, FbStride dstStride, int dstX,
+          int width, int height,
+          FbBits *tile, FbStride tileStride,
+          int tileWidth, int tileHeight,
+	  int alu, FbBits pm, int bpp,
+	  int xRot, int yRot)
+{
+	int tileX, tileY;
+	int widthTmp;
+	int h, w;
+	int x, y;
+
+	modulus(-yRot, tileHeight, tileY);
+	y = 0;
+	while (height) {
+		h = tileHeight - tileY;
+		if (h > height)
+			h = height;
+		height -= h;
+		widthTmp = width;
+		x = dstX;
+		modulus(dstX - xRot, tileWidth, tileX);
+		while (widthTmp) {
+			w = tileWidth - tileX;
+			if (w > widthTmp)
+				w = widthTmp;
+			widthTmp -= w;
+			fbBlt(tile + tileY * tileStride,
+			      tileStride,
+			      tileX,
+			      dst + y * dstStride,
+			      dstStride, x, w, h, alu, pm, bpp, FALSE, FALSE);
+			x += w;
+			tileX = 0;
+		}
+		y += h;
+		tileY = 0;
+	}
+}
+
+void
+fbTile(FbBits *dst, FbStride dstStride, int dstX,
+       int width, int height,
+       FbBits *tile, FbStride tileStride,
+       int tileWidth, int tileHeight,
+       int alu, FbBits pm, int bpp,
+       int xRot, int yRot)
+{
+	DBG(("%s tile=%dx%d, size=%dx%d\n", __FUNCTION__,
+	     tileWidth, tileHeight, width, height));
+
+	if (FbEvenTile(tileWidth))
+		fbEvenTile(dst, dstStride, dstX, width, height,
+			   tile, tileStride, tileHeight, alu, pm, xRot, yRot);
+	else
+		fbOddTile(dst, dstStride, dstX, width, height,
+			  tile, tileStride, tileWidth, tileHeight,
+			  alu, pm, bpp, xRot, yRot);
+}
diff --git a/src/sna/fb/fbutil.c b/src/sna/fb/fbutil.c
new file mode 100644
index 0000000..61b63ad
--- /dev/null
+++ b/src/sna/fb/fbutil.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright © 1998 Keith Packard
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fb.h"
+
+FbBits
+fbReplicatePixel(Pixel p, int bpp)
+{
+	FbBits b = p;
+
+	b &= FbFullMask(bpp);
+	while (bpp < FB_UNIT) {
+		b |= b << bpp;
+		bpp <<= 1;
+	}
+	return b;
+}
+
+/*
+ * Stipple masks are independent of bit/byte order as long
+ * as bitorder == byteorder.  FB doesn't handle the case
+ * where these differ
+ */
+#define __mask(x,w)	((FB_ALLONES << ((x) & FB_MASK)) & \
+			 (FB_ALLONES >> ((FB_UNIT - ((x) + (w))) & FB_MASK)))
+#define _mask(x,w)	__mask((x)*(w),(w))
+#define mask(b,n,w)	((((b) >> (n)) & 1) * _mask(n,w))
+
+#define _C1(b,n,w) mask(b,n,w)
+#define _C2(b,n,w) (_C1(b,n,w) | _C1(b,n+1,w))
+#define _C4(b,n,w) (_C2(b,n,w) | _C2(b,n+2,w))
+#define C8(b,w) (_C4(b,0,w) | _C4(b,4,w))
+#define C4(b,w) _C4(b,0,w)
+#define C2(b,w) _C2(b,0,w)
+#define C1(b,w) _C1(b,0,w)
+
+static const FbBits fbStipple8Bits[256] = {
+	C8(0, 4), C8(1, 4), C8(2, 4), C8(3, 4), C8(4, 4), C8(5, 4),
+	C8(6, 4), C8(7, 4), C8(8, 4), C8(9, 4), C8(10, 4), C8(11, 4),
+	C8(12, 4), C8(13, 4), C8(14, 4), C8(15, 4), C8(16, 4), C8(17, 4),
+	C8(18, 4), C8(19, 4), C8(20, 4), C8(21, 4), C8(22, 4), C8(23, 4),
+	C8(24, 4), C8(25, 4), C8(26, 4), C8(27, 4), C8(28, 4), C8(29, 4),
+	C8(30, 4), C8(31, 4), C8(32, 4), C8(33, 4), C8(34, 4), C8(35, 4),
+	C8(36, 4), C8(37, 4), C8(38, 4), C8(39, 4), C8(40, 4), C8(41, 4),
+	C8(42, 4), C8(43, 4), C8(44, 4), C8(45, 4), C8(46, 4), C8(47, 4),
+	C8(48, 4), C8(49, 4), C8(50, 4), C8(51, 4), C8(52, 4), C8(53, 4),
+	C8(54, 4), C8(55, 4), C8(56, 4), C8(57, 4), C8(58, 4), C8(59, 4),
+	C8(60, 4), C8(61, 4), C8(62, 4), C8(63, 4), C8(64, 4), C8(65, 4),
+	C8(66, 4), C8(67, 4), C8(68, 4), C8(69, 4), C8(70, 4), C8(71, 4),
+	C8(72, 4), C8(73, 4), C8(74, 4), C8(75, 4), C8(76, 4), C8(77, 4),
+	C8(78, 4), C8(79, 4), C8(80, 4), C8(81, 4), C8(82, 4), C8(83, 4),
+	C8(84, 4), C8(85, 4), C8(86, 4), C8(87, 4), C8(88, 4), C8(89, 4),
+	C8(90, 4), C8(91, 4), C8(92, 4), C8(93, 4), C8(94, 4), C8(95, 4),
+	C8(96, 4), C8(97, 4), C8(98, 4), C8(99, 4), C8(100, 4), C8(101, 4),
+	C8(102, 4), C8(103, 4), C8(104, 4), C8(105, 4), C8(106, 4), C8(107, 4),
+	C8(108, 4), C8(109, 4), C8(110, 4), C8(111, 4), C8(112, 4), C8(113, 4),
+	C8(114, 4), C8(115, 4), C8(116, 4), C8(117, 4), C8(118, 4), C8(119, 4),
+	C8(120, 4), C8(121, 4), C8(122, 4), C8(123, 4), C8(124, 4), C8(125, 4),
+	C8(126, 4), C8(127, 4), C8(128, 4), C8(129, 4), C8(130, 4), C8(131, 4),
+	C8(132, 4), C8(133, 4), C8(134, 4), C8(135, 4), C8(136, 4), C8(137, 4),
+	C8(138, 4), C8(139, 4), C8(140, 4), C8(141, 4), C8(142, 4), C8(143, 4),
+	C8(144, 4), C8(145, 4), C8(146, 4), C8(147, 4), C8(148, 4), C8(149, 4),
+	C8(150, 4), C8(151, 4), C8(152, 4), C8(153, 4), C8(154, 4), C8(155, 4),
+	C8(156, 4), C8(157, 4), C8(158, 4), C8(159, 4), C8(160, 4), C8(161, 4),
+	C8(162, 4), C8(163, 4), C8(164, 4), C8(165, 4), C8(166, 4), C8(167, 4),
+	C8(168, 4), C8(169, 4), C8(170, 4), C8(171, 4), C8(172, 4), C8(173, 4),
+	C8(174, 4), C8(175, 4), C8(176, 4), C8(177, 4), C8(178, 4), C8(179, 4),
+	C8(180, 4), C8(181, 4), C8(182, 4), C8(183, 4), C8(184, 4), C8(185, 4),
+	C8(186, 4), C8(187, 4), C8(188, 4), C8(189, 4), C8(190, 4), C8(191, 4),
+	C8(192, 4), C8(193, 4), C8(194, 4), C8(195, 4), C8(196, 4), C8(197, 4),
+	C8(198, 4), C8(199, 4), C8(200, 4), C8(201, 4), C8(202, 4), C8(203, 4),
+	C8(204, 4), C8(205, 4), C8(206, 4), C8(207, 4), C8(208, 4), C8(209, 4),
+	C8(210, 4), C8(211, 4), C8(212, 4), C8(213, 4), C8(214, 4), C8(215, 4),
+	C8(216, 4), C8(217, 4), C8(218, 4), C8(219, 4), C8(220, 4), C8(221, 4),
+	C8(222, 4), C8(223, 4), C8(224, 4), C8(225, 4), C8(226, 4), C8(227, 4),
+	C8(228, 4), C8(229, 4), C8(230, 4), C8(231, 4), C8(232, 4), C8(233, 4),
+	C8(234, 4), C8(235, 4), C8(236, 4), C8(237, 4), C8(238, 4), C8(239, 4),
+	C8(240, 4), C8(241, 4), C8(242, 4), C8(243, 4), C8(244, 4), C8(245, 4),
+	C8(246, 4), C8(247, 4), C8(248, 4), C8(249, 4), C8(250, 4), C8(251, 4),
+	C8(252, 4), C8(253, 4), C8(254, 4), C8(255, 4),
+};
+
+static const FbBits fbStipple4Bits[16] = {
+	C4(0, 8), C4(1, 8), C4(2, 8), C4(3, 8), C4(4, 8), C4(5, 8),
+	C4(6, 8), C4(7, 8), C4(8, 8), C4(9, 8), C4(10, 8), C4(11, 8),
+	C4(12, 8), C4(13, 8), C4(14, 8), C4(15, 8),
+};
+
+static const FbBits fbStipple2Bits[4] = {
+	C2(0, 16), C2(1, 16), C2(2, 16), C2(3, 16),
+};
+
+static const FbBits fbStipple1Bits[2] = {
+	C1(0, 32), C1(1, 32),
+};
+const FbBits *const fbStippleTable[] = {
+	0,
+	fbStipple1Bits,
+	fbStipple2Bits,
+	0,
+	fbStipple4Bits,
+	0,
+	0,
+	0,
+	fbStipple8Bits,
+};
diff --git a/src/sna/sna.h b/src/sna/sna.h
index 3219e15..7f4c0bf 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -42,9 +42,10 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #endif
 
 #include <stdint.h>
-
 #include "compiler.h"
 
+#include <xorg-server.h>
+
 #include <xf86Crtc.h>
 #include <xf86str.h>
 #include <windowstr.h>
@@ -52,7 +53,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <picturestr.h>
 #include <gcstruct.h>
 
-#include <xorg-server.h>
 #include <pciaccess.h>
 
 #include <xf86drmMode.h>
@@ -67,8 +67,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <libudev.h>
 #endif
 
-#include "compiler.h"
-
 #define DBG(x)
 
 #define DEBUG_ALL (HAS_DEBUG_FULL || 0)
@@ -114,6 +112,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include "kgem.h"
 #include "sna_damage.h"
 #include "sna_render.h"
+#include "fb/fb.h"
 
 #define SNA_CURSOR_X			64
 #define SNA_CURSOR_Y			SNA_CURSOR_X
@@ -150,18 +149,9 @@ struct sna_glyph {
 	uint16_t size, pos;
 };
 
-extern DevPrivateKeyRec sna_private_index;
-extern DevPrivateKeyRec sna_pixmap_index;
-extern DevPrivateKeyRec sna_gc_index;
-extern DevPrivateKeyRec sna_glyph_key;
-
 static inline PixmapPtr get_window_pixmap(WindowPtr window)
 {
-#if 0
-	return window->drawable.pScreen->GetWindowPixmap(window)
-#else
-	return *(void **)window->devPrivates;
-#endif
+	return fbGetWindowPixmap(window);
 }
 
 static inline PixmapPtr get_drawable_pixmap(DrawablePtr drawable)
@@ -259,7 +249,6 @@ struct sna {
 
 	ScreenBlockHandlerProcPtr BlockHandler;
 	ScreenWakeupHandlerProcPtr WakeupHandler;
-	CloseScreenProcPtr CloseScreen;
 
 	PicturePtr clear;
 	struct {
@@ -565,8 +554,7 @@ static inline uint32_t pixmap_size(PixmapPtr pixmap)
 		pixmap->drawable.width * pixmap->drawable.bitsPerPixel/8;
 }
 
-Bool sna_accel_pre_init(struct sna *sna);
-Bool sna_accel_init(ScreenPtr sreen, struct sna *sna);
+bool sna_accel_init(ScreenPtr sreen, struct sna *sna);
 void sna_accel_block_handler(struct sna *sna, struct timeval **tv);
 void sna_accel_wakeup_handler(struct sna *sna);
 void sna_accel_watch_flush(struct sna *sna, int enable);
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index e553baf..099075b 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -36,14 +36,15 @@
 #include <X11/fonts/font.h>
 #include <X11/fonts/fontstruct.h>
 
-#include <fb.h>
 #include <dixfontstr.h>
 
+#include <mi.h>
+#include <migc.h>
+#include <miline.h>
+#include <micmap.h>
 #ifdef RENDER
 #include <mipict.h>
-#include <fbpict.h>
 #endif
-#include <miline.h>
 #include <shmint.h>
 
 #include <sys/time.h>
@@ -113,11 +114,11 @@ static void __sna_fallback_flush(DrawablePtr d)
 	box.x2 = pixmap->drawable.width;
 	box.y2 = pixmap->drawable.height;
 
-	tmp = fbCreatePixmap(pixmap->drawable.pScreen,
-			     pixmap->drawable.width,
-			     pixmap->drawable.height,
-			     pixmap->drawable.depth,
-			     0);
+	tmp = sna_pixmap_create_unattached(pixmap->drawable.pScreen,
+					   pixmap->drawable.width,
+					   pixmap->drawable.height,
+					   pixmap->drawable.depth,
+					   0);
 
 	DBG(("%s: comparing with direct read...\n", __FUNCTION__));
 	sna_read_boxes(sna,
@@ -138,7 +139,7 @@ static void __sna_fallback_flush(DrawablePtr d)
 		src += pixmap->devKind;
 		dst += tmp->devKind;
 	}
-	fbDestroyPixmap(tmp);
+	tmp->drawable.pScreen->DestroyPixmap(tmp);
 }
 #define FALLBACK_FLUSH(d) __sna_fallback_flush(d)
 #else
@@ -187,6 +188,8 @@ static const uint8_t fill_ROP[] = {
 static const GCOps sna_gc_ops;
 static const GCOps sna_gc_ops__cpu;
 static GCOps sna_gc_ops__tmp;
+static const GCFuncs sna_gc_funcs;
+static const GCFuncs sna_gc_funcs__cpu;
 
 static inline void region_set(RegionRec *r, const BoxRec *b)
 {
@@ -471,9 +474,13 @@ static void sna_pixmap_free_cpu(struct sna *sna, struct sna_pixmap *priv)
 		priv->pixmap->devPrivate.ptr = NULL;
 }
 
-static Bool sna_destroy_private(PixmapPtr pixmap, struct sna_pixmap *priv)
+static bool sna_destroy_private(PixmapPtr pixmap)
 {
 	struct sna *sna = to_sna_from_pixmap(pixmap);
+	struct sna_pixmap *priv = sna_pixmap(pixmap);
+
+	if (priv == NULL)
+		return true;
 
 	list_del(&priv->list);
 	list_del(&priv->inactive);
@@ -612,7 +619,11 @@ struct kgem_bo *sna_pixmap_change_tiling(PixmapPtr pixmap, uint32_t tiling)
 
 static inline void sna_set_pixmap(PixmapPtr pixmap, struct sna_pixmap *sna)
 {
-	dixSetPrivate(&pixmap->devPrivates, &sna_pixmap_index, sna);
+#if 0
+	dixSetPrivate(&pixmap->devPrivates, &sna_private_index, sna);
+#else
+	((void **)pixmap->devPrivates)[1] = sna;
+#endif
 	assert(sna_pixmap(pixmap) == sna);
 }
 
@@ -672,17 +683,74 @@ bool sna_pixmap_attach_to_bo(PixmapPtr pixmap, struct kgem_bo *bo)
 	return true;
 }
 
-static inline PixmapPtr
+static int bits_per_pixel(int depth)
+{
+	switch (depth) {
+	case 1: return 1;
+	case 4:
+	case 8: return 8;
+	case 15:
+	case 16: return 16;
+	case 24:
+	case 30:
+	case 32: return 32;
+	default: return 0;
+	}
+}
+static PixmapPtr
 create_pixmap(struct sna *sna, ScreenPtr screen,
 	      int width, int height, int depth,
-	      unsigned usage)
+	      unsigned usage_hint)
 {
 	PixmapPtr pixmap;
+	size_t datasize;
+	size_t stride;
+	int base, bpp;
+
+	bpp = bits_per_pixel(depth);
+	if (bpp == 0)
+		return NullPixmap;
+
+	stride = ((width * bpp + FB_MASK) >> FB_SHIFT) * sizeof(FbBits);
+	if (stride / 4 > 32767 || height > 32767)
+		return NullPixmap;
+
+	datasize = height * stride;
+	base = screen->totalPixmapSize;
+	if (base & 15) {
+		int adjust = 16 - (base & 15);
+		base += adjust;
+		datasize += adjust;
+	}
 
-	pixmap = fbCreatePixmap(screen, width, height, depth, usage);
-	if (pixmap == NullPixmap)
+	pixmap = AllocatePixmap(screen, datasize);
+	if (!pixmap)
 		return NullPixmap;
 
+	((void **)pixmap->devPrivates)[0] = sna;
+
+	pixmap->drawable.type = DRAWABLE_PIXMAP;
+	pixmap->drawable.class = 0;
+	pixmap->drawable.pScreen = screen;
+	pixmap->drawable.depth = depth;
+	pixmap->drawable.bitsPerPixel = bpp;
+	pixmap->drawable.id = 0;
+	pixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
+	pixmap->drawable.x = 0;
+	pixmap->drawable.y = 0;
+	pixmap->drawable.width = width;
+	pixmap->drawable.height = height;
+	pixmap->devKind = stride;
+	pixmap->refcnt = 1;
+	pixmap->devPrivate.ptr =  (char *)pixmap + base;
+
+#ifdef COMPOSITE
+	pixmap->screen_x = 0;
+	pixmap->screen_y = 0;
+#endif
+
+	pixmap->usage_hint = usage_hint;
+
 	DBG(("%s: serial=%ld, usage=%d, %dx%d\n",
 	     __FUNCTION__,
 	     pixmap->drawable.serialNumber,
@@ -690,8 +758,6 @@ create_pixmap(struct sna *sna, ScreenPtr screen,
 	     pixmap->drawable.width,
 	     pixmap->drawable.height));
 
-	assert(sna_private_index.offset == 0);
-	dixSetPrivate(&pixmap->devPrivates, &sna_private_index, sna);
 	return pixmap;
 }
 
@@ -701,7 +767,7 @@ sna_pixmap_create_shm(ScreenPtr screen,
 		      char *addr)
 {
 	struct sna *sna = to_sna_from_screen(screen);
-	int bpp = BitsPerPixel(depth);
+	int bpp = bits_per_pixel(depth);
 	int pitch = PixmapBytePad(width, depth);
 	struct sna_pixmap *priv;
 	PixmapPtr pixmap;
@@ -741,7 +807,7 @@ sna_pixmap_create_shm(ScreenPtr screen,
 
 		priv = sna_pixmap_attach(pixmap);
 		if (!priv) {
-			fbDestroyPixmap(pixmap);
+			FreePixmap(pixmap);
 			return NullPixmap;
 		}
 	}
@@ -749,7 +815,7 @@ sna_pixmap_create_shm(ScreenPtr screen,
 	priv->cpu_bo = kgem_create_map(&sna->kgem, addr, pitch*height, false);
 	if (priv->cpu_bo == NULL) {
 		free(priv);
-		fbDestroyPixmap(pixmap);
+		FreePixmap(pixmap);
 		return GetScratchPixmapHeader(screen, width, height, depth,
 					      bpp, pitch, addr);
 	}
@@ -787,7 +853,7 @@ sna_pixmap_create_scratch(ScreenPtr screen,
 	DBG(("%s(%d, %d, %d, tiling=%d)\n", __FUNCTION__,
 	     width, height, depth, tiling));
 
-	bpp = BitsPerPixel(depth);
+	bpp = bits_per_pixel(depth);
 	if (tiling == I915_TILING_Y && !sna->have_render)
 		tiling = I915_TILING_X;
 
@@ -833,7 +899,7 @@ sna_pixmap_create_scratch(ScreenPtr screen,
 
 		priv = sna_pixmap_attach(pixmap);
 		if (!priv) {
-			fbDestroyPixmap(pixmap);
+			FreePixmap(pixmap);
 			return NullPixmap;
 		}
 	}
@@ -846,7 +912,7 @@ sna_pixmap_create_scratch(ScreenPtr screen,
 				      CREATE_TEMPORARY);
 	if (priv->gpu_bo == NULL) {
 		free(priv);
-		fbDestroyPixmap(pixmap);
+		FreePixmap(pixmap);
 		return NullPixmap;
 	}
 
@@ -956,15 +1022,14 @@ fallback:
 
 static Bool sna_destroy_pixmap(PixmapPtr pixmap)
 {
-	if (pixmap->refcnt == 1) {
-		struct sna_pixmap *priv = sna_pixmap(pixmap);
-		if (priv) {
-			if (!sna_destroy_private(pixmap, priv))
-				return TRUE;
-		}
-	}
+	if (--pixmap->refcnt)
+		return TRUE;
 
-	return fbDestroyPixmap(pixmap);
+	if (!sna_destroy_private(pixmap))
+		return TRUE;
+
+	FreePixmap(pixmap);
+	return TRUE;
 }
 
 static inline bool pixmap_inplace(struct sna *sna,
@@ -1991,9 +2056,9 @@ inline static unsigned drawable_gc_flags(DrawablePtr draw,
 		return MOVE_READ | MOVE_WRITE;
 	}
 
-	if (fbGetGCPrivate(gc)->and) {
+	if (fb_gc(gc)->and) {
 		DBG(("%s: read due to rop %d:%x\n",
-		     __FUNCTION__, gc->alu, (unsigned)fbGetGCPrivate(gc)->and));
+		     __FUNCTION__, gc->alu, (unsigned)fb_gc(gc)->and));
 		return MOVE_READ | MOVE_WRITE;
 	}
 
@@ -2425,7 +2490,7 @@ sna_pixmap_create_upload(ScreenPtr screen,
 	struct sna *sna = to_sna_from_screen(screen);
 	PixmapPtr pixmap;
 	struct sna_pixmap *priv;
-	int bpp = BitsPerPixel(depth);
+	int bpp = bits_per_pixel(depth);
 	void *ptr;
 
 	DBG(("%s(%d, %d, %d, flags=%x)\n", __FUNCTION__,
@@ -2446,7 +2511,7 @@ sna_pixmap_create_upload(ScreenPtr screen,
 
 		priv = malloc(sizeof(*priv));
 		if (!priv) {
-			fbDestroyPixmap(pixmap);
+			FreePixmap(pixmap);
 			return NullPixmap;
 		}
 
@@ -2461,7 +2526,7 @@ sna_pixmap_create_upload(ScreenPtr screen,
 					     flags, &ptr);
 	if (!priv->gpu_bo) {
 		free(priv);
-		fbDestroyPixmap(pixmap);
+		FreePixmap(pixmap);
 		return NullPixmap;
 	}
 
@@ -2699,25 +2764,35 @@ active:
 
 static bool must_check sna_validate_pixmap(DrawablePtr draw, PixmapPtr pixmap)
 {
-	bool ret = true;
-
 	if (draw->bitsPerPixel == pixmap->drawable.bitsPerPixel &&
 	    FbEvenTile(pixmap->drawable.width *
 		       pixmap->drawable.bitsPerPixel)) {
 		DBG(("%s: flushing pixmap\n", __FUNCTION__));
-		ret = sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE);
+		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE))
+			return false;
+
+		fbPadPixmap(pixmap);
 	}
 
-	return ret;
+	return true;
 }
 
-static bool must_check sna_gc_move_to_cpu(GCPtr gc, DrawablePtr drawable)
+static bool must_check sna_gc_move_to_cpu(GCPtr gc,
+					  DrawablePtr drawable,
+					  RegionPtr region)
 {
 	struct sna_gc *sgc = sna_gc(gc);
 	long changes = sgc->changes;
 
 	DBG(("%s, changes=%lx\n", __FUNCTION__, changes));
 
+	assert(gc->ops == (GCOps *)&sna_gc_ops);
+	assert(gc->funcs == (GCFuncs *)&sna_gc_funcs);
+
+	sgc->priv = region;
+	gc->ops = (GCOps *)&sna_gc_ops__cpu;
+	gc->funcs = (GCFuncs *)&sna_gc_funcs__cpu;
+
 	if (gc->clientClipType == CT_PIXMAP) {
 		PixmapPtr clip = gc->clientClip;
 		gc->clientClip = BitmapToRegion(gc->pScreen, clip);
@@ -2730,6 +2805,11 @@ static bool must_check sna_gc_move_to_cpu(GCPtr gc, DrawablePtr drawable)
 	if (changes || drawable->serialNumber != sgc->serial) {
 		gc->serialNumber = sgc->serial;
 
+		if (fb_gc(gc)->bpp != drawable->bitsPerPixel) {
+			changes |= GCStipple | GCForeground | GCBackground | GCPlaneMask;
+			fb_gc(gc)->bpp = drawable->bitsPerPixel;
+		}
+
 		if (changes & GCTile && !gc->tileIsPixel) {
 			DBG(("%s: flushing tile pixmap\n", __FUNCTION__));
 			if (!sna_validate_pixmap(drawable, gc->tile.pixmap))
@@ -2738,7 +2818,7 @@ static bool must_check sna_gc_move_to_cpu(GCPtr gc, DrawablePtr drawable)
 
 		if (changes & GCStipple && gc->stipple) {
 			DBG(("%s: flushing stipple pixmap\n", __FUNCTION__));
-			if (!sna_pixmap_move_to_cpu(gc->stipple, MOVE_READ))
+			if (!sna_validate_pixmap(drawable, gc->stipple))
 				return false;
 		}
 
@@ -2760,6 +2840,15 @@ static bool must_check sna_gc_move_to_cpu(GCPtr gc, DrawablePtr drawable)
 	}
 }
 
+static void sna_gc_move_to_gpu(GCPtr gc)
+{
+	assert(gc->ops == (GCOps *)&sna_gc_ops__cpu);
+	assert(gc->funcs == (GCFuncs *)&sna_gc_funcs__cpu);
+
+	gc->ops = (GCOps *)&sna_gc_ops;
+	gc->funcs = (GCFuncs *)&sna_gc_funcs;
+}
+
 static inline bool clip_box(BoxPtr box, GCPtr gc)
 {
 	const BoxRec *clip;
@@ -3491,10 +3580,12 @@ sna_put_image(DrawablePtr drawable, GCPtr gc, int depth,
 	if (priv == NULL) {
 		DBG(("%s: fbPutImage, unattached(%d, %d, %d, %d)\n",
 		     __FUNCTION__, x, y, w, h));
-		if (sna_gc_move_to_cpu(gc, drawable))
+		if (sna_gc_move_to_cpu(gc, drawable, NULL)) {
 			fbPutImage(drawable, gc, depth,
 				   x, y, w, h, left,
 				   format, bits);
+			sna_gc_move_to_gpu(gc);
+		}
 		return;
 	}
 
@@ -3563,17 +3654,19 @@ fallback:
 	DBG(("%s: fallback\n", __FUNCTION__));
 	RegionTranslate(&region, -dx, -dy);
 
-	if (!sna_gc_move_to_cpu(gc, drawable))
+	if (!sna_gc_move_to_cpu(gc, drawable, &region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &region,
 					     drawable_gc_flags(drawable, gc,
 							       true)))
-		goto out;
+		goto out_gc;
 
 	DBG(("%s: fbPutImage(%d, %d, %d, %d)\n",
 	     __FUNCTION__, x, y, w, h));
 	fbPutImage(drawable, gc, depth, x, y, w, h, left, format, bits);
 	FALLBACK_FLUSH(drawable);
+out_gc:
+	sna_gc_move_to_gpu(gc);
 out:
 	RegionUninit(&region);
 }
@@ -4284,23 +4377,26 @@ sna_copy_area(DrawablePtr src, DrawablePtr dst, GCPtr gc,
 			return NULL;
 
 		ret = NULL;
-		if (!sna_gc_move_to_cpu(gc, dst))
+		if (!sna_gc_move_to_cpu(gc, dst, &region))
 			goto out;
 
 		if (!sna_drawable_move_region_to_cpu(dst, &region, MOVE_READ | MOVE_WRITE))
-			goto out;
+			goto out_gc;
 
 		RegionTranslate(&region,
 				src_x - dst_x - dst->x + src->x,
 				src_y - dst_y - dst->y + src->y);
 		if (!sna_drawable_move_region_to_cpu(src, &region, MOVE_READ))
-			goto out;
+			goto out_gc;
 
-		ret = fbCopyArea(src, dst, gc,
-				  src_x, src_y,
-				  width, height,
-				  dst_x, dst_y);
+		ret = miDoCopy(src, dst, gc,
+			       src_x, src_y,
+			       width, height,
+			       dst_x, dst_y,
+			       fbCopyNtoN, 0, 0);
 		FALLBACK_FLUSH(dst);
+out_gc:
+		sna_gc_move_to_gpu(gc);
 out:
 		RegionUninit(&region);
 		return ret;
@@ -4355,79 +4451,6 @@ find_clip_box_for_y(const BoxRec *begin, const BoxRec *end, int16_t y)
 	return find_clip_box_for_y(mid, end, y);
 }
 
-static void
-sna_fill_spans__cpu(DrawablePtr drawable,
-		    GCPtr gc, int n,
-		    DDXPointPtr pt, int *width, int sorted)
-{
-	RegionRec *clip = sna_gc(gc)->priv;
-
-	DBG(("%s x %d\n", __FUNCTION__, n));
-
-	while (n--) {
-		BoxRec b;
-
-		DBG(("%s: (%d, %d) + %d\n",
-		     __FUNCTION__, pt->x, pt->y, *width));
-
-		*(DDXPointRec *)&b = *pt++;
-		b.x2 = b.x1 + *width++;
-		b.y2 = b.y1 + 1;
-
-		if (!box_intersect(&b, &clip->extents))
-			continue;
-
-		if (region_is_singular(clip)) {
-			DBG(("%s: singular fill: (%d, %d) x %d\n",
-			     __FUNCTION__, b.x1, b.y1, b.x2 - b.x1));
-			fbFill(drawable, gc, b.x1, b.y1, b.x2 - b.x1, 1);
-		} else {
-			const BoxRec * const clip_start = RegionBoxptr(clip);
-			const BoxRec * const clip_end = clip_start + clip->data->numRects;
-			const BoxRec *c;
-
-			DBG(("%s: multiple fills: (%d, %d) x %d, clip start((%d, %d), (%d,%d)), end((%d, %d), (%d, %d))\n",
-			     __FUNCTION__, b.x1, b.y1, b.x2 - b.x1,
-			     clip_start->x1, clip_start->y1,
-			     clip_start->x2, clip_start->y2,
-			     clip_end[-1].x1, clip_end[-1].y1,
-			     clip_end[-1].x2, clip_end[-1].y2));
-
-			c = find_clip_box_for_y(clip_start, clip_end, b.y1);
-			while (c != clip_end) {
-				int16_t x1, x2;
-
-				DBG(("%s: clip box? (%d, %d), (%d, %d)\n",
-				     __FUNCTION__,
-				     c->x1, c->y1, c->x2, c->y2));
-
-				if (b.y2 <= c->y1 || b.x2 <= c->x1)
-					break;
-
-				if (b.x1 > c->x2) {
-					c++;
-					continue;
-				}
-
-				x1 = c->x1;
-				x2 = c->x2;
-				c++;
-
-				if (x1 < b.x1)
-					x1 = b.x1;
-				if (x2 > b.x2)
-					x2 = b.x2;
-				if (x2 > x1) {
-					DBG(("%s: fbFill(%d, %d) x %d\n",
-					     __FUNCTION__, x1, b.y1, x2 - x1));
-					fbFill(drawable, gc,
-					       x1, b.y1, x2 - x1, 1);
-				}
-			}
-		}
-	}
-}
-
 struct sna_fill_spans {
 	struct sna *sna;
 	PixmapPtr pixmap;
@@ -5300,16 +5323,18 @@ fallback:
 	if (!RegionNotEmpty(&region))
 		return;
 
-	if (!sna_gc_move_to_cpu(gc, drawable))
+	if (!sna_gc_move_to_cpu(gc, drawable, &region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &region,
 					     drawable_gc_flags(drawable,
 							       gc, n > 1)))
-		goto out;
+		goto out_gc;
 
 	DBG(("%s: fbFillSpans\n", __FUNCTION__));
 	fbFillSpans(drawable, gc, n, pt, width, sorted);
 	FALLBACK_FLUSH(drawable);
+out_gc:
+	sna_gc_move_to_gpu(gc);
 out:
 	RegionUninit(&region);
 }
@@ -5339,16 +5364,18 @@ fallback:
 	if (!RegionNotEmpty(&region))
 		return;
 
-	if (!sna_gc_move_to_cpu(gc, drawable))
+	if (!sna_gc_move_to_cpu(gc, drawable, &region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &region,
 					     drawable_gc_flags(drawable,
 							       gc, true)))
-		goto out;
+		goto out_gc;
 
 	DBG(("%s: fbSetSpans\n", __FUNCTION__));
 	fbSetSpans(drawable, gc, src, pt, width, n, sorted);
 	FALLBACK_FLUSH(drawable);
+out_gc:
+	sna_gc_move_to_gpu(gc);
 out:
 	RegionUninit(&region);
 }
@@ -5822,16 +5849,21 @@ sna_copy_plane(DrawablePtr src, DrawablePtr dst, GCPtr gc,
 
 fallback:
 	DBG(("%s: fallback\n", __FUNCTION__));
-	if (!sna_gc_move_to_cpu(gc, dst))
+	if (!sna_gc_move_to_cpu(gc, dst, &region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(dst, &region,
 					     MOVE_READ | MOVE_WRITE))
-		goto out;
+		goto out_gc;
 
 	DBG(("%s: fbCopyPlane(%d, %d, %d, %d, %d,%d) %x\n",
 	     __FUNCTION__, src_x, src_y, w, h, dst_x, dst_y, (unsigned)bit));
-	ret = fbCopyPlane(src, dst, gc, src_x, src_y, w, h, dst_x, dst_y, bit);
+	ret = miDoCopy(src, dst, gc,
+		       src_x, src_y, w, h, dst_x, dst_y,
+		       src->bitsPerPixel > 1 ? fbCopyNto1 : fbCopy1toN,
+		       bit, 0);
 	FALLBACK_FLUSH(dst);
+out_gc:
+	sna_gc_move_to_gpu(gc);
 out:
 	RegionUninit(&region);
 	return ret;
@@ -5894,7 +5926,7 @@ sna_poly_point_blt(DrawablePtr drawable,
 			b = box;
 		} while (n);
 	} else {
-		RegionPtr clip = fbGetCompositeClip(gc);
+		RegionPtr clip = gc->pCompositeClip;
 
 		while (n--) {
 			int x, y;
@@ -5976,13 +6008,6 @@ sna_poly_point_extents(DrawablePtr drawable, GCPtr gc,
 }
 
 static void
-sna_poly_point__cpu(DrawablePtr drawable, GCPtr gc,
-	       int mode, int n, DDXPointPtr pt)
-{
-	fbPolyPoint(drawable, gc, mode, n, pt);
-}
-
-static void
 sna_poly_point(DrawablePtr drawable, GCPtr gc,
 	       int mode, int n, DDXPointPtr pt)
 {
@@ -6035,16 +6060,18 @@ fallback:
 	if (!RegionNotEmpty(&region))
 		return;
 
-	if (!sna_gc_move_to_cpu(gc, drawable))
+	if (!sna_gc_move_to_cpu(gc, drawable, &region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &region,
 					     drawable_gc_flags(drawable, gc,
 							       n > 1)))
-		goto out;
+		goto out_gc;
 
 	DBG(("%s: fbPolyPoint\n", __FUNCTION__));
 	fbPolyPoint(drawable, gc, mode, n, pt);
 	FALLBACK_FLUSH(drawable);
+out_gc:
+	sna_gc_move_to_gpu(gc);
 out:
 	RegionUninit(&region);
 }
@@ -7058,34 +7085,23 @@ fallback:
 	if (!RegionNotEmpty(&data.region))
 		return;
 
-	if (!sna_gc_move_to_cpu(gc, drawable))
+	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
 					     drawable_gc_flags(drawable, gc,
 							       !(data.flags & 4 && n == 2))))
-		goto out;
-
-	/* Install FillSpans in case we hit a fallback path in fbPolyLine */
-	sna_gc(gc)->priv = &data.region;
-	assert(gc->ops == (GCOps *)&sna_gc_ops);
-	gc->ops = (GCOps *)&sna_gc_ops__cpu;
+		goto out_gc;
 
 	DBG(("%s: fbPolyLine\n", __FUNCTION__));
 	fbPolyLine(drawable, gc, mode, n, pt);
 	FALLBACK_FLUSH(drawable);
 
-	gc->ops = (GCOps *)&sna_gc_ops;
+out_gc:
+	sna_gc_move_to_gpu(gc);
 out:
 	RegionUninit(&data.region);
 }
 
-static void
-sna_poly_line__cpu(DrawablePtr drawable, GCPtr gc,
-		   int mode, int n, DDXPointPtr pt)
-{
-	fbPolyLine(drawable, gc, mode, n, pt);
-}
-
 static inline void box_from_seg(BoxPtr b, xSegment *seg, GCPtr gc)
 {
 	if (seg->x1 == seg->x2) {
@@ -7913,23 +7929,19 @@ fallback:
 	if (!RegionNotEmpty(&data.region))
 		return;
 
-	if (!sna_gc_move_to_cpu(gc, drawable))
+	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
 					     drawable_gc_flags(drawable, gc,
 							       !(data.flags & 4 && n == 1))))
-		goto out;
-
-	/* Install FillSpans in case we hit a fallback path in fbPolySegment */
-	sna_gc(gc)->priv = &data.region;
-	assert(gc->ops == (GCOps *)&sna_gc_ops);
-	gc->ops = (GCOps *)&sna_gc_ops__cpu;
+		goto out_gc;
 
 	DBG(("%s: fbPolySegment\n", __FUNCTION__));
 	fbPolySegment(drawable, gc, n, seg);
 	FALLBACK_FLUSH(drawable);
 
-	gc->ops = (GCOps *)&sna_gc_ops;
+out_gc:
+	sna_gc_move_to_gpu(gc);
 out:
 	RegionUninit(&data.region);
 }
@@ -8519,16 +8531,18 @@ fallback:
 	if (!RegionNotEmpty(&region))
 		return;
 
-	if (!sna_gc_move_to_cpu(gc, drawable))
+	if (!sna_gc_move_to_cpu(gc, drawable, &region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &region,
 					     drawable_gc_flags(drawable,
 							       gc, true)))
 		goto out;
 
-	DBG(("%s: fbPolyRectangle\n", __FUNCTION__));
-	fbPolyRectangle(drawable, gc, n, r);
+	DBG(("%s: miPolyRectangle\n", __FUNCTION__));
+	miPolyRectangle(drawable, gc, n, r);
 	FALLBACK_FLUSH(drawable);
+out_gc:
+	sna_gc_move_to_gpu(gc);
 out:
 	RegionUninit(&region);
 }
@@ -8698,23 +8712,19 @@ fallback:
 	if (!RegionNotEmpty(&data.region))
 		return;
 
-	if (!sna_gc_move_to_cpu(gc, drawable))
+	if (!sna_gc_move_to_cpu(gc, drawable, &data.region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &data.region,
 					     drawable_gc_flags(drawable,
 							       gc, true)))
-		goto out;
-
-	/* Install FillSpans in case we hit a fallback path in fbPolyArc */
-	sna_gc(gc)->priv = &data.region;
-	assert(gc->ops == (GCOps *)&sna_gc_ops);
-	gc->ops = (GCOps *)&sna_gc_ops__cpu;
+		goto out_gc;
 
 	DBG(("%s -- fbPolyArc\n", __FUNCTION__));
 	fbPolyArc(drawable, gc, n, arc);
 	FALLBACK_FLUSH(drawable);
 
-	gc->ops = (GCOps *)&sna_gc_ops;
+out_gc:
+	sna_gc_move_to_gpu(gc);
 out:
 	RegionUninit(&data.region);
 }
@@ -9050,21 +9060,18 @@ fallback:
 		return;
 	}
 
-	if (!sna_gc_move_to_cpu(gc, draw))
+	if (!sna_gc_move_to_cpu(gc, draw, &data.region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(draw, &data.region,
 					     drawable_gc_flags(draw, gc,
 							       true)))
-		goto out;
+		goto out_gc;
 
 	DBG(("%s: fallback -- miFillPolygon -> sna_fill_spans__cpu\n",
 	     __FUNCTION__));
-	sna_gc(gc)->priv = &data.region;
-	assert(gc->ops == (GCOps *)&sna_gc_ops);
-	gc->ops = (GCOps *)&sna_gc_ops__cpu;
-
 	miFillPolygon(draw, gc, shape, mode, n, pt);
-	gc->ops = (GCOps *)&sna_gc_ops;
+out_gc:
+	sna_gc_move_to_gpu(gc);
 out:
 	RegionUninit(&data.region);
 }
@@ -10465,72 +10472,18 @@ fallback:
 		return;
 	}
 
-	if (!sna_gc_move_to_cpu(gc, draw))
+	if (!sna_gc_move_to_cpu(gc, draw, &region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(draw, &region,
 					     drawable_gc_flags(draw, gc,
 							       n > 1)))
-		goto out;
+		goto out_gc;
 
 	DBG(("%s: fallback - fbPolyFillRect\n", __FUNCTION__));
-	if (region.data == NULL) {
-		do {
-			BoxRec box;
-
-			box.x1 = rect->x + draw->x;
-			box.y1 = rect->y + draw->y;
-			box.x2 = bound(box.x1, rect->width);
-			box.y2 = bound(box.y1, rect->height);
-			rect++;
-
-			if (box_intersect(&box, &region.extents)) {
-				DBG(("%s: fallback - fbFill((%d, %d), (%d, %d))\n",
-				     __FUNCTION__,
-				     box.x1, box.y1,
-				     box.x2-box.x1, box.y2-box.y1));
-				fbFill(draw, gc,
-				       box.x1, box.y1,
-				       box.x2-box.x1, box.y2-box.y1);
-			}
-		} while (--n);
-	} else {
-		const BoxRec * const clip_start = RegionBoxptr(&region);
-		const BoxRec * const clip_end = clip_start + region.data->numRects;
-		const BoxRec *c;
-
-		do {
-			BoxRec box;
-
-			box.x1 = rect->x + draw->x;
-			box.y1 = rect->y + draw->y;
-			box.x2 = bound(box.x1, rect->width);
-			box.y2 = bound(box.y1, rect->height);
-			rect++;
-
-			c = find_clip_box_for_y(clip_start,
-						clip_end,
-						box.y1);
-
-			while (c != clip_end) {
-				BoxRec b;
-
-				if (box.y2 <= c->y1)
-					break;
-
-				b = box;
-				if (box_intersect(&b, c++)) {
-					DBG(("%s: fallback - fbFill((%d, %d), (%d, %d))\n",
-					     __FUNCTION__,
-					       b.x1, b.y1,
-					       b.x2-b.x1, b.y2-b.y1));
-					fbFill(draw, gc,
-					       b.x1, b.y1,
-					       b.x2-b.x1, b.y2-b.y1);
-				}
-			}
-		} while (--n);
-	}
+	fbPolyFillRect(draw, gc, n, rect);
 	FALLBACK_FLUSH(draw);
+out_gc:
+	sna_gc_move_to_gpu(gc);
 out:
 	RegionUninit(&region);
 }
@@ -10650,21 +10603,19 @@ fallback:
 		return;
 	}
 
-	if (!sna_gc_move_to_cpu(gc, draw))
+	if (!sna_gc_move_to_cpu(gc, draw, &data.region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(draw, &data.region,
 					     drawable_gc_flags(draw, gc,
 							       true)))
-		goto out;
+		goto out_gc;
 
 	DBG(("%s: fallback -- miPolyFillArc -> sna_fill_spans__cpu\n",
 	     __FUNCTION__));
-	sna_gc(gc)->priv = &data.region;
-	assert(gc->ops == (GCOps *)&sna_gc_ops);
-	gc->ops = (GCOps *)&sna_gc_ops__cpu;
 
 	miPolyFillArc(draw, gc, n, arc);
-	gc->ops = (GCOps *)&sna_gc_ops;
+out_gc:
+	sna_gc_move_to_gpu(gc);
 out:
 	RegionUninit(&data.region);
 }
@@ -10682,6 +10633,8 @@ sna_realize_font(ScreenPtr screen, FontPtr font)
 {
 	struct sna_font *priv;
 
+	DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key));
+
 	priv = calloc(1, sizeof(struct sna_font));
 	if (priv == NULL)
 		return FALSE;
@@ -10700,6 +10653,8 @@ sna_unrealize_font(ScreenPtr screen, FontPtr font)
 	struct sna_font *priv = FontGetPrivate(font, sna_font_key);
 	int i, j;
 
+	DBG(("%s (key=%d)\n", __FUNCTION__, sna_font_key));
+
 	if (priv == NULL)
 		return TRUE;
 
@@ -11110,17 +11065,19 @@ force_fallback:
 		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
 				     Linear8Bit, &n, info);
 
-		if (!sna_gc_move_to_cpu(gc, drawable))
+		if (!sna_gc_move_to_cpu(gc, drawable, &region))
 			goto out;
 		if (!sna_drawable_move_region_to_cpu(drawable, &region,
 						     drawable_gc_flags(drawable,
 								       gc, true)))
-			goto out;
+			goto out_gc;
 
 		DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
 		fbPolyGlyphBlt(drawable, gc, x, y, n,
 			       info, FONTGLYPHS(gc->font));
 		FALLBACK_FLUSH(drawable);
+out_gc:
+		sna_gc_move_to_gpu(gc);
 	}
 out:
 	RegionUninit(&region);
@@ -11203,16 +11160,18 @@ force_fallback:
 				     FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit,
 				     &n, info);
 
-		if (!sna_gc_move_to_cpu(gc, drawable))
+		if (!sna_gc_move_to_cpu(gc, drawable, &region))
 			goto out;
 		if (!sna_drawable_move_region_to_cpu(drawable, &region,
 						     drawable_gc_flags(drawable, gc, true)))
-			goto out;
+			goto out_gc;
 
 		DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
 		fbPolyGlyphBlt(drawable, gc, x, y, n,
 			       info, FONTGLYPHS(gc->font));
 		FALLBACK_FLUSH(drawable);
+out_gc:
+		sna_gc_move_to_gpu(gc);
 	}
 out:
 	RegionUninit(&region);
@@ -11304,17 +11263,19 @@ force_fallback:
 		gc->font->get_glyphs(gc->font, count, (unsigned char *)chars,
 				     Linear8Bit, &n, info);
 
-		if (!sna_gc_move_to_cpu(gc, drawable))
+		if (!sna_gc_move_to_cpu(gc, drawable, &region))
 			goto out;
 		if (!sna_drawable_move_region_to_cpu(drawable, &region,
 						     drawable_gc_flags(drawable,
 								       gc, n > 1)))
-			goto out;
+			goto out_gc;
 
 		DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
 		fbImageGlyphBlt(drawable, gc, x, y, n,
 				info, FONTGLYPHS(gc->font));
 		FALLBACK_FLUSH(drawable);
+out_gc:
+		sna_gc_move_to_gpu(gc);
 	}
 out:
 	RegionUninit(&region);
@@ -11399,17 +11360,19 @@ force_fallback:
 				     FONTLASTROW(gc->font) ? TwoD16Bit : Linear16Bit,
 				     &n, info);
 
-		if (!sna_gc_move_to_cpu(gc, drawable))
+		if (!sna_gc_move_to_cpu(gc, drawable, &region))
 			goto out;
 		if (!sna_drawable_move_region_to_cpu(drawable, &region,
 						     drawable_gc_flags(drawable,
 								       gc, n > 1)))
-			goto out;
+			goto out_gc;
 
 		DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
 		fbImageGlyphBlt(drawable, gc, x, y, n,
 				info, FONTGLYPHS(gc->font));
 		FALLBACK_FLUSH(drawable);
+out_gc:
+		sna_gc_move_to_gpu(gc);
 	}
 out:
 	RegionUninit(&region);
@@ -11695,17 +11658,19 @@ sna_image_glyph(DrawablePtr drawable, GCPtr gc,
 
 fallback:
 	DBG(("%s: fallback\n", __FUNCTION__));
-	if (!sna_gc_move_to_cpu(gc, drawable))
+	if (!sna_gc_move_to_cpu(gc, drawable, &region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &region,
 					     drawable_gc_flags(drawable,
 							       gc, n > 1)))
-		goto out;
+		goto out_gc;
 
 	DBG(("%s: fallback -- fbImageGlyphBlt\n", __FUNCTION__));
 	fbImageGlyphBlt(drawable, gc, x, y, n, info, base);
 	FALLBACK_FLUSH(drawable);
 
+out_gc:
+	sna_gc_move_to_gpu(gc);
 out:
 	RegionUninit(&region);
 }
@@ -11774,17 +11739,19 @@ sna_poly_glyph(DrawablePtr drawable, GCPtr gc,
 
 fallback:
 	DBG(("%s: fallback\n", __FUNCTION__));
-	if (!sna_gc_move_to_cpu(gc, drawable))
+	if (!sna_gc_move_to_cpu(gc, drawable, &region))
 		goto out;
 	if (!sna_drawable_move_region_to_cpu(drawable, &region,
 					     drawable_gc_flags(drawable,
 							       gc, true)))
-		goto out;
+		goto out_gc;
 
 	DBG(("%s: fallback -- fbPolyGlyphBlt\n", __FUNCTION__));
 	fbPolyGlyphBlt(drawable, gc, x, y, n, info, base);
 	FALLBACK_FLUSH(drawable);
 
+out_gc:
+	sna_gc_move_to_gpu(gc);
 out:
 	RegionUninit(&region);
 }
@@ -11956,19 +11923,21 @@ sna_push_pixels(GCPtr gc, PixmapPtr bitmap, DrawablePtr drawable,
 	}
 
 	DBG(("%s: fallback\n", __FUNCTION__));
-	if (!sna_gc_move_to_cpu(gc, drawable))
+	if (!sna_gc_move_to_cpu(gc, drawable, &region))
 		goto out;
 	if (!sna_pixmap_move_to_cpu(bitmap, MOVE_READ))
-		goto out;
+		goto out_gc;
 	if (!sna_drawable_move_region_to_cpu(drawable, &region,
 					     drawable_gc_flags(drawable,
 							       gc, false)))
-		goto out;
+		goto out_gc;
 
 	DBG(("%s: fallback, fbPushPixels(%d, %d, %d %d)\n",
 	     __FUNCTION__, w, h, x, y));
 	fbPushPixels(gc, bitmap, drawable, w, h, x, y);
 	FALLBACK_FLUSH(drawable);
+out_gc:
+	sna_gc_move_to_gpu(gc);
 out:
 	RegionUninit(&region);
 }
@@ -11997,26 +11966,26 @@ static const GCOps sna_gc_ops = {
 };
 
 static const GCOps sna_gc_ops__cpu = {
-	sna_fill_spans__cpu,
-	sna_set_spans,
-	sna_put_image,
-	sna_copy_area,
-	sna_copy_plane,
-	sna_poly_point__cpu,
-	sna_poly_line__cpu,
-	sna_poly_segment,
-	sna_poly_rectangle,
-	sna_poly_arc,
-	sna_poly_fill_polygon,
-	sna_poly_fill_rect,
-	sna_poly_fill_arc,
-	sna_poly_text8,
-	sna_poly_text16,
-	sna_image_text8,
-	sna_image_text16,
-	sna_image_glyph,
-	sna_poly_glyph,
-	sna_push_pixels,
+	fbFillSpans,
+	fbSetSpans,
+	fbPutImage,
+	fbCopyArea,
+	fbCopyPlane,
+	fbPolyPoint,
+	fbPolyLine,
+	fbPolySegment,
+	miPolyRectangle,
+	fbPolyArc,
+	miFillPolygon,
+	fbPolyFillRect,
+	miPolyFillArc,
+	miPolyText8,
+	miPolyText16,
+	miImageText8,
+	miImageText16,
+	fbImageGlyphBlt,
+	fbPolyGlyphBlt,
+	fbPushPixels
 };
 
 static GCOps sna_gc_ops__tmp = {
@@ -12065,10 +12034,22 @@ static const GCFuncs sna_gc_funcs = {
 	miCopyClip
 };
 
+static const GCFuncs sna_gc_funcs__cpu = {
+	fbValidateGC,
+	miChangeGC,
+	miCopyGC,
+	miDestroyGC,
+	miChangeClip,
+	miDestroyClip,
+	miCopyClip
+};
+
 static int sna_create_gc(GCPtr gc)
 {
-	if (!fbCreateGC(gc))
-		return FALSE;
+	gc->miTranslate = 1;
+	gc->fExpose = 1;
+
+	fb_gc(gc)->bpp = bits_per_pixel(gc->depth);
 
 	gc->funcs = (GCFuncs *)&sna_gc_funcs;
 	gc->ops = (GCOps *)&sna_gc_ops;
@@ -12084,6 +12065,9 @@ sna_get_image(DrawablePtr drawable,
 	RegionRec region;
 	unsigned int flags;
 
+	if (!fbDrawableEnabled(drawable))
+		return;
+
 	DBG(("%s (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
 
 	region.extents.x1 = x + drawable->x;
@@ -12126,6 +12110,9 @@ sna_get_spans(DrawablePtr drawable, int wMax,
 {
 	RegionRec region;
 
+	if (!fbDrawableEnabled(drawable))
+		return;
+
 	if (sna_spans_extents(drawable, NULL, n, pt, width, &region.extents) == 0)
 		return;
 
@@ -12145,13 +12132,8 @@ sna_copy_window(WindowPtr win, DDXPointRec origin, RegionPtr src)
 	int dx, dy;
 
 	DBG(("%s origin=(%d, %d)\n", __FUNCTION__, origin.x, origin.y));
-
-	if (wedged(sna)) {
-		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
-		if (sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE))
-			fbCopyWindow(win, origin, src);
+	if (!fbWindowEnabled(win))
 		return;
-	}
 
 	dx = origin.x - win->drawable.x;
 	dy = origin.y - win->drawable.y;
@@ -12164,8 +12146,17 @@ sna_copy_window(WindowPtr win, DDXPointRec origin, RegionPtr src)
 		RegionTranslate(&dst, -pixmap->screen_x, -pixmap->screen_y);
 #endif
 
-	miCopyRegion(&pixmap->drawable, &pixmap->drawable,
-		     NULL, &dst, dx, dy, sna_self_copy_boxes, 0, NULL);
+	if (wedged(sna)) {
+		DBG(("%s: fallback -- wedged\n", __FUNCTION__));
+		if (!sna_pixmap_move_to_cpu(pixmap, MOVE_READ | MOVE_WRITE))
+			return;
+
+		miCopyRegion(&pixmap->drawable, &pixmap->drawable,
+			     0, &dst, dx, dy, fbCopyNtoN, 0, NULL);
+	} else {
+		miCopyRegion(&pixmap->drawable, &pixmap->drawable,
+			     NULL, &dst, dx, dy, sna_self_copy_boxes, 0, NULL);
+	}
 
 	RegionUninit(&dst);
 }
@@ -12189,7 +12180,7 @@ static Bool sna_change_window_attributes(WindowPtr win, unsigned long mask)
 		ret &= sna_validate_pixmap(&win->drawable, win->border.pixmap);
 	}
 
-	return ret && fbChangeWindowAttributes(win, mask);
+	return ret;
 }
 
 static void
@@ -12585,20 +12576,112 @@ static void sna_accel_debug_memory(struct sna *sna)
 static void sna_accel_debug_memory(struct sna *sna) { }
 #endif
 
-Bool sna_accel_pre_init(struct sna *sna)
+static ShmFuncs shm_funcs = { sna_pixmap_create_shm, NULL };
+
+static PixmapPtr
+sna_get_window_pixmap(WindowPtr window)
+{
+	return get_window_pixmap(window);
+}
+
+static void
+sna_set_window_pixmap(WindowPtr window, PixmapPtr pixmap)
+{
+	*(PixmapPtr *)window->devPrivates = pixmap;
+}
+
+static Bool
+sna_create_window(WindowPtr win)
 {
+	sna_set_window_pixmap(win, win->drawable.pScreen->devPrivate);
 	return TRUE;
 }
 
-static ShmFuncs shm_funcs = { sna_pixmap_create_shm, NULL };
+static Bool
+sna_map_window(WindowPtr win)
+{
+	return TRUE;
+}
+
+static Bool
+sna_position_window(WindowPtr win, int x, int y)
+{
+	return TRUE;
+}
 
-Bool sna_accel_init(ScreenPtr screen, struct sna *sna)
+static Bool
+sna_unmap_window(WindowPtr win)
+{
+	return TRUE;
+}
+
+static Bool
+sna_destroy_window(WindowPtr win)
+{
+	return TRUE;
+}
+
+static void
+sna_query_best_size(int class,
+		    unsigned short *width, unsigned short *height,
+		    ScreenPtr screen)
+{
+	unsigned short w;
+
+	switch (class) {
+	case CursorShape:
+		if (*width > screen->width)
+			*width = screen->width;
+		if (*height > screen->height)
+			*height = screen->height;
+		break;
+
+	case TileShape:
+	case StippleShape:
+		w = *width;
+		if ((w & (w - 1)) && w < FB_UNIT) {
+			for (w = 1; w < *width; w <<= 1)
+				;
+			*width = w;
+		}
+		break;
+	}
+}
+
+static void sna_store_colors(ColormapPtr cmap, int n, xColorItem *def)
+{
+}
+
+static bool sna_picture_init(ScreenPtr screen)
+{
+	PictureScreenPtr ps;
+
+	if (!miPictureInit(screen, NULL, 0))
+		return false;
+
+	ps = GetPictureScreen(screen);
+	assert(ps != NULL);
+
+	ps->Composite = sna_composite;
+	ps->CompositeRects = sna_composite_rectangles;
+	ps->Glyphs = sna_glyphs;
+	ps->UnrealizeGlyph = sna_glyph_unrealize;
+	ps->AddTraps = sna_add_traps;
+	ps->Trapezoids = sna_composite_trapezoids;
+	ps->Triangles = sna_composite_triangles;
+#if PICTURE_SCREEN_VERSION >= 2
+	ps->TriStrip = sna_composite_tristrip;
+	ps->TriFan = sna_composite_trifan;
+#endif
+
+	return true;
+}
+
+bool sna_accel_init(ScreenPtr screen, struct sna *sna)
 {
 	const char *backend;
 
 	sna_font_key = AllocateFontPrivateIndex();
-	screen->RealizeFont = sna_realize_font;
-	screen->UnrealizeFont = sna_unrealize_font;
 
 	list_init(&sna->dirty_pixmaps);
 	list_init(&sna->active_pixmaps);
@@ -12611,35 +12694,53 @@ Bool sna_accel_init(ScreenPtr screen, struct sna *sna)
 	sna->timer_expire[DEBUG_MEMORY_TIMER] = GetTimeInMillis()+ 10 * 1000;
 #endif
 
-	screen->CreateGC = sna_create_gc;
+	screen->defColormap = FakeClientID(0);
+	/* let CreateDefColormap do whatever it wants for pixels */
+	screen->blackPixel = screen->whitePixel = (Pixel) 0;
+	screen->QueryBestSize = sna_query_best_size;
+	assert(screen->GetImage == NULL);
 	screen->GetImage = sna_get_image;
+	assert(screen->GetSpans == NULL);
 	screen->GetSpans = sna_get_spans;
-	screen->CopyWindow = sna_copy_window;
+	assert(screen->CreateWindow == NULL);
+	screen->CreateWindow = sna_create_window;
+	assert(screen->DestroyWindow == NULL);
+	screen->DestroyWindow = sna_destroy_window;
+	screen->PositionWindow = sna_position_window;
 	screen->ChangeWindowAttributes = sna_change_window_attributes;
+	screen->RealizeWindow = sna_map_window;
+	screen->UnrealizeWindow = sna_unmap_window;
+	screen->CopyWindow = sna_copy_window;
+	assert(screen->CreatePixmap == NULL);
 	screen->CreatePixmap = sna_create_pixmap;
+	assert(screen->DestroyPixmap == NULL);
 	screen->DestroyPixmap = sna_destroy_pixmap;
-
-#ifdef RENDER
-	{
-		PictureScreenPtr ps = GetPictureScreenIfSet(screen);
-		if (ps) {
-			ps->Composite = sna_composite;
-			ps->CompositeRects = sna_composite_rectangles;
-			ps->Glyphs = sna_glyphs;
-			ps->UnrealizeGlyph = sna_glyph_unrealize;
-			ps->AddTraps = sna_add_traps;
-			ps->Trapezoids = sna_composite_trapezoids;
-			ps->Triangles = sna_composite_triangles;
-#if PICTURE_SCREEN_VERSION >= 2
-			ps->TriStrip = sna_composite_tristrip;
-			ps->TriFan = sna_composite_trifan;
-#endif
-		}
-	}
-#endif
+	screen->RealizeFont = sna_realize_font;
+	screen->UnrealizeFont = sna_unrealize_font;
+	assert(screen->CreateGC == NULL);
+	screen->CreateGC = sna_create_gc;
+	screen->CreateColormap = miInitializeColormap;
+	screen->DestroyColormap = (void (*)(ColormapPtr)) NoopDDA;
+	screen->InstallColormap = miInstallColormap;
+	screen->UninstallColormap = miUninstallColormap;
+	screen->ListInstalledColormaps = miListInstalledColormaps;
+	screen->ResolveColor = miResolveColor;
+	assert(screen->StoreColors = PictureStoreColors);
+	screen->StoreColors = sna_store_colors;
+	screen->BitmapToRegion = fbBitmapToRegion;
+
+	assert(screen->GetWindowPixmap == NULL);
+	screen->GetWindowPixmap = sna_get_window_pixmap;
+	assert(screen->SetWindowPixmap == NULL);
+	screen->SetWindowPixmap = sna_set_window_pixmap;
 
 	if (USE_SHM_VMAP && sna->kgem.has_vmap)
 		ShmRegisterFuncs(screen, &shm_funcs);
+	else
+		ShmRegisterFbFuncs(screen);
+
+	if (!sna_picture_init(screen))
+		return false;
 
 	backend = "no";
 	sna->have_render = false;
@@ -12718,9 +12819,9 @@ void sna_accel_close(struct sna *sna)
 	sna_glyphs_close(sna);
 
 	if (sna->freed_pixmap) {
-		assert(sna->freed_pixmap->refcnt == 1);
+		assert(sna->freed_pixmap->refcnt == 0);
 		free(sna_pixmap(sna->freed_pixmap));
-		fbDestroyPixmap(sna->freed_pixmap);
+		FreePixmap(sna->freed_pixmap);
 		sna->freed_pixmap = NULL;
 	}
 
diff --git a/src/sna/sna_blt.c b/src/sna/sna_blt.c
index 7690afe..0b0471e 100644
--- a/src/sna/sna_blt.c
+++ b/src/sna/sna_blt.c
@@ -38,9 +38,6 @@
 #include "sna_reg.h"
 #include "rop.h"
 
-#include <mipict.h>
-#include <fbpict.h>
-
 #if DEBUG_BLT
 #undef DBG
 #define DBG(x) ErrorF x
diff --git a/src/sna/sna_composite.c b/src/sna/sna_composite.c
index 4941477..606acb6 100644
--- a/src/sna/sna_composite.c
+++ b/src/sna/sna_composite.c
@@ -32,9 +32,9 @@
 #include "sna.h"
 #include "sna_render.h"
 #include "sna_render_inline.h"
+#include "fb/fbpict.h"
 
 #include <mipict.h>
-#include <fbpict.h>
 
 #if DEBUG_COMPOSITE
 #undef DBG
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 0b1a494..7c1d3bc 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -45,11 +45,9 @@
 #include <xf86drm.h>
 #include <xf86DDC.h> /* for xf86InterpretEDID */
 
-#include <fb.h>
-#include <fbpict.h>
-
 #include "sna.h"
 #include "sna_reg.h"
+#include "fb/fbpict.h"
 
 #include "intel_options.h"
 
@@ -2651,7 +2649,8 @@ sna_crtc_redisplay__fallback(xf86CrtcPtr crtc, RegionPtr region)
 	if (ptr == NULL)
 		return;
 
-	pixmap = fbCreatePixmap(screen, 0, 0, sna->front->drawable.depth, 0);
+	pixmap = sna_pixmap_create_unattached(screen,
+					      0, 0, sna->front->drawable.depth);
 	if (pixmap == NullPixmap)
 		return;
 
diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c
index eb4776b..d12c2b0 100644
--- a/src/sna/sna_driver.c
+++ b/src/sna/sna_driver.c
@@ -48,8 +48,10 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <xf86cmap.h>
 #include <xf86drm.h>
 #include <xf86RandR12.h>
+#include <mi.h>
 #include <micmap.h>
-#include <fb.h>
+#include <mipict.h>
+#include <mibstore.h>
 
 #include "compiler.h"
 #include "sna.h"
@@ -78,11 +80,11 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #define DBG(x) ErrorF x
 #endif
 
-DevPrivateKeyRec sna_private_index;
-DevPrivateKeyRec sna_pixmap_index;
-DevPrivateKeyRec sna_gc_index;
-DevPrivateKeyRec sna_glyph_key;
-DevPrivateKeyRec sna_glyph_image_key;
+static DevPrivateKeyRec sna_private_index;
+static DevPrivateKeyRec sna_pixmap_index;
+static DevPrivateKeyRec sna_gc_index;
+static DevPrivateKeyRec sna_glyph_key;
+static DevPrivateKeyRec sna_window_key;
 
 static Bool sna_enter_vt(VT_FUNC_ARGS_DECL);
 
@@ -556,16 +558,10 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int flags)
 	/* Set display resolution */
 	xf86SetDpi(scrn, 0, 0);
 
-	/* Load the required sub modules */
-	if (!xf86LoadSubModule(scrn, "fb")) {
-		PreInitCleanup(scrn);
-		return FALSE;
-	}
-
 	/* Load the dri2 module if requested. */
 	xf86LoadSubModule(scrn, "dri2");
 
-	return sna_accel_pre_init(sna);
+	return TRUE;
 }
 
 static void
@@ -753,6 +749,8 @@ static Bool sna_close_screen(CLOSE_SCREEN_ARGS_DECL)
 {
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
 	struct sna *sna = to_sna(scrn);
+	DepthPtr depths;
+	int d;
 
 	DBG(("%s\n", __FUNCTION__));
 
@@ -771,11 +769,12 @@ static Bool sna_close_screen(CLOSE_SCREEN_ARGS_DECL)
 
 	xf86_cursors_fini(screen);
 
-	/* XXX unhook devPrivate otherwise fbCloseScreen frees it! */
-	screen->devPrivate = NULL;
+	depths = screen->allowedDepths;
+	for (d = 0; d < screen->numDepths; d++)
+		free(depths[d].vids);
+	free(depths);
 
-	screen->CloseScreen = sna->CloseScreen;
-	(*screen->CloseScreen) (CLOSE_SCREEN_ARGS);
+	free(screen->visuals);
 
 	if (sna->directRenderingOpen) {
 		sna_dri_close(sna, screen);
@@ -812,7 +811,7 @@ sna_register_all_privates(void)
 	assert(sna_pixmap_index.offset == sizeof(void*));
 
 	if (!dixRegisterPrivateKey(&sna_gc_index, PRIVATE_GC,
-				   sizeof(struct sna_gc)))
+				   sizeof(FbGCPrivate)))
 		return FALSE;
 	assert(sna_gc_index.offset == 0);
 
@@ -821,6 +820,11 @@ sna_register_all_privates(void)
 		return FALSE;
 	assert(sna_glyph_key.offset == 0);
 
+	if (!dixRegisterPrivateKey(&sna_window_key,
+				   PRIVATE_WINDOW, 0))
+		return FALSE;
+	assert(sna_window_key.offset == 0);
+
 	return TRUE;
 }
 
@@ -835,7 +839,12 @@ sna_screen_init(SCREEN_INIT_ARGS_DECL)
 {
 	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
 	struct sna *sna = to_sna(scrn);
-	VisualPtr visual;
+	VisualPtr visuals;
+	DepthPtr depths;
+	int nvisuals;
+	int ndepths;
+	int rootdepth;
+	VisualID defaultVisual;
 
 	DBG(("%s\n", __FUNCTION__));
 
@@ -852,16 +861,23 @@ sna_screen_init(SCREEN_INIT_ARGS_DECL)
 	if (!miSetPixmapDepths())
 		return FALSE;
 
-	if (!fbScreenInit(screen, NULL,
+	rootdepth = 0;
+	if (!miInitVisuals(&visuals, &depths, &nvisuals, &ndepths, &rootdepth,
+			   &defaultVisual,
+			   ((unsigned long)1 << (scrn->bitsPerPixel - 1)),
+			   8, -1))
+		return FALSE;
+
+	if (!miScreenInit(screen, NULL,
 			  scrn->virtualX, scrn->virtualY,
-			  scrn->xDpi, scrn->yDpi,
-			  scrn->displayWidth, scrn->bitsPerPixel))
+			  scrn->xDpi, scrn->yDpi, 0,
+			  rootdepth, ndepths, depths,
+			  defaultVisual, nvisuals, visuals))
 		return FALSE;
-	assert(fbGetWinPrivateKey()->offset == 0);
 
 	if (scrn->bitsPerPixel > 8) {
 		/* Fixup RGB ordering */
-		visual = screen->visuals + screen->numVisuals;
+		VisualPtr visual = screen->visuals + screen->numVisuals;
 		while (--visual >= screen->visuals) {
 			if ((visual->class | DynamicClass) == DirectColor) {
 				visual->offsetRed = scrn->offset.red;
@@ -874,16 +890,16 @@ sna_screen_init(SCREEN_INIT_ARGS_DECL)
 		}
 	}
 
-	fbPictureInit(screen, NULL, 0);
-
-	xf86SetBlackWhitePixels(screen);
-
+	assert(screen->CloseScreen == NULL);
+	screen->CloseScreen = sna_close_screen;
 	if (!sna_accel_init(screen, sna)) {
 		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
 			   "Hardware acceleration initialization failed\n");
 		return FALSE;
 	}
 
+	xf86SetBlackWhitePixels(screen);
+
 	miInitializeBackingStore(screen);
 	xf86SetBackingStore(screen);
 	xf86SetSilkenMouse(screen);
@@ -914,8 +930,6 @@ sna_screen_init(SCREEN_INIT_ARGS_DECL)
 	screen->WakeupHandler = sna_wakeup_handler;
 
 	screen->SaveScreen = xf86SaveScreen;
-	sna->CloseScreen = screen->CloseScreen;
-	screen->CloseScreen = sna_close_screen;
 	screen->CreateScreenResources = sna_create_screen_resources;
 
 	if (!xf86CrtcScreenInit(screen))
diff --git a/src/sna/sna_glyphs.c b/src/sna/sna_glyphs.c
index d9a3dcf..0179520 100644
--- a/src/sna/sna_glyphs.c
+++ b/src/sna/sna_glyphs.c
@@ -65,10 +65,9 @@
 #include "sna.h"
 #include "sna_render.h"
 #include "sna_render_inline.h"
+#include "fb/fbpict.h"
 
 #include <mipict.h>
-#include <fbpict.h>
-#include <fb.h>
 
 #if DEBUG_GLYPHS
 #undef DBG
diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c
index c22965c..f6a562b 100644
--- a/src/sna/sna_render.c
+++ b/src/sna/sna_render.c
@@ -28,8 +28,7 @@
 #include "sna.h"
 #include "sna_render.h"
 #include "sna_render_inline.h"
-
-#include <fb.h>
+#include "fb/fbpict.h"
 
 #if DEBUG_RENDER
 #undef DBG
@@ -108,7 +107,7 @@ static Bool
 no_render_copy_boxes(struct sna *sna, uint8_t alu,
 		     PixmapPtr src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
 		     PixmapPtr dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
-		     const BoxRec *box, int n)
+		     const BoxRec *box, int n, unsigned flags)
 {
 	DBG(("%s (n=%d)\n", __FUNCTION__, n));
 
diff --git a/src/sna/sna_tiling.c b/src/sna/sna_tiling.c
index b20eceb..ae14d79 100644
--- a/src/sna/sna_tiling.c
+++ b/src/sna/sna_tiling.c
@@ -31,8 +31,7 @@
 
 #include "sna.h"
 #include "sna_render.h"
-
-#include <fbpict.h>
+#include "fb/fbpict.h"
 
 #if DEBUG_RENDER
 #undef DBG
diff --git a/src/sna/sna_trapezoids.c b/src/sna/sna_trapezoids.c
index d83c083..56c6a3e 100644
--- a/src/sna/sna_trapezoids.c
+++ b/src/sna/sna_trapezoids.c
@@ -34,10 +34,9 @@
 #include "sna.h"
 #include "sna_render.h"
 #include "sna_render_inline.h"
+#include "fb/fbpict.h"
 
-#include <fb.h>
 #include <mipict.h>
-#include <fbpict.h>
 
 #if DEBUG_TRAPEZOIDS
 #undef DBG
@@ -5213,9 +5212,8 @@ trapezoid_span_fallback(CARD8 op, PicturePtr src, PicturePtr dst,
 
 	DBG(("%s: mask (%dx%d), dx=(%d, %d)\n",
 	     __FUNCTION__, extents.x2, extents.y2, dx, dy));
-	scratch = fbCreatePixmap(screen,
-				 extents.x2, extents.y2, 8,
-				 CREATE_PIXMAP_USAGE_SCRATCH);
+	scratch = sna_pixmap_create_unattached(screen,
+					       extents.x2, extents.y2, 8);
 	if (!scratch)
 		return true;
 
@@ -5882,8 +5880,17 @@ sna_add_traps(PicturePtr picture, INT16 x, INT16 y, int n, xTrap *t)
 
 	DBG(("%s -- fallback\n", __FUNCTION__));
 	if (sna_drawable_move_to_cpu(picture->pDrawable,
-				     MOVE_READ | MOVE_WRITE))
-		fbAddTraps(picture, x, y, n, t);
+				     MOVE_READ | MOVE_WRITE)) {
+		pixman_image_t *image;
+		int dx, dy;
+
+		if (!(image = image_from_pict(picture, FALSE, &dx, &dy)))
+			return;
+
+		pixman_add_traps(image, x + dx, y + dy, n, (pixman_trap_t *)t);
+
+		free_pixman_pict(picture, image);
+	}
 }
 
 static inline void


More information about the xorg-commit mailing list