xf86-video-intel: 14 commits - src/sna/gen2_render.c src/sna/gen3_render.c src/sna/gen4_render.c src/sna/gen5_render.c src/sna/gen6_render.c src/sna/gen7_render.c src/sna/kgem.c src/sna/sna_accel.c src/sna/sna_blt.c src/sna/sna_damage.c src/sna/sna_damage.h src/sna/sna.h src/sna/sna_render.h

Chris Wilson ickle at kemper.freedesktop.org
Fri Oct 21 09:16:37 PDT 2011


 src/sna/gen2_render.c |   20 +
 src/sna/gen3_render.c |   19 +
 src/sna/gen4_render.c |   16 +
 src/sna/gen5_render.c |   37 +++
 src/sna/gen6_render.c |   32 ++
 src/sna/gen7_render.c |   32 ++
 src/sna/kgem.c        |    3 
 src/sna/sna.h         |   15 +
 src/sna/sna_accel.c   |  471 +++++++++++++++++++++++++++--------------
 src/sna/sna_blt.c     |   49 +++-
 src/sna/sna_damage.c  |  570 +++++++++++++++++++++++++++++++++++++++-----------
 src/sna/sna_damage.h  |   47 +++-
 src/sna/sna_render.h  |    3 
 13 files changed, 1002 insertions(+), 312 deletions(-)

New commits:
commit a18f559961135fa288dda3b94207abb0b6d4d302
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Oct 21 16:37:09 2011 +0100

    sna: Fix debug compilation
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_damage.c b/src/sna/sna_damage.c
index 6fd8fe8..6492205 100644
--- a/src/sna/sna_damage.c
+++ b/src/sna/sna_damage.c
@@ -628,16 +628,16 @@ __sna_damage_add_boxes(struct sna_damage *damage,
 
 #if DEBUG_DAMAGE
 struct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
-					 const BoxRec *box, int n,
+					 const BoxRec *b, int n,
 					 int16_t dx, int16_t dy)
 {
 	char damage_buf[1000];
 
 	DBG(("%s(%s + [(%d, %d), (%d, %d) ... x %d])\n", __FUNCTION__,
 	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
-	     box->x1, box->y1, box->x2, box->y2, n));
+	     b->x1, b->y1, b->x2, b->y2, n));
 
-	damage = __sna_damage_add_boxes(damage, boxes, n, dx, dy);
+	damage = __sna_damage_add_boxes(damage, b, n, dx, dy);
 
 	ErrorF("  = %s\n",
 	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage));
@@ -646,10 +646,10 @@ struct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
 }
 #else
 struct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
-					 const BoxRec *box, int n,
+					 const BoxRec *b, int n,
 					 int16_t dx, int16_t dy)
 {
-	return __sna_damage_add_boxes(damage, box, n, dx, dy);
+	return __sna_damage_add_boxes(damage, b, n, dx, dy);
 }
 #endif
 
@@ -734,9 +734,9 @@ struct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage,
 {
 	char damage_buf[1000];
 
-	DBG(("%s(%s + [(%d, %d), (%d, %d) ... x %d])\n", __FUNCTION__,
+	DBG(("%s(%s + [(%d, %d)x(%d, %d) ... x %d])\n", __FUNCTION__,
 	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
-	     box->x1, box->y1, box->x2, box->y2, n));
+	     r->x, r->y, r->width, r->height, n));
 
 	damage = __sna_damage_add_rectangles(damage, r, n, dx, dy);
 
@@ -826,9 +826,9 @@ struct sna_damage *_sna_damage_add_points(struct sna_damage *damage,
 {
 	char damage_buf[1000];
 
-	DBG(("%s(%s + [(%d, %d), (%d, %d) ... x %d])\n", __FUNCTION__,
+	DBG(("%s(%s + [(%d, %d) ... x %d])\n", __FUNCTION__,
 	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
-	     box->x1, box->y1, box->x2, box->y2, n));
+	     p->x, p->y, n));
 
 	damage = __sna_damage_add_points(damage, p, n, dx, dy);
 
commit a3a075201c8e47cfad6ec296b7baf549deb44cb3
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Oct 21 15:30:52 2011 +0100

    sna: Treat a bo marked as being last seen on the GPU as requiring a flush
    
    We are hitting this path upon retiring the old scanout buffer following
    a page-flip. We want to treat this as being hot and available for reuse,
    so mark it as such until the next retirement pass.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index d5084f8..6f98f27 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -564,12 +564,11 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
 	kgem->need_expire = true;
 	if (bo->rq) {
 		list_move(&bo->list, active(kgem, bo->size));
-	} else if (bo->needs_flush) {
+	} else if (bo->needs_flush | bo->gpu) {
 		assert(list_is_empty(&bo->request));
 		list_add(&bo->request, &kgem->flushing);
 		list_move(&bo->list, active(kgem, bo->size));
 	} else {
-		assert(bo->gpu == 0);
 		list_move(&bo->list, inactive(kgem, bo->size));
 	}
 
commit 999d13f32162ce11fe4042825b5b849073944ca8
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Oct 21 12:43:02 2011 +0100

    sna: Fast path unclipped points
    
    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 f78bd5c..636544e 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -2140,7 +2140,8 @@ static Bool
 sna_poly_point_blt(DrawablePtr drawable,
 		   struct kgem_bo *bo,
 		   struct sna_damage **damage,
-		   GCPtr gc, int mode, int n, DDXPointPtr pt)
+		   GCPtr gc, int mode, int n, DDXPointPtr pt,
+		   bool clipped)
 {
 	struct sna *sna = to_sna_from_drawable(drawable);
 	PixmapPtr pixmap = get_drawable_pixmap(drawable);
@@ -2149,7 +2150,8 @@ sna_poly_point_blt(DrawablePtr drawable,
 	DDXPointRec last;
 	int16_t dx, dy;
 
-	DBG(("%s: alu=%d, pixel=%08lx\n", __FUNCTION__, gc->alu, gc->fgPixel));
+	DBG(("%s: alu=%d, pixel=%08lx, clipped?=%d\n",
+	     __FUNCTION__, gc->alu, gc->fgPixel, clipped));
 
 	if (!sna_fill_init_blt(&fill, sna, pixmap, bo, gc->alu, gc->fgPixel))
 		return FALSE;
@@ -2159,7 +2161,30 @@ sna_poly_point_blt(DrawablePtr drawable,
 	last.x = drawable->x;
 	last.y = drawable->y;
 
-	while (n--) {
+	if (!clipped) {
+		last.x += dx;
+		last.y += dy;
+
+		sna_damage_add_points(damage, pt, n, last.x, last.y);
+		do {
+			BoxRec r;
+
+			r.x1 = pt->x;
+			r.y1 = pt->y;
+			pt++;
+
+			r.x1 += last.x;
+			r.y1 += last.y;
+			if (mode == CoordModePrevious) {
+				last.x = r.x1;
+				last.y = r.y1;
+			}
+
+			r.x2 = r.x1 + 1;
+			r.y2 = r.y1 + 1;
+			fill.box(sna, &fill, &r);
+		} while (--n);
+	} else while (n--) {
 		int x, y;
 
 		x = pt->x;
@@ -2194,14 +2219,15 @@ sna_poly_point_blt(DrawablePtr drawable,
 	return TRUE;
 }
 
-static Bool
+static unsigned
 sna_poly_point_extents(DrawablePtr drawable, GCPtr gc,
 		       int mode, int n, DDXPointPtr pt, BoxPtr out)
 {
 	BoxRec box;
+	bool clipped;
 
 	if (n == 0)
-		return true;
+		return 0;
 
 	box.x2 = box.x1 = pt->x;
 	box.y2 = box.y1 = pt->y;
@@ -2212,9 +2238,12 @@ sna_poly_point_extents(DrawablePtr drawable, GCPtr gc,
 	box.x2++;
 	box.y2++;
 
-	trim_and_translate_box(&box, drawable, gc);
+	clipped = trim_and_translate_box(&box, drawable, gc);
+	if (box_empty(&box))
+		return 0;
+
 	*out = box;
-	return box_empty(&box);
+	return 1 | clipped << 1;
 }
 
 static void
@@ -2223,16 +2252,19 @@ sna_poly_point(DrawablePtr drawable, GCPtr gc,
 {
 	struct sna *sna = to_sna_from_drawable(drawable);
 	RegionRec region;
+	unsigned flags;
 
 	DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d)\n",
 	     __FUNCTION__, mode, n, pt[0].x, pt[0].y));
 
-	if (sna_poly_point_extents(drawable, gc, mode, n, pt, &region.extents))
+	flags = sna_poly_point_extents(drawable, gc, mode, n, pt, &region.extents);
+	if (flags == 0)
 		return;
 
-	DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__,
+	DBG(("%s: extents (%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
 	     region.extents.x1, region.extents.y1,
-	     region.extents.x2, region.extents.y2));
+	     region.extents.x2, region.extents.y2,
+	     flags));
 
 	if (FORCE_FALLBACK)
 		goto fallback;
@@ -2252,15 +2284,15 @@ sna_poly_point(DrawablePtr drawable, GCPtr gc,
 		if (sna_drawable_use_gpu_bo(drawable, &region.extents) &&
 		    sna_poly_point_blt(drawable,
 				       priv->gpu_bo,
-				       priv->gpu_only ? NULL : &priv->gpu_damage,
-				       gc, mode, n, pt))
+				      priv->gpu_only ? NULL : reduce_damage(drawable, &priv->gpu_damage, &region.extents),
+				       gc, mode, n, pt, flags & 2))
 			return;
 
 		if (sna_drawable_use_cpu_bo(drawable, &region.extents) &&
 		    sna_poly_point_blt(drawable,
 				       priv->cpu_bo,
-				       &priv->cpu_damage,
-				       gc, mode, n, pt))
+				       reduce_damage(drawable, &priv->cpu_damage, &region.extents),
+				       gc, mode, n, pt, flags & 2))
 			return;
 	}
 
diff --git a/src/sna/sna_damage.c b/src/sna/sna_damage.c
index e33fc34..6fd8fe8 100644
--- a/src/sna/sna_damage.c
+++ b/src/sna/sna_damage.c
@@ -371,6 +371,69 @@ _sna_damage_create_elt_from_rectangles(struct sna_damage *damage,
 	}
 }
 
