xf86-video-intel: 9 commits - src/intel_module.c src/sna/gen2_render.c src/sna/gen2_render.h src/sna/gen3_render.c src/sna/kgem.c src/sna/kgem_debug.c src/sna/kgem_debug_gen3.c src/sna/kgem_debug.h src/sna/kgem.h src/sna/Makefile.am src/sna/sna_render.c src/sna/sna_render.h src/sna/sna_trapezoids.c src/sna/sna_video.c src/sna/sna_video_overlay.c

Chris Wilson ickle at kemper.freedesktop.org
Fri Jul 1 14:19:18 PDT 2011


 src/intel_module.c          |   21 
 src/sna/Makefile.am         |    1 
 src/sna/gen2_render.c       | 1418 +++++++++++++++++++++++++++++++++++++-------
 src/sna/gen2_render.h       |   22 
 src/sna/gen3_render.c       |  193 +++--
 src/sna/kgem.c              |   71 ++
 src/sna/kgem.h              |    6 
 src/sna/kgem_debug.c        |    4 
 src/sna/kgem_debug.h        |    3 
 src/sna/kgem_debug_gen3.c   |    5 
 src/sna/sna_render.c        |  227 ++++++-
 src/sna/sna_render.h        |   19 
 src/sna/sna_trapezoids.c    |    2 
 src/sna/sna_video.c         |    2 
 src/sna/sna_video_overlay.c |    4 
 15 files changed, 1645 insertions(+), 353 deletions(-)

New commits:
commit 5c8a108d2c99f542372efb1734c96ddd2af6bc76
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jul 1 21:24:43 2011 +0100

    sna/gen2: Recompute blend pipeline for component-alpha pass
    
    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 f1275e3..3f0b902 100644
--- a/src/sna/gen2_render.c
+++ b/src/sna/gen2_render.c
@@ -325,6 +325,7 @@ gen2_emit_texture(struct sna *sna,
 
 static void
 gen2_get_blend_factors(const struct sna_composite_op *op,
+		       int blend,
 		       uint32_t *c_out,
 		       uint32_t *a_out)
 {
@@ -348,7 +349,7 @@ gen2_get_blend_factors(const struct sna_composite_op *op,
 
 
 	/* Get the source picture's channels into TBx_ARG1 */
-	if ((op->has_component_alpha && gen2_blend_op[op->op].src_alpha) ||
+	if ((op->has_component_alpha && gen2_blend_op[blend].src_alpha) ||
 	    op->dst.format == PICT_a8) {
 		/* Producing source alpha value, so the first set of channels
 		 * is src.A instead of src.X.  We also do this if the destination
@@ -626,7 +627,7 @@ static void gen2_emit_composite_state(struct sna *sna,
 
 	gen2_disable_logic_op(sna);
 
-	gen2_get_blend_factors(op, &cblend, &ablend);
+	gen2_get_blend_factors(op, op->op, &cblend, &ablend);
 	OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 |
 		  LOAD_TEXTURE_BLEND_STAGE(0) | 1);
 	OUT_BATCH(cblend);
@@ -839,7 +840,7 @@ static void gen2_magic_ca_pass(struct sna *sna,
 		  gen2_get_blend_cntl(PictOpAdd, TRUE, op->dst.format) |
 		  S8_ENABLE_COLOR_BUFFER_WRITE);
 
-	gen2_get_blend_factors(op, &cblend, &ablend);
+	gen2_get_blend_factors(op, PictOpAdd, &cblend, &ablend);
 	OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 |
 		  LOAD_TEXTURE_BLEND_STAGE(0) | 1);
 	OUT_BATCH(cblend);
commit 121511d3bd63da5eca28edf971aae3d062aed46e
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jul 1 16:54:28 2011 +0100

    sna/gen2: Pack solid sources into the default diffuse component
    
    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 495e3fa..f1275e3 100644
--- a/src/sna/gen2_render.c
+++ b/src/sna/gen2_render.c
@@ -355,28 +355,43 @@ gen2_get_blend_factors(const struct sna_composite_op *op,
 		 * is a8, in which case src.G is what's written, and the other
 		 * channels are ignored.
 		 */
-		ablend |= TB0A_ARG1_SEL_TEXEL0;
-		cblend |= TB0C_ARG1_SEL_TEXEL0 | TB0C_ARG1_REPLICATE_ALPHA;
+		if (op->src.is_solid) {
+			ablend |= TB0A_ARG1_SEL_DIFFUSE;
+			cblend |= TB0C_ARG1_SEL_DIFFUSE | TB0C_ARG1_REPLICATE_ALPHA;
+		} else {
+			ablend |= TB0A_ARG1_SEL_TEXEL0;
+			cblend |= TB0C_ARG1_SEL_TEXEL0 | TB0C_ARG1_REPLICATE_ALPHA;
+		}
 	} else {
-		if (PICT_FORMAT_RGB(op->src.pict_format) != 0)
+		if (op->src.is_solid)
+			cblend |= TB0C_ARG1_SEL_DIFFUSE;
+		else if (PICT_FORMAT_RGB(op->src.pict_format) != 0)
 			cblend |= TB0C_ARG1_SEL_TEXEL0;
 		else
 			cblend |= TB0C_ARG1_SEL_ONE | TB0C_ARG1_INVERT;	/* 0.0 */
-		if (op->src.is_opaque)
+		if (op->src.is_solid)
+			ablend |= TB0A_ARG1_SEL_DIFFUSE;
+		else if (op->src.is_opaque)
 			ablend |= TB0A_ARG1_SEL_ONE;
 		else
 			ablend |= TB0A_ARG1_SEL_TEXEL0;
 	}
 
 	if (op->mask.bo) {
-		cblend |= TB0C_OP_MODULATE;
-		cblend |= TB0C_ARG2_SEL_TEXEL1;
+		if (op->src.is_solid) {
+			cblend |= TB0C_ARG2_SEL_TEXEL0;
+			ablend |= TB0A_ARG2_SEL_TEXEL0;
+		} else {
+			cblend |= TB0C_ARG2_SEL_TEXEL1;
+			ablend |= TB0A_ARG2_SEL_TEXEL1;
+		}
+
 		if (op->dst.format == PICT_a8 ||
 		    !op->has_component_alpha ||
 		    PICT_FORMAT_RGB(op->mask.pict_format) == 0)
 			cblend |= TB0C_ARG2_REPLICATE_ALPHA;
 
-		ablend |= TB0A_ARG2_SEL_TEXEL1;
+		cblend |= TB0C_OP_MODULATE;
 		ablend |= TB0A_OP_MODULATE;
 	} else {
 		cblend |= TB0C_OP_ARG1;
@@ -594,13 +609,14 @@ static void gen2_emit_composite_state(struct sna *sna,
 {
 	uint32_t texcoordfmt;
 	uint32_t cblend, ablend;
+	int tex;
 
 	gen2_get_batch(sna, op);
 	gen2_emit_target(sna, op);
 
 	OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
 		  I1_LOAD_S(2) | I1_LOAD_S(3) | I1_LOAD_S(8) | 2);
-	OUT_BATCH((1 + (op->mask.bo != NULL)) << 12);
+	OUT_BATCH((!op->src.is_solid + (op->mask.bo != NULL)) << 12);
 	OUT_BATCH(S3_CULLMODE_NONE | S3_VERTEXHAS_XY);
 	OUT_BATCH(S8_ENABLE_COLOR_BLEND | S8_BLENDFUNC_ADD |
 		  gen2_get_blend_cntl(op->op,
@@ -616,22 +632,25 @@ static void gen2_emit_composite_state(struct sna *sna,
 	OUT_BATCH(cblend);
 	OUT_BATCH(ablend);
 
-	texcoordfmt = 0;
-	if (op->src.is_affine)
-		texcoordfmt |= TEXCOORDFMT_2D << 0;
-	else
-		texcoordfmt |= TEXCOORDFMT_3D << 0;
+	tex = texcoordfmt = 0;
+	if (!op->src.is_solid) {
+		if (op->src.is_affine)
+			texcoordfmt |= TEXCOORDFMT_2D << (2*tex);
+		else
+			texcoordfmt |= TEXCOORDFMT_3D << (2*tex);
+		gen2_emit_texture(sna, &op->src, tex++);
+	} else {
+		OUT_BATCH(_3DSTATE_DFLT_DIFFUSE_CMD);
+		OUT_BATCH(op->src.u.gen2.pixel);
+	}
 	if (op->mask.bo) {
 		if (op->mask.is_affine)
-			texcoordfmt |= TEXCOORDFMT_2D << 2;
+			texcoordfmt |= TEXCOORDFMT_2D << (2*tex);
 		else
-			texcoordfmt |= TEXCOORDFMT_3D << 2;
+			texcoordfmt |= TEXCOORDFMT_3D << (2*tex);
+		gen2_emit_texture(sna, &op->mask, tex++);
 	}
 	OUT_BATCH(_3DSTATE_VERTEX_FORMAT_2_CMD | texcoordfmt);
-
-	gen2_emit_texture(sna, &op->src, 0);
-	if (op->mask.bo)
-		gen2_emit_texture(sna, &op->mask, 1);
 }
 
 static inline void
@@ -675,34 +694,136 @@ gen2_emit_composite_vertex(struct sna *sna,
 			   int16_t dstX, int16_t dstY)
 {
 	gen2_emit_composite_dstcoord(sna, dstX, dstY);
-	gen2_emit_composite_texcoord(sna, &op->src, srcX, srcY);
+	if (!op->src.is_solid)
+		gen2_emit_composite_texcoord(sna, &op->src, srcX, srcY);
 	if (op->mask.bo)
 		gen2_emit_composite_texcoord(sna, &op->mask, mskX, mskY);
 }
 
-static void
+fastcall static void
 gen2_emit_composite_primitive(struct sna *sna,
 			      const struct sna_composite_op *op,
-			      int16_t srcX, int16_t srcY,
-			      int16_t mskX, int16_t mskY,
-			      int16_t dstX, int16_t dstY,
-			      int16_t w, int16_t h)
+			      const struct sna_composite_rectangles *r)
 {
-	dstX += op->dst.x;
-	dstY += op->dst.y;
-
 	gen2_emit_composite_vertex(sna, op,
-				   srcX + w, srcY + h,
-				   mskX + w, mskY + h,
-				   dstX + w, dstY + h);
+				   r->src.x + r->width,
+				   r->src.y + r->height,
+				   r->mask.x + r->width,
+				   r->mask.y + r->height,
+				   op->dst.x + r->dst.x + r->width,
+				   op->dst.y + r->dst.y + r->height);
 	gen2_emit_composite_vertex(sna, op,
-				   srcX, srcY + h,
-				   mskX, mskY + h,
-				   dstX, dstY + h);
+				   r->src.x,
+				   r->src.y + r->height,
+				   r->mask.x,
+				   r->mask.y + r->height,
+				   op->dst.x + r->dst.x,
+				   op->dst.y + r->dst.y + r->height);
 	gen2_emit_composite_vertex(sna, op,
-				   srcX, srcY,
-				   mskX, mskY,
-				   dstX, dstY);
+				   r->src.x,
+				   r->src.y,
+				   r->mask.x,
+				   r->mask.y,
+				   op->dst.x + r->dst.x,
+				   op->dst.y + r->dst.y);
+}
+
+fastcall static void
+gen2_emit_composite_primitive_constant(struct sna *sna,
+				       const struct sna_composite_op *op,
+				       const struct sna_composite_rectangles *r)
+{
+	int16_t dst_x = r->dst.x + op->dst.x;
+	int16_t dst_y = r->dst.y + op->dst.y;
+
+	gen2_emit_composite_dstcoord(sna, dst_x + r->width, dst_y + r->height);
+	gen2_emit_composite_dstcoord(sna, dst_x, dst_y + r->height);
+	gen2_emit_composite_dstcoord(sna, dst_x, dst_y);
+}
+
+fastcall static void
+gen2_emit_composite_primitive_identity(struct sna *sna,
+				       const struct sna_composite_op *op,
+				       const struct sna_composite_rectangles *r)
+{
+	float w = r->width;
+	float h = r->height;
+	float *v;
+
+	v = (float *)sna->kgem.batch + sna->kgem.nbatch;
+	sna->kgem.nbatch += 12;
+
+	v[8] = v[4] = r->dst.x + op->dst.x;
+	v[0] = v[4] + w;
+
+	v[9] = r->dst.y + op->dst.y;
+	v[5] = v[1] = v[9] + h;
+
+	v[10] = v[6] = (r->src.x + op->src.offset[0]) * op->src.scale[0];
+	v[2] = v[6] + w * op->src.scale[0];
+
+	v[11] = (r->src.y + op->src.offset[1]) * op->src.scale[1];
+	v[7] = v[3] = v[11] + h * op->src.scale[1];
+}
+
+fastcall static void
+gen2_emit_composite_primitive_affine(struct sna *sna,
+				     const struct sna_composite_op *op,
+				     const struct sna_composite_rectangles *r)
+{
+	PictTransform *transform = op->src.transform;
+	int16_t dst_x = r->dst.x + op->dst.x;
+	int16_t dst_y = r->dst.y + op->dst.y;
+	int src_x = r->src.x + (int)op->src.offset[0];
+	int src_y = r->src.y + (int)op->src.offset[1];
+	float sx, sy;
+
+	_sna_get_transformed_coordinates(src_x + r->width, src_y + r->height,
+					 transform,
+					 &sx, &sy);
+
+	gen2_emit_composite_dstcoord(sna, dst_x + r->width, dst_y + r->height);
+	OUT_VERTEX(sx * op->src.scale[0]);
+	OUT_VERTEX(sy * op->src.scale[1]);
+
+	_sna_get_transformed_coordinates(src_x, src_y + r->height,
+					 transform,
+					 &sx, &sy);
+	gen2_emit_composite_dstcoord(sna, dst_x, dst_y + r->height);
+	OUT_VERTEX(sx * op->src.scale[0]);
+	OUT_VERTEX(sy * op->src.scale[1]);
+
+	_sna_get_transformed_coordinates(src_x, src_y,
+					 transform,
+					 &sx, &sy);
+	gen2_emit_composite_dstcoord(sna, dst_x, dst_y);
+	OUT_VERTEX(sx * op->src.scale[0]);
+	OUT_VERTEX(sy * op->src.scale[1]);
+}
+
+fastcall static void
+gen2_emit_composite_primitive_constant_identity_mask(struct sna *sna,
+						     const struct sna_composite_op *op,
+						     const struct sna_composite_rectangles *r)
+{
+	float w = r->width;
+	float h = r->height;
+	float *v;
+
+	v = (float *)sna->kgem.batch + sna->kgem.nbatch;
+	sna->kgem.nbatch += 12;
+
+	v[8] = v[4] = r->dst.x + op->dst.x;
+	v[0] = v[4] + w;
+
+	v[9] = r->dst.y + op->dst.y;
+	v[5] = v[1] = v[9] + h;
+
+	v[10] = v[6] = (r->mask.x + op->mask.offset[0]) * op->mask.scale[0];
+	v[2] = v[6] + w * op->mask.scale[0];
+
+	v[11] = (r->mask.y + op->mask.offset[1]) * op->mask.scale[1];
+	v[7] = v[3] = v[11] + h * op->mask.scale[1];
 }
 
 static void gen2_magic_ca_pass(struct sna *sna,
@@ -790,11 +911,7 @@ gen2_render_composite_blt(struct sna *sna,
 		gen2_get_rectangles(sna, op, 1);
 	}
 
-	gen2_emit_composite_primitive(sna, op,
-				      r->src.x, r->src.y,
-				      r->mask.x, r->mask.y,
-				      r->dst.x, r->dst.y,
-				      r->width, r->height);
+	op->prim_emit(sna, op, r);
 }
 
 static void
@@ -813,12 +930,19 @@ gen2_render_composite_boxes(struct sna *sna,
 		nbox -= nbox_this_time;
 
 		do {
-			gen2_emit_composite_primitive(sna, op,
-						      box->x1, box->y1,
-						      box->x1, box->y1,
-						      box->x1, box->y1,
-						      box->x2 - box->x1,
-						      box->y2 - box->y1);
+			struct sna_composite_rectangles r;
+
+			DBG(("  %s: (%d, %d) x (%d, %d)\n", __FUNCTION__,
+			     box->x1, box->y1,
+			     box->x2 - box->x1,
+			     box->y2 - box->y1));
+
+			r.dst.x  = box->x1; r.dst.y  = box->y1;
+			r.width = box->x2 - box->x1;
+			r.height = box->y2 - box->y1;
+			r.src = r.mask = r.dst;
+
+			op->prim_emit(sna, op, &r);
 			box++;
 		} while (--nbox_this_time);
 	} while (nbox);
@@ -1099,8 +1223,6 @@ gen2_render_composite(struct sna *sna,
 					    width,  height,
 					    tmp);
 
-	memset(&tmp->u.gen2, 0, sizeof(tmp->u.gen2));
-
 	if (!gen2_composite_set_target(sna, tmp, dst)) {
 		DBG(("%s: unable to set render target\n",
 		     __FUNCTION__));
@@ -1159,11 +1281,26 @@ gen2_render_composite(struct sna *sna,
 	}
 
 	tmp->floats_per_vertex = 2;
-	if (tmp->src.bo)
+	if (!tmp->src.is_solid)
 		tmp->floats_per_vertex += tmp->src.is_affine ? 2 : 3;
 	if (tmp->mask.bo)
 		tmp->floats_per_vertex += tmp->mask.is_affine ? 2 : 3;
 
+	tmp->prim_emit = gen2_emit_composite_primitive;
+	if (tmp->mask.bo) {
+		if (tmp->mask.transform == NULL) {
+			if (tmp->src.is_solid)
+				tmp->prim_emit = gen2_emit_composite_primitive_constant_identity_mask;
+		}
+	} else {
+		if (tmp->src.is_solid)
+			tmp->prim_emit = gen2_emit_composite_primitive_constant;
+		else if (tmp->src.transform == NULL)
+			tmp->prim_emit = gen2_emit_composite_primitive_identity;
+		else if (tmp->src.is_affine)
+			tmp->prim_emit = gen2_emit_composite_primitive_affine;
+	}
+
 	tmp->blt   = gen2_render_composite_blt;
 	tmp->boxes = gen2_render_composite_boxes;
 	tmp->done  = gen2_render_composite_done;
commit a303f85c163979276ff13e00b7c56f55b5fd1d07
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jul 1 16:27:11 2011 +0100

    sna/gen2: Remove unused state from invariant setup
    
    ... and also some state that gets clobbered when we install the
    composite pipelines.
    
    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 f4177f7..495e3fa 100644
--- a/src/sna/gen2_render.c
+++ b/src/sna/gen2_render.c
@@ -115,6 +115,7 @@ gen2_buf_tiling(uint32_t tiling)
 {
 	uint32_t v = 0;
 	switch (tiling) {
+	default: assert(0);
 	case I915_TILING_Y: v |= BUF_3D_TILE_WALK_Y;
 	case I915_TILING_X: v |= BUF_3D_TILED_SURFACE;
 	case I915_TILING_NONE: break;
@@ -427,34 +428,22 @@ static void gen2_emit_invariant(struct sna *sna)
 	OUT_BATCH(_3DSTATE_MAP_CUBE | MAP_UNIT(2));
 	OUT_BATCH(_3DSTATE_MAP_CUBE | MAP_UNIT(3));
 
-	OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD |
-		  MAP_UNIT(0) |
+	OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD | MAP_UNIT(0) |
 		  DISABLE_TEX_STREAM_BUMP |
-		  ENABLE_TEX_STREAM_COORD_SET |
-		  TEX_STREAM_COORD_SET(0) |
-		  ENABLE_TEX_STREAM_MAP_IDX |
-		  TEX_STREAM_MAP_IDX(0));
-	OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD |
-		  MAP_UNIT(1) |
+		  ENABLE_TEX_STREAM_COORD_SET | TEX_STREAM_COORD_SET(0) |
+		  ENABLE_TEX_STREAM_MAP_IDX | TEX_STREAM_MAP_IDX(0));
+	OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD | MAP_UNIT(1) |
 		  DISABLE_TEX_STREAM_BUMP |
-		  ENABLE_TEX_STREAM_COORD_SET |
-		  TEX_STREAM_COORD_SET(1) |
-		  ENABLE_TEX_STREAM_MAP_IDX |
-		  TEX_STREAM_MAP_IDX(1));
-	OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD |
-		  MAP_UNIT(2) |
+		  ENABLE_TEX_STREAM_COORD_SET | TEX_STREAM_COORD_SET(1) |
+		  ENABLE_TEX_STREAM_MAP_IDX | TEX_STREAM_MAP_IDX(1));
+	OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD | MAP_UNIT(2) |
 		  DISABLE_TEX_STREAM_BUMP |
-		  ENABLE_TEX_STREAM_COORD_SET |
-		  TEX_STREAM_COORD_SET(2) |
-		  ENABLE_TEX_STREAM_MAP_IDX |
-		  TEX_STREAM_MAP_IDX(2));
-	OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD |
-		  MAP_UNIT(3) |
+		  ENABLE_TEX_STREAM_COORD_SET | TEX_STREAM_COORD_SET(2) |
+		  ENABLE_TEX_STREAM_MAP_IDX | TEX_STREAM_MAP_IDX(2));
+	OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD | MAP_UNIT(3) |
 		  DISABLE_TEX_STREAM_BUMP |
-		  ENABLE_TEX_STREAM_COORD_SET |
-		  TEX_STREAM_COORD_SET(3) |
-		  ENABLE_TEX_STREAM_MAP_IDX |
-		  TEX_STREAM_MAP_IDX(3));
+		  ENABLE_TEX_STREAM_COORD_SET | TEX_STREAM_COORD_SET(3) |
+		  ENABLE_TEX_STREAM_MAP_IDX | TEX_STREAM_MAP_IDX(3));
 
 	OUT_BATCH(_3DSTATE_MAP_COORD_TRANSFORM);
 	OUT_BATCH(DISABLE_TEX_TRANSFORM | TEXTURE_SET(0));
@@ -465,15 +454,11 @@ static void gen2_emit_invariant(struct sna *sna)
 	OUT_BATCH(_3DSTATE_MAP_COORD_TRANSFORM);
 	OUT_BATCH(DISABLE_TEX_TRANSFORM | TEXTURE_SET(3));
 
-	OUT_BATCH(_3DSTATE_RASTER_RULES_CMD |
-		  ENABLE_POINT_RASTER_RULE |
-		  OGL_POINT_RASTER_RULE |
-		  ENABLE_LINE_STRIP_PROVOKE_VRTX |
-		  ENABLE_TRI_FAN_PROVOKE_VRTX |
-		  ENABLE_TRI_STRIP_PROVOKE_VRTX |
-		  LINE_STRIP_PROVOKE_VRTX(1) |
-		  TRI_FAN_PROVOKE_VRTX(2) |
-		  TRI_STRIP_PROVOKE_VRTX(2));
+	OUT_BATCH(_3DSTATE_MAP_COORD_SETBIND_CMD);
+	OUT_BATCH(TEXBIND_SET3(TEXCOORDSRC_VTXSET_3) |
+		  TEXBIND_SET2(TEXCOORDSRC_VTXSET_2) |
+		  TEXBIND_SET1(TEXCOORDSRC_VTXSET_1) |
+		  TEXBIND_SET0(TEXCOORDSRC_VTXSET_0));
 
 	OUT_BATCH(_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT);
 
@@ -484,12 +469,6 @@ static void gen2_emit_invariant(struct sna *sna)
 	OUT_BATCH(MAGIC_W_STATE_DWORD1);
 	OUT_BATCH_F(1.0);
 
-	OUT_BATCH(_3DSTATE_MAP_COORD_SETBIND_CMD);
-	OUT_BATCH(TEXBIND_SET3(TEXCOORDSRC_VTXSET_3) |
-		  TEXBIND_SET2(TEXCOORDSRC_VTXSET_2) |
-		  TEXBIND_SET1(TEXCOORDSRC_VTXSET_1) |
-		  TEXBIND_SET0(TEXCOORDSRC_VTXSET_0));
-
 	OUT_BATCH(_3DSTATE_INDPT_ALPHA_BLEND_CMD |
 		  DISABLE_INDPT_ALPHA_BLEND |
 		  ENABLE_ALPHA_BLENDFUNC | ABLENDFUNC_ADD);
@@ -498,70 +477,9 @@ static void gen2_emit_invariant(struct sna *sna)
 	OUT_BATCH(0);
 
 	OUT_BATCH(_3DSTATE_MODES_1_CMD |
-		  ENABLE_COLR_BLND_FUNC |
-		  BLENDFUNC_ADD |
+		  ENABLE_COLR_BLND_FUNC | BLENDFUNC_ADD |
 		  ENABLE_SRC_BLND_FACTOR | SRC_BLND_FACT(BLENDFACTOR_ONE) |
 		  ENABLE_DST_BLND_FACTOR | DST_BLND_FACT(BLENDFACTOR_ZERO));
-	OUT_BATCH(_3DSTATE_MODES_2_CMD);
-	OUT_BATCH(_3DSTATE_MODES_3_CMD |
-		  ENABLE_ALPHA_SHADE_MODE | ALPHA_SHADE_MODE(SHADE_MODE_LINEAR) |
-		  ENABLE_FOG_SHADE_MODE | FOG_SHADE_MODE(SHADE_MODE_LINEAR) |
-		  ENABLE_SPEC_SHADE_MODE | SPEC_SHADE_MODE(SHADE_MODE_LINEAR) |
-		  ENABLE_COLOR_SHADE_MODE | COLOR_SHADE_MODE(SHADE_MODE_LINEAR) |
-		  ENABLE_CULL_MODE | CULLMODE_NONE);
-
-	OUT_BATCH(_3DSTATE_ENABLES_1_CMD |
-		  DISABLE_LOGIC_OP |
-		  DISABLE_STENCIL_TEST |
-		  DISABLE_DEPTH_BIAS |
-		  DISABLE_SPEC_ADD |
-		  DISABLE_FOG |
-		  DISABLE_ALPHA_TEST |
-		  ENABLE_COLOR_BLEND |
-		  DISABLE_DEPTH_TEST);
-	OUT_BATCH(_3DSTATE_ENABLES_2_CMD |
-		  DISABLE_STENCIL_WRITE |
-		  ENABLE_TEX_CACHE |
-		  DISABLE_DITHER |
-		  ENABLE_COLOR_MASK |
-		  ENABLE_COLOR_WRITE |
-		  DISABLE_DEPTH_WRITE);
-
-	OUT_BATCH(_3DSTATE_STIPPLE);
-
-	/* Set default blend state */
-	OUT_BATCH(_3DSTATE_MAP_BLEND_OP_CMD(0) |
-		  TEXPIPE_COLOR |
-		  ENABLE_TEXOUTPUT_WRT_SEL |
-		  TEXOP_OUTPUT_CURRENT |
-		  DISABLE_TEX_CNTRL_STAGE |
-		  TEXOP_SCALE_1X |
-		  TEXOP_MODIFY_PARMS |
-		  TEXOP_LAST_STAGE |
-		  TEXBLENDOP_ARG1);
-	OUT_BATCH(_3DSTATE_MAP_BLEND_OP_CMD(0) |
-		  TEXPIPE_ALPHA |
-		  ENABLE_TEXOUTPUT_WRT_SEL |
-		  TEXOP_OUTPUT_CURRENT |
-		  TEXOP_SCALE_1X |
-		  TEXOP_MODIFY_PARMS |
-		  TEXBLENDOP_ARG1);
-	OUT_BATCH(_3DSTATE_MAP_BLEND_ARG_CMD(0) |
-		  TEXPIPE_COLOR |
-		  TEXBLEND_ARG1 |
-		  TEXBLENDARG_MODIFY_PARMS |
-		  TEXBLENDARG_DIFFUSE);
-	OUT_BATCH(_3DSTATE_MAP_BLEND_ARG_CMD(0) |
-		  TEXPIPE_ALPHA |
-		  TEXBLEND_ARG1 |
-		  TEXBLENDARG_MODIFY_PARMS |
-		  TEXBLENDARG_DIFFUSE);
-
-	OUT_BATCH(_3DSTATE_AA_CMD |
-		  AA_LINE_ECAAR_WIDTH_ENABLE |
-		  AA_LINE_ECAAR_WIDTH_1_0 |
-		  AA_LINE_REGION_WIDTH_ENABLE |
-		  AA_LINE_REGION_WIDTH_1_0 | AA_LINE_DISABLE);
 
 	sna->render_state.gen2.need_invariant = FALSE;
 }
commit 120c98ac10435c8e848a8337c1f544f81a05cd3a
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jul 1 14:55:44 2011 +0100

    sna: Downsample sources 2x too large to fit in the 3D pipeline
    
    This is quite trivial to hit given the 2k limits on gen2/gen3. We
    compromise on image quality by pre-downscaling the source by a fixed
    factor to make it fit into the pipeline in preference to performing the
    entire operation on the CPU.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/Makefile.am b/src/sna/Makefile.am
index dfd8a57..d76480d 100644
--- a/src/sna/Makefile.am
+++ b/src/sna/Makefile.am
@@ -90,6 +90,7 @@ if DEBUG
 libsna_la_SOURCES += \
 	kgem_debug.c \
 	kgem_debug.h \
+	kgem_debug_gen2.c \
 	kgem_debug_gen3.c \
 	kgem_debug_gen4.c \
 	kgem_debug_gen5.c \
diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index 88b1d83..6fe6e93 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -1819,6 +1819,64 @@ struct kgem_bo *kgem_upload_source_image(struct kgem *kgem,
 	return bo;
 }
 
+struct kgem_bo *kgem_upload_source_image_halved(struct kgem *kgem,
+						pixman_format_code_t format,
+						const void *data,
+						int x, int y,
+						int width, int height,
+						int stride, int bpp)
+{
+	int dst_stride = ALIGN(width * bpp / 2, 32) >> 3;
+	int size = dst_stride * height / 2;
+	struct kgem_bo *bo;
+	pixman_image_t *src_image, *dst_image;
+	pixman_transform_t t;
+	void *dst;
+
+	DBG(("%s : (%d, %d), (%d, %d), stride=%d, bpp=%d\n",
+	     __FUNCTION__, x, y, width, height, stride, bpp));
+
+	bo = kgem_create_buffer(kgem, size, KGEM_BUFFER_WRITE, &dst);
+	if (bo == NULL)
+		return NULL;
+
+	dst_image = pixman_image_create_bits(format, width/2, height/2,
+					     dst, dst_stride);
+	if (dst_image == NULL)
+		goto cleanup_bo;
+
+	src_image = pixman_image_create_bits(format, width, height,
+					     (uint32_t*)data, stride);
+	if (src_image == NULL)
+		goto cleanup_dst;
+
+	memset(&t, 0, sizeof(t));
+	t.matrix[0][0] = 2 << 16;
+	t.matrix[1][1] = 2 << 16;
+	t.matrix[2][2] = 1 << 16;
+	pixman_image_set_transform(src_image, &t);
+	pixman_image_set_filter(src_image, PIXMAN_FILTER_BILINEAR, NULL, 0);
+
+	pixman_image_composite(PIXMAN_OP_SRC,
+			       src_image, NULL, dst_image,
+			       x, y,
+			       0, 0,
+			       0, 0,
+			       width/2, height/2);
+
+	pixman_image_unref(src_image);
+	pixman_image_unref(dst_image);
+
+	bo->pitch = dst_stride;
+	return bo;
+
+cleanup_dst:
+	pixman_image_unref(dst_image);
+cleanup_bo:
+	kgem_bo_destroy(kgem, bo);
+	return NULL;
+}
+
 void kgem_buffer_sync(struct kgem *kgem, struct kgem_bo *_bo)
 {
 	struct kgem_partial_bo *bo;
diff --git a/src/sna/kgem.h b/src/sna/kgem.h
index fac30af..013809c 100644
--- a/src/sna/kgem.h
+++ b/src/sna/kgem.h
@@ -141,6 +141,12 @@ struct kgem_bo *kgem_upload_source_image(struct kgem *kgem,
 					 int x, int y,
 					 int width, int height,
 					 int stride, int bpp);
+struct kgem_bo *kgem_upload_source_image_halved(struct kgem *kgem,
+						pixman_format_code_t format,
+						const void *data,
+						int x, int y,
+						int width, int height,
+						int stride, int bpp);
 
 int kgem_choose_tiling(struct kgem *kgem,
 		       int tiling, int width, int height, int bpp);
diff --git a/src/sna/kgem_debug.c b/src/sna/kgem_debug.c
index 0dcd706..20fe8a2 100644
--- a/src/sna/kgem_debug.c
+++ b/src/sna/kgem_debug.c
@@ -352,6 +352,8 @@ static int (*decode_3d(int gen))(struct kgem*, uint32_t)
 		return kgem_gen4_decode_3d;
 	} else if (gen >= 30) {
 		return kgem_gen3_decode_3d;
+	} else if (gen >= 20) {
+		return kgem_gen2_decode_3d;
 	}
 	assert(0);
 }
@@ -366,6 +368,8 @@ static void (*finish_state(int gen))(struct kgem*)
 		return kgem_gen4_finish_state;
 	} else if (gen >= 30) {
 		return kgem_gen3_finish_state;
+	} else if (gen >= 20) {
+		return kgem_gen2_finish_state;
 	}
 	assert(0);
 }
diff --git a/src/sna/kgem_debug.h b/src/sna/kgem_debug.h
index f9a931d..9211dcb 100644
--- a/src/sna/kgem_debug.h
+++ b/src/sna/kgem_debug.h
@@ -25,4 +25,7 @@ void kgem_gen4_finish_state(struct kgem *kgem);
 int kgem_gen3_decode_3d(struct kgem *kgem, uint32_t offset);
 void kgem_gen3_finish_state(struct kgem *kgem);
 
+int kgem_gen2_decode_3d(struct kgem *kgem, uint32_t offset);
+void kgem_gen2_finish_state(struct kgem *kgem);
+
 #endif