+static void
+_sna_damage_create_elt_from_points(struct sna_damage *damage,
+				   const DDXPointRec *p, int count,
+				   int16_t dx, int16_t dy)
+{
+	struct sna_damage_elt *elt;
+	int i;
+
+	DBG(("    %s: n=%d, prev=(remain %d)\n", __FUNCTION__,
+	     damage->n,
+	     damage->last_box ? damage->last_box->remain : 0));
+
+	if (damage->last_box) {
+		int n;
+		BoxRec *b;
+
+		n = count;
+		if (n > damage->last_box->remain)
+			n = damage->last_box->remain;
+
+		elt = damage->elts + damage->n-1;
+		b = elt->box + elt->n;
+		for (i = 0; i < n; i++) {
+			b[i].x1 = p[i].x + dx;
+			b[i].x2 = b[i].x1 + 1;
+			b[i].y1 = p[i].y + dy;
+			b[i].y2 = b[i].y1 + 1;
+		}
+		elt->n += n;
+		damage->last_box->remain -= n;
+		if (damage->last_box->remain == 0)
+			damage->last_box = NULL;
+
+		count -=n;
+		p += n;
+		if (count == 0)
+			return;
+	}
+
+	if (damage->n == damage->size) {
+		int newsize = damage->size * 2;
+		struct sna_damage_elt *newelts = realloc(damage->elts,
+							 newsize*sizeof(*elt));
+		if (newelts == NULL)
+			return;
+
+		damage->elts = newelts;
+		damage->size = newsize;
+	}
+
+	DBG(("    %s(): new elt\n", __FUNCTION__));
+
+	elt = damage->elts + damage->n++;
+	elt->n = count;
+	elt->box = _sna_damage_create_boxes(damage, count);
+	for (i = 0; i < count; i++) {
+		elt->box[i].x1 = p[i].x + dx;
+		elt->box[i].x2 = elt->box[i].x1 + 1;
+		elt->box[i].y1 = p[i].y + dy;
+		elt->box[i].y2 = elt->box[i].y1 + 1;
+	}
+}
+
 static void free_list(struct list *head)
 {
 	while (!list_is_empty(head)) {
@@ -621,8 +684,7 @@ __sna_damage_add_rectangles(struct sna_damage *damage,
 			extents.y2 = r[i].y + r[i].height;
 	}
 
-	if (extents.y2 <= extents.y1 || extents.x2 <= extents.x1)
-		return damage;
+	assert(extents.y2 > extents.y1 && extents.x2 > extents.x1);
 
 	extents.x1 += dx;
 	extents.x2 += dx;
@@ -692,6 +754,98 @@ struct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage,
 }
 #endif
 
+/* XXX pass in extents? */
+inline static struct sna_damage *
+__sna_damage_add_points(struct sna_damage *damage,
+			const DDXPointRec *p, int n,
+			int16_t dx, int16_t dy)
+{
+	BoxRec extents;
+	int i;
+
+	assert(n);
+
+	extents.x2 = extents.x1 = p[0].x;
+	extents.y2 = extents.y1 = p[0].y;
+	for (i = 1; i < n; i++) {
+		if (extents.x1 > p[i].x)
+			extents.x1 = p[i].x;
+		else if (extents.x2 < p[i].x)
+			extents.x2 = p[i].x;
+		if (extents.y1 > p[i].y)
+			extents.y1 = p[i].y;
+		else if (extents.y2 < p[i].y)
+			extents.y2 = p[i].y;
+	}
+
+	extents.x1 += dx;
+	extents.x2 += dx + 1;
+	extents.y1 += dy;
+	extents.y2 += dy + 1;
+
+	if (!damage)
+		damage = _sna_damage_create();
+	else switch (damage->mode) {
+	case DAMAGE_ALL:
+		return damage;
+	case DAMAGE_SUBTRACT:
+		__sna_damage_reduce(damage);
+	case DAMAGE_ADD:
+		break;
+	}
+
+	if (pixman_region_contains_rectangle(&damage->region,
+					     &extents) == PIXMAN_REGION_IN)
+		return damage;
+
+	_sna_damage_create_elt_from_points(damage, p, n, dx, dy);
+
+	if (REGION_NUM_RECTS(&damage->region) == 0) {
+		damage->region.extents = *damage->elts[0].box;
+		damage->region.data = NULL;
+		damage->extents = extents;
+	} else {
+		if (damage->extents.x1 > extents.x1)
+			damage->extents.x1 = extents.x1;
+		if (damage->extents.x2 < extents.x2)
+			damage->extents.x2 = extents.x2;
+
+		if (damage->extents.y1 > extents.y1)
+			damage->extents.y1 = extents.y1;
+		if (damage->extents.y2 < extents.y2)
+			damage->extents.y2 = extents.y2;
+	}
+
+	return damage;
+}
+
+#if DEBUG_DAMAGE
+struct sna_damage *_sna_damage_add_points(struct sna_damage *damage,
+					  const DDXPointRec *p, int n,
+					  int16_t dx, int16_t dy)
+{
+	char damage_buf[1000];
+
+	DBG(("%s(%s + [(%d, %d), (%d, %d) ... x %d])\n", __FUNCTION__,
+	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
+	     box->x1, box->y1, box->x2, box->y2, n));
+
+	damage = __sna_damage_add_points(damage, p, n, dx, dy);
+
+	ErrorF("  = %s\n",
+	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage));
+
+	return damage;
+}
+#else
+struct sna_damage *_sna_damage_add_points(struct sna_damage *damage,
+					  const DDXPointRec *p, int n,
+					  int16_t dx, int16_t dy)
+{
+	return __sna_damage_add_points(damage, p, n, dx, dy);
+}
+#endif
+
 inline static struct sna_damage *__sna_damage_add_box(struct sna_damage *damage,
 						      const BoxRec *box)
 {
diff --git a/src/sna/sna_damage.h b/src/sna/sna_damage.h
index 30058db..2dc2737 100644
--- a/src/sna/sna_damage.h
+++ b/src/sna/sna_damage.h
@@ -60,6 +60,17 @@ static inline void sna_damage_add_rectangles(struct sna_damage **damage,
 		*damage = _sna_damage_add_rectangles(*damage, r, n, dx, dy);
 }
 
+struct sna_damage *_sna_damage_add_points(struct sna_damage *damage,
+					  const DDXPointRec *p, int n,
+					  int16_t dx, int16_t dy);
+static inline void sna_damage_add_points(struct sna_damage **damage,
+					 const DDXPointRec *p, int n,
+					 int16_t dx, int16_t dy)
+{
+	if (damage)
+		*damage = _sna_damage_add_points(*damage, p, n, dx, dy);
+}
+
 struct sna_damage *_sna_damage_is_all(struct sna_damage *damage,
 				       int width, int height);
 static inline bool sna_damage_is_all(struct sna_damage **damage,
@@ -68,6 +79,9 @@ static inline bool sna_damage_is_all(struct sna_damage **damage,
 	if (*damage == NULL)
 		return false;
 
+	if ((*damage)->n)
+		return false;
+
 	switch ((*damage)->mode) {
 	case DAMAGE_ALL:
 		return true;
commit eb80013f4ea50ad4f54b4d1d90c5e9da27e1c34c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Oct 21 11:49:55 2011 +0100

    sna: Fast path for unclipped rectangles
    
    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 c420f0a..f78bd5c 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -2395,7 +2395,7 @@ sna_poly_line_blt(DrawablePtr drawable,
 					}
 					DBG(("%s: (%d, %d) -> (%d, %d) clipping line (%d, %d), (%d, %d) against box (%d, %d), (%d, %d)\n",
 					     __FUNCTION__,
-					     last.x, last.y, x, y,
+					     last.x, last.y, p.x, p.y,
 					     r.x1, r.y1, r.x2, r.y2,
 					     box->x1, box->y1, box->x2, box->y2));
 					if (box_intersect(&r, box)) {
@@ -3026,7 +3026,8 @@ sna_poly_fill_rect_blt(DrawablePtr drawable,
 		       struct kgem_bo *bo,
 		       struct sna_damage **damage,
 		       GCPtr gc, int n,
-		       xRectangle *rect)
+		       xRectangle *rect,
+		       bool clipped)
 {
 	struct sna *sna = to_sna_from_drawable(drawable);
 	PixmapPtr pixmap = get_drawable_pixmap(drawable);
@@ -3035,8 +3036,10 @@ sna_poly_fill_rect_blt(DrawablePtr drawable,
 	uint32_t pixel = gc->fillStyle == FillSolid ? gc->fgPixel : gc->tile.pixel;
 	int16_t dx, dy;
 
-	DBG(("%s x %d [(%d, %d)+(%d, %d)...]\n",
-	     __FUNCTION__, n, rect->x, rect->y, rect->width, rect->height));
+	DBG(("%s x %d [(%d, %d)+(%d, %d)...], clipped?=%d\n",
+	     __FUNCTION__,
+	     n, rect->x, rect->y, rect->width, rect->height,
+	     clipped));
 
 	if (n == 1 && clip->data == NULL) {
 		BoxPtr box = &clip->extents;
@@ -3071,7 +3074,23 @@ sna_poly_fill_rect_blt(DrawablePtr drawable,
 	}
 
 	get_drawable_deltas(drawable, pixmap, &dx, &dy);
-	if (clip->data == NULL) {
+	if (!clipped) {
+		dx += drawable->x;
+		dy += drawable->y;
+
+		sna_damage_add_rectangles(damage, rect, n, dx, dy);
+		do {
+			BoxRec r;
+
+			r.x1 = rect->x + dx;
+			r.y1 = rect->y + dy;
+			r.x2 = bound(r.x1, rect->width);
+			r.y2 = bound(r.y1, rect->height);
+			rect++;
+
+			fill.box(sna, &fill, &r);
+		} while (--n);
+	} else if (clip->data == NULL) {
 		BoxPtr box = &clip->extents;
 		while (n--) {
 			BoxRec r;
@@ -3367,15 +3386,16 @@ sna_poly_fill_rect_tiled(DrawablePtr drawable,
 	return TRUE;
 }
 
-static Bool
+static unsigned
 sna_poly_fill_rect_extents(DrawablePtr drawable, GCPtr gc,
 			   int n, xRectangle *rect,
 			   BoxPtr out)
 {
 	BoxRec box;
+	bool clipped;
 
 	if (n == 0)
-		return true;
+		return 0;
 
 	DBG(("%s: [0] = (%d, %d)x(%d, %d)\n",
 	     __FUNCTION__, rect->x, rect->y, rect->width, rect->height));
@@ -3389,9 +3409,12 @@ sna_poly_fill_rect_extents(DrawablePtr drawable, GCPtr gc,
 		box_add_rect(&box, rect);
 	}
 
-	trim_and_translate_box(&box, drawable, gc);
+	clipped = trim_and_translate_box(&box, drawable, gc);
+	if (box_empty(&box))
+		return 0;
+
 	*out = box;
-	return box_empty(&box);
+	return 1 | clipped << 1;
 }
 
 static void
@@ -3399,6 +3422,7 @@ sna_poly_fill_rect(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect)
 {
 	struct sna *sna = to_sna_from_drawable(draw);
 	RegionRec region;
+	unsigned flags;
 
 	DBG(("%s(n=%d, PlaneMask: %lx (solid %d), solid fill: %d [style=%d, tileIsPixel=%d], alu=%d)\n", __FUNCTION__,
 	     n, gc->planemask, !!PM_IS_SOLID(draw, gc->planemask),
@@ -3407,11 +3431,17 @@ sna_poly_fill_rect(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect)
 	     gc->fillStyle, gc->tileIsPixel,
 	     gc->alu));
 
-	if (sna_poly_fill_rect_extents(draw, gc, n, rect, &region.extents)) {
+	flags = sna_poly_fill_rect_extents(draw, gc, n, rect, &region.extents);
+	if (flags == 0) {
 		DBG(("%s, nothing to do\n", __FUNCTION__));
 		return;
 	}
 
+	DBG(("%s: extents(%d, %d), (%d, %d), flags=%x\n", __FUNCTION__,
+	     region.extents.x1, region.extents.y1,
+	     region.extents.x2, region.extents.y2,
+	     flags));
+
 	if (FORCE_FALLBACK)
 		goto fallback;
 
@@ -3435,14 +3465,14 @@ sna_poly_fill_rect(DrawablePtr draw, GCPtr gc, int n, xRectangle *rect)
 		    sna_poly_fill_rect_blt(draw,
 					   priv->gpu_bo,
 					   priv->gpu_only ? NULL : reduce_damage(draw, &priv->gpu_damage, &region.extents),
-					   gc, n, rect))
+					   gc, n, rect, flags & 2))
 			return;
 
 		if (sna_drawable_use_cpu_bo(draw, &region.extents) &&
 		    sna_poly_fill_rect_blt(draw,
 					   priv->cpu_bo,
 					   reduce_damage(draw, &priv->cpu_damage, &region.extents),
-					   gc, n, rect))
+					   gc, n, rect, flags & 2))
 			return;
 	} else if (gc->fillStyle == FillTiled) {
 		struct sna_pixmap *priv = sna_pixmap_from_drawable(draw);
diff --git a/src/sna/sna_blt.c b/src/sna/sna_blt.c
index b317e9e..9ab7d8e 100644
--- a/src/sna/sna_blt.c
+++ b/src/sna/sna_blt.c
@@ -1617,10 +1617,7 @@ Bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
 	    src_bo->tiling, dst_bo->tiling,
 	    src_bo->pitch, dst_bo->pitch));
 
-	if (src_bo->tiling == I915_TILING_Y)
-		return FALSE;
-
-	if (dst_bo->tiling == I915_TILING_Y)
+	if (src_bo->tiling == I915_TILING_Y || dst_bo->tiling == I915_TILING_Y)
 		return FALSE;
 
 	cmd = XY_SRC_COPY_BLT_CMD;
@@ -1688,16 +1685,14 @@ Bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
 			b[1] = br13;
 			b[2] = ((box->y1 + dst_dy) << 16) | (box->x1 + dst_dx);
 			b[3] = ((box->y2 + dst_dy) << 16) | (box->x2 + dst_dx);
-			b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4,
-					      dst_bo,
+			b[4] = kgem_add_reloc(kgem, kgem->nbatch + 4, dst_bo,
 					      I915_GEM_DOMAIN_RENDER << 16 |
 					      I915_GEM_DOMAIN_RENDER |
 					      KGEM_RELOC_FENCED,
 					      0);
 			b[5] = ((box->y1 + src_dy) << 16) | (box->x1 + src_dx);
 			b[6] = src_pitch;
-			b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7,
-					      src_bo,
+			b[7] = kgem_add_reloc(kgem, kgem->nbatch + 7, src_bo,
 					      I915_GEM_DOMAIN_RENDER << 16 |
 					      KGEM_RELOC_FENCED,
 					      0);
@@ -1705,11 +1700,12 @@ Bool sna_blt_copy_boxes(struct sna *sna, uint8_t alu,
 			box++;
 		} while (--nbox_this_time);
 
-		if (nbox) {
-			_kgem_submit(kgem);
-			_kgem_set_mode(kgem, KGEM_BLT);
-		}
-	} while (nbox);
+		if (!nbox)
+			break;
+
+		_kgem_submit(kgem);
+		_kgem_set_mode(kgem, KGEM_BLT);
+	} while (1);
 
 	if (kgem->gen >= 60 && kgem_check_batch(kgem, 3)) {
 		uint32_t *b = kgem->batch + kgem->nbatch;
diff --git a/src/sna/sna_damage.c b/src/sna/sna_damage.c
index 7a97c37..e33fc34 100644
--- a/src/sna/sna_damage.c
+++ b/src/sna/sna_damage.c
@@ -246,9 +246,9 @@ _sna_damage_create_elt(struct sna_damage *damage,
 }
 
 static void
-_sna_damage_create_elt_with_translation(struct sna_damage *damage,
-					const BoxRec *boxes, int count,
-					int16_t dx, int16_t dy)
+_sna_damage_create_elt_from_boxes(struct sna_damage *damage,
+				  const BoxRec *boxes, int count,
+				  int16_t dx, int16_t dy)
 {
 	struct sna_damage_elt *elt;
 	int i;
@@ -308,6 +308,69 @@ _sna_damage_create_elt_with_translation(struct sna_damage *damage,
 	}
 }
 
+static void
+_sna_damage_create_elt_from_rectangles(struct sna_damage *damage,
+				       const xRectangle *r, int count,
+				       int16_t dx, int16_t dy)
+{
+	struct sna_damage_elt *elt;
+	int i;
+
+	DBG(("    %s: n=%d, prev=(remain %d)\n", __FUNCTION__,
+	     damage->n,
+	     damage->last_box ? damage->last_box->remain : 0));
+
+	if (damage->last_box) {
+		int n;
+		BoxRec *b;
+
+		n = count;
+		if (n > damage->last_box->remain)
+			n = damage->last_box->remain;
+
+		elt = damage->elts + damage->n-1;
+		b = elt->box + elt->n;
+		for (i = 0; i < n; i++) {
+			b[i].x1 = r[i].x + dx;
+			b[i].x2 = b[i].x1 + r[i].width;
+			b[i].y1 = r[i].y + dy;
+			b[i].y2 = b[i].y1 + r[i].height;
+		}
+		elt->n += n;
+		damage->last_box->remain -= n;
+		if (damage->last_box->remain == 0)
+			damage->last_box = NULL;
+
+		count -=n;
+		r += n;
+		if (count == 0)
+			return;
+	}
+
+	if (damage->n == damage->size) {
+		int newsize = damage->size * 2;
+		struct sna_damage_elt *newelts = realloc(damage->elts,
+							 newsize*sizeof(*elt));
+		if (newelts == NULL)
+			return;
+
+		damage->elts = newelts;
+		damage->size = newsize;
+	}
+
+	DBG(("    %s(): new elt\n", __FUNCTION__));
+
+	elt = damage->elts + damage->n++;
+	elt->n = count;
+	elt->box = _sna_damage_create_boxes(damage, count);
+	for (i = 0; i < count; i++) {
+		elt->box[i].x1 = r[i].x + dx;
+		elt->box[i].x2 = elt->box[i].x1 + r[i].width;
+		elt->box[i].y1 = r[i].y + dy;
+		elt->box[i].y2 = elt->box[i].y1 + r[i].height;
+	}
+}
+
 static void free_list(struct list *head)
 {
 	while (!list_is_empty(head)) {
@@ -445,6 +508,17 @@ __sna_damage_add_boxes(struct sna_damage *damage,
 
 	assert(n);
 
+	if (!damage)
+		damage = _sna_damage_create();
+	else switch (damage->mode) {
+	case DAMAGE_ALL:
+		return damage;
+	case DAMAGE_SUBTRACT:
+		__sna_damage_reduce(damage);
+	case DAMAGE_ADD:
+		break;
+	}
+
 	extents = box[0];
 	for (i = 1; i < n; i++) {
 		if (extents.x1 > box[i].x1)
@@ -457,33 +531,23 @@ __sna_damage_add_boxes(struct sna_damage *damage,
 			extents.y2 = box[i].y2;
 	}
 
-	if (extents.y2 <= extents.y1 || extents.x2 <= extents.x1)
-		return damage;
+	assert(extents.y2 > extents.y1 && extents.x2 > extents.x1);
 
 	extents.x1 += dx;
 	extents.x2 += dx;
 	extents.y1 += dy;
 	extents.y2 += dy;
 
-	if (!damage)
-		damage = _sna_damage_create();
-	else switch (damage->mode) {
-	case DAMAGE_ALL:
-		return damage;
-	case DAMAGE_SUBTRACT:
-		__sna_damage_reduce(damage);
-	case DAMAGE_ADD:
-		break;
-	}
-
 	if (pixman_region_contains_rectangle(&damage->region,
 					     &extents) == PIXMAN_REGION_IN)
 		return damage;
 
-	_sna_damage_create_elt_with_translation(damage, box, n, dx, dy);
+	_sna_damage_create_elt_from_boxes(damage, box, n, dx, dy);
 
-	if (REGION_NUM_RECTS(&damage->region) <= 1) {
-		__sna_damage_reduce(damage);
+	if (REGION_NUM_RECTS(&damage->region) == 0) {
+		damage->region.extents = *damage->elts[0].box;
+		damage->region.data = NULL;
+		damage->extents = extents;
 	} else {
 		if (damage->extents.x1 > extents.x1)
 			damage->extents.x1 = extents.x1;
@@ -532,6 +596,102 @@ static void _pixman_region_union_box(RegionRec *region, const BoxRec *box)
 	pixman_region_union(region, region, &u);
 }
 
+inline static struct sna_damage *
+__sna_damage_add_rectangles(struct sna_damage *damage,
+			    const xRectangle *r, int n,
+			    int16_t dx, int16_t dy)
+{
+	BoxRec extents;
+	int i;
+
+	assert(n);
+
+	extents.x1 = r[0].x;
+	extents.x2 = r[0].x + r[0].width;
+	extents.y1 = r[0].y;
+	extents.y2 = r[0].y + r[0].height;
+	for (i = 1; i < n; i++) {
+		if (extents.x1 > r[i].x)
+			extents.x1 = r[i].x;
+		if (extents.x2 < r[i].x + r[i].width)
+			extents.x2 = r[i].x + r[i].width;
+		if (extents.y1 > r[i].y)
+			extents.y1 = r[i].y;
+		if (extents.y2 < r[i].y + r[i].height)
+			extents.y2 = r[i].y + r[i].height;
+	}
+
+	if (extents.y2 <= extents.y1 || extents.x2 <= extents.x1)
+		return damage;
+
+	extents.x1 += dx;
+	extents.x2 += dx;
+	extents.y1 += dy;
+	extents.y2 += dy;
+
+	if (!damage)
+		damage = _sna_damage_create();
+	else switch (damage->mode) {
+	case DAMAGE_ALL:
+		return damage;
+	case DAMAGE_SUBTRACT:
+		__sna_damage_reduce(damage);
+	case DAMAGE_ADD:
+		break;
+	}
+
+	if (pixman_region_contains_rectangle(&damage->region,
+					     &extents) == PIXMAN_REGION_IN)
+		return damage;
+
+	_sna_damage_create_elt_from_rectangles(damage, r, n, dx, dy);
+
+	if (REGION_NUM_RECTS(&damage->region) == 0) {
+		damage->region.extents = *damage->elts[0].box;
+		damage->region.data = NULL;
+		damage->extents = extents;
+	} else {
+		if (damage->extents.x1 > extents.x1)
+			damage->extents.x1 = extents.x1;
+		if (damage->extents.x2 < extents.x2)
+			damage->extents.x2 = extents.x2;
+
+		if (damage->extents.y1 > extents.y1)
+			damage->extents.y1 = extents.y1;
+		if (damage->extents.y2 < extents.y2)
+			damage->extents.y2 = extents.y2;
+	}
+
+	return damage;
+}
+
+#if DEBUG_DAMAGE
+struct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage,
+					      const xRectangle *r, int n,
+					      int16_t dx, int16_t dy)
+{
+	char damage_buf[1000];
+
+	DBG(("%s(%s + [(%d, %d), (%d, %d) ... x %d])\n", __FUNCTION__,
+	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
+	     box->x1, box->y1, box->x2, box->y2, n));
+
+	damage = __sna_damage_add_rectangles(damage, r, n, dx, dy);
+
+	ErrorF("  = %s\n",
+	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage));
+
+	return damage;
+}
+#else
+struct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage,
+					      const xRectangle *r, int n,
+					      int16_t dx, int16_t dy)
+{
+	return __sna_damage_add_rectangles(damage, r, n, dx, dy);
+}
+#endif
+
 inline static struct sna_damage *__sna_damage_add_box(struct sna_damage *damage,
 						      const BoxRec *box)
 {
diff --git a/src/sna/sna_damage.h b/src/sna/sna_damage.h
index c402304..30058db 100644
--- a/src/sna/sna_damage.h
+++ b/src/sna/sna_damage.h
@@ -49,6 +49,17 @@ static inline void sna_damage_add_boxes(struct sna_damage **damage,
 	*damage = _sna_damage_add_boxes(*damage, box, n, dx, dy);
 }
 
+struct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage,
+					      const xRectangle *r, int n,
+					      int16_t dx, int16_t dy);
+static inline void sna_damage_add_rectangles(struct sna_damage **damage,
+					     const xRectangle *r, int n,
+					     int16_t dx, int16_t dy)
+{
+	if (damage)
+		*damage = _sna_damage_add_rectangles(*damage, r, n, dx, dy);
+}
+
 struct sna_damage *_sna_damage_is_all(struct sna_damage *damage,
 				       int width, int height);
 static inline bool sna_damage_is_all(struct sna_damage **damage,
commit d6ae86a51cc49dbba579838edd24a94e8f68294c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Oct 21 03:06:20 2011 +0100

    sna: Optimise reduce_damage() to handle all-damaged pixmaps
    
    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 83106a2..c420f0a 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -1960,6 +1960,11 @@ reduce_damage(DrawablePtr drawable,
 	if (*damage == NULL)
 		return damage;
 
+	if (sna_damage_is_all(damage,
+			      pixmap->drawable.width,
+			      pixmap->drawable.height))
+		return NULL;
+
 	get_drawable_deltas(drawable, pixmap, &dx, &dy);
 
 	r = *box;
commit 5b945b85ee938688412df6adfea488766f4656af
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Oct 21 02:45:50 2011 +0100

    sna: Fast-path unclipped fill spans
    
    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 e3d2779..83106a2 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -1768,7 +1768,7 @@ sna_fill_spans_blt(DrawablePtr drawable,
 		   struct kgem_bo *bo, struct sna_damage **damage,
 		   GCPtr gc, int n,
 		   DDXPointPtr pt, int *width, int sorted,
-		   const BoxRec *extents)
+		   const BoxRec *extents, bool clipped)
 {
 	struct sna *sna = to_sna_from_drawable(drawable);
 	PixmapPtr pixmap = get_drawable_pixmap(drawable);
@@ -1799,7 +1799,36 @@ sna_fill_spans_blt(DrawablePtr drawable,
 	}
 
 	get_drawable_deltas(drawable, pixmap, &dx, &dy);
-	do {
+	if (!clipped) {
+		if (damage) {
+			do {
+				BoxRec box;
+
+				box.x1 = pt->x + dx;
+				box.x2 = box.x1 + *width++;
+				box.y1 = pt->y + dy;
+				box.y2 = box.y1 + 1;
+				pt++;
+
+				fill.box(sna, &fill, &box);
+
+				assert_pixmap_contains_box(pixmap, &box);
+				sna_damage_add_box(damage, &box);
+			} while (--n);
+		} else {
+			do {
+				BoxRec box;
+
+				box.x1 = pt->x + dx;
+				box.x2 = box.x1 + *width++;
+				box.y1 = pt->y + dy;
+				box.y2 = box.y1 + 1;
+				pt++;
+
+				fill.box(sna, &fill, &box);
+			} while (--n);
+		}
+	} else do {
 		int16_t X1 = pt->x;
 		int16_t y = pt->y;
 		int16_t X2 = X1 + (int)*width;
@@ -1877,15 +1906,16 @@ sna_fill_spans_blt(DrawablePtr drawable,
 	return TRUE;
 }
 
-static Bool
+static unsigned
 sna_spans_extents(DrawablePtr drawable, GCPtr gc,
 		  int n, DDXPointPtr pt, int *width,
 		  BoxPtr out)
 {
 	BoxRec box;
+	bool clipped = false;
 
 	if (n == 0)
-		return true;
+		return 0;
 
 	box.x1 = pt->x;
 	box.x2 = box.x1 + *width;
@@ -1909,10 +1939,13 @@ sna_spans_extents(DrawablePtr drawable, GCPtr gc,
 	if (gc) {
 		if (!gc->miTranslate)
 			translate_box(&box, drawable);
-		clip_box(&box, gc);
+		clipped = clip_box(&box, gc);
 	}
+	if (box_empty(&box))
+		return 0;
+
 	*out = box;
-	return box_empty(&box);
+	return 1 | clipped << 1;
 }
 
 static struct sna_damage **
@@ -1960,11 +1993,14 @@ sna_fill_spans(DrawablePtr drawable, GCPtr gc, int n,
 {
 	struct sna *sna = to_sna_from_drawable(drawable);
 	RegionRec region;
+	unsigned flags;
 
 	DBG(("%s(n=%d, pt[0]=(%d, %d)\n",
 	     __FUNCTION__, n, pt[0].x, pt[0].y));
 
-	if (sna_spans_extents(drawable, gc, n, pt, width, &region.extents))
+
+	flags = sna_spans_extents(drawable, gc, n, pt, width, &region.extents);
+	if (flags == 0)
 		return;
 
 	DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__,
@@ -1996,7 +2032,7 @@ sna_fill_spans(DrawablePtr drawable, GCPtr gc, int n,
 				       priv->gpu_bo,
 				       priv->gpu_only ? NULL : reduce_damage(drawable, &priv->gpu_damage, &region.extents),
 				       gc, n, pt, width, sorted,
-				       &region.extents))
+				       &region.extents, flags & 2))
 			return;
 
 		if (sna_drawable_use_cpu_bo(drawable, &region.extents) &&
@@ -2004,7 +2040,7 @@ sna_fill_spans(DrawablePtr drawable, GCPtr gc, int n,
 				       priv->cpu_bo,
 				       reduce_damage(drawable, &priv->cpu_damage, &region.extents),
 				       gc, n, pt, width, sorted,
-				       &region.extents))
+				       &region.extents, flags & 2))
 			return;
 	} else if (gc->fillStyle == FillTiled) {
 		xRectangle *rect;
@@ -2049,7 +2085,7 @@ sna_set_spans(DrawablePtr drawable, GCPtr gc, char *src,
 {
 	RegionRec region;
 
-	if (sna_spans_extents(drawable, gc, n, pt, width, &region.extents))
+	if (sna_spans_extents(drawable, gc, n, pt, width, &region.extents) == 0)
 		return;
 
 	DBG(("%s: extents=(%d, %d), (%d, %d)\n", __FUNCTION__,
@@ -3886,7 +3922,7 @@ sna_get_spans(DrawablePtr drawable, int wMax,
 {
 	RegionRec region;
 
-	if (sna_spans_extents(drawable, NULL, n, pt, width, &region.extents))
+	if (sna_spans_extents(drawable, NULL, n, pt, width, &region.extents) == 0)
 		return;
 
 	region.data = NULL;
commit e9a193e9803bb69fc4a7e712f33a36ba395b3c89
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Oct 21 02:20:22 2011 +0100

    sna: Short-circuit GetWindowPixmap() to speed-up pixmap retrieval
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna.h b/src/sna/sna.h
index e67e227..ec4429d 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -145,14 +145,23 @@ struct sna_pixmap {
 	uint8_t gpu :1;
 };
 
-static inline PixmapPtr get_drawable_pixmap(DrawablePtr drawable)
+extern DevPrivateKey sna_window_key;
+
+static inline PixmapPtr get_window_pixmap(WindowPtr window)
 {
-	ScreenPtr screen = drawable->pScreen;
+#if 0
+	return window->drawable.pScreen->GetWindowPixmap(window)
+#else
+	return dixGetPrivate(&window->devPrivates, sna_window_key);
+#endif
+}
 
+static inline PixmapPtr get_drawable_pixmap(DrawablePtr drawable)
+{
 	if (drawable->type == DRAWABLE_PIXMAP)
 		return (PixmapPtr)drawable;
 	else
-		return screen->GetWindowPixmap((WindowPtr)drawable);
+		return get_window_pixmap((WindowPtr)drawable);
 }
 
 extern DevPrivateKeyRec sna_pixmap_index;
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index d818d2c..e3d2779 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -62,6 +62,7 @@
 #define USE_SPANS 0
 
 DevPrivateKeyRec sna_pixmap_index;
+DevPrivateKey sna_window_key;
 
 static inline void region_set(RegionRec *r, const BoxRec *b)
 {
@@ -4157,6 +4158,8 @@ Bool sna_accel_init(ScreenPtr screen, struct sna *sna)
 	if (!sna_glyphs_init(screen))
 		return FALSE;
 
+	sna_window_key = fbGetWinPrivateKey();
+
 	list_init(&sna->dirty_pixmaps);
 	list_init(&sna->deferred_free);
 
commit 662402e41e5c7976002a71a7f961ca97c771b1f3
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Oct 21 02:11:19 2011 +0100

    sna: Micro-optimise PolyLine blt
    
    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 5de1b57..d818d2c 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -2258,8 +2258,6 @@ sna_poly_line_blt(DrawablePtr drawable,
 	get_drawable_deltas(drawable, pixmap, &dx, &dy);
 
 	if (!clipped) {
-		int x, y;
-
 		dx += drawable->x;
 		dy += drawable->y;
 
@@ -2269,30 +2267,35 @@ sna_poly_line_blt(DrawablePtr drawable,
 
 		while (--n) {
 			BoxRec r;
+			DDXPointRec p;
 
-			x = pt->x;
-			y = pt->y;
-			pt++;
+			p = *pt++;
 			if (mode == CoordModePrevious) {
-				x += last.x;
-				y += last.y;
+				p.x += last.x;
+				p.y += last.y;
 			} else {
-				x += dx;
-				y += dy;
+				p.x += dx;
+				p.y += dy;
 			}
-			if (last.x == x) {
+			if (last.x == p.x) {
 				r.x1 = last.x;
 				r.x2 = last.x + 1;
+			} else if (last.x < p.x) {
+				r.x1 = last.x;
+				r.x2 = p.x;
 			} else {
-				r.x1 = last.x < x ? last.x : x;
-				r.x2 = last.x > x ? last.x : x;
+				r.x1 = p.x;
+				r.x2 = last.x;
 			}
-			if (last.y == y) {
+			if (last.y == p.y) {
 				r.y1 = last.y;
 				r.y2 = last.y + 1;
+			} else if (last.y < p.y) {
+				r.y1 = last.y;
+				r.y2 = p.y;
 			} else {
-				r.y1 = last.y < y ? last.y : y;
-				r.y2 = last.y > y ? last.y : y;
+				r.y1 = p.y;
+				r.y2 = last.y;
 			}
 			DBG(("%s: blt (%d, %d), (%d, %d)\n",
 			     __FUNCTION__,
@@ -2303,8 +2306,7 @@ sna_poly_line_blt(DrawablePtr drawable,
 				sna_damage_add_box(damage, &r);
 			}
 
-			last.x = x;
-			last.y = y;
+			last = p;
 		}
 	} else {
 		last.x = drawable->x;
@@ -2314,36 +2316,40 @@ sna_poly_line_blt(DrawablePtr drawable,
 		while (n--) {
 			int nclip;
 			BoxPtr box;
-			int x, y;
+			DDXPointRec p;
 
-			x = pt->x;
-			y = pt->y;
-			pt++;
+			p = *pt++;
 			if (mode == CoordModePrevious) {
-				x += last.x;
-				y += last.y;
+				p.x += last.x;
+				p.y += last.y;
 			} else {
-				x += drawable->x;
-				y += drawable->y;
+				p.x += drawable->x;
+				p.y += drawable->y;
 			}
 
 			if (!first) {
 				for (nclip = REGION_NUM_RECTS(clip), box = REGION_RECTS(clip); nclip--; box++) {
 					BoxRec r;
 
-					if (last.x == x) {
+					if (last.x == p.x) {
 						r.x1 = last.x;
 						r.x2 = last.x + 1;
+					} else if (last.x < p.x) {
+						r.x1 = last.x;
+						r.x2 = p.x;
 					} else {
-						r.x1 = last.x < x ? last.x : x;
-						r.x2 = last.x > x ? last.x : x;
+						r.x1 = p.x;
+						r.x2 = last.x;
 					}
-					if (last.y == y) {
+					if (last.y == p.y) {
 						r.y1 = last.y;
 						r.y2 = last.y + 1;
+					} else if (last.y < p.y) {
+						r.y1 = last.y;
+						r.y2 = p.y;
 					} else {
-						r.y1 = last.y < y ? last.y : y;
-						r.y2 = last.y > y ? last.y : y;
+						r.y1 = p.y;
+						r.y2 = last.y;
 					}
 					DBG(("%s: (%d, %d) -> (%d, %d) clipping line (%d, %d), (%d, %d) against box (%d, %d), (%d, %d)\n",
 					     __FUNCTION__,
@@ -2367,8 +2373,7 @@ sna_poly_line_blt(DrawablePtr drawable,
 				}
 			}
 
-			last.x = x;
-			last.y = y;
+			last = p;
 			first = 0;
 		}
 	}
commit c2040fb8e62076d87f7a5b407505ee3f3482945e
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Oct 21 02:00:44 2011 +0100

    sna: Remove the memset(0) of the fill op
    
    The backends are all expected to initialise the state required.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/gen2_render.c b/src/sna/gen2_render.c
index 98360b8..7c72f41 100644
--- a/src/sna/gen2_render.c
+++ b/src/sna/gen2_render.c
@@ -2099,6 +2099,7 @@ gen2_render_fill(struct sna *sna, uint8_t alu,
 	tmp->base.dst.height = dst->drawable.height;
 	tmp->base.dst.format = sna_format_for_depth(dst->drawable.depth);
 	tmp->base.dst.bo = dst_bo;
+	tmp->base.dst.x = tmp->base.dst.y = 0;
 	tmp->base.floats_per_vertex = 2;
 	tmp->base.floats_per_rect = 6;
 
diff --git a/src/sna/gen4_render.c b/src/sna/gen4_render.c
index f099fbf..0092f60 100644
--- a/src/sna/gen4_render.c
+++ b/src/sna/gen4_render.c
@@ -2558,6 +2558,7 @@ gen4_render_fill(struct sna *sna, uint8_t alu,
 	op->base.dst.height = dst->drawable.height;
 	op->base.dst.format = sna_format_for_depth(dst->drawable.depth);
 	op->base.dst.bo = dst_bo;
+	op->base.dst.x = op->base.dst.y = 0;
 
 	op->base.src.bo =
 		sna_render_get_solid(sna,
@@ -2566,6 +2567,10 @@ gen4_render_fill(struct sna *sna, uint8_t alu,
 	op->base.src.filter = SAMPLER_FILTER_NEAREST;
 	op->base.src.repeat = SAMPLER_EXTEND_REPEAT;
 
+	op->base.mask.bo = NULL;
+	op->base.mask.filter = SAMPLER_FILTER_NEAREST;
+	op->base.mask.repeat = SAMPLER_EXTEND_NONE;
+
 	op->base.is_affine = TRUE;
 	op->base.floats_per_vertex = 3;
 	op->base.u.gen4.wm_kernel = WM_KERNEL;
diff --git a/src/sna/gen5_render.c b/src/sna/gen5_render.c
index db69f06..041e918 100644
--- a/src/sna/gen5_render.c
+++ b/src/sna/gen5_render.c
@@ -1219,8 +1219,11 @@ gen5_emit_invariant(struct sna *sna)
 {
 	/* Ironlake errata workaround: Before disabling the clipper,
 	 * you have to MI_FLUSH to get the pipeline idle.
+	 *
+	 * However, the kernel flushes the pipeline between batches,
+	 * so we should be safe....
+	 * OUT_BATCH(MI_FLUSH | MI_INHIBIT_RENDER_CACHE_FLUSH);
 	 */
-	OUT_BATCH(MI_FLUSH | MI_INHIBIT_RENDER_CACHE_FLUSH);
 	OUT_BATCH(GEN5_PIPELINE_SELECT | PIPELINE_SELECT_3D);
 
 	gen5_emit_sip(sna);
@@ -2573,6 +2576,7 @@ gen5_render_fill(struct sna *sna, uint8_t alu,
 	op->base.dst.height = dst->drawable.height;
 	op->base.dst.format = sna_format_for_depth(dst->drawable.depth);
 	op->base.dst.bo = dst_bo;
+	op->base.dst.x = op->base.dst.y = 0;
 
 	op->base.src.bo =
 		sna_render_get_solid(sna,
@@ -2581,6 +2585,10 @@ gen5_render_fill(struct sna *sna, uint8_t alu,
 	op->base.src.filter = SAMPLER_FILTER_NEAREST;
 	op->base.src.repeat = SAMPLER_EXTEND_REPEAT;
 
+	op->base.mask.bo = NULL;
+	op->base.mask.filter = SAMPLER_FILTER_NEAREST;
+	op->base.mask.repeat = SAMPLER_EXTEND_NONE;
+
 	op->base.is_affine = TRUE;
 	op->base.floats_per_vertex = 3;
 	op->base.u.gen5.wm_kernel = WM_KERNEL;
diff --git a/src/sna/gen6_render.c b/src/sna/gen6_render.c
index fc2fc47..838819d 100644
--- a/src/sna/gen6_render.c
+++ b/src/sna/gen6_render.c
@@ -2793,6 +2793,7 @@ gen6_render_fill(struct sna *sna, uint8_t alu,
 	op->base.dst.height = dst->drawable.height;
 	op->base.dst.format = sna_format_for_depth(dst->drawable.depth);
 	op->base.dst.bo = dst_bo;
+	op->base.dst.x = op->base.dst.y = 0;
 
 	op->base.src.bo =
 		sna_render_get_solid(sna,
@@ -2801,6 +2802,10 @@ gen6_render_fill(struct sna *sna, uint8_t alu,
 	op->base.src.filter = SAMPLER_FILTER_NEAREST;
 	op->base.src.repeat = SAMPLER_EXTEND_REPEAT;
 
+	op->base.mask.bo = NULL;
+	op->base.mask.filter = SAMPLER_FILTER_NEAREST;
+	op->base.mask.repeat = SAMPLER_EXTEND_NONE;
+
 	op->base.is_affine = TRUE;
 	op->base.floats_per_vertex = 3;
 	op->base.floats_per_rect = 9;
diff --git a/src/sna/gen7_render.c b/src/sna/gen7_render.c
index ae77320..ccc0037 100644
--- a/src/sna/gen7_render.c
+++ b/src/sna/gen7_render.c
@@ -2944,6 +2944,7 @@ gen7_render_fill(struct sna *sna, uint8_t alu,
 	op->base.dst.height = dst->drawable.height;
 	op->base.dst.format = sna_format_for_depth(dst->drawable.depth);
 	op->base.dst.bo = dst_bo;
+	op->base.dst.x = op->base.dst.y = 0;
 
 	op->base.src.bo =
 		sna_render_get_solid(sna,
@@ -2952,6 +2953,10 @@ gen7_render_fill(struct sna *sna, uint8_t alu,
 	op->base.src.filter = SAMPLER_FILTER_NEAREST;
 	op->base.src.repeat = SAMPLER_EXTEND_REPEAT;
 
+	op->base.mask.bo = NULL;
+	op->base.mask.filter = SAMPLER_FILTER_NEAREST;
+	op->base.mask.repeat = SAMPLER_EXTEND_NONE;
+
 	op->base.is_affine = TRUE;
 	op->base.floats_per_vertex = 3;
 
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 4b59b55..5de1b57 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -1740,7 +1740,7 @@ box_intersect(BoxPtr a, const BoxRec *b)
 	return a->x1 < a->x2 && a->y1 < a->y2;
 }
 
-static Bool
+inline static bool
 sna_fill_init_blt(struct sna_fill_op *fill,
 		  struct sna *sna,
 		  PixmapPtr pixmap,
@@ -1748,7 +1748,6 @@ sna_fill_init_blt(struct sna_fill_op *fill,
 		  uint8_t alu,
 		  uint32_t pixel)
 {
-	memset(fill, 0, sizeof(*fill));
 	return sna->render.fill(sna, alu, pixmap, bo, pixel, fill);
 }
 
commit 7e7759db4c1dbf8b782fab9b9ca95cfa1db6cf59
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Oct 21 01:41:56 2011 +0100

    sna: Pass a BoxRec to the fill op
    
    For many of the core drawing routines, passing a BoxRec for the fill is
    more convenient since they already have one generated by the clip
    intersection.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/gen2_render.c b/src/sna/gen2_render.c
index 6b30069..98360b8 100644
--- a/src/sna/gen2_render.c
+++ b/src/sna/gen2_render.c
@@ -2038,6 +2038,24 @@ gen2_render_fill_blt(struct sna *sna,
 	VERTEX(y);
 }
 
+fastcall static void
+gen2_render_fill_box(struct sna *sna,
+		     const struct sna_fill_op *op,
+		     const BoxRec *box)
+{
+	if (!gen2_get_rectangles(sna, &op->base, 1)) {
+		gen2_emit_fill_state(sna, &op->base);
+		gen2_get_rectangles(sna, &op->base, 1);
+	}
+
+	VERTEX(box->x2);
+	VERTEX(box->y2);
+	VERTEX(box->x1);
+	VERTEX(box->y2);
+	VERTEX(box->x1);
+	VERTEX(box->y1);
+}
+
 static void
 gen2_render_fill_done(struct sna *sna, const struct sna_fill_op *op)
 {
@@ -2096,6 +2114,7 @@ gen2_render_fill(struct sna *sna, uint8_t alu,
 	}
 
 	tmp->blt  = gen2_render_fill_blt;
+	tmp->box  = gen2_render_fill_box;
 	tmp->done = gen2_render_fill_done;
 
 	gen2_emit_fill_state(sna, &tmp->base);
diff --git a/src/sna/gen3_render.c b/src/sna/gen3_render.c
index 90797d7..6d91f32 100644
--- a/src/sna/gen3_render.c
+++ b/src/sna/gen3_render.c
@@ -3793,6 +3793,24 @@ gen3_render_fill_blt(struct sna *sna,
 	OUT_VERTEX(y);
 }
 
+fastcall static void
+gen3_render_fill_box(struct sna *sna,
+		     const struct sna_fill_op *op,
+		     const BoxRec *box)
+{
+	if (!gen3_get_rectangles(sna, &op->base, 1)) {
+		gen3_emit_composite_state(sna, &op->base);
+		gen3_get_rectangles(sna, &op->base, 1);
+	}
+
+	OUT_VERTEX(box->x2);
+	OUT_VERTEX(box->y2);
+	OUT_VERTEX(box->x1);
+	OUT_VERTEX(box->y2);
+	OUT_VERTEX(box->x1);
+	OUT_VERTEX(box->y1);
+}
+
 static void
 gen3_render_fill_done(struct sna *sna, const struct sna_fill_op *op)
 {
@@ -3852,6 +3870,7 @@ gen3_render_fill(struct sna *sna, uint8_t alu,
 		kgem_submit(&sna->kgem);
 
 	tmp->blt  = gen3_render_fill_blt;
+	tmp->box  = gen3_render_fill_box;
 	tmp->done = gen3_render_fill_done;
 
 	gen3_emit_composite_state(sna, &tmp->base);
diff --git a/src/sna/gen4_render.c b/src/sna/gen4_render.c
index 2c988ff..f099fbf 100644
--- a/src/sna/gen4_render.c
+++ b/src/sna/gen4_render.c
@@ -2503,6 +2503,16 @@ gen4_render_fill_blt(struct sna *sna, const struct sna_fill_op *op,
 	gen4_render_fill_rectangle(sna, &op->base, x, y, w, h);
 }
 
+fastcall static void
+gen4_render_fill_box(struct sna *sna,
+		     const struct sna_fill_op *op,
+		     const BoxRec *box)
+{
+	gen4_render_fill_rectangle(sna, &op->base,
+				   box->x1, box->y1,
+				   box->x2-box->x1, box->y2-box->y1);
+}
+
 static void
 gen4_render_fill_done(struct sna *sna, const struct sna_fill_op *op)
 {
@@ -2568,6 +2578,7 @@ gen4_render_fill(struct sna *sna, uint8_t alu,
 	gen4_align_vertex(sna, &op->base);
 
 	op->blt  = gen4_render_fill_blt;
+	op->box  = gen4_render_fill_box;
 	op->done = gen4_render_fill_done;
 	return TRUE;
 }
diff --git a/src/sna/gen5_render.c b/src/sna/gen5_render.c
index d246d01..db69f06 100644
--- a/src/sna/gen5_render.c
+++ b/src/sna/gen5_render.c
@@ -2504,6 +2504,32 @@ gen5_render_fill_blt(struct sna *sna,
 	OUT_VERTEX_F(0);
 }
 
+fastcall static void
+gen5_render_fill_box(struct sna *sna,
+		     const struct sna_fill_op *op,
+		     const BoxRec *box)
+{
+	DBG(("%s: (%d, %d),(%d, %d)\n", __FUNCTION__,
+	     box->x1, box->y1, box->x2, box->y2));
+
+	if (!gen5_get_rectangles(sna, &op->base, 1)) {
+		gen5_fill_bind_surfaces(sna, &op->base);
+		gen5_get_rectangles(sna, &op->base, 1);
+	}
+
+	OUT_VERTEX(box->x2, box->y2);
+	OUT_VERTEX_F(1);
+	OUT_VERTEX_F(1);
+
+	OUT_VERTEX(box->x1, box->y2);
+	OUT_VERTEX_F(0);
+	OUT_VERTEX_F(1);
+
+	OUT_VERTEX(box->x1, box->y1);
+	OUT_VERTEX_F(0);
+	OUT_VERTEX_F(0);
+}
+
 static void
 gen5_render_fill_done(struct sna *sna,
 		      const struct sna_fill_op *op)
@@ -2567,6 +2593,7 @@ gen5_render_fill(struct sna *sna, uint8_t alu,
 	gen5_align_vertex(sna, &op->base);
 
 	op->blt  = gen5_render_fill_blt;
+	op->box  = gen5_render_fill_box;
 	op->done = gen5_render_fill_done;
 	return TRUE;
 }
diff --git a/src/sna/gen6_render.c b/src/sna/gen6_render.c
index badade0..fc2fc47 100644
--- a/src/sna/gen6_render.c
+++ b/src/sna/gen6_render.c
@@ -2720,6 +2720,32 @@ gen6_render_fill_blt(struct sna *sna,
 	OUT_VERTEX_F(0);
 }
 
+fastcall static void
+gen6_render_fill_box(struct sna *sna,
+		     const struct sna_fill_op *op,
+		     const BoxRec *box)
+{
+	DBG(("%s: (%d, %d),(%d, %d)\n", __FUNCTION__,
+	     box->x1, box->y1, box->x2, box->y2));
+
+	if (!gen6_get_rectangles(sna, &op->base, 1)) {
+		gen6_emit_fill_state(sna, &op->base);
+		gen6_get_rectangles(sna, &op->base, 1);
+	}
+
+	OUT_VERTEX(box->x2, box->y2);
+	OUT_VERTEX_F(1);
+	OUT_VERTEX_F(1);
+
+	OUT_VERTEX(box->x1, box->y2);
+	OUT_VERTEX_F(0);
+	OUT_VERTEX_F(1);
+
+	OUT_VERTEX(box->x1, box->y1);
+	OUT_VERTEX_F(0);
+	OUT_VERTEX_F(0);
+}
+
 static void
 gen6_render_fill_done(struct sna *sna, const struct sna_fill_op *op)
 {
@@ -2791,6 +2817,7 @@ gen6_render_fill(struct sna *sna, uint8_t alu,
 	gen6_align_vertex(sna, &op->base);
 
 	op->blt  = gen6_render_fill_blt;
+	op->box  = gen6_render_fill_box;
 	op->done = gen6_render_fill_done;
 	return TRUE;
 }
diff --git a/src/sna/gen7_render.c b/src/sna/gen7_render.c
index 16c1462..ae77320 100644
--- a/src/sna/gen7_render.c
+++ b/src/sna/gen7_render.c
@@ -2870,6 +2870,32 @@ gen7_render_fill_blt(struct sna *sna,
 	OUT_VERTEX_F(0);
 }
 
+fastcall static void
+gen7_render_fill_box(struct sna *sna,
+		     const struct sna_fill_op *op,
+		     const BoxRec *box)
+{
+	DBG(("%s: (%d, %d),(%d, %d)\n", __FUNCTION__,
+	     box->x1, box->y1, box->x2, box->y2));
+
+	if (!gen7_get_rectangles(sna, &op->base, 1)) {
+		gen7_emit_fill_state(sna, &op->base);
+		gen7_get_rectangles(sna, &op->base, 1);
+	}
+
+	OUT_VERTEX(box->x2, box->y2);
+	OUT_VERTEX_F(1);
+	OUT_VERTEX_F(1);
+
+	OUT_VERTEX(box->x1, box->y2);
+	OUT_VERTEX_F(0);
+	OUT_VERTEX_F(1);
+
+	OUT_VERTEX(box->x1, box->y1);
+	OUT_VERTEX_F(0);
+	OUT_VERTEX_F(0);
+}
+
 static void
 gen7_render_fill_done(struct sna *sna, const struct sna_fill_op *op)
 {
@@ -2941,6 +2967,7 @@ gen7_render_fill(struct sna *sna, uint8_t alu,
 	gen7_align_vertex(sna, &op->base);
 
 	op->blt  = gen7_render_fill_blt;
+	op->box  = gen7_render_fill_box;
 	op->done = gen7_render_fill_done;
 	return TRUE;
 }
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 648f928..4b59b55 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -2298,9 +2298,7 @@ sna_poly_line_blt(DrawablePtr drawable,
 			DBG(("%s: blt (%d, %d), (%d, %d)\n",
 			     __FUNCTION__,
 			     r.x1, r.y1, r.x2, r.y2));
-			fill.blt(sna, &fill,
-				 r.x1, r.y1,
-				 r.x2-r.x1, r.y2-r.y1);
+			fill.box(sna, &fill, &r);
 			if (damage) {
 				assert_pixmap_contains_box(pixmap, &r);
 				sna_damage_add_box(damage, &r);
@@ -2361,9 +2359,7 @@ sna_poly_line_blt(DrawablePtr drawable,
 						DBG(("%s: blt (%d, %d), (%d, %d)\n",
 						     __FUNCTION__,
 						     r.x1, r.y1, r.x2, r.y2));
-						fill.blt(sna, &fill,
-							 r.x1, r.y1,
-							 r.x2-r.x1, r.y2-r.y1);
+						fill.box(sna, &fill, &r);
 						if (damage) {
 							assert_pixmap_contains_box(pixmap, &r);
 							sna_damage_add_box(damage, &r);
@@ -2681,9 +2677,7 @@ sna_poly_segment_blt(DrawablePtr drawable,
 				r.x2 += dx;
 				r.y1 += dy;
 				r.y2 += dy;
-				fill.blt(sna, &fill,
-					 r.x1, r.y1,
-					 r.x2-r.x1, r.y2-r.y1);
+				fill.box(sna, &fill, &r);
 				if (damage) {
 					assert_pixmap_contains_box(pixmap, &r);
 					sna_damage_add_box(damage, &r);
@@ -3047,9 +3041,7 @@ sna_poly_fill_rect_blt(DrawablePtr drawable,
 				r.x2 += dx;
 				r.y1 += dy;
 				r.y2 += dy;
-				fill.blt(sna, &fill,
-					 r.x1, r.y1,
-					 r.x2-r.x1, r.y2-r.y1);
+				fill.box(sna, &fill, &r);
 				if (damage) {
 					assert_pixmap_contains_box(pixmap, &r);
 					sna_damage_add_box(damage, &r);
@@ -3078,9 +3070,7 @@ sna_poly_fill_rect_blt(DrawablePtr drawable,
 				box->x2 += dx;
 				box->y1 += dy;
 				box->y2 += dy;
-				fill.blt(sna, &fill,
-					 box->x1, box->y1,
-					 box->x2-box->x1, box->y2-box->y1);
+				fill.box(sna, &fill, box);
 				if (damage) {
 					assert_pixmap_contains_box(pixmap, box);
 					sna_damage_add_box(damage, box);
@@ -3155,9 +3145,7 @@ sna_poly_fill_rect_tiled(DrawablePtr drawable,
 					r.x2 += dx;
 					r.y1 += dy;
 					r.y2 += dy;
-					fill.blt(sna, &fill,
-						 r.x1, r.y1,
-						 r.x2-r.x1, r.y2-r.y1);
+					fill.box(sna, &fill, &r);
 					if (damage) {
 						assert_pixmap_contains_box(pixmap, &r);
 						sna_damage_add_box(damage, &r);
@@ -3186,10 +3174,7 @@ sna_poly_fill_rect_tiled(DrawablePtr drawable,
 					box->x2 += dx;
 					box->y1 += dy;
 					box->y2 += dy;
-					fill.blt(sna, &fill,
-						 box->x1, box->y1,
-						 box->x2-box->x1,
-						 box->y2-box->y1);
+					fill.box(sna, &fill, box);
 					if (damage) {
 						assert_pixmap_contains_box(pixmap, box);
 						sna_damage_add_box(damage, box);
diff --git a/src/sna/sna_blt.c b/src/sna/sna_blt.c
index 2343838..b317e9e 100644
--- a/src/sna/sna_blt.c
+++ b/src/sna/sna_blt.c
@@ -1272,6 +1272,32 @@ static void sna_blt_fill_op_blt(struct sna *sna,
 	sna_blt_fill_one(sna, &op->base.u.blt, x, y, width, height);
 }
 
+fastcall static void sna_blt_fill_op_box(struct sna *sna,
+					 const struct sna_fill_op *op,
+					 const BoxRec *box)
+{
+	struct kgem *kgem = &sna->kgem;
+	uint32_t *b;
+
+	DBG(("%s: (%d, %d), (%d, %d): %08x\n", __FUNCTION__,
+	     box->x1, box->y1, box->x2, box->y2,
+	     op->base.u.blt.pixel));
+
+	assert(box->x1 >= 0);
+	assert(box->y1 >= 0);
+	assert(box->y2 * op->base.u.blt.bo[0]->pitch <= op->base.u.blt.bo[0]->size);
+
+	if (!kgem_check_batch(kgem, 3))
+		sna_blt_fill_begin(sna, &op->base.u.blt);
+
+	b = kgem->batch + kgem->nbatch;
+	kgem->nbatch += 3;
+
+	b[0] = op->base.u.blt.cmd;
+	b[1] = box->y1 << 16 | box->x1;
+	b[2] = box->y2 << 16 | box->x2;
+}
+
 static void sna_blt_fill_op_done(struct sna *sna,
 				 const struct sna_fill_op *fill)
 {
@@ -1300,6 +1326,7 @@ bool sna_blt_fill(struct sna *sna, uint8_t alu,
 		return FALSE;
 
 	fill->blt  = sna_blt_fill_op_blt;
+	fill->box  = sna_blt_fill_op_box;
 	fill->done = sna_blt_fill_op_done;
 	return TRUE;
 }
diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h
index 0f174f6..d30c0b6 100644
--- a/src/sna/sna_render.h
+++ b/src/sna/sna_render.h
@@ -157,6 +157,9 @@ struct sna_fill_op {
 
 	void (*blt)(struct sna *sna, const struct sna_fill_op *op,
 		    int16_t x, int16_t y, int16_t w, int16_t h);
+	fastcall void (*box)(struct sna *sna,
+			     const struct sna_fill_op *op,
+			     const BoxRec *box);
 	void (*done)(struct sna *sna, const struct sna_fill_op *op);
 };
 
commit 98bca2dbb9c33c548b1d9789ddb633ae0389c8f1
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Oct 21 01:07:52 2011 +0100

    sna: Check whether we can blt whilst determining the PolyLine extents
    
    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 33b079c..648f928 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -2237,33 +2237,6 @@ fallback:
 }
 
 static Bool
-sna_poly_line_can_blt(int mode, int n, DDXPointPtr pt)
-{
-	int i;
-
-	if (mode == CoordModePrevious) {
-		for (i = 1; i < n; i++) {
-			if (pt[i].x != 0 && pt[i].y != 0) {
-				DBG(("%s: diagonal segment[%d]=(%d,%d)\n",
-				     __FUNCTION__, i, pt[i].x, pt[i].y));
-				return FALSE;
-			}
-		}
-	} else {
-		for (i = 1; i < n; i++) {
-			if (pt[i].x != pt[i-1].x && pt[i].y != pt[i-1].y) {
-				DBG(("%s: diagonal segment[%d]=(%d,%d)->(%d,%d)\n",
-				     __FUNCTION__, i,
-				     pt[i-1].x, pt[i-1].y, pt[i].x, pt[i].y));
-				return FALSE;
-			}
-		}
-	}
-
-	return TRUE;
-}
-
-static Bool
 sna_poly_line_blt(DrawablePtr drawable,
 		  struct kgem_bo *bo,
 		  struct sna_damage **damage,
@@ -2408,16 +2381,17 @@ sna_poly_line_blt(DrawablePtr drawable,
 	return TRUE;
 }
 
-static Bool
+static unsigned
 sna_poly_line_extents(DrawablePtr drawable, GCPtr gc,
 		      int mode, int n, DDXPointPtr pt,
-		      BoxPtr out, bool *clipped)
+		      BoxPtr out)
 {
 	BoxRec box;
 	int extra = gc->lineWidth >> 1;
+	bool clip, blt = true;
 
 	if (n == 0)
-		return true;
+		return 0;
 
 	if (n > 1) {
 		if (gc->joinStyle == JoinMiter)
@@ -2435,11 +2409,20 @@ sna_poly_line_extents(DrawablePtr drawable, GCPtr gc,
 			pt++;
 			x += pt->x;
 			y += pt->y;
+			if (blt)
+				blt &= pt->x == 0 || pt->y == 0;
 			box_add_pt(&box, x, y);
 		}
 	} else {
+		int x = box.x1;
+		int y = box.y1;
 		while (--n) {
 			pt++;
+			if (blt) {
+				blt &= pt->x == x || pt->y == y;
+				x = pt->x;
+				y = pt->y;
+			}
 			box_add_pt(&box, pt->x, pt->y);
 		}
 	}
@@ -2453,9 +2436,12 @@ sna_poly_line_extents(DrawablePtr drawable, GCPtr gc,
 		box.y2 += extra;
 	}
 
-	*clipped = trim_and_translate_box(&box, drawable, gc);
+	clip = trim_and_translate_box(&box, drawable, gc);
+	if (box_empty(&box))
+		return 0;
+
 	*out = box;
-	return box_empty(&box);
+	return 1 | blt << 1 | clip << 2;
 }
 
 static void
@@ -2464,13 +2450,14 @@ sna_poly_line(DrawablePtr drawable, GCPtr gc,
 {
 	struct sna *sna = to_sna_from_drawable(drawable);
 	RegionRec region;
-	bool clipped;
+	unsigned flags;
 
 	DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d), lineWidth=%d\n",
 	     __FUNCTION__, mode, n, pt[0].x, pt[0].y, gc->lineWidth));
 
-	if (sna_poly_line_extents(drawable, gc, mode, n, pt,
-				  &region.extents, &clipped))
+	flags = sna_poly_line_extents(drawable, gc, mode, n, pt,
+				      &region.extents);
+	if (flags == 0)
 		return;
 
 	DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__,
@@ -2491,12 +2478,12 @@ sna_poly_line(DrawablePtr drawable, GCPtr gc,
 	     gc->lineStyle, gc->lineStyle == LineSolid,
 	     gc->lineWidth,
 	     gc->planemask, PM_IS_SOLID(drawable, gc->planemask),
-	     sna_poly_line_can_blt(mode, n, pt)));
+	     flags & 2));
 	if (gc->fillStyle == FillSolid &&
 	    gc->lineStyle == LineSolid &&
 	    (gc->lineWidth == 0 || gc->lineWidth == 1) &&
 	    PM_IS_SOLID(drawable, gc->planemask) &&
-	    sna_poly_line_can_blt(mode, n, pt)) {
+	    flags & 2) {
 		struct sna_pixmap *priv = sna_pixmap_from_drawable(drawable);
 
 		DBG(("%s: trying solid fill [%08lx]\n",
@@ -2506,14 +2493,14 @@ sna_poly_line(DrawablePtr drawable, GCPtr gc,
 		    sna_poly_line_blt(drawable,
 				      priv->gpu_bo,
 				      priv->gpu_only ? NULL : reduce_damage(drawable, &priv->gpu_damage, &region.extents),
-				      gc, mode, n, pt, clipped))
+				      gc, mode, n, pt, flags & 4))
 			return;
 
 		if (sna_drawable_use_cpu_bo(drawable, &region.extents) &&
 		    sna_poly_line_blt(drawable,
 				      priv->cpu_bo,
 				      reduce_damage(drawable, &priv->cpu_damage, &region.extents),
-				      gc, mode, n, pt, clipped))
+				      gc, mode, n, pt, flags & 4))
 			return;
 	}
 
commit 91f49549750aac99d38ae8f3a132c955a2c8d8f5
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Oct 21 00:42:43 2011 +0100

    sna: Speed-up blitting of unclipped lines
    
    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 8153d34..33b079c 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -916,37 +916,45 @@ static void sna_gc_move_to_cpu(GCPtr gc)
 		sna_drawable_move_to_cpu(&gc->tile.pixmap->drawable, false);
 }
 
-static inline void trim_box(BoxPtr box, DrawablePtr d)
+static inline bool trim_box(BoxPtr box, DrawablePtr d)
 {
+	bool clipped = false;
+
 	if (box->x1 < 0)
-		box->x1 = 0;
+		box->x1 = 0, clipped = true;
 	if (box->x2 > d->width)
-		box->x2 = d->width;
+		box->x2 = d->width, clipped = true;
 
 	if (box->y1 < 0)
-		box->y1 = 0;
+		box->y1 = 0, clipped = true;
 	if (box->y2 > d->height)
-		box->y2 = d->height;
+		box->y2 = d->height, clipped = true;
+
+	return clipped;
 }
 
-static inline void clip_box(BoxPtr box, GCPtr gc)
+static inline bool clip_box(BoxPtr box, GCPtr gc)
 {
 	const BoxRec *clip;
+	bool clipped;
 
 	if (!gc->pCompositeClip)
-		return;
+		return false;
 
 	clip = &gc->pCompositeClip->extents;
 
+	clipped = gc->pCompositeClip->data != NULL;
 	if (box->x1 < clip->x1)
-		box->x1 = clip->x1;
+		box->x1 = clip->x1, clipped = true;
 	if (box->x2 > clip->x2)
-		box->x2 = clip->x2;
+		box->x2 = clip->x2, clipped = true;
 
 	if (box->y1 < clip->y1)
-		box->y1 = clip->y1;
+		box->y1 = clip->y1, clipped = true;
 	if (box->y2 > clip->y2)
-		box->y2 = clip->y2;
+		box->y2 = clip->y2, clipped = true;
+
+	return clipped;
 }
 
 static inline void translate_box(BoxPtr box, DrawablePtr d)
@@ -958,11 +966,12 @@ static inline void translate_box(BoxPtr box, DrawablePtr d)
 	box->y2 += d->y;
 }
 
-static inline void trim_and_translate_box(BoxPtr box, DrawablePtr d, GCPtr gc)
+static inline bool trim_and_translate_box(BoxPtr box, DrawablePtr d, GCPtr gc)
 {
-	trim_box(box, d);
+	bool clipped = trim_box(box, d);
 	translate_box(box, d);
-	clip_box(box, gc);
+	clipped |= clip_box(box, gc);
+	return clipped;
 }
 
 static inline void box_add_pt(BoxPtr box, int16_t x, int16_t y)
@@ -2258,7 +2267,8 @@ static Bool
 sna_poly_line_blt(DrawablePtr drawable,
 		  struct kgem_bo *bo,
 		  struct sna_damage **damage,
-		  GCPtr gc, int mode, int n, DDXPointPtr pt)
+		  GCPtr gc, int mode, int n, DDXPointPtr pt,
+		  bool clipped)
 {
 	struct sna *sna = to_sna_from_drawable(drawable);
 	PixmapPtr pixmap = get_drawable_pixmap(drawable);
@@ -2275,71 +2285,124 @@ sna_poly_line_blt(DrawablePtr drawable,
 
 	get_drawable_deltas(drawable, pixmap, &dx, &dy);
 
-	last.x = drawable->x;
-	last.y = drawable->y;
-	first = 1;
-
-	while (n--) {
-		int nclip;
-		BoxPtr box;
+	if (!clipped) {
 		int x, y;
 
-		x = pt->x;
-		y = pt->y;
+		dx += drawable->x;
+		dy += drawable->y;
+
+		last.x = pt->x + dx;
+		last.y = pt->y + dy;
 		pt++;
-		if (mode == CoordModePrevious) {
-			x += last.x;
-			y += last.y;
-		} else {
-			x += drawable->x;
-			y += drawable->y;
+
+		while (--n) {
+			BoxRec r;
+
+			x = pt->x;
+			y = pt->y;
+			pt++;
+			if (mode == CoordModePrevious) {
+				x += last.x;
+				y += last.y;
+			} else {
+				x += dx;
+				y += dy;
+			}
+			if (last.x == x) {
+				r.x1 = last.x;
+				r.x2 = last.x + 1;
+			} else {
+				r.x1 = last.x < x ? last.x : x;
+				r.x2 = last.x > x ? last.x : x;
+			}
+			if (last.y == y) {
+				r.y1 = last.y;
+				r.y2 = last.y + 1;
+			} else {
+				r.y1 = last.y < y ? last.y : y;
+				r.y2 = last.y > y ? last.y : y;
+			}
+			DBG(("%s: blt (%d, %d), (%d, %d)\n",
+			     __FUNCTION__,
+			     r.x1, r.y1, r.x2, r.y2));
+			fill.blt(sna, &fill,
+				 r.x1, r.y1,
+				 r.x2-r.x1, r.y2-r.y1);
+			if (damage) {
+				assert_pixmap_contains_box(pixmap, &r);
+				sna_damage_add_box(damage, &r);
+			}
+
+			last.x = x;
+			last.y = y;
 		}
+	} else {
+		last.x = drawable->x;
+		last.y = drawable->y;
+		first = 1;
 
-		if (!first) {
-			for (nclip = REGION_NUM_RECTS(clip), box = REGION_RECTS(clip); nclip--; box++) {
-				BoxRec r;
+		while (n--) {
+			int nclip;
+			BoxPtr box;
+			int x, y;
 
-				if (last.x == x) {
-					r.x1 = last.x;
-					r.x2 = last.x + 1;
-				} else {
-					r.x1 = last.x < x ? last.x : x;
-					r.x2 = last.x > x ? last.x : x;
-				}
-				if (last.y == y) {
-					r.y1 = last.y;
-					r.y2 = last.y + 1;
-				} else {
-					r.y1 = last.y < y ? last.y : y;
-					r.y2 = last.y > y ? last.y : y;
-				}
-				DBG(("%s: (%d, %d) -> (%d, %d) clipping line (%d, %d), (%d, %d) against box (%d, %d), (%d, %d)\n",
-				     __FUNCTION__,
-				     last.x, last.y, x, y,
-				     r.x1, r.y1, r.x2, r.y2,
-				     box->x1, box->y1, box->x2, box->y2));
-				if (box_intersect(&r, box)) {
-					r.x1 += dx;
-					r.x2 += dx;
-					r.y1 += dy;
-					r.y2 += dy;
-					DBG(("%s: blt (%d, %d), (%d, %d)\n",
+			x = pt->x;
+			y = pt->y;
+			pt++;
+			if (mode == CoordModePrevious) {
+				x += last.x;
+				y += last.y;
+			} else {
+				x += drawable->x;
+				y += drawable->y;
+			}
+
+			if (!first) {
+				for (nclip = REGION_NUM_RECTS(clip), box = REGION_RECTS(clip); nclip--; box++) {
+					BoxRec r;
+
+					if (last.x == x) {
+						r.x1 = last.x;
+						r.x2 = last.x + 1;
+					} else {
+						r.x1 = last.x < x ? last.x : x;
+						r.x2 = last.x > x ? last.x : x;
+					}
+					if (last.y == y) {
+						r.y1 = last.y;
+						r.y2 = last.y + 1;
+					} else {
+						r.y1 = last.y < y ? last.y : y;
+						r.y2 = last.y > y ? last.y : y;
+					}
+					DBG(("%s: (%d, %d) -> (%d, %d) clipping line (%d, %d), (%d, %d) against box (%d, %d), (%d, %d)\n",
 					     __FUNCTION__,
-					     r.x1, r.y1, r.x2, r.y2));
-					fill.blt(sna, &fill,
-						 r.x1, r.y1,
-						 r.x2-r.x1, r.y2-r.y1);
-					if (damage) {
-						assert_pixmap_contains_box(pixmap, &r);
-						sna_damage_add_box(damage, &r);
+					     last.x, last.y, x, y,
+					     r.x1, r.y1, r.x2, r.y2,
+					     box->x1, box->y1, box->x2, box->y2));
+					if (box_intersect(&r, box)) {
+						r.x1 += dx;
+						r.x2 += dx;
+						r.y1 += dy;
+						r.y2 += dy;
+						DBG(("%s: blt (%d, %d), (%d, %d)\n",
+						     __FUNCTION__,
+						     r.x1, r.y1, r.x2, r.y2));
+						fill.blt(sna, &fill,
+							 r.x1, r.y1,
+							 r.x2-r.x1, r.y2-r.y1);
+						if (damage) {
+							assert_pixmap_contains_box(pixmap, &r);
+							sna_damage_add_box(damage, &r);
+						}
 					}
 				}
 			}
-		}
 
-		last.x = x;
-		last.y = y;
-		first = 0;
+			last.x = x;
+			last.y = y;
+			first = 0;
+		}
 	}
 	fill.done(sna, &fill);
 	return TRUE;
@@ -2348,7 +2411,7 @@ sna_poly_line_blt(DrawablePtr drawable,
 static Bool
 sna_poly_line_extents(DrawablePtr drawable, GCPtr gc,
 		      int mode, int n, DDXPointPtr pt,
-		      BoxPtr out)
+		      BoxPtr out, bool *clipped)
 {
 	BoxRec box;
 	int extra = gc->lineWidth >> 1;
@@ -2390,7 +2453,7 @@ sna_poly_line_extents(DrawablePtr drawable, GCPtr gc,
 		box.y2 += extra;
 	}
 
-	trim_and_translate_box(&box, drawable, gc);
+	*clipped = trim_and_translate_box(&box, drawable, gc);
 	*out = box;
 	return box_empty(&box);
 }
@@ -2401,11 +2464,13 @@ sna_poly_line(DrawablePtr drawable, GCPtr gc,
 {
 	struct sna *sna = to_sna_from_drawable(drawable);
 	RegionRec region;
+	bool clipped;
 
 	DBG(("%s(mode=%d, n=%d, pt[0]=(%d, %d), lineWidth=%d\n",
 	     __FUNCTION__, mode, n, pt[0].x, pt[0].y, gc->lineWidth));
 
-	if (sna_poly_line_extents(drawable, gc, mode, n, pt, &region.extents))
+	if (sna_poly_line_extents(drawable, gc, mode, n, pt,
+				  &region.extents, &clipped))
 		return;
 
 	DBG(("%s: extents (%d, %d), (%d, %d)\n", __FUNCTION__,
@@ -2440,15 +2505,15 @@ sna_poly_line(DrawablePtr drawable, GCPtr gc,
 		if (sna_drawable_use_gpu_bo(drawable, &region.extents) &&
 		    sna_poly_line_blt(drawable,
 				      priv->gpu_bo,
-				      priv->gpu_only ? NULL : &priv->gpu_damage,
-				      gc, mode, n, pt))
+				      priv->gpu_only ? NULL : reduce_damage(drawable, &priv->gpu_damage, &region.extents),
+				      gc, mode, n, pt, clipped))
 			return;
 
 		if (sna_drawable_use_cpu_bo(drawable, &region.extents) &&
 		    sna_poly_line_blt(drawable,
 				      priv->cpu_bo,
-				      &priv->cpu_damage,
-				      gc, mode, n, pt))
+				      reduce_damage(drawable, &priv->cpu_damage, &region.extents),
+				      gc, mode, n, pt, clipped))
 			return;
 	}
 
commit 06d7574d7da047a6314be5af27f4ac47ccd5a350
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Oct 20 21:38:30 2011 +0100

    sna/damage: Stash the last freed damage for quick reallocation
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_damage.c b/src/sna/sna_damage.c
index 0194f5c..7a97c37 100644
--- a/src/sna/sna_damage.c
+++ b/src/sna/sna_damage.c
@@ -48,6 +48,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  * cheapy discard no-ops.
  */
 
+static struct sna_damage *__freed_damage;
+
 #if DEBUG_DAMAGE
 #undef DBG
 #define DBG(x) ErrorF x
@@ -146,7 +148,11 @@ static struct sna_damage *_sna_damage_create(void)
 {
 	struct sna_damage *damage;
 
-	damage = malloc(sizeof(*damage));
+	if (__freed_damage) {
+		damage = __freed_damage;
+		__freed_damage = NULL;
+	} else
+		damage = malloc(sizeof(*damage));
 	damage->n = 0;
 	damage->size = 16;
 	damage->elts = malloc(sizeof(*damage->elts) * damage->size);
@@ -958,7 +964,10 @@ void __sna_damage_destroy(struct sna_damage *damage)
 	free_list(&damage->boxes);
 
 	pixman_region_fini(&damage->region);
-	free(damage);
+	if (__freed_damage == NULL)
+		__freed_damage = damage;
+	else
+		free(damage);
 }
 
 #if DEBUG_DAMAGE && TEST_DAMAGE
commit 1471ef82b595a207dc8873c45176ec31f277a43f
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Oct 20 21:32:14 2011 +0100

    sna/damage: Only track the mode globally
    
    As damage accumulation is handled modally, we do not need to track the
    mode per elt and so attempt to simplify the code.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_damage.c b/src/sna/sna_damage.c
index b5d0084..0194f5c 100644
--- a/src/sna/sna_damage.c
+++ b/src/sna/sna_damage.c
@@ -31,6 +31,23 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include "sna.h"
 #include "sna_damage.h"
 
+/*
+ * sna_damage is a batching layer on top of the regular pixman_region_t.
+ * It is required as the ever-growing accumulation of invidual small
+ * damage regions is an O(n^2) operation. Instead the accumulation of a
+ * batch can be done in closer to O(n.lgn), and so prevents abysmal
+ * performance in x11perf -copywinwin10.
+ *
+ * As with the core of SNA, damage is handled modally. That is, it
+ * accumulates whilst rendering and then subtracts during migration of the
+ * pixmap from GPU to CPU or vice versa. As such we can track the current
+ * mode globally and when that mode switches perform the update of the region
+ * in a single operation.
+ *
+ * Furthermore, we can track whether the whole pixmap is damaged and so
+ * cheapy discard no-ops.
+ */
+
 #if DEBUG_DAMAGE
 #undef DBG
 #define DBG(x) ErrorF x
@@ -121,10 +138,6 @@ struct sna_damage_box {
 };
 
 struct sna_damage_elt {
-	enum mode {
-		ADD,
-		SUBTRACT,
-	} mode;
 	BoxPtr box;
 	uint16_t n;
 };
@@ -134,13 +147,12 @@ static struct sna_damage *_sna_damage_create(void)
 	struct sna_damage *damage;
 
 	damage = malloc(sizeof(*damage));
-	damage->all = 0;
 	damage->n = 0;
 	damage->size = 16;
 	damage->elts = malloc(sizeof(*damage->elts) * damage->size);
 	list_init(&damage->boxes);
 	damage->last_box = NULL;
-	damage->mode = ADD;
+	damage->mode = DAMAGE_ADD;
 	pixman_region_init(&damage->region);
 	damage->extents.x1 = damage->extents.y1 = MAXSHORT;
 	damage->extents.x2 = damage->extents.y2 = MINSHORT;
@@ -180,18 +192,15 @@ static BoxPtr _sna_damage_create_boxes(struct sna_damage *damage,
 
 static void
 _sna_damage_create_elt(struct sna_damage *damage,
-		       enum mode mode,
 		       const BoxRec *boxes, int count)
 {
 	struct sna_damage_elt *elt;
 
-	DBG(("    %s(%s): n=%d, prev=(%s, remain %d)\n", __FUNCTION__,
-	     mode == ADD ? "add" : "subtract",
+	DBG(("    %s: n=%d, prev=(remain %d)\n", __FUNCTION__,
 	     damage->n,
-	     damage->n ? damage->elts[damage->n-1].mode == ADD ? "add" : "subtract" : "none",
 	     damage->last_box ? damage->last_box->remain : 0));
 
-	if (damage->last_box && damage->elts[damage->n-1].mode == mode) {
+	if (damage->last_box) {
 		int n;
 
 		n = count;
@@ -225,7 +234,6 @@ _sna_damage_create_elt(struct sna_damage *damage,
 	DBG(("    %s(): new elt\n", __FUNCTION__));
 
 	elt = damage->elts + damage->n++;
-	elt->mode = mode;
 	elt->n = count;
 	elt->box = memcpy(_sna_damage_create_boxes(damage, count),
 			  boxes, count * sizeof(BoxRec));
@@ -233,20 +241,17 @@ _sna_damage_create_elt(struct sna_damage *damage,
 
 static void
 _sna_damage_create_elt_with_translation(struct sna_damage *damage,
-					enum mode mode,
 					const BoxRec *boxes, int count,
 					int16_t dx, int16_t dy)
 {
 	struct sna_damage_elt *elt;
 	int i;
 
-	DBG(("    %s(%s): n=%d, prev=(%s, remain %d)\n", __FUNCTION__,
-	     mode == ADD ? "add" : "subtract",
+	DBG(("    %s: n=%d, prev=(remain %d)\n", __FUNCTION__,
 	     damage->n,
-	     damage->n ? damage->elts[damage->n-1].mode == ADD ? "add" : "subtract" : "none",
 	     damage->last_box ? damage->last_box->remain : 0));
 
-	if (damage->last_box && damage->elts[damage->n-1].mode == mode) {
+	if (damage->last_box) {
 		int n;
 		BoxRec *b;
 
@@ -287,7 +292,6 @@ _sna_damage_create_elt_with_translation(struct sna_damage *damage,
 	DBG(("    %s(): new elt\n", __FUNCTION__));
 
 	elt = damage->elts + damage->n++;
-	elt->mode = mode;
 	elt->n = count;
 	elt->box = _sna_damage_create_boxes(damage, count);
 	for (i = 0; i < count; i++) {
@@ -309,64 +313,35 @@ static void free_list(struct list *head)
 
 static void __sna_damage_reduce(struct sna_damage *damage)
 {
-	int n, m, j;
-	int nboxes;
+	int n, nboxes;
 	BoxPtr boxes;
 	pixman_region16_t tmp, *region = &damage->region;
 
-	assert(!damage->all);
+	assert(damage->mode != DAMAGE_ALL);
+	assert(damage->n);
 
 	DBG(("    reduce: before damage.n=%d region.n=%d\n",
 	     damage->n, REGION_NUM_RECTS(region)));
 
-	m = 0;
 	nboxes = damage->elts[0].n;
-	boxes = damage->elts[0].box;
-	for (n = 1; n < damage->n; n++) {
-		if (damage->elts[n].mode != damage->elts[m].mode) {
-			if (!boxes) {
-				boxes = malloc(sizeof(BoxRec)*nboxes);
-				nboxes = 0;
-				for (j = m; j < n; j++) {
-					memcpy(boxes+nboxes,
-					       damage->elts[j].box,
-					       damage->elts[j].n*sizeof(BoxRec));
-					nboxes += damage->elts[j].n;
-				}
-			}
-
-			pixman_region_init_rects(&tmp, boxes, nboxes);
-			if (damage->elts[m].mode == ADD)
-				pixman_region_union(region, region, &tmp);
-			else
-				pixman_region_subtract(region, region, &tmp);
-			pixman_region_fini(&tmp);
-
-			if (boxes != damage->elts[m].box)
-				free(boxes);
-
-			m = n;
-			boxes = damage->elts[n].box;
-			nboxes = damage->elts[n].n;
-		} else {
-			boxes = NULL;
+	if (damage->n == 1) {
+		boxes = damage->elts[0].box;
+	} else {
+		for (n = 1; n < damage->n; n++)
 			nboxes += damage->elts[n].n;
-		}
-	}
 
-	if (!boxes) {
 		boxes = malloc(sizeof(BoxRec)*nboxes);
 		nboxes = 0;
-		for (j = m; j < n; j++) {
+		for (n = 0; n < damage->n; n++) {
 			memcpy(boxes+nboxes,
-			       damage->elts[j].box,
-			       damage->elts[j].n*sizeof(BoxRec));
-			nboxes += damage->elts[j].n;
+			       damage->elts[n].box,
+			       damage->elts[n].n*sizeof(BoxRec));
+			nboxes += damage->elts[n].n;
 		}
 	}
 
 	pixman_region_init_rects(&tmp, boxes, nboxes);
-	if (damage->elts[m].mode == ADD)
+	if (damage->mode == DAMAGE_ADD)
 		pixman_region_union(region, region, &tmp);
 	else
 		pixman_region_subtract(region, region, &tmp);
@@ -374,13 +349,13 @@ static void __sna_damage_reduce(struct sna_damage *damage)
 
 	damage->extents = region->extents;
 
-	if (boxes != damage->elts[m].box)
+	if (boxes != damage->elts[0].box)
 		free(boxes);
 
 	damage->n = 0;
+	damage->mode = DAMAGE_ADD;
 	free_list(&damage->boxes);
 	damage->last_box = NULL;
-	damage->mode = ADD;
 
 	DBG(("    reduce: after region.n=%d\n", REGION_NUM_RECTS(region)));
 }
@@ -393,13 +368,14 @@ inline static struct sna_damage *__sna_damage_add(struct sna_damage *damage,
 
 	if (!damage)
 		damage = _sna_damage_create();
-
-	if (damage->all)
+	else switch (damage->mode) {
+	case DAMAGE_ALL:
 		return damage;
-
-	if (damage->mode == SUBTRACT)
+	case DAMAGE_SUBTRACT:
 		__sna_damage_reduce(damage);
-	damage->mode = ADD;
+	case DAMAGE_ADD:
+		break;
+	}
 
 	if (REGION_NUM_RECTS(&damage->region) <= 1) {
 		pixman_region_union(&damage->region, &damage->region, region);
@@ -411,9 +387,8 @@ inline static struct sna_damage *__sna_damage_add(struct sna_damage *damage,
 					     &region->extents) == PIXMAN_REGION_IN)
 		return damage;
 
-	_sna_damage_create_elt(damage, ADD,
-			       REGION_RECTS(region),
-			       REGION_NUM_RECTS(region));
+	_sna_damage_create_elt(damage,
+			       REGION_RECTS(region), REGION_NUM_RECTS(region));
 
 	if (damage->extents.x1 > region->extents.x1)
 		damage->extents.x1 = region->extents.x1;
@@ -486,29 +461,34 @@ __sna_damage_add_boxes(struct sna_damage *damage,
 
 	if (!damage)
 		damage = _sna_damage_create();
-
-	if (damage->all)
+	else switch (damage->mode) {
+	case DAMAGE_ALL:
 		return damage;
-
-	if (damage->mode == SUBTRACT)
+	case DAMAGE_SUBTRACT:
 		__sna_damage_reduce(damage);
-	damage->mode = ADD;
+	case DAMAGE_ADD:
+		break;
+	}
 
 	if (pixman_region_contains_rectangle(&damage->region,
 					     &extents) == PIXMAN_REGION_IN)
 		return damage;
 
-	_sna_damage_create_elt_with_translation(damage, ADD, box, n, dx, dy);
+	_sna_damage_create_elt_with_translation(damage, box, n, dx, dy);
 
-	if (damage->extents.x1 > extents.x1)
-		damage->extents.x1 = extents.x1;
-	if (damage->extents.x2 < extents.x2)
-		damage->extents.x2 = extents.x2;
-
-	if (damage->extents.y1 > extents.y1)
-		damage->extents.y1 = extents.y1;
-	if (damage->extents.y2 < extents.y2)
-		damage->extents.y2 = extents.y2;
+	if (REGION_NUM_RECTS(&damage->region) <= 1) {
+		__sna_damage_reduce(damage);
+	} else {
+		if (damage->extents.x1 > extents.x1)
+			damage->extents.x1 = extents.x1;
+		if (damage->extents.x2 < extents.x2)
+			damage->extents.x2 = extents.x2;
+
+		if (damage->extents.y1 > extents.y1)
+			damage->extents.y1 = extents.y1;
+		if (damage->extents.y2 < extents.y2)
+			damage->extents.y2 = extents.y2;
+	}
 
 	return damage;
 }
@@ -524,7 +504,7 @@ struct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
 	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
 	     box->x1, box->y1, box->x2, box->y2, n));
 
-	damage = __sna_damage_add_box(damage, boxes, n, dx, dy);
+	damage = __sna_damage_add_boxes(damage, boxes, n, dx, dy);
 
 	ErrorF("  = %s\n",
 	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage));
@@ -540,6 +520,12 @@ struct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
 }
 #endif
 
+static void _pixman_region_union_box(RegionRec *region, const BoxRec *box)
+{
+	RegionRec u = { *box, NULL };
+	pixman_region_union(region, region, &u);
+}
+
 inline static struct sna_damage *__sna_damage_add_box(struct sna_damage *damage,
 						      const BoxRec *box)
 {
@@ -548,25 +534,31 @@ inline static struct sna_damage *__sna_damage_add_box(struct sna_damage *damage,
 
 	if (!damage)
 		damage = _sna_damage_create();
-
-	if (damage->all)
+	else switch (damage->mode) {
+	case DAMAGE_ALL:
 		return damage;
-
-	if (damage->mode == SUBTRACT)
+	case DAMAGE_SUBTRACT:
 		__sna_damage_reduce(damage);
-	damage->mode = ADD;
+	case DAMAGE_ADD:
+		break;
+	}
 
-	if (REGION_NUM_RECTS(&damage->region) == 0) {
+	switch (REGION_NUM_RECTS(&damage->region)) {
+	case 0:
 		pixman_region_init_rects(&damage->region, box, 1);
 		damage->extents = *box;
 		return damage;
+	case 1:
+		_pixman_region_union_box(&damage->region, box);
+		damage->extents = damage->region.extents;
+		return damage;
 	}
 
 	if (pixman_region_contains_rectangle(&damage->region,
 					     (BoxPtr)box) == PIXMAN_REGION_IN)
 		return damage;
 
-	_sna_damage_create_elt(damage, ADD, box, 1);
+	_sna_damage_create_elt(damage, box, 1);
 
 	if (damage->extents.x1 > box->x1)
 		damage->extents.x1 = box->x1;
@@ -621,8 +613,7 @@ struct sna_damage *_sna_damage_all(struct sna_damage *damage,
 
 	pixman_region_init_rect(&damage->region, 0, 0, width, height);
 	damage->extents = damage->region.extents;
-	damage->mode = ADD;
-	damage->all = 1;
+	damage->mode = DAMAGE_ALL;
 
 	return damage;
 }
@@ -632,9 +623,6 @@ struct sna_damage *_sna_damage_is_all(struct sna_damage *damage,
 {
 	BoxRec box;
 
-	if (damage->mode == SUBTRACT)
-		return damage;
-
 	box.x1 = box.y1 = 0;
 	box.x2 = width;
 	box.y2 = height;
@@ -677,7 +665,10 @@ static struct sna_damage *__sna_damage_subtract(struct sna_damage *damage,
 	if (!sna_damage_maybe_contains_box(damage, &region->extents))
 		return damage;
 
-	if (damage->n == 0) {
+	if (damage->mode != DAMAGE_SUBTRACT) {
+		if (damage->n)
+			__sna_damage_reduce(damage);
+
 		if (pixman_region_equal(region, &damage->region)) {
 			__sna_damage_destroy(damage);
 			return NULL;
@@ -694,16 +685,15 @@ static struct sna_damage *__sna_damage_subtract(struct sna_damage *damage,
 					       &damage->region,
 					       region);
 			damage->extents = damage->region.extents;
-			damage->all = 0;
+			damage->mode = DAMAGE_ADD; /* reduce from ALL */
 			return damage;
 		}
+
+		damage->mode = DAMAGE_SUBTRACT;
 	}
 
-	damage->all = 0;
-	damage->mode = SUBTRACT;
-	_sna_damage_create_elt(damage, SUBTRACT,
-			       REGION_RECTS(region),
-			       REGION_NUM_RECTS(region));
+	_sna_damage_create_elt(damage,
+			       REGION_RECTS(region), REGION_NUM_RECTS(region));
 
 	return damage;
 }
@@ -748,7 +738,10 @@ inline static struct sna_damage *__sna_damage_subtract_box(struct sna_damage *da
 	if (!sna_damage_maybe_contains_box(damage, box))
 		return damage;
 
-	if (damage->n == 0) {
+	if (damage->mode != DAMAGE_SUBTRACT) {
+		if (damage->n)
+			__sna_damage_reduce(damage);
+
 		if (!pixman_region_not_empty(&damage->region)) {
 			__sna_damage_destroy(damage);
 			return NULL;
@@ -762,15 +755,14 @@ inline static struct sna_damage *__sna_damage_subtract_box(struct sna_damage *da
 					       &damage->region,
 					       &region);
 			damage->extents = damage->region.extents;
-			damage->all = 0;
+			damage->mode = DAMAGE_ADD;
 			return damage;
 		}
-	}
 
-	damage->all = 0;
-	damage->mode = SUBTRACT;
-	_sna_damage_create_elt(damage, SUBTRACT, box, 1);
+		damage->mode = DAMAGE_SUBTRACT;
+	}
 
+	_sna_damage_create_elt(damage, box, 1);
 	return damage;
 }
 
@@ -805,14 +797,14 @@ static int _sna_damage_contains_box(struct sna_damage *damage,
 	if (!damage)
 		return PIXMAN_REGION_OUT;
 
-	if (damage->all)
+	if (damage->mode == DAMAGE_ALL)
 		return PIXMAN_REGION_IN;
 
 	if (!sna_damage_maybe_contains_box(damage, box))
 		return PIXMAN_REGION_OUT;
 
 	if (damage->n) {
-		if (damage->mode != SUBTRACT) {
+		if (damage->mode != DAMAGE_SUBTRACT) {
 			int ret = pixman_region_contains_rectangle(&damage->region,
 								   (BoxPtr)box);
 			if (ret == PIXMAN_REGION_IN)
@@ -859,6 +851,11 @@ static Bool _sna_damage_intersect(struct sna_damage *damage,
 	if (!damage)
 		return FALSE;
 
+	if (damage->mode == DAMAGE_ALL) {
+		RegionCopy(result, region);
+		return TRUE;
+	}
+
 	if (region->extents.x2 <= damage->extents.x1 ||
 	    region->extents.x1 >= damage->extents.x2)
 		return FALSE;
diff --git a/src/sna/sna_damage.h b/src/sna/sna_damage.h
index 454ad84..c402304 100644
--- a/src/sna/sna_damage.h
+++ b/src/sna/sna_damage.h
@@ -4,15 +4,20 @@
 #include <regionstr.h>
 #include <list.h>
 
-#define fastcall __attribute__((regparm(3)))
+#include "compiler.h"
 
 struct sna_damage_elt;
 struct sna_damage_box;
 
 struct sna_damage {
 	BoxRec extents;
-	int n, size, mode, all;
 	pixman_region16_t region;
+	enum sna_damage_mode {
+		DAMAGE_ADD = 0,
+		DAMAGE_SUBTRACT,
+		DAMAGE_ALL,
+	} mode;
+	int n, size;
 	struct sna_damage_elt *elts;
 	struct sna_damage_box *last_box;
 	struct list boxes;
@@ -52,11 +57,16 @@ static inline bool sna_damage_is_all(struct sna_damage **damage,
 	if (*damage == NULL)
 		return false;
 
-	if ((*damage)->all)
+	switch ((*damage)->mode) {
+	case DAMAGE_ALL:
 		return true;
-
-	*damage = _sna_damage_is_all(*damage, width, height);
-	return (*damage)->all;
+	case DAMAGE_SUBTRACT:
+		return false;
+	default:
+	case DAMAGE_ADD:
+		*damage = _sna_damage_is_all(*damage, width, height);
+		return (*damage)->mode == DAMAGE_ALL;
+	}
 }
 
 struct sna_damage *_sna_damage_all(struct sna_damage *damage,


More information about the xorg-commit mailing list