diff --git a/src/sna/kgem_debug_gen3.c b/src/sna/kgem_debug_gen3.c
index da1d9fc..6709a8e 100644
--- a/src/sna/kgem_debug_gen3.c
+++ b/src/sna/kgem_debug_gen3.c
@@ -1552,9 +1552,6 @@ out:
 
 int kgem_gen3_decode_3d(struct kgem *kgem, uint32_t offset)
 {
-    uint32_t opcode;
-    unsigned int idx;
-
     struct {
 	uint32_t opcode;
 	int min_len;
@@ -1572,6 +1569,8 @@ int kgem_gen3_decode_3d(struct kgem *kgem, uint32_t offset)
 	{ 0x07, 1, 1, "3DSTATE_RASTERIZATION_RULES" },
     };
     uint32_t *data = kgem->batch + offset;
+    uint32_t opcode;
+    unsigned int idx;
 
     opcode = (data[0] & 0x1f000000) >> 24;
 
diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c
index 72a3c1e..baf51c3 100644
--- a/src/sna/sna_render.c
+++ b/src/sna/sna_render.c
@@ -427,6 +427,212 @@ sna_render_pixmap_bo(struct sna *sna,
 	return bo != NULL;
 }
 
+static int sna_render_picture_downsample(struct sna *sna,
+					 PicturePtr picture,
+					 struct sna_composite_channel *channel,
+					 int16_t x, int16_t y,
+					 int16_t w, int16_t h,
+					 int16_t dst_x, int16_t dst_y)
+{
+	struct kgem_bo *bo = NULL;
+	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
+	int16_t ox, oy, ow, oh;
+	BoxRec box;
+
+	assert(w && h);
+
+	DBG(("%s (%d, %d)x(%d, %d) [dst=(%d, %d)]\n",
+	     __FUNCTION__, x, y, w, h, dst_x, dst_y));
+
+	ow = w;
+	oh = h;
+
+	ox = box.x1 = x;
+	oy = box.y1 = y;
+	box.x2 = x + w;
+	box.y2 = y + h;
+	if (channel->transform) {
+		pixman_vector_t v;
+
+		pixman_transform_bounds(channel->transform, &box);
+
+		v.vector[0] = ox << 16;
+		v.vector[1] = oy << 16;
+		v.vector[2] =  1 << 16;
+		pixman_transform_point(channel->transform, &v);
+		ox = v.vector[0] / v.vector[2];
+		oy = v.vector[1] / v.vector[2];
+	}
+
+	if (channel->repeat != RepeatNone) {
+		if (box.x1 < 0 ||
+		    box.y1 < 0 ||
+		    box.x2 > pixmap->drawable.width ||
+		    box.y2 > pixmap->drawable.height) {
+			/* XXX tiled repeats? */
+			box.x1 = box.y1 = 0;
+			box.x2 = pixmap->drawable.width;
+			box.y2 = pixmap->drawable.height;
+
+			if (!channel->is_affine) {
+				DBG(("%s: fallback -- repeating project transform too large for texture\n",
+				     __FUNCTION__));
+				return sna_render_picture_fixup(sna,
+								picture,
+								channel,
+								x, y, ow, oh,
+								dst_x, dst_y);
+			}
+		}
+	} else {
+		if (box.x1 < 0)
+			box.x1 = 0;
+		if (box.y1 < 0)
+			box.y1 = 0;
+		if (box.x2 > pixmap->drawable.width)
+			box.x2 = pixmap->drawable.width;
+		if (box.y2 > pixmap->drawable.height)
+			box.y2 = pixmap->drawable.height;
+	}
+
+	w = box.x2 - box.x1;
+	h = box.y2 - box.y1;
+	assert(w && h);
+	if (w > 2*sna->render.max_3d_size || h > 2*sna->render.max_3d_size)
+		goto fixup;
+
+	if (texture_is_cpu(pixmap, &box) && !move_to_gpu(pixmap, &box)) {
+		bo = kgem_upload_source_image_halved(&sna->kgem,
+						     picture->format,
+						     pixmap->devPrivate.ptr,
+						     box.x1, box.y1, w, h,
+						     pixmap->devKind,
+						     pixmap->drawable.bitsPerPixel);
+		if (!bo) {
+			DBG(("%s: failed to upload source image, using clear\n",
+			     __FUNCTION__));
+			return 0;
+		}
+	} else {
+		ScreenPtr screen = pixmap->drawable.pScreen;
+		PicturePtr tmp_src, tmp_dst;
+		PictFormatPtr format;
+		struct sna_pixmap *priv;
+		pixman_transform_t t;
+		PixmapPtr tmp;
+		int error, i, j, ww, hh;
+
+		if (!sna_pixmap_force_to_gpu(pixmap))
+			goto fixup;
+
+		tmp = screen->CreatePixmap(screen,
+					   w/2, h/2, pixmap->drawable.depth,
+					   CREATE_PIXMAP_USAGE_SCRATCH);
+		if (!tmp)
+			goto fixup;
+
+		priv = sna_pixmap(tmp);
+		if (!priv) {
+			screen->DestroyPixmap(tmp);
+			goto fixup;
+		}
+
+		format = PictureMatchFormat(screen,
+					    pixmap->drawable.depth,
+					    picture->format);
+
+		tmp_dst = CreatePicture(0, &tmp->drawable, format, 0, NULL,
+					serverClient, &error);
+
+		tmp_src = CreatePicture(0, &pixmap->drawable, format, 0, NULL,
+					serverClient, &error);
+		tmp_src->filter = PictFilterBilinear;
+		memset(&t, 0, sizeof(t));
+		t.matrix[0][0] = 2 << 16;
+		t.matrix[1][1] = 2 << 16;
+		t.matrix[2][2] = 1 << 16;
+		tmp_src->transform = &t;
+
+		ValidatePicture(tmp_dst);
+		ValidatePicture(tmp_src);
+
+		ww = w/4; hh = h/4;
+
+		DBG(("%s downsampling using %dx%d GPU tiles\n",
+		     __FUNCTION__, ww, hh));
+
+		for (i = 0; i < 2; i++) {
+			for (j = 0; j < 2; j++) {
+				struct sna_composite_op op;
+				BoxRec b;
+
+				memset(&op, 0, sizeof(op));
+				if (!sna->render.composite(sna,
+							   PictOpSrc,
+							   tmp_src, NULL, tmp_dst,
+							   box.x1 + ww*j, box.y1 + hh*i,
+							   0, 0,
+							   ww*j, hh*i,
+							   ww, hh,
+							   &op)) {
+					tmp_src->transform = NULL;
+					FreePicture(tmp_src, 0);
+					FreePicture(tmp_dst, 0);
+					screen->DestroyPixmap(tmp);
+					goto fixup;
+				}
+
+				b.x1 = ww*j;
+				b.y1 = hh*i;
+				b.x2 = b.x1 + ww;
+				b.y2 = b.y1 + hh;
+
+				op.boxes(sna, &op, &b, 1);
+				op.done(sna, &op);
+			}
+		}
+
+		bo = kgem_bo_reference(priv->gpu_bo);
+
+		tmp_src->transform = NULL;
+		FreePicture(tmp_src, 0);
+		FreePicture(tmp_dst, 0);
+		screen->DestroyPixmap(tmp);
+	}
+
+	if (ox == x && oy == y) {
+		x = y = 0;
+	} else if (channel->transform) {
+		pixman_vector_t v;
+		pixman_transform_t m;
+
+		v.vector[0] = (ox - box.x1) << 16;
+		v.vector[1] = (oy - box.y1) << 16;
+		v.vector[2] = 1 << 16;
+		pixman_transform_invert(&m, channel->transform);
+		pixman_transform_point(&m, &v);
+		x = v.vector[0] / v.vector[2];
+		y = v.vector[1] / v.vector[2];
+	} else {
+		x = ox - box.x1;
+		y = oy - box.y1;
+	}
+
+	channel->offset[0] = x - dst_x;
+	channel->offset[1] = y - dst_y;
+	channel->scale[0] = 1./w;
+	channel->scale[1] = 1./h;
+	channel->width  = w / 2;
+	channel->height = h / 2;
+	channel->bo = bo;
+	return 1;
+
+fixup:
+	return sna_render_picture_fixup(sna, picture, channel,
+					x, y, w, h,
+					dst_x, dst_y);
+}
+
 int
 sna_render_picture_extract(struct sna *sna,
 			   PicturePtr picture,
@@ -517,8 +723,9 @@ sna_render_picture_extract(struct sna *sna,
 	if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) {
 		DBG(("%s: fallback -- sample too large for texture (%d, %d)x(%d, %d)\n",
 		     __FUNCTION__, box.x1, box.y1, w, h));
-		return sna_render_picture_fixup(sna, picture, channel,
-						x, y, ow, oh, dst_x, dst_y);
+		return sna_render_picture_downsample(sna, picture, channel,
+						     x, y, ow, oh,
+						     dst_x, dst_y);
 	}
 
 	if (texture_is_cpu(pixmap, &box) && !move_to_gpu(pixmap, &box)) {
commit f6c8c3bb6fd75bca6c7704b7d5869a5d44ce3832
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jul 1 11:17:32 2011 +0100

    sna/gen2: Use specular component for solid spans
    
    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 770ec7e..f4177f7 100644
--- a/src/sna/gen2_render.c
+++ b/src/sna/gen2_render.c
@@ -936,6 +936,7 @@ gen2_composite_solid_init(struct sna *sna,
 	channel->pict_format = PICT_a8r8g8b8;
 
 	channel->bo = sna_render_get_solid(sna, color);
+	channel->u.gen2.pixel = color;
 
 	channel->scale[0]  = channel->scale[1]  = 1;
 	channel->offset[0] = channel->offset[1] = 0;
@@ -1282,6 +1283,101 @@ cleanup_dst:
 }
 
 static void
+gen2_emit_composite_spans_primitive_constant(struct sna *sna,
+					     const struct sna_composite_spans_op *op,
+					     const BoxRec *box,
+					     float opacity)
+{
+	float *v = (float *)sna->kgem.batch + sna->kgem.nbatch;
+	uint32_t alpha = (uint8_t)(255 * opacity) << 24;
+	sna->kgem.nbatch += 9;
+
+	v[0] = op->base.dst.x + box->x2;
+	v[1] = op->base.dst.y + box->y2;
+	*((uint32_t *)v + 2) = alpha;
+
+	v[3] = op->base.dst.x + box->x1;
+	v[4] = v[1];
+	*((uint32_t *)v + 5) = alpha;
+
+	v[6] = v[3];
+	v[7] = op->base.dst.y + box->y1;
+	*((uint32_t *)v + 8) = alpha;
+}
+
+static void
+gen2_emit_composite_spans_primitive_identity_source(struct sna *sna,
+						    const struct sna_composite_spans_op *op,
+						    const BoxRec *box,
+						    float opacity)
+{
+	float *v = (float *)sna->kgem.batch + sna->kgem.nbatch;
+	uint32_t alpha = (uint8_t)(255 * opacity) << 24;
+	sna->kgem.nbatch += 15;
+
+	v[0] = op->base.dst.x + box->x2;
+	v[1] = op->base.dst.y + box->y2;
+	*((uint32_t *)v + 2) = alpha;
+	v[3] = (op->base.src.offset[0] + box->x2) * op->base.src.scale[0];
+	v[4] = (op->base.src.offset[1] + box->y2) * op->base.src.scale[1];
+
+	v[5] = op->base.dst.x + box->x1;
+	v[6] = v[1];
+	*((uint32_t *)v + 7) = alpha;
+	v[8] = (op->base.src.offset[0] + box->x1) * op->base.src.scale[0];
+	v[9] = v[4];
+
+	v[10] = v[5];
+	v[11] = op->base.dst.y + box->y1;
+	*((uint32_t *)v + 12) = alpha;
+	v[13] = v[8];
+	v[14] = (op->base.src.offset[1] + box->y1) * op->base.src.scale[1];
+}
+
+static void
+gen2_emit_composite_spans_primitive_affine_source(struct sna *sna,
+						  const struct sna_composite_spans_op *op,
+						  const BoxRec *box,
+						  float opacity)
+{
+	PictTransform *transform = op->base.src.transform;
+	uint32_t alpha = (uint8_t)(255 * opacity) << 24;
+	float x, y, *v;
+       
+	v = (float *)sna->kgem.batch + sna->kgem.nbatch;
+	sna->kgem.nbatch += 15;
+
+	v[0]  = op->base.dst.x + box->x2;
+	v[6]  = v[1] = op->base.dst.y + box->y2;
+	v[10] = v[5] = op->base.dst.x + box->x1;
+	v[11] = op->base.dst.y + box->y1;
+	*((uint32_t *)v + 2) = alpha;
+	*((uint32_t *)v + 7) = alpha;
+	*((uint32_t *)v + 12) = alpha;
+
+	_sna_get_transformed_coordinates((int)op->base.src.offset[0] + box->x2,
+					 (int)op->base.src.offset[1] + box->y2,
+					 transform,
+					 &x, &y);
+	v[3] = x * op->base.src.scale[0];
+	v[4] = y * op->base.src.scale[1];
+
+	_sna_get_transformed_coordinates((int)op->base.src.offset[0] + box->x1,
+					 (int)op->base.src.offset[1] + box->y2,
+					 transform,
+					 &x, &y);
+	v[8] = x * op->base.src.scale[0];
+	v[9] = y * op->base.src.scale[1];
+
+	_sna_get_transformed_coordinates((int)op->base.src.offset[0] + box->x1,
+					 (int)op->base.src.offset[1] + box->y1,
+					 transform,
+					 &x, &y);
+	v[13] = x * op->base.src.scale[0];
+	v[14] = y * op->base.src.scale[1];
+}
+
+static void
 gen2_emit_composite_spans_vertex(struct sna *sna,
 				 const struct sna_composite_spans_op *op,
 				 int16_t x, int16_t y,
@@ -1318,9 +1414,14 @@ gen2_emit_spans_pipeline(struct sna *sna,
 		TB0A_ARG1_SEL_DIFFUSE |
 		TB0A_OUTPUT_WRITE_CURRENT;
 
-	if (op->base.dst.format == PICT_a8) {
+	if (op->base.src.is_solid) {
+		ablend |= TB0A_ARG2_SEL_SPECULAR;
+		cblend |= TB0C_ARG2_SEL_SPECULAR;
+		if (op->base.dst.format == PICT_a8)
+			cblend |= TB0C_ARG2_REPLICATE_ALPHA;
+	} else if (op->base.dst.format == PICT_a8) {
 		ablend |= TB0A_ARG2_SEL_TEXEL0;
-		cblend |= TB0C_ARG2_SEL_TEXEL0 | TB0C_ARG2_REPLICATE_ALPHA;;
+		cblend |= TB0C_ARG2_SEL_TEXEL0 | TB0C_ARG2_REPLICATE_ALPHA;
 	} else {
 		if (PICT_FORMAT_RGB(op->base.src.pict_format) != 0)
 			cblend |= TB0C_ARG2_SEL_TEXEL0;
@@ -1347,18 +1448,23 @@ static void gen2_emit_composite_spans_state(struct sna *sna,
 
 	OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
 		  I1_LOAD_S(2) | I1_LOAD_S(3) | I1_LOAD_S(8) | 2);
-	OUT_BATCH(1 << 12);
+	OUT_BATCH(!op->base.src.is_solid << 12);
 	OUT_BATCH(S3_CULLMODE_NONE | S3_VERTEXHAS_XY | S3_DIFFUSE_PRESENT);
 	OUT_BATCH(S8_ENABLE_COLOR_BLEND | S8_BLENDFUNC_ADD |
 		  gen2_get_blend_cntl(op->base.op, FALSE, op->base.dst.format) |
 		  S8_ENABLE_COLOR_BUFFER_WRITE);
 
+	gen2_disable_logic_op(sna);
 	gen2_emit_spans_pipeline(sna, op);
 
-	OUT_BATCH(_3DSTATE_VERTEX_FORMAT_2_CMD |
-		  (op->base.src.is_affine ? TEXCOORDFMT_2D : TEXCOORDFMT_3D));
-
-	gen2_emit_texture(sna, &op->base.src, 0);
+	if (op->base.src.is_solid) {
+		OUT_BATCH(_3DSTATE_DFLT_SPECULAR_CMD);
+		OUT_BATCH(op->base.src.u.gen2.pixel);
+	} else {
+		OUT_BATCH(_3DSTATE_VERTEX_FORMAT_2_CMD |
+			  (op->base.src.is_affine ? TEXCOORDFMT_2D : TEXCOORDFMT_3D));
+		gen2_emit_texture(sna, &op->base.src, 0);
+	}
 }
 
 static void
@@ -1469,8 +1575,27 @@ gen2_render_composite_spans(struct sna *sna,
 
 	tmp->prim_emit = gen2_emit_composite_spans_primitive;
 	tmp->base.floats_per_vertex = 3;
-	if (tmp->base.src.bo)
+	if (tmp->base.src.is_solid) {
+		tmp->prim_emit = gen2_emit_composite_spans_primitive_constant;
+	} else {
+		assert(tmp->base.src.bo);
 		tmp->base.floats_per_vertex += tmp->base.src.is_affine ? 2 : 3;
+		if (tmp->base.src.transform == NULL)
+			tmp->prim_emit = gen2_emit_composite_spans_primitive_identity_source;
+		else if (tmp->base.src.is_affine)
+			tmp->prim_emit = gen2_emit_composite_spans_primitive_affine_source;
+
+		if (kgem_bo_is_dirty(tmp->base.src.bo)) {
+			if (tmp->base.src.bo == tmp->base.dst.bo) {
+				kgem_emit_flush(&sna->kgem);
+			} else {
+				OUT_BATCH(_3DSTATE_MODES_5_CMD |
+					  PIPELINE_FLUSH_RENDER_CACHE |
+					  PIPELINE_FLUSH_TEXTURE_CACHE);
+				kgem_clear_dirty(&sna->kgem);
+			}
+		}
+	}
 
 	tmp->boxes = gen2_render_composite_spans_boxes;
 	tmp->done  = gen2_render_composite_spans_done;
@@ -1480,17 +1605,6 @@ gen2_render_composite_spans(struct sna *sna,
 	if (!kgem_check_bo(&sna->kgem, tmp->base.src.bo))
 		kgem_submit(&sna->kgem);
 
-	if (kgem_bo_is_dirty(tmp->base.src.bo)) {
-		if (tmp->base.src.bo == tmp->base.dst.bo) {
-			kgem_emit_flush(&sna->kgem);
-		} else {
-			OUT_BATCH(_3DSTATE_MODES_5_CMD |
-				  PIPELINE_FLUSH_RENDER_CACHE |
-				  PIPELINE_FLUSH_TEXTURE_CACHE);
-			kgem_clear_dirty(&sna->kgem);
-		}
-	}
-
 	gen2_emit_composite_spans_state(sna, tmp);
 	return TRUE;
 
diff --git a/src/sna/gen2_render.h b/src/sna/gen2_render.h
index c10d540..2f41e9a 100644
--- a/src/sna/gen2_render.h
+++ b/src/sna/gen2_render.h
@@ -80,7 +80,7 @@
 
 #define _3DSTATE_DFLT_DIFFUSE_CMD	(CMD_3D | (0x1d<<24) | (0x99<<16))
 
-#define _3DSTATE_DFLT_SPEC_CMD		(CMD_3D | (0x1d<<24) | (0x9a<<16))
+#define _3DSTATE_DFLT_SPECULAR_CMD	(CMD_3D | (0x1d<<24) | (0x9a<<16))
 
 #define _3DSTATE_DFLT_Z_CMD		(CMD_3D | (0x1d<<24) | (0x98<<16))
 
@@ -745,6 +745,8 @@
 #define TB0C_ARG2_REPLICATE_ALPHA	(1<<17)
 #define TB0C_ARG2_INVERT		(1<<16)
 #define TB0C_ARG2_SEL_ONE		(0 << 12)
+#define TB0C_ARG2_SEL_DIFFUSE		(3 << 12)
+#define TB0C_ARG2_SEL_SPECULAR		(4 << 12)
 #define TB0C_ARG2_SEL_FACTOR		(1 << 12)
 #define TB0C_ARG2_SEL_TEXEL0		(6 << 12)
 #define TB0C_ARG2_SEL_TEXEL1		(7 << 12)
@@ -754,6 +756,7 @@
 #define TB0C_ARG1_INVERT		(1<<10)
 #define TB0C_ARG1_SEL_ONE		(0 << 6)
 #define TB0C_ARG1_SEL_DIFFUSE		(3 << 6)
+#define TB0C_ARG1_SEL_SPECULAR		(4 << 6)
 #define TB0C_ARG1_SEL_TEXEL0		(6 << 6)
 #define TB0C_ARG1_SEL_TEXEL1		(7 << 6)
 #define TB0C_ARG1_SEL_TEXEL2		(8 << 6)
@@ -775,6 +778,7 @@
 #define TB0A_ARG2_INVERT		(1<<16)
 #define TB0A_ARG2_SEL_ONE		(0 << 12)
 #define TB0A_ARG2_SEL_DIFFUSE		(3 << 12)
+#define TB0A_ARG2_SEL_SPECULAR		(4 << 12)
 #define TB0A_ARG2_SEL_TEXEL0		(6 << 12)
 #define TB0A_ARG2_SEL_TEXEL1		(7 << 12)
 #define TB0A_ARG2_SEL_TEXEL2		(8 << 12)
@@ -782,6 +786,7 @@
 #define TB0A_ARG1_INVERT		(1<<10)
 #define TB0A_ARG1_SEL_ONE		(0 << 6)
 #define TB0A_ARG1_SEL_DIFFUSE		(3 << 6)
+#define TB0A_ARG1_SEL_SPECULAR		(4 << 6)
 #define TB0A_ARG1_SEL_TEXEL0		(6 << 6)
 #define TB0A_ARG1_SEL_TEXEL1		(7 << 6)
 #define TB0A_ARG1_SEL_TEXEL2		(8 << 6)
diff --git a/src/sna/gen3_render.c b/src/sna/gen3_render.c
index aba1b8d..ee8de2d 100644
--- a/src/sna/gen3_render.c
+++ b/src/sna/gen3_render.c
@@ -616,7 +616,7 @@ gen3_emit_composite_texcoord(struct sna *sna,
 {
 	float s = 0, t = 0, w = 1;
 
-	switch (channel->gen3.type) {
+	switch (channel->u.gen3.type) {
 	case SHADER_OPACITY:
 	case SHADER_NONE:
 	case SHADER_ZERO:
@@ -701,7 +701,7 @@ gen3_linear_coord(struct sna *sna,
 		  const struct sna_composite_channel *channel,
 		  int in, int out)
 {
-	int c = channel->gen3.constants;
+	int c = channel->u.gen3.constants;
 
 	if (!channel->is_affine) {
 		gen3_2d_perspective(sna, in, FS_U0);
@@ -719,14 +719,14 @@ gen3_radial_coord(struct sna *sna,
 		  const struct sna_composite_channel *channel,
 		  int in, int out)
 {
-	int c = channel->gen3.constants;
+	int c = channel->u.gen3.constants;
 
 	if (!channel->is_affine) {
 		gen3_2d_perspective(sna, in, FS_U0);
 		in = FS_U0;
 	}
 
-	switch (channel->gen3.mode) {
+	switch (channel->u.gen3.mode) {
 	case RADIAL_ONE:
 		/*
 		   pdx = (x - c1x) / dr, pdy = (y - c1y) / dr;
@@ -806,7 +806,7 @@ gen3_composite_emit_shader(struct sna *sna,
 
 	src = &op->src;
 	mask = &op->mask;
-	if (mask->gen3.type == SHADER_NONE)
+	if (mask->u.gen3.type == SHADER_NONE)
 		mask = NULL;
 
 	if (mask && src->is_opaque &&
@@ -816,12 +816,12 @@ gen3_composite_emit_shader(struct sna *sna,
 		mask = NULL;
 	}
 
-	id = (src->gen3.type |
+	id = (src->u.gen3.type |
 	      src->is_affine << 4 |
 	      src->alpha_fixup << 5 |
 	      src->rb_reversed << 6);
 	if (mask) {
-		id |= (mask->gen3.type << 8 |
+		id |= (mask->u.gen3.type << 8 |
 		       mask->is_affine << 12 |
 		       gen3_blend_op[blend].src_alpha << 13 |
 		       op->has_component_alpha << 14 |
@@ -838,7 +838,7 @@ gen3_composite_emit_shader(struct sna *sna,
 
 	shader_offset = sna->kgem.nbatch++;
 	t = 0;
-	switch (src->gen3.type) {
+	switch (src->u.gen3.type) {
 	case SHADER_NONE:
 	case SHADER_OPACITY:
 		assert(0);
@@ -858,7 +858,7 @@ gen3_composite_emit_shader(struct sna *sna,
 	}
 
 	if (mask == NULL) {
-		if (src->gen3.type == SHADER_ZERO) {
+		if (src->u.gen3.type == SHADER_ZERO) {
 			gen3_fs_mov(FS_OC, gen3_fs_operand_zero());
 			goto done;
 		}
@@ -867,13 +867,13 @@ gen3_composite_emit_shader(struct sna *sna,
 			goto done;
 		}
 		/* No mask, so load directly to output color */
-		if (src->gen3.type != SHADER_CONSTANT) {
+		if (src->u.gen3.type != SHADER_CONSTANT) {
 			if (dst_is_alpha || src->rb_reversed ^ op->rb_reversed)
 				src_reg = FS_R0;
 			else
 				src_reg = FS_OC;
 		}
-		switch (src->gen3.type) {
+		switch (src->u.gen3.type) {
 		case SHADER_LINEAR:
 			gen3_linear_coord(sna, src, FS_T0, FS_R0);
 			gen3_fs_texld(src_reg, FS_S0, FS_R0);
@@ -916,7 +916,7 @@ gen3_composite_emit_shader(struct sna *sna,
 		if (op->rb_reversed)
 			out_reg = FS_U0;
 
-		switch (mask->gen3.type) {
+		switch (mask->u.gen3.type) {
 		case SHADER_CONSTANT:
 			gen3_fs_dcl(FS_T9);
 			mask_reg = FS_T9;
@@ -935,7 +935,7 @@ gen3_composite_emit_shader(struct sna *sna,
 		}
 
 		t = 0;
-		switch (src->gen3.type) {
+		switch (src->u.gen3.type) {
 		case SHADER_LINEAR:
 			gen3_linear_coord(sna, src, FS_T0, FS_R0);
 			gen3_fs_texld(FS_R0, FS_S0, FS_R0);
@@ -969,7 +969,7 @@ gen3_composite_emit_shader(struct sna *sna,
 		if (src->rb_reversed)
 			gen3_fs_mov(src_reg, gen3_fs_operand(src_reg, Z, Y, X, W));
 
-		switch (mask->gen3.type) {
+		switch (mask->u.gen3.type) {
 		case SHADER_LINEAR:
 			gen3_linear_coord(sna, mask, FS_T0 + t, FS_R1);
 			gen3_fs_texld(FS_R1, FS_S0 + t, FS_R1);
@@ -1188,17 +1188,17 @@ static void gen3_emit_composite_state(struct sna *sna,
 
 	ss2 = ~0;
 	tex_count = 0;
-	switch (op->src.gen3.type) {
+	switch (op->src.u.gen3.type) {
 	case SHADER_OPACITY:
 	case SHADER_NONE:
 		assert(0);
 	case SHADER_ZERO:
 		break;
 	case SHADER_CONSTANT:
-		if (op->src.gen3.mode != state->last_diffuse) {
+		if (op->src.u.gen3.mode != state->last_diffuse) {
 			OUT_BATCH(_3DSTATE_DFLT_DIFFUSE_CMD);
-			OUT_BATCH(op->src.gen3.mode);
-			state->last_diffuse = op->src.gen3.mode;
+			OUT_BATCH(op->src.u.gen3.mode);
+			state->last_diffuse = op->src.u.gen3.mode;
 		}
 		break;
 	case SHADER_LINEAR:
@@ -1223,15 +1223,15 @@ static void gen3_emit_composite_state(struct sna *sna,
 		tex_count++;
 		break;
 	}
-	switch (op->mask.gen3.type) {
+	switch (op->mask.u.gen3.type) {
 	case SHADER_NONE:
 	case SHADER_ZERO:
 		break;
 	case SHADER_CONSTANT:
-		if (op->mask.gen3.mode != state->last_specular) {
+		if (op->mask.u.gen3.mode != state->last_specular) {
 			OUT_BATCH(_3DSTATE_DFLT_SPEC_CMD);
-			OUT_BATCH(op->mask.gen3.mode);
-			state->last_specular = op->mask.gen3.mode;
+			OUT_BATCH(op->mask.u.gen3.mode);
+			state->last_specular = op->mask.u.gen3.mode;
 		}
 		break;
 	case SHADER_LINEAR:
@@ -1731,10 +1731,10 @@ gen3_init_solid(struct sna *sna,
 		struct sna_composite_channel *channel,
 		uint32_t color)
 {
-	channel->gen3.mode = color;
-	channel->gen3.type = SHADER_CONSTANT;
+	channel->u.gen3.mode = color;
+	channel->u.gen3.type = SHADER_CONSTANT;
 	if (color == 0)
-		channel->gen3.type = SHADER_ZERO;
+		channel->u.gen3.type = SHADER_ZERO;
 	if ((color & 0xff000000) == 0xff000000)
 		channel->is_opaque = true;
 
@@ -1749,7 +1749,7 @@ gen3_init_solid(struct sna *sna,
 
 static void gen3_composite_channel_convert(struct sna_composite_channel *channel)
 {
-	if (channel->gen3.type == SHADER_TEXTURE)
+	if (channel->u.gen3.type == SHADER_TEXTURE)
 		channel->repeat = gen3_texture_repeat(channel->repeat);
 	else
 		channel->repeat = gen3_gradient_repeat(channel->repeat);
@@ -1837,7 +1837,7 @@ gen3_init_linear(struct sna *sna,
 	offset = dx*x0 + dy*y0;
 
 	n = op->u.gen3.num_constants;
-	channel->gen3.constants = FS_C0 + n / 4;
+	channel->u.gen3.constants = FS_C0 + n / 4;
 	op->u.gen3.constants[n++] = dx;
 	op->u.gen3.constants[n++] = dy;
 	op->u.gen3.constants[n++] = -offset;
@@ -1846,11 +1846,11 @@ gen3_init_linear(struct sna *sna,
 	if (!gen3_gradient_setup(sna, picture, channel, ox, oy))
 		return 0;
 
-	channel->gen3.type = SHADER_LINEAR;
+	channel->u.gen3.type = SHADER_LINEAR;
 	op->u.gen3.num_constants = n;
 
 	DBG(("%s: dx=%f, dy=%f, offset=%f, constants=%d\n",
-	     __FUNCTION__, dx, dy, -offset, channel->gen3.constants - FS_C0));
+	     __FUNCTION__, dx, dy, -offset, channel->u.gen3.constants - FS_C0));
 	return 1;
 }
 
@@ -1872,7 +1872,7 @@ gen3_init_radial(struct sna *sna,
 	r1 = xFixedToDouble(radial->c1.radius);
 
 	n = op->u.gen3.num_constants;
-	channel->gen3.constants = FS_C0 + n / 4;
+	channel->u.gen3.constants = FS_C0 + n / 4;
 	if (radial->c2.x == radial->c1.x && radial->c2.y == radial->c1.y) {
 		if (radial->c2.radius == radial->c1.radius)
 			return 0;
@@ -1882,7 +1882,7 @@ gen3_init_radial(struct sna *sna,
 		op->u.gen3.constants[n++] = 1. / dr;
 		op->u.gen3.constants[n++] = -r1 / dr;
 
-		channel->gen3.mode = RADIAL_ONE;
+		channel->u.gen3.mode = RADIAL_ONE;
 	} else {
 		op->u.gen3.constants[n++] = -xFixedToDouble(radial->c1.x);
 		op->u.gen3.constants[n++] = -xFixedToDouble(radial->c1.y);
@@ -1894,13 +1894,13 @@ gen3_init_radial(struct sna *sna,
 		op->u.gen3.constants[n++] = -2 * r1 * dr;
 		op->u.gen3.constants[n++] = 1 / (2 * (dx*dx + dy*dy - dr*dr));
 
-		channel->gen3.mode = RADIAL_TWO;
+		channel->u.gen3.mode = RADIAL_TWO;
 	}
 
 	if (!gen3_gradient_setup(sna, picture, channel, ox, oy))
 		return 0;
 
-	channel->gen3.type = SHADER_RADIAL;
+	channel->u.gen3.type = SHADER_RADIAL;
 	op->u.gen3.num_constants = n;
 	return 1;
 }
@@ -2175,7 +2175,7 @@ gen3_render_composite(struct sna *sna,
 			return FALSE;
 	}
 
-	tmp->src.gen3.type = SHADER_TEXTURE;
+	tmp->src.u.gen3.type = SHADER_TEXTURE;
 	tmp->src.is_affine = TRUE;
 	DBG(("%s: preparing source\n", __FUNCTION__));
 	switch (gen3_composite_picture(sna, src, tmp, &tmp->src,
@@ -2185,20 +2185,20 @@ gen3_render_composite(struct sna *sna,
 	case -1:
 		goto cleanup_dst;
 	case 0:
-		tmp->src.gen3.type = SHADER_ZERO;
+		tmp->src.u.gen3.type = SHADER_ZERO;
 		break;
 	case 1:
 		gen3_composite_channel_convert(&tmp->src);
 		break;
 	}
-	DBG(("%s: source type=%d\n", __FUNCTION__, tmp->src.gen3.type));
+	DBG(("%s: source type=%d\n", __FUNCTION__, tmp->src.u.gen3.type));
 
-	tmp->mask.gen3.type = SHADER_NONE;
+	tmp->mask.u.gen3.type = SHADER_NONE;
 	tmp->mask.is_affine = TRUE;
 	tmp->need_magic_ca_pass = FALSE;
 	tmp->has_component_alpha = FALSE;
-	if (mask && tmp->src.gen3.type != SHADER_ZERO) {
-		tmp->mask.gen3.type = SHADER_TEXTURE;
+	if (mask && tmp->src.u.gen3.type != SHADER_ZERO) {
+		tmp->mask.u.gen3.type = SHADER_TEXTURE;
 		DBG(("%s: preparing mask\n", __FUNCTION__));
 		switch (gen3_composite_picture(sna, mask, tmp, &tmp->mask,
 					       mask_x, mask_y,
@@ -2207,68 +2207,68 @@ gen3_render_composite(struct sna *sna,
 		case -1:
 			goto cleanup_src;
 		case 0:
-			tmp->mask.gen3.type = SHADER_ZERO;
+			tmp->mask.u.gen3.type = SHADER_ZERO;
 			break;
 		case 1:
 			gen3_composite_channel_convert(&tmp->mask);
 			break;
 		}
-		DBG(("%s: mask type=%d\n", __FUNCTION__, tmp->mask.gen3.type));
+		DBG(("%s: mask type=%d\n", __FUNCTION__, tmp->mask.u.gen3.type));
 
-		if (tmp->mask.gen3.type == SHADER_ZERO) {
+		if (tmp->mask.u.gen3.type == SHADER_ZERO) {
 			if (tmp->src.bo) {
 				kgem_bo_destroy(&sna->kgem,
 						tmp->src.bo);
 				tmp->src.bo = NULL;
 			}
-			tmp->src.gen3.type = SHADER_ZERO;
-			tmp->mask.gen3.type = SHADER_NONE;
+			tmp->src.u.gen3.type = SHADER_ZERO;
+			tmp->mask.u.gen3.type = SHADER_NONE;
 		}
 
-		if (tmp->mask.gen3.type != SHADER_NONE &&
+		if (tmp->mask.u.gen3.type != SHADER_NONE &&
 		    mask->componentAlpha && PICT_FORMAT_RGB(mask->format)) {
 			/* Check if it's component alpha that relies on a source alpha
 			 * and on the source value.  We can only get one of those
 			 * into the single source value that we get to blend with.
 			 */
 			tmp->has_component_alpha = TRUE;
-			if (tmp->mask.gen3.type == SHADER_CONSTANT &&
-			    tmp->mask.gen3.mode == 0xffffffff) {
-				tmp->mask.gen3.type = SHADER_NONE;
+			if (tmp->mask.u.gen3.type == SHADER_CONSTANT &&
+			    tmp->mask.u.gen3.mode == 0xffffffff) {
+				tmp->mask.u.gen3.type = SHADER_NONE;
 				tmp->has_component_alpha = FALSE;
-			} else if (tmp->src.gen3.type == SHADER_CONSTANT &&
-				   tmp->src.gen3.mode == 0xffffffff) {
+			} else if (tmp->src.u.gen3.type == SHADER_CONSTANT &&
+				   tmp->src.u.gen3.mode == 0xffffffff) {
 				tmp->src = tmp->mask;
-				tmp->mask.gen3.type = SHADER_NONE;
+				tmp->mask.u.gen3.type = SHADER_NONE;
 				tmp->mask.bo = NULL;
 				tmp->has_component_alpha = FALSE;
-			} else if (tmp->src.gen3.type == SHADER_CONSTANT &&
-				   tmp->mask.gen3.type == SHADER_CONSTANT) {
+			} else if (tmp->src.u.gen3.type == SHADER_CONSTANT &&
+				   tmp->mask.u.gen3.type == SHADER_CONSTANT) {
 				uint32_t a,r,g,b;
 
-				a = mult(tmp->src.gen3.mode,
-					 tmp->mask.gen3.mode,
+				a = mult(tmp->src.u.gen3.mode,
+					 tmp->mask.u.gen3.mode,
 					 24);
-				r = mult(tmp->src.gen3.mode,
-					 tmp->mask.gen3.mode,
+				r = mult(tmp->src.u.gen3.mode,
+					 tmp->mask.u.gen3.mode,
 					 16);
-				g = mult(tmp->src.gen3.mode,
-					 tmp->mask.gen3.mode,
+				g = mult(tmp->src.u.gen3.mode,
+					 tmp->mask.u.gen3.mode,
 					 8);
-				b = mult(tmp->src.gen3.mode,
-					 tmp->mask.gen3.mode,
+				b = mult(tmp->src.u.gen3.mode,
+					 tmp->mask.u.gen3.mode,
 					 0);
 
 				DBG(("%s: combining constant source/mask: %x x %x -> %x\n",
 				     __FUNCTION__,
-				     tmp->src.gen3.mode,
-				     tmp->mask.gen3.mode,
+				     tmp->src.u.gen3.mode,
+				     tmp->mask.u.gen3.mode,
 				     a << 24 | r << 16 | g << 8 | b));
 
-				tmp->src.gen3.mode =
+				tmp->src.u.gen3.mode =
 					a << 24 | r << 16 | g << 8 | b;
 
-				tmp->mask.gen3.type = SHADER_NONE;
+				tmp->mask.u.gen3.type = SHADER_NONE;
 				tmp->has_component_alpha = FALSE;
 			} else if (gen3_blend_op[op].src_alpha &&
 				   (gen3_blend_op[op].src_blend != BLENDFACT_ZERO)) {
@@ -2282,13 +2282,13 @@ gen3_render_composite(struct sna *sna,
 		}
 	}
 	DBG(("%s: final src/mask type=%d/%d, affine=%d/%d\n", __FUNCTION__,
-	     tmp->src.gen3.type, tmp->mask.gen3.type,
+	     tmp->src.u.gen3.type, tmp->mask.u.gen3.type,
 	     tmp->src.is_affine, tmp->mask.is_affine));
 
 	tmp->prim_emit = gen3_emit_composite_primitive;
-	if (tmp->mask.gen3.type == SHADER_NONE ||
-	    tmp->mask.gen3.type == SHADER_CONSTANT) {
-		switch (tmp->src.gen3.type) {
+	if (tmp->mask.u.gen3.type == SHADER_NONE ||
+	    tmp->mask.u.gen3.type == SHADER_CONSTANT) {
+		switch (tmp->src.u.gen3.type) {
 		case SHADER_NONE:
 		case SHADER_CONSTANT:
 			tmp->prim_emit = gen3_emit_composite_primitive_constant;
@@ -2307,9 +2307,9 @@ gen3_render_composite(struct sna *sna,
 				tmp->prim_emit = gen3_emit_composite_primitive_affine_source;
 			break;
 		}
-	} else if (tmp->mask.gen3.type == SHADER_TEXTURE) {
+	} else if (tmp->mask.u.gen3.type == SHADER_TEXTURE) {
 		if (tmp->mask.transform == NULL) {
-			if (tmp->src.gen3.type == SHADER_CONSTANT)
+			if (tmp->src.u.gen3.type == SHADER_CONSTANT)
 				tmp->prim_emit = gen3_emit_composite_primitive_constant_identity_mask;
 			else if (tmp->src.transform == NULL)
 				tmp->prim_emit = gen3_emit_composite_primitive_identity_source_mask;
@@ -2319,18 +2319,18 @@ gen3_render_composite(struct sna *sna,
 	}
 
 	tmp->floats_per_vertex = 2;
-	if (tmp->src.gen3.type != SHADER_CONSTANT &&
-	    tmp->src.gen3.type != SHADER_ZERO)
+	if (tmp->src.u.gen3.type != SHADER_CONSTANT &&
+	    tmp->src.u.gen3.type != SHADER_ZERO)
 		tmp->floats_per_vertex += tmp->src.is_affine ? 2 : 4;
-	if (tmp->mask.gen3.type != SHADER_NONE &&
-	    tmp->mask.gen3.type != SHADER_CONSTANT)
+	if (tmp->mask.u.gen3.type != SHADER_NONE &&
+	    tmp->mask.u.gen3.type != SHADER_CONSTANT)
 		tmp->floats_per_vertex += tmp->mask.is_affine ? 2 : 4;
 	DBG(("%s: floats_per_vertex = 2 + %d + %d = %d\n", __FUNCTION__,
-	     (tmp->src.gen3.type != SHADER_CONSTANT &&
-	      tmp->src.gen3.type != SHADER_ZERO) ?
+	     (tmp->src.u.gen3.type != SHADER_CONSTANT &&
+	      tmp->src.u.gen3.type != SHADER_ZERO) ?
 	     tmp->src.is_affine ? 2 : 4 : 0,
-	     (tmp->mask.gen3.type != SHADER_NONE &&
-	      tmp->mask.gen3.type != SHADER_CONSTANT) ?
+	     (tmp->mask.u.gen3.type != SHADER_NONE &&
+	      tmp->mask.u.gen3.type != SHADER_CONSTANT) ?
 	     tmp->mask.is_affine ? 2 : 4 : 0,
 	     tmp->floats_per_vertex));
 
@@ -2670,7 +2670,7 @@ gen3_render_composite_spans(struct sna *sna,
 			return FALSE;
 	}
 
-	tmp->base.src.gen3.type = SHADER_TEXTURE;
+	tmp->base.src.u.gen3.type = SHADER_TEXTURE;
 	tmp->base.src.is_affine = TRUE;
 	DBG(("%s: preparing source\n", __FUNCTION__));
 	switch (gen3_composite_picture(sna, src, &tmp->base, &tmp->base.src,
@@ -2680,19 +2680,19 @@ gen3_render_composite_spans(struct sna *sna,
 	case -1:
 		goto cleanup_dst;
 	case 0:
-		tmp->base.src.gen3.type = SHADER_ZERO;
+		tmp->base.src.u.gen3.type = SHADER_ZERO;
 		break;
 	case 1:
 		gen3_composite_channel_convert(&tmp->base.src);
 		break;
 	}
-	DBG(("%s: source type=%d\n", __FUNCTION__, tmp->base.src.gen3.type));
+	DBG(("%s: source type=%d\n", __FUNCTION__, tmp->base.src.u.gen3.type));
 
-	if (tmp->base.src.gen3.type != SHADER_ZERO)
-		tmp->base.mask.gen3.type = SHADER_OPACITY;
+	if (tmp->base.src.u.gen3.type != SHADER_ZERO)
+		tmp->base.mask.u.gen3.type = SHADER_OPACITY;
 
 	tmp->prim_emit = gen3_emit_composite_spans_primitive;
-	switch (tmp->base.src.gen3.type) {
+	switch (tmp->base.src.u.gen3.type) {
 	case SHADER_NONE:
 		assert(0);
 	case SHADER_ZERO:
@@ -2717,11 +2717,11 @@ gen3_render_composite_spans(struct sna *sna,
 	}
 
 	tmp->base.floats_per_vertex = 2;
-	if (tmp->base.src.gen3.type != SHADER_CONSTANT &&
-	    tmp->base.src.gen3.type != SHADER_ZERO)
+	if (tmp->base.src.u.gen3.type != SHADER_CONSTANT &&
+	    tmp->base.src.u.gen3.type != SHADER_ZERO)
 		tmp->base.floats_per_vertex += tmp->base.src.is_affine ? 2 : 3;
 	tmp->base.floats_per_vertex +=
-		tmp->base.mask.gen3.type == SHADER_OPACITY;
+		tmp->base.mask.u.gen3.type == SHADER_OPACITY;
 
 	tmp->boxes = gen3_render_composite_spans_boxes;
 	tmp->done  = gen3_render_composite_spans_done;
@@ -3230,7 +3230,7 @@ gen3_render_copy_setup_source(struct sna *sna,
 			      PixmapPtr pixmap,
 			      struct kgem_bo *bo)
 {
-	channel->gen3.type = SHADER_TEXTURE;
+	channel->u.gen3.type = SHADER_TEXTURE;
 	channel->filter = gen3_filter(PictFilterNearest);
 	channel->repeat = gen3_texture_repeat(RepeatNone);
 	channel->width  = pixmap->drawable.width;
@@ -3313,7 +3313,7 @@ gen3_render_copy_boxes(struct sna *sna, uint8_t alu,
 	gen3_render_copy_setup_source(sna, &tmp.src, src, src_bo);
 
 	tmp.floats_per_vertex = 4;
-	tmp.mask.gen3.type = SHADER_NONE;
+	tmp.mask.u.gen3.type = SHADER_NONE;
 
 	gen3_emit_composite_state(sna, &tmp);
 	gen3_align_vertex(sna, &tmp);
@@ -3441,7 +3441,7 @@ gen3_render_copy(struct sna *sna, uint8_t alu,
 	gen3_render_copy_setup_source(sna, &tmp->base.src, src, src_bo);
 
 	tmp->base.floats_per_vertex = 4;
-	tmp->base.mask.gen3.type = SHADER_NONE;
+	tmp->base.mask.u.gen3.type = SHADER_NONE;
 
 	if (!kgem_check_bo(&sna->kgem, dst_bo))
 		kgem_submit(&sna->kgem);
@@ -3559,8 +3559,8 @@ gen3_render_fill_boxes(struct sna *sna,
 	tmp.dst.bo = dst_bo;
 	tmp.floats_per_vertex = 2;
 
-	tmp.src.gen3.type = op == PictOpClear ? SHADER_ZERO : SHADER_CONSTANT;
-	tmp.src.gen3.mode = pixel;
+	tmp.src.u.gen3.type = op == PictOpClear ? SHADER_ZERO : SHADER_CONSTANT;
+	tmp.src.u.gen3.mode = pixel;
 
 	if (!kgem_check_bo(&sna->kgem, dst_bo))
 		kgem_submit(&sna->kgem);
@@ -3660,8 +3660,8 @@ gen3_render_fill(struct sna *sna, uint8_t alu,
 	tmp->base.dst.bo = dst_bo;
 	tmp->base.floats_per_vertex = 2;
 
-	tmp->base.src.gen3.type = SHADER_CONSTANT;
-	tmp->base.src.gen3.mode =
+	tmp->base.src.u.gen3.type = SHADER_CONSTANT;
+	tmp->base.src.u.gen3.mode =
 		sna_rgba_for_color(color, dst->drawable.depth);
 
 	if (!kgem_check_bo(&sna->kgem, dst_bo))
diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h
index 012b090..8330395 100644
--- a/src/sna/sna_render.h
+++ b/src/sna/sna_render.h
@@ -53,11 +53,16 @@ struct sna_composite_op {
 		int16_t offset[2];
 		float scale[2];
 
-		struct gen3_shader_channel {
-			int type;
-			uint32_t mode;
-			uint32_t constants;
-		} gen3;
+		union {
+			struct {
+				uint32_t pixel;
+			} gen2;
+			struct gen3_shader_channel {
+				int type;
+				uint32_t mode;
+				uint32_t constants;
+			} gen3;
+		} u;
 	} src, mask;
 	uint32_t is_affine : 1;
 	uint32_t has_component_alpha : 1;
commit de14e3c8595f9e315dc3ce23ad15b04e118499f4
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jul 1 09:58:27 2011 +0100

    sna/gen2: Add missing render fallbacks for blt ops
    
    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 82c7e15..770ec7e 100644
--- a/src/sna/gen2_render.c
+++ b/src/sna/gen2_render.c
@@ -45,6 +45,18 @@
 #define NDEBUG 1
 #endif
 
+#define NO_COMPOSITE 0
+#define NO_COMPOSITE_SPANS 0
+#define NO_COPY 0
+#define NO_COPY_BOXES 0
+#define NO_FILL 0
+#define NO_FILL_BOXES 0
+
+#define PREFER_COPY 0
+#define PREFER_COPY_BOXES 0
+#define PREFER_FILL 0
+#define PREFER_FILL_BOXES 0
+
 #define OUT_BATCH(v) batch_emit(sna, v)
 #define OUT_BATCH_F(v) batch_emit_float(sna, v)
 #define OUT_VERTEX(v) batch_emit_float(sna, v)
@@ -617,6 +629,48 @@ static void gen2_emit_target(struct sna *sna, const struct sna_composite_op *op)
 	sna->render_state.gen2.target = op->dst.bo->unique_id;
 }
 
+static void gen2_disable_logic_op(struct sna *sna)
+{
+	if (!sna->render_state.gen2.logic_op_enabled)
+		return;
+
+	OUT_BATCH(_3DSTATE_ENABLES_1_CMD |
+		  DISABLE_LOGIC_OP | ENABLE_COLOR_BLEND);
+
+	sna->render_state.gen2.logic_op_enabled = 0;
+}
+
+static void gen2_enable_logic_op(struct sna *sna, int op)
+{
+	uint8_t logic_op[] = {
+		LOGICOP_CLEAR,		/* GXclear */
+		LOGICOP_AND,		/* GXand */
+		LOGICOP_AND_RVRSE, 	/* GXandReverse */
+		LOGICOP_COPY,		/* GXcopy */
+		LOGICOP_AND_INV,	/* GXandInverted */
+		LOGICOP_NOOP,		/* GXnoop */
+		LOGICOP_XOR,		/* GXxor */
+		LOGICOP_OR,		/* GXor */
+		LOGICOP_NOR,		/* GXnor */
+		LOGICOP_EQUIV,		/* GXequiv */
+		LOGICOP_INV,		/* GXinvert */
+		LOGICOP_OR_RVRSE,	/* GXorReverse */
+		LOGICOP_COPY_INV,	/* GXcopyInverted */
+		LOGICOP_OR_INV,		/* GXorInverted */
+		LOGICOP_NAND,		/* GXnand */
+		LOGICOP_SET		/* GXset */
+	};
+
+	if (!sna->render_state.gen2.logic_op_enabled) {
+		OUT_BATCH(_3DSTATE_ENABLES_1_CMD |
+			  ENABLE_LOGIC_OP | DISABLE_COLOR_BLEND);
+		sna->render_state.gen2.logic_op_enabled = 1;
+	}
+
+	OUT_BATCH(_3DSTATE_MODES_4_CMD |
+		  ENABLE_LOGIC_OP_FUNC | LOGIC_OP_FUNC(logic_op[op]));
+}
+
 static void gen2_emit_composite_state(struct sna *sna,
 				      const struct sna_composite_op *op)
 {
@@ -636,6 +690,8 @@ static void gen2_emit_composite_state(struct sna *sna,
 				      op->dst.format) |
 		  S8_ENABLE_COLOR_BUFFER_WRITE);
 
+	gen2_disable_logic_op(sna);
+
 	gen2_get_blend_factors(op, &cblend, &ablend);
 	OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 |
 		  LOAD_TEXTURE_BLEND_STAGE(0) | 1);
@@ -1247,41 +1303,8 @@ gen2_emit_composite_spans_primitive(struct sna *sna,
 	gen2_emit_composite_spans_vertex(sna, op, box->x1, box->y1, opacity);
 }
 
-#if 0
-static void gen2_emit_fill_blend_op(struct sna *sna)
-{
-	/* Set default blend state */
-	OUT_BATCH(_3DSTATE_MAP_BLEND_OP_CMD(0) |
-		  TEXPIPE_COLOR |
-		  ENABLE_TEXOUTPUT_WRT_SEL |
-		  TEXOP_OUTPUT_CURRENT |
-		  DISABLE_TEX_CNTRL_STAGE |
-		  TEXOP_SCALE_1X |
-		  TEXOP_MODIFY_PARMS |
-		  TEXOP_LAST_STAGE |
-		  TEXBLENDOP_ARG1);
-	OUT_BATCH(_3DSTATE_MAP_BLEND_OP_CMD(0) |
-		  TEXPIPE_ALPHA |
-		  ENABLE_TEXOUTPUT_WRT_SEL |
-		  TEXOP_OUTPUT_CURRENT |
-		  TEXOP_SCALE_1X |
-		  TEXOP_MODIFY_PARMS |
-		  TEXBLENDOP_ARG1);
-	OUT_BATCH(_3DSTATE_MAP_BLEND_ARG_CMD(0) |
-		  TEXPIPE_COLOR |
-		  TEXBLEND_ARG1 |
-		  TEXBLENDARG_MODIFY_PARMS |
-		  TEXBLENDARG_DIFFUSE);
-	OUT_BATCH(_3DSTATE_MAP_BLEND_ARG_CMD(0) |
-		  TEXPIPE_ALPHA |
-		  TEXBLEND_ARG1 |
-		  TEXBLENDARG_MODIFY_PARMS |
-		  TEXBLENDARG_DIFFUSE);
-}
-#endif
-
 static void
-gen2_emit_spans_blend_op(struct sna *sna,
+gen2_emit_spans_pipeline(struct sna *sna,
 			 const struct sna_composite_spans_op *op)
 {
 	uint32_t cblend, ablend;
@@ -1330,7 +1353,7 @@ static void gen2_emit_composite_spans_state(struct sna *sna,
 		  gen2_get_blend_cntl(op->base.op, FALSE, op->base.dst.format) |
 		  S8_ENABLE_COLOR_BUFFER_WRITE);
 
-	gen2_emit_spans_blend_op(sna, op);
+	gen2_emit_spans_pipeline(sna, op);
 
 	OUT_BATCH(_3DSTATE_VERTEX_FORMAT_2_CMD |
 		  (op->base.src.is_affine ? TEXCOORDFMT_2D : TEXCOORDFMT_3D));
@@ -1478,20 +1501,20 @@ cleanup_dst:
 }
 
 static void
-gen2_emit_fill_blend_op(struct sna *sna, const struct sna_composite_op *op)
+gen2_emit_fill_pipeline(struct sna *sna, const struct sna_composite_op *op)
 {
 	uint32_t blend;
 
 	OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 |
 		  LOAD_TEXTURE_BLEND_STAGE(0) | 1);
+
 	blend = TB0C_LAST_STAGE | TB0C_RESULT_SCALE_1X | TB0C_OP_ARG1 |
 		TB0C_ARG1_SEL_DIFFUSE |
 		TB0C_OUTPUT_WRITE_CURRENT;
-
 	if (op->dst.format == PICT_a8)
 		blend |= TB0C_ARG1_REPLICATE_ALPHA;
-
 	OUT_BATCH(blend);
+
 	OUT_BATCH(TB0A_RESULT_SCALE_1X | TB0A_OP_ARG1 |
 		  TB0A_ARG1_SEL_DIFFUSE |
 		  TB0A_OUTPUT_WRITE_CURRENT);
@@ -1512,7 +1535,7 @@ static void gen2_emit_fill_composite_state(struct sna *sna,
 		  gen2_get_blend_cntl(op->op, FALSE, op->dst.format) |
 		  S8_ENABLE_COLOR_BUFFER_WRITE);
 
-	gen2_emit_fill_blend_op(sna, op);
+	gen2_emit_fill_pipeline(sna, op);
 
 	OUT_BATCH(_3DSTATE_DFLT_DIFFUSE_CMD);
 	OUT_BATCH(pixel);
@@ -1590,7 +1613,8 @@ gen2_render_fill_boxes(struct sna *sna,
 						      dst, dst_bo,
 						      box, n);
 
-	if (gen2_render_fill_boxes_try_blt(sna, op, format, color,
+	if (!PREFER_FILL_BOXES &&
+	    gen2_render_fill_boxes_try_blt(sna, op, format, color,
 					   dst, dst_bo,
 					   box, n))
 		return TRUE;
@@ -1649,10 +1673,383 @@ gen2_render_fill_boxes(struct sna *sna,
 	return TRUE;
 }
 
+static void gen2_emit_fill_state(struct sna *sna,
+				 const struct sna_composite_op *op)
+{
+	gen2_get_batch(sna, op);
+	gen2_emit_target(sna, op);
+
+	OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
+		  I1_LOAD_S(2) |
+		  I1_LOAD_S(3) |
+		  I1_LOAD_S(8) |
+		  2);
+	OUT_BATCH(0);
+	OUT_BATCH(S3_CULLMODE_NONE | S3_VERTEXHAS_XY);
+	OUT_BATCH(S8_ENABLE_COLOR_BUFFER_WRITE);
+
+	gen2_enable_logic_op(sna, op->op);
+	gen2_emit_fill_pipeline(sna, op);
+
+	OUT_BATCH(_3DSTATE_DFLT_DIFFUSE_CMD);
+	OUT_BATCH(op->u.gen2.pixel);
+}
+
+static void
+gen2_render_fill_blt(struct sna *sna,
+		     const struct sna_fill_op *op,
+		     int16_t x, int16_t y, int16_t w, int16_t h)
+{
+	if (!gen2_get_rectangles(sna, &op->base, 1)) {
+		gen2_emit_fill_state(sna, &op->base);
+		gen2_get_rectangles(sna, &op->base, 1);
+	}
+
+	OUT_VERTEX(x+w);
+	OUT_VERTEX(y+h);
+	OUT_VERTEX(x);
+	OUT_VERTEX(y+h);
+	OUT_VERTEX(x);
+	OUT_VERTEX(y);
+}
+
+static void
+gen2_render_fill_done(struct sna *sna, const struct sna_fill_op *op)
+{
+	gen2_vertex_flush(sna);
+	_kgem_set_mode(&sna->kgem, KGEM_RENDER);
+}
+
+static Bool
+gen2_render_fill(struct sna *sna, uint8_t alu,
+		 PixmapPtr dst, struct kgem_bo *dst_bo,
+		 uint32_t color,
+		 struct sna_fill_op *tmp)
+{
+#if NO_FILL
+	return sna_blt_fill(sna, alu,
+			    dst_bo, dst->drawable.bitsPerPixel,
+			    color,
+			    tmp);
+#endif
+
+	/* Prefer to use the BLT if already engaged */
+	if (!PREFER_FILL && sna->kgem.mode == KGEM_BLT &&
+	    sna_blt_fill(sna, alu,
+			 dst_bo, dst->drawable.bitsPerPixel,
+			 color,
+			 tmp))
+		return TRUE;
+
+	/* Must use the BLT if we can't RENDER... */
+	if (dst->drawable.width > 2048 ||
+	    dst->drawable.height > 2048 ||
+	    dst_bo->pitch > 8192)
+		return sna_blt_fill(sna, alu,
+				    dst_bo, dst->drawable.bitsPerPixel,
+				    color,
+				    tmp);
+
+	tmp->base.op = alu;
+	tmp->base.dst.pixmap = dst;
+	tmp->base.dst.width = dst->drawable.width;
+	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.floats_per_vertex = 2;
+
+	tmp->base.u.gen2.pixel =
+		sna_rgba_for_color(color, dst->drawable.depth);
+
+	if (!kgem_check_bo(&sna->kgem, dst_bo))
+		kgem_submit(&sna->kgem);
+
+	tmp->blt  = gen2_render_fill_blt;
+	tmp->done = gen2_render_fill_done;
+
+	gen2_emit_fill_state(sna, &tmp->base);
+	return TRUE;
+}
+
+static void
+gen2_render_copy_setup_source(struct sna *sna,
+			      struct sna_composite_channel *channel,
+			      PixmapPtr pixmap,
+			      struct kgem_bo *bo)
+{
+	channel->filter = PictFilterNearest;
+	channel->repeat = RepeatNone;
+	channel->width  = pixmap->drawable.width;
+	channel->height = pixmap->drawable.height;
+	channel->scale[0] = 1./pixmap->drawable.width;
+	channel->scale[1] = 1./pixmap->drawable.height;
+	channel->offset[0] = 0;
+	channel->offset[1] = 0;
+	channel->pict_format = sna_format_for_depth(pixmap->drawable.depth);
+	channel->bo = bo;
+	channel->is_affine = 1;
+}
+
+static void
+gen2_emit_copy_pipeline(struct sna *sna, const struct sna_composite_op *op)
+{
+	uint32_t blend;
+
+	OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 |
+		  LOAD_TEXTURE_BLEND_STAGE(0) | 1);
+
+	blend = TB0C_LAST_STAGE | TB0C_RESULT_SCALE_1X | TB0C_OP_ARG1 |
+		TB0C_OUTPUT_WRITE_CURRENT;
+	if (op->dst.format == PICT_a8)
+		blend |= TB0C_ARG1_REPLICATE_ALPHA;
+	else if (PICT_FORMAT_RGB(op->src.pict_format) != 0)
+		blend |= TB0C_ARG1_SEL_TEXEL0;
+	else
+		blend |= TB0C_ARG1_SEL_ONE | TB0C_ARG1_INVERT;	/* 0.0 */
+	OUT_BATCH(blend);
+
+	blend = TB0A_RESULT_SCALE_1X | TB0A_OP_ARG1 |
+		TB0A_OUTPUT_WRITE_CURRENT;
+	if (PICT_FORMAT_A(op->src.pict_format) == 0)
+		blend |= TB0A_ARG1_SEL_ONE;
+	else
+		blend |= TB0A_ARG1_SEL_TEXEL0;
+	OUT_BATCH(blend);
+}
+
+static void gen2_emit_copy_state(struct sna *sna, const struct sna_composite_op *op)
+{
+	gen2_get_batch(sna, op);
+	gen2_emit_target(sna, op);
+
+	OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
+		  I1_LOAD_S(2) |
+		  I1_LOAD_S(3) |
+		  I1_LOAD_S(8) |
+		  2);
+	OUT_BATCH(1<<12);
+	OUT_BATCH(S3_CULLMODE_NONE | S3_VERTEXHAS_XY);
+	OUT_BATCH(S8_ENABLE_COLOR_BUFFER_WRITE);
+
+	gen2_enable_logic_op(sna, op->op);
+	gen2_emit_copy_pipeline(sna, op);
+
+	OUT_BATCH(_3DSTATE_VERTEX_FORMAT_2_CMD | TEXCOORDFMT_2D);
+	gen2_emit_texture(sna, &op->src, 0);
+}
+
+static Bool
+gen2_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)
+{
+	struct sna_composite_op tmp;
+
+#if NO_COPY_BOXES
+	if (!sna_blt_compare_depth(&src->drawable, &dst->drawable))
+		return FALSE;
+
+	return sna_blt_copy_boxes(sna, alu,
+				  src_bo, src_dx, src_dy,
+				  dst_bo, dst_dx, dst_dy,
+				  dst->drawable.bitsPerPixel,
+				  box, n);
+#endif
+
+	DBG(("%s (%d, %d)->(%d, %d) x %d\n",
+	     __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy, n));
+
+	if (!PREFER_COPY_BOXES &&
+	    sna_blt_compare_depth(&src->drawable, &dst->drawable) &&
+	    sna_blt_copy_boxes(sna, alu,
+			       src_bo, src_dx, src_dy,
+			       dst_bo, dst_dx, dst_dy,
+			       dst->drawable.bitsPerPixel,
+			       box, n))
+		return TRUE;
+
+	if (src_bo == dst_bo || /* XXX handle overlap using 3D ? */
+	    src_bo->pitch > 8192 ||
+	    src->drawable.width > 2048 ||
+	    src->drawable.height > 2048 ||
+	    dst_bo->pitch > 8192 ||
+	    dst->drawable.width > 2048 ||
+	    dst->drawable.height > 2048) {
+		if (!sna_blt_compare_depth(&src->drawable, &dst->drawable))
+			return FALSE;
+
+		return sna_blt_copy_boxes(sna, alu,
+					  src_bo, src_dx, src_dy,
+					  dst_bo, dst_dx, dst_dy,
+					  dst->drawable.bitsPerPixel,
+					  box, n);
+	}
+
+	if (!kgem_check_bo(&sna->kgem, dst_bo))
+		kgem_submit(&sna->kgem);
+	if (!kgem_check_bo(&sna->kgem, src_bo))
+		kgem_submit(&sna->kgem);
+
+	if (kgem_bo_is_dirty(src_bo))
+		kgem_emit_flush(&sna->kgem);
+
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.op = alu;
+
+	tmp.dst.pixmap = dst;
+	tmp.dst.width = dst->drawable.width;
+	tmp.dst.height = dst->drawable.height;
+	tmp.dst.format = sna_format_for_depth(dst->drawable.depth);
+	tmp.dst.bo = dst_bo;
+
+	tmp.floats_per_vertex = 4;
+
+	gen2_render_copy_setup_source(sna, &tmp.src, src, src_bo);
+	gen2_emit_copy_state(sna, &tmp);
+	do {
+		int n_this_time;
+
+		n_this_time = gen2_get_rectangles(sna, &tmp, n);
+		if (n_this_time == 0) {
+			gen2_emit_copy_state(sna, &tmp);
+			n_this_time = gen2_get_rectangles(sna, &tmp, n);
+		}
+		n -= n_this_time;
+
+		do {
+			DBG(("	(%d, %d) -> (%d, %d) + (%d, %d)\n",
+			     box->x1 + src_dx, box->y1 + src_dy,
+			     box->x1 + dst_dx, box->y1 + dst_dy,
+			     box->x2 - box->x1, box->y2 - box->y1));
+			OUT_VERTEX(box->x2 + dst_dx);
+			OUT_VERTEX(box->y2 + dst_dy);
+			OUT_VERTEX((box->x2 + src_dx) * tmp.src.scale[0]);
+			OUT_VERTEX((box->y2 + src_dy) * tmp.src.scale[1]);
+
+			OUT_VERTEX(box->x1 + dst_dx);
+			OUT_VERTEX(box->y2 + dst_dy);
+			OUT_VERTEX((box->x1 + src_dx) * tmp.src.scale[0]);
+			OUT_VERTEX((box->y2 + src_dy) * tmp.src.scale[1]);
+
+			OUT_VERTEX(box->x1 + dst_dx);
+			OUT_VERTEX(box->y1 + dst_dy);
+			OUT_VERTEX((box->x1 + src_dx) * tmp.src.scale[0]);
+			OUT_VERTEX((box->y1 + src_dy) * tmp.src.scale[1]);
+
+			box++;
+		} while (--n_this_time);
+	} while (n);
+
+	gen2_vertex_flush(sna);
+	_kgem_set_mode(&sna->kgem, KGEM_RENDER);
+	return TRUE;
+}
+
+static void
+gen2_render_copy_blt(struct sna *sna,
+		     const struct sna_copy_op *op,
+		     int16_t sx, int16_t sy,
+		     int16_t w, int16_t h,
+		     int16_t dx, int16_t dy)
+{
+	if (!gen2_get_rectangles(sna, &op->base, 1)) {
+		gen2_emit_copy_state(sna, &op->base);
+		gen2_get_rectangles(sna, &op->base, 1);
+	}
+
+	OUT_VERTEX(dx+w);
+	OUT_VERTEX(dy+h);
+	OUT_VERTEX((sx+w)*op->base.src.scale[0]);
+	OUT_VERTEX((sy+h)*op->base.src.scale[1]);
+
+	OUT_VERTEX(dx);
+	OUT_VERTEX(dy+h);
+	OUT_VERTEX(sx*op->base.src.scale[0]);
+	OUT_VERTEX((sy+h)*op->base.src.scale[1]);
+
+	OUT_VERTEX(dx);
+	OUT_VERTEX(dy);
+	OUT_VERTEX(sx*op->base.src.scale[0]);
+	OUT_VERTEX(sy*op->base.src.scale[1]);
+}
+
+static void
+gen2_render_copy_done(struct sna *sna, const struct sna_copy_op *op)
+{
+	gen2_vertex_flush(sna);
+	_kgem_set_mode(&sna->kgem, KGEM_RENDER);
+}
+
+static Bool
+gen2_render_copy(struct sna *sna, uint8_t alu,
+		 PixmapPtr src, struct kgem_bo *src_bo,
+		 PixmapPtr dst, struct kgem_bo *dst_bo,
+		 struct sna_copy_op *tmp)
+{
+#if NO_COPY
+	if (!sna_blt_compare_depth(&src->drawable, &dst->drawable))
+		return FALSE;
+
+	return sna_blt_copy(sna, alu,
+			    src_bo, dst_bo,
+			    dst->drawable.bitsPerPixel,
+			    tmp);
+#endif
+
+	/* Prefer to use the BLT */
+	if (!PREFER_COPY && sna->kgem.mode == KGEM_BLT &&
+	    sna_blt_compare_depth(&src->drawable, &dst->drawable) &&
+	    sna_blt_copy(sna, alu,
+			 src_bo, dst_bo,
+			 dst->drawable.bitsPerPixel,
+			 tmp))
+		return TRUE;
+
+	/* Must use the BLT if we can't RENDER... */
+	if (src->drawable.width > 2048 || src->drawable.height > 2048 ||
+	    dst->drawable.width > 2048 || dst->drawable.height > 2048 ||
+	    src_bo->pitch > 8192 || dst_bo->pitch > 8192) {
+		if (!sna_blt_compare_depth(&src->drawable, &dst->drawable))
+			return FALSE;
+
+		return sna_blt_copy(sna, alu, src_bo, dst_bo,
+				    dst->drawable.bitsPerPixel,
+				    tmp);
+	}
+
+	tmp->base.op = alu;
+
+	tmp->base.dst.pixmap = dst;
+	tmp->base.dst.width = dst->drawable.width;
+	tmp->base.dst.height = dst->drawable.height;
+	tmp->base.dst.format = sna_format_for_depth(dst->drawable.depth);
+	tmp->base.dst.bo = dst_bo;
+
+	gen2_render_copy_setup_source(sna, &tmp->base.src, src, src_bo);
+
+	tmp->base.floats_per_vertex = 4;
+
+	if (!kgem_check_bo(&sna->kgem, dst_bo))
+		kgem_submit(&sna->kgem);
+	if (!kgem_check_bo(&sna->kgem, src_bo))
+		kgem_submit(&sna->kgem);
+
+	if (kgem_bo_is_dirty(src_bo))
+		kgem_emit_flush(&sna->kgem);
+
+	tmp->blt  = gen2_render_copy_blt;
+	tmp->done = gen2_render_copy_done;
+
+	gen2_emit_composite_state(sna, &tmp->base);
+	return TRUE;
+}
+
 static void
 gen2_render_reset(struct sna *sna)
 {
 	sna->render_state.gen2.need_invariant = TRUE;
+	sna->render_state.gen2.logic_op_enabled = FALSE;
 	sna->render_state.gen2.vertex_offset = 0;
 	sna->render_state.gen2.target = 0;
 }
@@ -1674,7 +2071,11 @@ Bool gen2_render_init(struct sna *sna)
 	render->composite_spans = gen2_render_composite_spans;
 	render->fill_boxes = gen2_render_fill_boxes;
 
-	/* XXX Y-tiling copies */
+	render->fill = gen2_render_fill;
+	render->copy = gen2_render_copy;
+	render->copy_boxes = gen2_render_copy_boxes;
+
+	/* XXX YUV color space conversion for video? */
 
 	render->reset = gen2_render_reset;
 	render->flush = gen2_render_flush;
diff --git a/src/sna/gen2_render.h b/src/sna/gen2_render.h
index a1767ad..c10d540 100644
--- a/src/sna/gen2_render.h
+++ b/src/sna/gen2_render.h
@@ -585,6 +585,7 @@
 #define S3_ENABLE_LOCAL_DEPTH_BIAS	     (1<<3)
 #define S3_ENABLE_SPRITE_POINT		     (1<<1)
 #define S3_ENABLE_ANTIALIASING		     1
+#define S7_ENABLE_LOGIC_OP		     (1<<0)
 #define S8_ENABLE_ALPHA_TEST		     (1<<31)
 #define S8_ALPHA_TEST_FUNC_SHIFT	     28
 #define S8_ALPHA_REFVALUE_SHIFT		     20
diff --git a/src/sna/gen3_render.c b/src/sna/gen3_render.c
index 92edc72..aba1b8d 100644
--- a/src/sna/gen3_render.c
+++ b/src/sna/gen3_render.c
@@ -3448,6 +3448,9 @@ gen3_render_copy(struct sna *sna, uint8_t alu,
 	if (!kgem_check_bo(&sna->kgem, src_bo))
 		kgem_submit(&sna->kgem);
 
+	if (kgem_bo_is_dirty(src_bo))
+		kgem_emit_flush(&sna->kgem);
+
 	tmp->blt  = gen3_render_copy_blt;
 	tmp->done = gen3_render_copy_done;
 
diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h
index 5b51be9..012b090 100644
--- a/src/sna/sna_render.h
+++ b/src/sna/sna_render.h
@@ -90,7 +90,7 @@ struct sna_composite_op {
 		} blt;
 
 		struct {
-			int nothing;
+			uint32_t pixel;
 		} gen2;
 
 		struct {
@@ -238,6 +238,7 @@ struct sna_render {
 struct gen2_render_state {
 	uint32_t target;
 	Bool need_invariant;
+	Bool logic_op_enabled;
 	uint16_t vertex_offset;
 };
 
commit ecbf6bbd27b1205dcf76cfe34ae2a7a3f5ec195a
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Jul 1 08:50:58 2011 +0100

    sna/gen2: Implement composite-spans
    
    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 06cab3c..82c7e15 100644
--- a/src/sna/gen2_render.c
+++ b/src/sna/gen2_render.c
@@ -330,12 +330,9 @@ gen2_get_blend_factors(const struct sna_composite_op *op,
 	 * pictures, but we need to implement it for 830/845 and there's no
 	 * harm done in leaving it in.
 	 */
-	cblend =
-		TB0C_LAST_STAGE | TB0C_RESULT_SCALE_1X | TB0C_OP_MODULE |
-		TB0C_OUTPUT_WRITE_CURRENT;
-	ablend =
-		TB0A_RESULT_SCALE_1X | TB0A_OP_MODULE |
-		TB0A_OUTPUT_WRITE_CURRENT;
+	cblend = TB0C_LAST_STAGE | TB0C_RESULT_SCALE_1X | TB0C_OUTPUT_WRITE_CURRENT;
+	ablend = TB0A_RESULT_SCALE_1X | TB0A_OUTPUT_WRITE_CURRENT;
+
 
 	/* Get the source picture's channels into TBx_ARG1 */
 	if ((op->has_component_alpha && gen2_blend_op[op->op].src_alpha) ||
@@ -359,13 +356,18 @@ gen2_get_blend_factors(const struct sna_composite_op *op,
 	}
 
 	if (op->mask.bo) {
+		cblend |= TB0C_OP_MODULATE;
 		cblend |= TB0C_ARG2_SEL_TEXEL1;
-		if (op->dst.format == PICT_a8 || !op->has_component_alpha)
+		if (op->dst.format == PICT_a8 ||
+		    !op->has_component_alpha ||
+		    PICT_FORMAT_RGB(op->mask.pict_format) == 0)
 			cblend |= TB0C_ARG2_REPLICATE_ALPHA;
+
 		ablend |= TB0A_ARG2_SEL_TEXEL1;
+		ablend |= TB0A_OP_MODULATE;
 	} else {
-		cblend |= TB0C_ARG2_SEL_ONE;
-		ablend |= TB0A_ARG2_SEL_ONE;
+		cblend |= TB0C_OP_ARG1;
+		ablend |= TB0A_OP_ARG1;
 	}
 
 	*c_out = cblend;
@@ -413,21 +415,6 @@ static void gen2_emit_invariant(struct sna *sna)
 	OUT_BATCH(_3DSTATE_MAP_CUBE | MAP_UNIT(2));
 	OUT_BATCH(_3DSTATE_MAP_CUBE | MAP_UNIT(3));
 
-	OUT_BATCH(_3DSTATE_DFLT_DIFFUSE_CMD);
-	OUT_BATCH(0);
-
-	OUT_BATCH(_3DSTATE_DFLT_SPEC_CMD);
-	OUT_BATCH(0);
-
-	OUT_BATCH(_3DSTATE_DFLT_Z_CMD);
-	OUT_BATCH(0);
-
-	OUT_BATCH(_3DSTATE_FOG_MODE_CMD);
-	OUT_BATCH(FOGFUNC_ENABLE |
-		  FOG_LINEAR_CONST | FOGSRC_INDEX_Z | ENABLE_FOG_DENSITY);
-	OUT_BATCH(0);
-	OUT_BATCH(0);
-
 	OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD |
 		  MAP_UNIT(0) |
 		  DISABLE_TEX_STREAM_BUMP |
@@ -473,12 +460,10 @@ static void gen2_emit_invariant(struct sna *sna)
 		  ENABLE_TRI_FAN_PROVOKE_VRTX |
 		  ENABLE_TRI_STRIP_PROVOKE_VRTX |
 		  LINE_STRIP_PROVOKE_VRTX(1) |
-		  TRI_FAN_PROVOKE_VRTX(2) | TRI_STRIP_PROVOKE_VRTX(2));
+		  TRI_FAN_PROVOKE_VRTX(2) |
+		  TRI_STRIP_PROVOKE_VRTX(2));
 
 	OUT_BATCH(_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT);
-	OUT_BATCH(_3DSTATE_SCISSOR_RECT_0_CMD);
-	OUT_BATCH(0);
-	OUT_BATCH(0);
 
 	OUT_BATCH(_3DSTATE_VERTEX_TRANSFORM);
 	OUT_BATCH(DISABLE_VIEWPORT_TRANSFORM | DISABLE_PERSPECTIVE_DIVIDE);
@@ -487,9 +472,6 @@ static void gen2_emit_invariant(struct sna *sna)
 	OUT_BATCH(MAGIC_W_STATE_DWORD1);
 	OUT_BATCH_F(1.0);
 
-	OUT_BATCH(_3DSTATE_COLOR_FACTOR_CMD);
-	OUT_BATCH(0x80808080);	/* .5 required in alpha for GL_DOT3_RGBA_EXT */
-
 	OUT_BATCH(_3DSTATE_MAP_COORD_SETBIND_CMD);
 	OUT_BATCH(TEXBIND_SET3(TEXCOORDSRC_VTXSET_3) |
 		  TEXBIND_SET2(TEXCOORDSRC_VTXSET_2) |
@@ -500,51 +482,22 @@ static void gen2_emit_invariant(struct sna *sna)
 		  DISABLE_INDPT_ALPHA_BLEND |
 		  ENABLE_ALPHA_BLENDFUNC | ABLENDFUNC_ADD);
 
-	OUT_BATCH(_3DSTATE_FOG_COLOR_CMD |
-		  FOG_COLOR_RED(0) | FOG_COLOR_GREEN(0) | FOG_COLOR_BLUE(0));
-
 	OUT_BATCH(_3DSTATE_CONST_BLEND_COLOR_CMD);
 	OUT_BATCH(0);
 
 	OUT_BATCH(_3DSTATE_MODES_1_CMD |
 		  ENABLE_COLR_BLND_FUNC |
 		  BLENDFUNC_ADD |
-		  ENABLE_SRC_BLND_FACTOR |
-		  SRC_BLND_FACT(BLENDFACTOR_ONE) |
+		  ENABLE_SRC_BLND_FACTOR | SRC_BLND_FACT(BLENDFACTOR_ONE) |
 		  ENABLE_DST_BLND_FACTOR | DST_BLND_FACT(BLENDFACTOR_ZERO));
-	OUT_BATCH(_3DSTATE_MODES_2_CMD |
-		  ENABLE_GLOBAL_DEPTH_BIAS |
-		  GLOBAL_DEPTH_BIAS(0) |
-		  ENABLE_ALPHA_TEST_FUNC |
-		  ALPHA_TEST_FUNC(0) |	/* always */
-		  ALPHA_REF_VALUE(0));
+	OUT_BATCH(_3DSTATE_MODES_2_CMD);
 	OUT_BATCH(_3DSTATE_MODES_3_CMD |
-		  ENABLE_DEPTH_TEST_FUNC |
-		  DEPTH_TEST_FUNC(0x2) |	/* COMPAREFUNC_LESS */
 		  ENABLE_ALPHA_SHADE_MODE | ALPHA_SHADE_MODE(SHADE_MODE_LINEAR) |
 		  ENABLE_FOG_SHADE_MODE | FOG_SHADE_MODE(SHADE_MODE_LINEAR) |
 		  ENABLE_SPEC_SHADE_MODE | SPEC_SHADE_MODE(SHADE_MODE_LINEAR) |
 		  ENABLE_COLOR_SHADE_MODE | COLOR_SHADE_MODE(SHADE_MODE_LINEAR) |
 		  ENABLE_CULL_MODE | CULLMODE_NONE);
 
-	OUT_BATCH(_3DSTATE_MODES_4_CMD |
-		  ENABLE_LOGIC_OP_FUNC | LOGIC_OP_FUNC(LOGICOP_COPY) |
-		  ENABLE_STENCIL_TEST_MASK | STENCIL_TEST_MASK(0xff) |
-		  ENABLE_STENCIL_WRITE_MASK | STENCIL_WRITE_MASK(0xff));
-
-	OUT_BATCH(_3DSTATE_STENCIL_TEST_CMD |
-		  ENABLE_STENCIL_PARMS |
-		  STENCIL_FAIL_OP(0) |	/* STENCILOP_KEEP */
-		  STENCIL_PASS_DEPTH_FAIL_OP(0) |	/* STENCILOP_KEEP */
-		  STENCIL_PASS_DEPTH_PASS_OP(0) |	/* STENCILOP_KEEP */
-		  ENABLE_STENCIL_TEST_FUNC | STENCIL_TEST_FUNC(0) |	/* COMPAREFUNC_ALWAYS */
-		  ENABLE_STENCIL_REF_VALUE | STENCIL_REF_VALUE(0));
-
-	OUT_BATCH(_3DSTATE_MODES_5_CMD |
-		  ENABLE_SPRITE_POINT_TEX | SPRITE_POINT_TEX_OFF |
-		  ENABLE_FIXED_LINE_WIDTH | FIXED_LINE_WIDTH(0x2) | /* 1.0 */
-		  ENABLE_FIXED_POINT_WIDTH | FIXED_POINT_WIDTH(1));
-
 	OUT_BATCH(_3DSTATE_ENABLES_1_CMD |
 		  DISABLE_LOGIC_OP |
 		  DISABLE_STENCIL_TEST |
@@ -567,22 +520,30 @@ static void gen2_emit_invariant(struct sna *sna)
 	/* Set default blend state */
 	OUT_BATCH(_3DSTATE_MAP_BLEND_OP_CMD(0) |
 		  TEXPIPE_COLOR |
-		  ENABLE_TEXOUTPUT_WRT_SEL | TEXOP_OUTPUT_CURRENT |
+		  ENABLE_TEXOUTPUT_WRT_SEL |
+		  TEXOP_OUTPUT_CURRENT |
 		  DISABLE_TEX_CNTRL_STAGE |
-		  TEXOP_SCALE_1X | TEXOP_MODIFY_PARMS |
-		  TEXOP_LAST_STAGE | TEXBLENDOP_ARG1);
+		  TEXOP_SCALE_1X |
+		  TEXOP_MODIFY_PARMS |
+		  TEXOP_LAST_STAGE |
+		  TEXBLENDOP_ARG1);
 	OUT_BATCH(_3DSTATE_MAP_BLEND_OP_CMD(0) |
 		  TEXPIPE_ALPHA |
-		  ENABLE_TEXOUTPUT_WRT_SEL | TEXOP_OUTPUT_CURRENT |
-		  TEXOP_SCALE_1X | TEXOP_MODIFY_PARMS | TEXBLENDOP_ARG1);
+		  ENABLE_TEXOUTPUT_WRT_SEL |
+		  TEXOP_OUTPUT_CURRENT |
+		  TEXOP_SCALE_1X |
+		  TEXOP_MODIFY_PARMS |
+		  TEXBLENDOP_ARG1);
 	OUT_BATCH(_3DSTATE_MAP_BLEND_ARG_CMD(0) |
 		  TEXPIPE_COLOR |
 		  TEXBLEND_ARG1 |
-		  TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_DIFFUSE);
+		  TEXBLENDARG_MODIFY_PARMS |
+		  TEXBLENDARG_DIFFUSE);
 	OUT_BATCH(_3DSTATE_MAP_BLEND_ARG_CMD(0) |
 		  TEXPIPE_ALPHA |
 		  TEXBLEND_ARG1 |
-		  TEXBLENDARG_MODIFY_PARMS | TEXBLENDARG_DIFFUSE);
+		  TEXBLENDARG_MODIFY_PARMS |
+		  TEXBLENDARG_DIFFUSE);
 
 	OUT_BATCH(_3DSTATE_AA_CMD |
 		  AA_LINE_ECAAR_WIDTH_ENABLE |
@@ -626,13 +587,12 @@ gen2_get_batch(struct sna *sna,
 		gen2_emit_invariant(sna);
 }
 
-static void gen2_emit_composite_state(struct sna *sna,
-				      const struct sna_composite_op *op)
+static void gen2_emit_target(struct sna *sna, const struct sna_composite_op *op)
 {
-	uint32_t texcoordfmt;
-	uint32_t cblend, ablend;
-
-	gen2_get_batch(sna, op);
+	if (sna->render_state.gen2.target == op->dst.bo->unique_id) {
+		kgem_bo_mark_dirty(op->dst.bo);
+		return;
+	}
 
 	OUT_BATCH(_3DSTATE_BUF_INFO_CMD);
 	OUT_BATCH(BUF_3D_ID_COLOR_BACK |
@@ -654,6 +614,18 @@ static void gen2_emit_composite_state(struct sna *sna,
 		  DRAW_XMAX(op->dst.width - 1));
 	OUT_BATCH(0);	/* yorig, xorig */
 
+	sna->render_state.gen2.target = op->dst.bo->unique_id;
+}
+
+static void gen2_emit_composite_state(struct sna *sna,
+				      const struct sna_composite_op *op)
+{
+	uint32_t texcoordfmt;
+	uint32_t cblend, ablend;
+
+	gen2_get_batch(sna, op);
+	gen2_emit_target(sna, op);
+
 	OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
 		  I1_LOAD_S(2) | I1_LOAD_S(3) | I1_LOAD_S(8) | 2);
 	OUT_BATCH((1 + (op->mask.bo != NULL)) << 12);
@@ -1042,7 +1014,7 @@ gen2_composite_picture(struct sna *sna,
 						  x, y, w, h, dst_x, dst_y);
 
 	channel->pict_format = picture->format;
-	if (pixmap->drawable.width > 8192 || pixmap->drawable.height > 8192)
+	if (pixmap->drawable.width > 2048 || pixmap->drawable.height > 2048)
 		return sna_render_picture_extract(sna, picture, channel,
 						  x, y, w, h, dst_x, dst_y);
 
@@ -1228,8 +1200,16 @@ gen2_render_composite(struct sna *sna,
 	if (!kgem_check_bo(&sna->kgem, tmp->mask.bo))
 		kgem_submit(&sna->kgem);
 
-	if (kgem_bo_is_dirty(tmp->src.bo) || kgem_bo_is_dirty(tmp->mask.bo))
-		kgem_emit_flush(&sna->kgem);
+	if (kgem_bo_is_dirty(tmp->src.bo) || kgem_bo_is_dirty(tmp->mask.bo)) {
+		if (tmp->src.bo == tmp->dst.bo || tmp->mask.bo == tmp->dst.bo) {
+			kgem_emit_flush(&sna->kgem);
+		} else {
+			OUT_BATCH(_3DSTATE_MODES_5_CMD |
+				  PIPELINE_FLUSH_RENDER_CACHE |
+				  PIPELINE_FLUSH_TEXTURE_CACHE);
+			kgem_clear_dirty(&sna->kgem);
+		}
+	}
 
 	gen2_emit_composite_state(sna, tmp);
 
@@ -1246,21 +1226,441 @@ cleanup_dst:
 }
 
 static void
-gen2_render_reset(struct sna *sna)
+gen2_emit_composite_spans_vertex(struct sna *sna,
+				 const struct sna_composite_spans_op *op,
+				 int16_t x, int16_t y,
+				 float opacity)
 {
-	sna->render_state.gen2.need_invariant = TRUE;
-	sna->render_state.gen2.vertex_offset = 0;
+	gen2_emit_composite_dstcoord(sna, x + op->base.dst.x, y + op->base.dst.y);
+	OUT_BATCH((uint8_t)(opacity * 255) << 24);
+	gen2_emit_composite_texcoord(sna, &op->base.src, x, y);
 }
 
 static void
-gen2_render_flush(struct sna *sna)
+gen2_emit_composite_spans_primitive(struct sna *sna,
+				    const struct sna_composite_spans_op *op,
+				    const BoxRec *box,
+				    float opacity)
+{
+	gen2_emit_composite_spans_vertex(sna, op, box->x2, box->y2, opacity);
+	gen2_emit_composite_spans_vertex(sna, op, box->x1, box->y2, opacity);
+	gen2_emit_composite_spans_vertex(sna, op, box->x1, box->y1, opacity);
+}
+
+#if 0
+static void gen2_emit_fill_blend_op(struct sna *sna)
+{
+	/* Set default blend state */
+	OUT_BATCH(_3DSTATE_MAP_BLEND_OP_CMD(0) |
+		  TEXPIPE_COLOR |
+		  ENABLE_TEXOUTPUT_WRT_SEL |
+		  TEXOP_OUTPUT_CURRENT |
+		  DISABLE_TEX_CNTRL_STAGE |
+		  TEXOP_SCALE_1X |
+		  TEXOP_MODIFY_PARMS |
+		  TEXOP_LAST_STAGE |
+		  TEXBLENDOP_ARG1);
+	OUT_BATCH(_3DSTATE_MAP_BLEND_OP_CMD(0) |
+		  TEXPIPE_ALPHA |
+		  ENABLE_TEXOUTPUT_WRT_SEL |
+		  TEXOP_OUTPUT_CURRENT |
+		  TEXOP_SCALE_1X |
+		  TEXOP_MODIFY_PARMS |
+		  TEXBLENDOP_ARG1);
+	OUT_BATCH(_3DSTATE_MAP_BLEND_ARG_CMD(0) |
+		  TEXPIPE_COLOR |
+		  TEXBLEND_ARG1 |
+		  TEXBLENDARG_MODIFY_PARMS |
+		  TEXBLENDARG_DIFFUSE);
+	OUT_BATCH(_3DSTATE_MAP_BLEND_ARG_CMD(0) |
+		  TEXPIPE_ALPHA |
+		  TEXBLEND_ARG1 |
+		  TEXBLENDARG_MODIFY_PARMS |
+		  TEXBLENDARG_DIFFUSE);
+}
+#endif
+
+static void
+gen2_emit_spans_blend_op(struct sna *sna,
+			 const struct sna_composite_spans_op *op)
+{
+	uint32_t cblend, ablend;
+
+	cblend =
+		TB0C_LAST_STAGE | TB0C_RESULT_SCALE_1X | TB0C_OP_MODULATE |
+	       	TB0C_ARG1_SEL_DIFFUSE | TB0C_ARG1_REPLICATE_ALPHA |
+		TB0C_OUTPUT_WRITE_CURRENT;
+	ablend =
+		TB0A_RESULT_SCALE_1X | TB0A_OP_MODULATE |
+		TB0A_ARG1_SEL_DIFFUSE |
+		TB0A_OUTPUT_WRITE_CURRENT;
+
+	if (op->base.dst.format == PICT_a8) {
+		ablend |= TB0A_ARG2_SEL_TEXEL0;
+		cblend |= TB0C_ARG2_SEL_TEXEL0 | TB0C_ARG2_REPLICATE_ALPHA;;
+	} else {
+		if (PICT_FORMAT_RGB(op->base.src.pict_format) != 0)
+			cblend |= TB0C_ARG2_SEL_TEXEL0;
+		else
+			cblend |= TB0C_ARG2_SEL_ONE | TB0C_ARG2_INVERT;
+
+		if (op->base.src.is_opaque)
+			ablend |= TB0A_ARG2_SEL_ONE;
+		else
+			ablend |= TB0A_ARG2_SEL_TEXEL0;
+	}
+
+	OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 |
+		  LOAD_TEXTURE_BLEND_STAGE(0) | 1);
+	OUT_BATCH(cblend);
+	OUT_BATCH(ablend);
+}
+
+static void gen2_emit_composite_spans_state(struct sna *sna,
+					    const struct sna_composite_spans_op *op)
+{
+	gen2_get_batch(sna, &op->base);
+	gen2_emit_target(sna, &op->base);
+
+	OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
+		  I1_LOAD_S(2) | I1_LOAD_S(3) | I1_LOAD_S(8) | 2);
+	OUT_BATCH(1 << 12);
+	OUT_BATCH(S3_CULLMODE_NONE | S3_VERTEXHAS_XY | S3_DIFFUSE_PRESENT);
+	OUT_BATCH(S8_ENABLE_COLOR_BLEND | S8_BLENDFUNC_ADD |
+		  gen2_get_blend_cntl(op->base.op, FALSE, op->base.dst.format) |
+		  S8_ENABLE_COLOR_BUFFER_WRITE);
+
+	gen2_emit_spans_blend_op(sna, op);
+
+	OUT_BATCH(_3DSTATE_VERTEX_FORMAT_2_CMD |
+		  (op->base.src.is_affine ? TEXCOORDFMT_2D : TEXCOORDFMT_3D));
+
+	gen2_emit_texture(sna, &op->base.src, 0);
+}
+
+static void
+gen2_render_composite_spans_boxes(struct sna *sna,
+				  const struct sna_composite_spans_op *op,
+				  const BoxRec *box, int nbox,
+				  float opacity)
+{
+	DBG(("%s: nbox=%d, src=+(%d, %d), opacity=%f, dst=+(%d, %d)\n",
+	     __FUNCTION__, nbox,
+	     op->base.src.offset[0], op->base.src.offset[1],
+	     opacity,
+	     op->base.dst.x, op->base.dst.y));
+
+	do {
+		int nbox_this_time;
+
+		nbox_this_time = gen2_get_rectangles(sna, &op->base, nbox);
+		if (nbox_this_time == 0) {
+			gen2_emit_composite_spans_state(sna, op);
+			nbox_this_time = gen2_get_rectangles(sna, &op->base, nbox);
+		}
+		nbox -= nbox_this_time;
+
+		do {
+			DBG(("  %s: (%d, %d) x (%d, %d)\n", __FUNCTION__,
+			     box->x1, box->y1,
+			     box->x2 - box->x1,
+			     box->y2 - box->y1));
+
+			op->prim_emit(sna, op, box++, opacity);
+		} while (--nbox_this_time);
+	} while (nbox);
+}
+
+static void
+gen2_render_composite_spans_done(struct sna *sna,
+				 const struct sna_composite_spans_op *op)
 {
 	gen2_vertex_flush(sna);
+	_kgem_set_mode(&sna->kgem, KGEM_RENDER);
+
+	DBG(("%s()\n", __FUNCTION__));
+
+	sna_render_composite_redirect_done(sna, &op->base);
+	if (op->base.src.bo)
+		kgem_bo_destroy(&sna->kgem, op->base.src.bo);
+}
+
+static Bool
+gen2_render_composite_spans(struct sna *sna,
+			    uint8_t op,
+			    PicturePtr src,
+			    PicturePtr dst,
+			    int16_t src_x,  int16_t src_y,
+			    int16_t dst_x,  int16_t dst_y,
+			    int16_t width,  int16_t height,
+			    struct sna_composite_spans_op *tmp)
+{
+	DBG(("%s(src=(%d, %d), dst=(%d, %d), size=(%d, %d))\n", __FUNCTION__,
+	     src_x, src_y, dst_x, dst_y, width, height));
+
+#if NO_COMPOSITE_SPANS
+	return FALSE;
+#endif
+
+	if (op >= ARRAY_SIZE(gen2_blend_op)) {
+		DBG(("%s: fallback due to unhandled blend op: %d\n",
+		     __FUNCTION__, op));
+		return FALSE;
+	}
+
+	if (!gen2_check_dst_format(dst->format)) {
+		DBG(("%s: fallback due to unhandled dst format: %x\n",
+		     __FUNCTION__, dst->format));
+		return FALSE;
+	}
+
+	if (need_tiling(sna, width, height))
+		return FALSE;
+
+	if (!gen2_composite_set_target(sna, &tmp->base, dst)) {
+		DBG(("%s: unable to set render target\n",
+		     __FUNCTION__));
+		return FALSE;
+	}
+
+	tmp->base.op = op;
+	if (tmp->base.dst.width > 2048 ||
+	    tmp->base.dst.height > 2048 ||
+	    tmp->base.dst.bo->pitch > 8192) {
+		if (!sna_render_composite_redirect(sna, &tmp->base,
+						   dst_x, dst_y, width, height))
+			return FALSE;
+	}
+
+	switch (gen2_composite_picture(sna, src, &tmp->base.src,
+				       src_x, src_y,
+				       width, height,
+				       dst_x, dst_y)) {
+	case -1:
+		goto cleanup_dst;
+	case 0:
+		gen2_composite_solid_init(sna, &tmp->base.src, 0);
+	case 1:
+		break;
+	}
+
+	tmp->prim_emit = gen2_emit_composite_spans_primitive;
+	tmp->base.floats_per_vertex = 3;
+	if (tmp->base.src.bo)
+		tmp->base.floats_per_vertex += tmp->base.src.is_affine ? 2 : 3;
+
+	tmp->boxes = gen2_render_composite_spans_boxes;
+	tmp->done  = gen2_render_composite_spans_done;
+
+	if (!kgem_check_bo(&sna->kgem, tmp->base.dst.bo))
+		kgem_submit(&sna->kgem);
+	if (!kgem_check_bo(&sna->kgem, tmp->base.src.bo))
+		kgem_submit(&sna->kgem);
+
+	if (kgem_bo_is_dirty(tmp->base.src.bo)) {
+		if (tmp->base.src.bo == tmp->base.dst.bo) {
+			kgem_emit_flush(&sna->kgem);
+		} else {
+			OUT_BATCH(_3DSTATE_MODES_5_CMD |
+				  PIPELINE_FLUSH_RENDER_CACHE |
+				  PIPELINE_FLUSH_TEXTURE_CACHE);
+			kgem_clear_dirty(&sna->kgem);
+		}
+	}
+
+	gen2_emit_composite_spans_state(sna, tmp);
+	return TRUE;
+
+cleanup_dst:
+	if (tmp->base.redirect.real_bo)
+		kgem_bo_destroy(&sna->kgem, tmp->base.dst.bo);
+	return FALSE;
 }
 
 static void
-gen2_render_fini(struct sna *sna)
+gen2_emit_fill_blend_op(struct sna *sna, const struct sna_composite_op *op)
 {
+	uint32_t blend;
+
+	OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_2 |
+		  LOAD_TEXTURE_BLEND_STAGE(0) | 1);
+	blend = TB0C_LAST_STAGE | TB0C_RESULT_SCALE_1X | TB0C_OP_ARG1 |
+		TB0C_ARG1_SEL_DIFFUSE |
+		TB0C_OUTPUT_WRITE_CURRENT;
+
+	if (op->dst.format == PICT_a8)
+		blend |= TB0C_ARG1_REPLICATE_ALPHA;
+
+	OUT_BATCH(blend);
+	OUT_BATCH(TB0A_RESULT_SCALE_1X | TB0A_OP_ARG1 |
+		  TB0A_ARG1_SEL_DIFFUSE |
+		  TB0A_OUTPUT_WRITE_CURRENT);
+}
+
+static void gen2_emit_fill_composite_state(struct sna *sna,
+					   const struct sna_composite_op *op,
+					   uint32_t pixel)
+{
+	gen2_get_batch(sna, op);
+	gen2_emit_target(sna, op);
+
+	OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 |
+		  I1_LOAD_S(2) | I1_LOAD_S(3) | I1_LOAD_S(8) | 2);
+	OUT_BATCH(0);
+	OUT_BATCH(S3_CULLMODE_NONE | S3_VERTEXHAS_XY);
+	OUT_BATCH(S8_ENABLE_COLOR_BLEND | S8_BLENDFUNC_ADD |
+		  gen2_get_blend_cntl(op->op, FALSE, op->dst.format) |
+		  S8_ENABLE_COLOR_BUFFER_WRITE);
+
+	gen2_emit_fill_blend_op(sna, op);
+
+	OUT_BATCH(_3DSTATE_DFLT_DIFFUSE_CMD);
+	OUT_BATCH(pixel);
+}
+
+static Bool
+gen2_render_fill_boxes_try_blt(struct sna *sna,
+			       CARD8 op, PictFormat format,
+			       const xRenderColor *color,
+			       PixmapPtr dst, struct kgem_bo *dst_bo,
+			       const BoxRec *box, int n)
+{
+	uint8_t alu = GXcopy;
+	uint32_t pixel;
+
+	if (!sna_get_pixel_from_rgba(&pixel,
+				     color->red,
+				     color->green,
+				     color->blue,
+				     color->alpha,
+				     format))
+		return FALSE;
+
+	if (op == PictOpClear) {
+		alu = GXclear;
+		pixel = 0;
+		op = PictOpSrc;
+	}
+
+	if (op == PictOpOver) {
+		if ((pixel & 0xff000000) == 0xff000000)
+			op = PictOpSrc;
+	}
+
+	if (op != PictOpSrc)
+		return FALSE;
+
+	return sna_blt_fill_boxes(sna, alu,
+				  dst_bo, dst->drawable.bitsPerPixel,
+				  pixel, box, n);
+}
+
+static Bool
+gen2_render_fill_boxes(struct sna *sna,
+		       CARD8 op,
+		       PictFormat format,
+		       const xRenderColor *color,
+		       PixmapPtr dst, struct kgem_bo *dst_bo,
+		       const BoxRec *box, int n)
+{
+	struct sna_composite_op tmp;
+	uint32_t pixel;
+
+#if NO_FILL_BOXES
+	return gen2_render_fill_boxes_try_blt(sna, op, format, color,
+					      dst, dst_bo,
+					      box, n);
+#endif
+
+	DBG(("%s (op=%d, format=%x, color=(%04x,%04x,%04x, %04x))\n",
+	     __FUNCTION__, op, (int)format,
+	     color->red, color->green, color->blue, color->alpha));
+
+	if (op >= ARRAY_SIZE(gen2_blend_op)) {
+		DBG(("%s: fallback due to unhandled blend op: %d\n",
+		     __FUNCTION__, op));
+		return FALSE;
+	}
+
+	if (dst->drawable.width > 2048 ||
+	    dst->drawable.height > 2048 ||
+	    dst_bo->pitch > 8192 ||
+	    !gen2_check_dst_format(format))
+		return gen2_render_fill_boxes_try_blt(sna, op, format, color,
+						      dst, dst_bo,
+						      box, n);
+
+	if (gen2_render_fill_boxes_try_blt(sna, op, format, color,
+					   dst, dst_bo,
+					   box, n))
+		return TRUE;
+
+	if (!sna_get_pixel_from_rgba(&pixel,
+				     color->red,
+				     color->green,
+				     color->blue,
+				     color->alpha,
+				     PICT_a8r8g8b8))
+		return FALSE;
+
+	DBG(("%s: using shader for op=%d, format=%x, pixel=%x\n",
+	     __FUNCTION__, op, (int)format, pixel));
+
+	if (pixel == 0)
+		op = PictOpClear;
+
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.op = op;
+	tmp.dst.pixmap = dst;
+	tmp.dst.width = dst->drawable.width;
+	tmp.dst.height = dst->drawable.height;
+	tmp.dst.format = format;
+	tmp.dst.bo = dst_bo;
+	tmp.floats_per_vertex = 2;
+
+	if (!kgem_check_bo(&sna->kgem, dst_bo))
+		kgem_submit(&sna->kgem);
+
+	gen2_emit_fill_composite_state(sna, &tmp, pixel);
+
+	do {
+		int n_this_time = gen2_get_rectangles(sna, &tmp, n);
+		if (n_this_time == 0) {
+			gen2_emit_fill_composite_state(sna, &tmp, pixel);
+			n_this_time = gen2_get_rectangles(sna, &tmp, n);
+		}
+		n -= n_this_time;
+
+		do {
+			DBG(("	(%d, %d), (%d, %d): %x\n",
+			     box->x1, box->y1, box->x2, box->y2, pixel));
+			OUT_VERTEX(box->x2);
+			OUT_VERTEX(box->y2);
+			OUT_VERTEX(box->x1);
+			OUT_VERTEX(box->y2);
+			OUT_VERTEX(box->x1);
+			OUT_VERTEX(box->y1);
+			box++;
+		} while (--n_this_time);
+	} while (n);
+
+	gen2_vertex_flush(sna);
+	_kgem_set_mode(&sna->kgem, KGEM_RENDER);
+	return TRUE;
+}
+
+static void
+gen2_render_reset(struct sna *sna)
+{
+	sna->render_state.gen2.need_invariant = TRUE;
+	sna->render_state.gen2.vertex_offset = 0;
+	sna->render_state.gen2.target = 0;
+}
+
+static void
+gen2_render_flush(struct sna *sna)
+{
+	gen2_vertex_flush(sna);
 }
 
 Bool gen2_render_init(struct sna *sna)
@@ -1271,12 +1671,13 @@ Bool gen2_render_init(struct sna *sna)
 	 * use the texture combiners.
 	 */
 	render->composite = gen2_render_composite;
+	render->composite_spans = gen2_render_composite_spans;
+	render->fill_boxes = gen2_render_fill_boxes;
 
 	/* XXX Y-tiling copies */
 
 	render->reset = gen2_render_reset;
 	render->flush = gen2_render_flush;
-	render->fini = gen2_render_fini;
 
 	render->max_3d_size = 2048;
 	return TRUE;
diff --git a/src/sna/gen2_render.h b/src/sna/gen2_render.h
index 945cd84..a1767ad 100644
--- a/src/sna/gen2_render.h
+++ b/src/sna/gen2_render.h
@@ -447,9 +447,8 @@
 #define _3DSTATE_MODES_5_CMD		(CMD_3D|(0x0c<<24))
 #define ENABLE_SPRITE_POINT_TEX		(1<<23)
 #define SPRITE_POINT_TEX_ON		(1<<22)
-#define SPRITE_POINT_TEX_OFF		0
-#define FLUSH_RENDER_CACHE		(1<<18)
-#define FLUSH_TEXTURE_CACHE		(1<<16)
+#define PIPELINE_FLUSH_RENDER_CACHE	(1<<18)
+#define PIPELINE_FLUSH_TEXTURE_CACHE	(1<<16)
 #define FIXED_LINE_WIDTH_MASK		0xfc00
 #define ENABLE_FIXED_LINE_WIDTH		(1<<15)
 #define FIXED_LINE_WIDTH(x)		((x)<<10)
@@ -735,7 +734,8 @@
 #define TB0C_RESULT_SCALE_1X		(0 << 29)
 #define TB0C_RESULT_SCALE_2X		(1 << 29)
 #define TB0C_RESULT_SCALE_4X		(2 << 29)
-#define TB0C_OP_MODULE			(3 << 25)
+#define TB0C_OP_ARG1			(1 << 25)
+#define TB0C_OP_MODULATE		(3 << 25)
 #define TB0C_OUTPUT_WRITE_CURRENT	(0 << 24)
 #define TB0C_OUTPUT_WRITE_ACCUM		(1 << 24)
 #define TB0C_ARG3_REPLICATE_ALPHA	(1<<23)
@@ -752,6 +752,7 @@
 #define TB0C_ARG1_REPLICATE_ALPHA	(1<<11)
 #define TB0C_ARG1_INVERT		(1<<10)
 #define TB0C_ARG1_SEL_ONE		(0 << 6)
+#define TB0C_ARG1_SEL_DIFFUSE		(3 << 6)
 #define TB0C_ARG1_SEL_TEXEL0		(6 << 6)
 #define TB0C_ARG1_SEL_TEXEL1		(7 << 6)
 #define TB0C_ARG1_SEL_TEXEL2		(8 << 6)
@@ -763,7 +764,8 @@
 #define TB0A_RESULT_SCALE_1X		(0 << 29)
 #define TB0A_RESULT_SCALE_2X		(1 << 29)
 #define TB0A_RESULT_SCALE_4X		(2 << 29)
-#define TB0A_OP_MODULE			(3 << 25)
+#define TB0A_OP_ARG1			(1 << 25)
+#define TB0A_OP_MODULATE		(3 << 25)
 #define TB0A_OUTPUT_WRITE_CURRENT	(0<<24)
 #define TB0A_OUTPUT_WRITE_ACCUM		(1<<24)
 #define TB0A_CTR_STAGE_SEL_BITS_XXX
@@ -771,12 +773,14 @@
 #define TB0A_ARG3_INVERT		(1<<17)
 #define TB0A_ARG2_INVERT		(1<<16)
 #define TB0A_ARG2_SEL_ONE		(0 << 12)
+#define TB0A_ARG2_SEL_DIFFUSE		(3 << 12)
 #define TB0A_ARG2_SEL_TEXEL0		(6 << 12)
 #define TB0A_ARG2_SEL_TEXEL1		(7 << 12)
 #define TB0A_ARG2_SEL_TEXEL2		(8 << 12)
 #define TB0A_ARG2_SEL_TEXEL3		(9 << 12)
 #define TB0A_ARG1_INVERT		(1<<10)
 #define TB0A_ARG1_SEL_ONE		(0 << 6)
+#define TB0A_ARG1_SEL_DIFFUSE		(3 << 6)
 #define TB0A_ARG1_SEL_TEXEL0		(6 << 6)
 #define TB0A_ARG1_SEL_TEXEL1		(7 << 6)
 #define TB0A_ARG1_SEL_TEXEL2		(8 << 6)
diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c
index 21afd26..72a3c1e 100644
--- a/src/sna/sna_render.c
+++ b/src/sna/sna_render.c
@@ -437,7 +437,7 @@ sna_render_picture_extract(struct sna *sna,
 {
 	struct kgem_bo *bo = NULL;
 	PixmapPtr pixmap = get_drawable_pixmap(picture->pDrawable);
-	int16_t ox, oy;
+	int16_t ox, oy, ow, oh;
 	BoxRec box;
 
 #if NO_EXTRACT
@@ -452,6 +452,9 @@ sna_render_picture_extract(struct sna *sna,
 		return -1;
 	}
 
+	ow = w;
+	oh = h;
+
 	ox = box.x1 = x;
 	oy = box.y1 = y;
 	box.x2 = x + w;
@@ -482,7 +485,11 @@ sna_render_picture_extract(struct sna *sna,
 			if (!channel->is_affine) {
 				DBG(("%s: fallback -- repeating project transform too large for texture\n",
 				     __FUNCTION__));
-				return -1;
+				return sna_render_picture_fixup(sna,
+								picture,
+								channel,
+								x, y, ow, oh,
+								dst_x, dst_y);
 			}
 		}
 	} else {
@@ -510,7 +517,8 @@ sna_render_picture_extract(struct sna *sna,
 	if (w > sna->render.max_3d_size || h > sna->render.max_3d_size) {
 		DBG(("%s: fallback -- sample too large for texture (%d, %d)x(%d, %d)\n",
 		     __FUNCTION__, box.x1, box.y1, w, h));
-		return -1;
+		return sna_render_picture_fixup(sna, picture, channel,
+						x, y, ow, oh, dst_x, dst_y);
 	}
 
 	if (texture_is_cpu(pixmap, &box) && !move_to_gpu(pixmap, &box)) {
@@ -528,7 +536,8 @@ sna_render_picture_extract(struct sna *sna,
 		if (!sna_pixmap_move_to_gpu(pixmap)) {
 			DBG(("%s: falback -- pixmap is not on the GPU\n",
 			     __FUNCTION__));
-			return -1;
+			return sna_render_picture_fixup(sna, picture, channel,
+							x, y, ow, oh, dst_x, dst_y);
 		}
 
 		bo = kgem_create_2d(&sna->kgem, w, h,
@@ -550,7 +559,8 @@ sna_render_picture_extract(struct sna *sna,
 					&box, 1)) {
 			DBG(("%s: fallback -- unable to copy boxes\n",
 			     __FUNCTION__));
-			return -1;
+			return sna_render_picture_fixup(sna, picture, channel,
+							x, y, ow, oh, dst_x, dst_y);
 		}
 	}
 
diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h
index c2d6f12..5b51be9 100644
--- a/src/sna/sna_render.h
+++ b/src/sna/sna_render.h
@@ -236,6 +236,7 @@ struct sna_render {
 };
 
 struct gen2_render_state {
+	uint32_t target;
 	Bool need_invariant;
 	uint16_t vertex_offset;
 };
diff --git a/src/sna/sna_trapezoids.c b/src/sna/sna_trapezoids.c
index db9e085..536034f 100644
--- a/src/sna/sna_trapezoids.c
+++ b/src/sna/sna_trapezoids.c
@@ -2073,7 +2073,7 @@ composite_unaligned_boxes(CARD8 op,
 
 	DBG(("%s\n", __FUNCTION__));
 
-	/* XXX need a span converter to handle overlapping traps */
+	/* need a span converter to handle overlapping traps */
 	if (ntrap > 1 && maskFormat)
 		return false;
 
commit c89b37d7b43c9e588097b7fadcba3bc13a03f8bc
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Jun 30 17:53:49 2011 +0100

    sna: Mappable aperture is region 0 on gen2
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index 27ed78c..88b1d83 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -293,9 +293,9 @@ static struct list *inactive(struct kgem *kgem,
 }
 
 static size_t
-agp_aperture_size(struct pci_device *dev)
+agp_aperture_size(struct pci_device *dev, int gen)
 {
-	return dev->regions[2].size;
+	return dev->regions[gen < 30 ? 0 :2].size;
 }
 
 void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, int gen)
@@ -358,12 +358,15 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, int gen)
 
 	kgem->aperture_high = aperture.aper_size * 3/4;
 	kgem->aperture_low = aperture.aper_size * 1/4;
-	DBG(("%s: aperture low=%d, high=%d\n", __FUNCTION__,
-	     kgem->aperture_low, kgem->aperture_high));
+	DBG(("%s: aperture low=%d [%d], high=%d [%d]\n", __FUNCTION__,
+	     kgem->aperture_low, kgem->aperture_low / (1024*1024),
+	     kgem->aperture_high, kgem->aperture_high / (1024*1024)));
 
-	kgem->aperture_mappable = agp_aperture_size(dev);
+	kgem->aperture_mappable = agp_aperture_size(dev, gen);
 	if (kgem->aperture_mappable == 0)
 		kgem->aperture_mappable = aperture.aper_size;
+	DBG(("%s: aperture mappable=%d [%d]\n", __FUNCTION__,
+	     kgem->aperture_mappable, kgem->aperture_mappable / (1024*1024)));
 
 	i = 8;
 	gp.param = I915_PARAM_NUM_FENCES_AVAIL;
commit c0434ab49035bf278dad6f5f84a541ea58536fb4
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Thu Jun 30 16:31:28 2011 +0100

    sna: Distinguish 830/845 vs 855/865 using the generation id
    
    Remove the PCI ID device checks by using the simpler check on the
    generation id for errata pertaining to 830/845.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/intel_module.c b/src/intel_module.c
index f6561bf..499814e 100644
--- a/src/intel_module.c
+++ b/src/intel_module.c
@@ -46,9 +46,18 @@ static const struct intel_device_info intel_i81x_info = {
 	.gen = 10,
 };
 
-static const struct intel_device_info intel_i8xx_info = {
+static const struct intel_device_info intel_i830_info = {
 	.gen = 20,
 };
+static const struct intel_device_info intel_i845_info = {
+	.gen = 20,
+};
+static const struct intel_device_info intel_i855_info = {
+	.gen = 21,
+};
+static const struct intel_device_info intel_i865_info = {
+	.gen = 21,
+};
 
 static const struct intel_device_info intel_i915_info = {
 	.gen = 30,
@@ -142,11 +151,11 @@ static const struct pci_id_match intel_device_match[] = {
 	INTEL_DEVICE_MATCH (PCI_CHIP_I810_E, &intel_i81x_info ),
 	INTEL_DEVICE_MATCH (PCI_CHIP_I815, &intel_i81x_info ),
 
-	INTEL_DEVICE_MATCH (PCI_CHIP_I830_M, &intel_i8xx_info ),
-	INTEL_DEVICE_MATCH (PCI_CHIP_845_G, &intel_i8xx_info ),
-	INTEL_DEVICE_MATCH (PCI_CHIP_I854, &intel_i8xx_info ),
-	INTEL_DEVICE_MATCH (PCI_CHIP_I855_GM, &intel_i8xx_info ),
-	INTEL_DEVICE_MATCH (PCI_CHIP_I865_G, &intel_i8xx_info ),
+	INTEL_DEVICE_MATCH (PCI_CHIP_I830_M, &intel_i830_info ),
+	INTEL_DEVICE_MATCH (PCI_CHIP_845_G, &intel_i845_info ),
+	INTEL_DEVICE_MATCH (PCI_CHIP_I854, &intel_i855_info ),
+	INTEL_DEVICE_MATCH (PCI_CHIP_I855_GM, &intel_i855_info ),
+	INTEL_DEVICE_MATCH (PCI_CHIP_I865_G, &intel_i865_info ),
 
 	INTEL_DEVICE_MATCH (PCI_CHIP_I915_G, &intel_i915_info ),
 	INTEL_DEVICE_MATCH (PCI_CHIP_E7221_G, &intel_i915_info ),
diff --git a/src/sna/gen2_render.c b/src/sna/gen2_render.c
index 34c053b..06cab3c 100644
--- a/src/sna/gen2_render.c
+++ b/src/sna/gen2_render.c
@@ -161,7 +161,7 @@ gen2_get_card_format(struct sna *sna, uint32_t format)
 		if (i8xx_tex_formats[i].fmt == format)
 			return i8xx_tex_formats[i].card_fmt;
 
-	if (IS_I830(sna) || IS_845G(sna)) {
+	if (sna->kgem.gen < 21) {
 		/* Whilst these are not directly supported on 830/845,
 		 * we only enable them when we can implicitly convert
 		 * them to a supported variant through the texture
@@ -969,7 +969,7 @@ gen2_check_card_format(struct sna *sna,
 
 	for (i = 0; i < ARRAY_SIZE(i85x_tex_formats); i++) {
 		if (i85x_tex_formats[i].fmt == format) {
-			if (!(IS_I830(sna) || IS_845G(sna)))
+			if (sna->kgem.gen >= 21)
 				return TRUE;
 
 			if ( source_is_covered(picture, x, y, w,h)) {
diff --git a/src/sna/sna_video.c b/src/sna/sna_video.c
index c0b1451..e50b3dd 100644
--- a/src/sna/sna_video.c
+++ b/src/sna/sna_video.c
@@ -196,7 +196,7 @@ sna_video_frame_init(struct sna *sna,
 			 * stride must be at least 512 bytes. Take the easy fix
 			 * and align on 512 bytes unconditionally. */
 			align = 512;
-		else if (IS_I830(sna) || IS_845G(sna))
+		else if (sna->kgem.gen < 21)
 			/* Harsh, errata on these chipsets limit the stride
 			 * to be a multiple of 256 bytes.
 			 */
diff --git a/src/sna/sna_video_overlay.c b/src/sna/sna_video_overlay.c
index c4838c2..422ce53 100644
--- a/src/sna/sna_video_overlay.c
+++ b/src/sna/sna_video_overlay.c
@@ -540,7 +540,7 @@ sna_video_overlay_query_video_attributes(ScrnInfoPtr scrn,
 
 	DBG(("%s: w is %d, h is %d\n", __FUNCTION__, *w, *h));
 
-	if (IS_845G(sna) || IS_I830(sna)) {
+	if (sna->kgem.gen < 21) {
 		if (*w > IMAGE_MAX_WIDTH_LEGACY)
 			*w = IMAGE_MAX_WIDTH_LEGACY;
 		if (*h > IMAGE_MAX_HEIGHT_LEGACY)
@@ -651,7 +651,7 @@ XF86VideoAdaptorPtr sna_video_overlay_setup(struct sna *sna,
 	adaptor->nEncodings = 1;
 	adaptor->pEncodings = xnfalloc(sizeof(DummyEncoding));
 	memcpy(adaptor->pEncodings, DummyEncoding, sizeof(DummyEncoding));
-	if (IS_845G(sna) || IS_I830(sna)) {
+	if (sna->kgem.gen < 21) {
 		adaptor->pEncodings->width = IMAGE_MAX_WIDTH_LEGACY;
 		adaptor->pEncodings->height = IMAGE_MAX_HEIGHT_LEGACY;
 	}


More information about the xorg-commit mailing list