xf86-video-intel: 4 commits - src/sna/gen2_render.c src/sna/sna_blt.c src/sna/sna_gradient.c src/sna/sna_render.c src/sna/sna_render.h

Chris Wilson ickle at kemper.freedesktop.org
Mon Jan 9 15:28:08 PST 2012


 src/sna/gen2_render.c  |  409 +++++++++++++++++++++++++++++++++++++------------
 src/sna/sna_blt.c      |   26 ++-
 src/sna/sna_gradient.c |    2 
 src/sna/sna_render.c   |    4 
 src/sna/sna_render.h   |    6 
 5 files changed, 340 insertions(+), 107 deletions(-)

New commits:
commit b76865fa3deff2f44a1158914a124b9c81d67eca
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon Jan 9 22:11:21 2012 +0000

    sna/gen2: Try to avoid creating a bo for solid colours
    
    As we try to use the diffuse/specular and only resort to using a texture
    operation for convenience in the rare case of a solid mask.
    
    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 2566be3..8f6a164 100644
--- a/src/sna/gen2_render.c
+++ b/src/sna/gen2_render.c
@@ -1100,12 +1100,12 @@ gen2_composite_solid_init(struct sna *sna,
 	channel->height = 1;
 	channel->pict_format = PICT_a8r8g8b8;
 
-	channel->bo = sna_render_get_solid(sna, color);
+	channel->bo = NULL;
 	channel->u.gen2.pixel = color;
 
 	channel->scale[0]  = channel->scale[1]  = 1;
 	channel->offset[0] = channel->offset[1] = 0;
-	return channel->bo != NULL;
+	return TRUE;
 }
 
 #define xFixedToDouble(f) pixman_fixed_to_double(f)
@@ -1738,6 +1738,10 @@ gen2_render_composite(struct sna *sna,
 				tmp->op = PictOpOutReverse;
 			}
 		}
+
+		/* convert solid to a texture (pure convenience) */
+		if (tmp->mask.is_solid)
+			tmp->mask.bo = sna_render_get_solid(sna, tmp->mask.u.gen2.pixel);
 	}
 
 	tmp->floats_per_vertex = 2;
commit 981aae104a96b41db88cc381cc7592818f3e1298
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon Jan 9 22:02:40 2012 +0000

    sna/gen2: Eliminate some switching between logic op and blend
    
    If the new mode can be done either using a logic op or with the blend
    unit, prefer the currently enabled unit.
    
    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 674b41e..2566be3 100644
--- a/src/sna/gen2_render.c
+++ b/src/sna/gen2_render.c
@@ -377,9 +377,7 @@ gen2_get_blend_factors(const struct sna_composite_op *op,
 			ablend |= TB0A_ARG2_SEL_TEXEL1;
 		}
 
-		if (op->dst.format == PICT_a8 ||
-		    !op->has_component_alpha ||
-		    PICT_FORMAT_RGB(op->mask.pict_format) == 0)
+		if (op->dst.format == PICT_a8 || !op->has_component_alpha)
 			cblend |= TB0C_ARG2_REPLICATE_ALPHA;
 
 		cblend |= TB0C_OP_MODULATE;
@@ -399,6 +397,9 @@ static uint32_t gen2_get_blend_cntl(int op,
 {
 	uint32_t sblend, dblend;
 
+	if (op <= PictOpSrc)
+		return S8_ENABLE_COLOR_BUFFER_WRITE;
+
 	sblend = gen2_blend_op[op].src_blend;
 	dblend = gen2_blend_op[op].dst_blend;
 
@@ -424,7 +425,9 @@ static uint32_t gen2_get_blend_cntl(int op,
 	}
 
 	return (sblend << S8_SRC_BLEND_FACTOR_SHIFT |
-		dblend << S8_DST_BLEND_FACTOR_SHIFT);
+		dblend << S8_DST_BLEND_FACTOR_SHIFT |
+		S8_ENABLE_COLOR_BLEND | S8_BLENDFUNC_ADD |
+		S8_ENABLE_COLOR_BUFFER_WRITE);
 }
 
 static void gen2_emit_invariant(struct sna *sna)
@@ -567,6 +570,8 @@ static void gen2_disable_logic_op(struct sna *sna)
 	if (!sna->render_state.gen2.logic_op_enabled)
 		return;
 
+	DBG(("%s\n", __FUNCTION__));
+
 	BATCH(_3DSTATE_ENABLES_1_CMD |
 	      DISABLE_LOGIC_OP | ENABLE_COLOR_BLEND);
 
@@ -595,9 +600,15 @@ static void gen2_enable_logic_op(struct sna *sna, int op)
 	};
 
 	if (sna->render_state.gen2.logic_op_enabled != op+1) {
-		if (!sna->render_state.gen2.logic_op_enabled)
+		if (!sna->render_state.gen2.logic_op_enabled) {
+			if (op == GXclear || op == GXcopy)
+				return;
+
+			DBG(("%s\n", __FUNCTION__));
+
 			BATCH(_3DSTATE_ENABLES_1_CMD |
 			      ENABLE_LOGIC_OP | DISABLE_COLOR_BLEND);
+		}
 
 		BATCH(_3DSTATE_MODES_4_CMD |
 		      ENABLE_LOGIC_OP_FUNC | LOGIC_OP_FUNC(logic_op[op]));
@@ -620,14 +631,12 @@ static void gen2_emit_composite_state(struct sna *sna,
 	      I1_LOAD_S(2) | I1_LOAD_S(3) | I1_LOAD_S(8) | 2);
 	BATCH((!op->src.is_solid + (op->mask.bo != NULL)) << 12);
 	BATCH(S3_CULLMODE_NONE | S3_VERTEXHAS_XY);
-	BATCH(S8_ENABLE_COLOR_BLEND | S8_BLENDFUNC_ADD |
-	      gen2_get_blend_cntl(op->op,
+	BATCH(gen2_get_blend_cntl(op->op,
 				  op->has_component_alpha,
-				  op->dst.format) |
-	      S8_ENABLE_COLOR_BUFFER_WRITE);
-	if (memcmp (sna->kgem.batch + sna->render_state.gen2.ls1,
-		    sna->kgem.batch + unwind,
-		    4 * sizeof(uint32_t)) == 0)
+				  op->dst.format));
+	if (memcmp(sna->kgem.batch + sna->render_state.gen2.ls1 + 1,
+		   sna->kgem.batch + unwind + 1,
+		   3 * sizeof(uint32_t)) == 0)
 		sna->kgem.nbatch = unwind;
 	else
 		sna->render_state.gen2.ls1 = unwind;
@@ -640,9 +649,9 @@ static void gen2_emit_composite_state(struct sna *sna,
 	      LOAD_TEXTURE_BLEND_STAGE(0) | 1);
 	BATCH(cblend);
 	BATCH(ablend);
-	if (memcmp (sna->kgem.batch + sna->render_state.gen2.ls2 + 1,
-		    sna->kgem.batch + unwind + 1,
-		    2 * sizeof(uint32_t)) == 0)
+	if (memcmp(sna->kgem.batch + sna->render_state.gen2.ls2 + 1,
+		   sna->kgem.batch + unwind + 1,
+		   2 * sizeof(uint32_t)) == 0)
 		sna->kgem.nbatch = unwind;
 	else
 		sna->render_state.gen2.ls2 = unwind;
@@ -899,9 +908,16 @@ static void gen2_magic_ca_pass(struct sna *sna,
 	if (!op->need_magic_ca_pass)
 		return;
 
+	DBG(("%s: batch=%x, vertex=%x\n", __FUNCTION__,
+	     sna->kgem.nbatch, sna->render_state.gen2.vertex_offset));
+
+	assert(op->mask.bo);
+	assert(op->has_component_alpha);
+
 	BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(8) | 0);
-	BATCH(S8_ENABLE_COLOR_BLEND | S8_BLENDFUNC_ADD |
-	      gen2_get_blend_cntl(PictOpAdd, TRUE, op->dst.format) |
+	BATCH(BLENDFACTOR_ONE << S8_SRC_BLEND_FACTOR_SHIFT |
+	      BLENDFACTOR_ONE << S8_DST_BLEND_FACTOR_SHIFT |
+	      S8_ENABLE_COLOR_BLEND | S8_BLENDFUNC_ADD |
 	      S8_ENABLE_COLOR_BUFFER_WRITE);
 	sna->render_state.gen2.ls1 = 0;
 
@@ -1978,9 +1994,9 @@ gen2_emit_spans_pipeline(struct sna *sna,
 	      LOAD_TEXTURE_BLEND_STAGE(0) | 1);
 	BATCH(cblend);
 	BATCH(ablend);
-	if (memcmp (sna->kgem.batch + sna->render_state.gen2.ls2 + 1,
-		    sna->kgem.batch + unwind + 1,
-		    2 * sizeof(uint32_t)) == 0)
+	if (memcmp(sna->kgem.batch + sna->render_state.gen2.ls2 + 1,
+		   sna->kgem.batch + unwind + 1,
+		   2 * sizeof(uint32_t)) == 0)
 		sna->kgem.nbatch = unwind;
 	else
 		sna->render_state.gen2.ls2 = unwind;
@@ -1999,12 +2015,10 @@ static void gen2_emit_composite_spans_state(struct sna *sna,
 	      I1_LOAD_S(2) | I1_LOAD_S(3) | I1_LOAD_S(8) | 2);
 	BATCH(!op->base.src.is_solid << 12);
 	BATCH(S3_CULLMODE_NONE | S3_VERTEXHAS_XY | S3_DIFFUSE_PRESENT);
-	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);
-	if (memcmp (sna->kgem.batch + sna->render_state.gen2.ls1,
-		    sna->kgem.batch + unwind,
-		    4 * sizeof(uint32_t)) == 0)
+	BATCH(gen2_get_blend_cntl(op->base.op, FALSE, op->base.dst.format));
+	if (memcmp(sna->kgem.batch + sna->render_state.gen2.ls1 + 1,
+		   sna->kgem.batch + unwind + 1,
+		   3 * sizeof(uint32_t)) == 0)
 		sna->kgem.nbatch = unwind;
 	else
 		sna->render_state.gen2.ls1 = unwind;
@@ -2224,9 +2238,9 @@ gen2_emit_fill_pipeline(struct sna *sna, const struct sna_composite_op *op)
 	      TB0A_ARG1_SEL_DIFFUSE |
 	      TB0A_OUTPUT_WRITE_CURRENT);
 
-	if (memcmp (sna->kgem.batch + sna->render_state.gen2.ls2 + 1,
-		    sna->kgem.batch + unwind + 1,
-		    2 * sizeof(uint32_t)) == 0)
+	if (memcmp(sna->kgem.batch + sna->render_state.gen2.ls2 + 1,
+		   sna->kgem.batch + unwind + 1,
+		   2 * sizeof(uint32_t)) == 0)
 		sna->kgem.nbatch = unwind;
 	else
 		sna->render_state.gen2.ls2 = unwind;
@@ -2246,12 +2260,10 @@ static void gen2_emit_fill_composite_state(struct sna *sna,
 	      I1_LOAD_S(2) | I1_LOAD_S(3) | I1_LOAD_S(8) | 2);
 	BATCH(0);
 	BATCH(S3_CULLMODE_NONE | S3_VERTEXHAS_XY);
-	BATCH(S8_ENABLE_COLOR_BLEND | S8_BLENDFUNC_ADD |
-	      gen2_get_blend_cntl(op->op, FALSE, op->dst.format) |
-	      S8_ENABLE_COLOR_BUFFER_WRITE);
-	if (memcmp (sna->kgem.batch + sna->render_state.gen2.ls1,
-		    sna->kgem.batch + ls1,
-		    4 * sizeof(uint32_t)) == 0)
+	BATCH(gen2_get_blend_cntl(op->op, FALSE, op->dst.format));
+	if (memcmp(sna->kgem.batch + sna->render_state.gen2.ls1 + 1,
+		   sna->kgem.batch + ls1 + 1,
+		   3 * sizeof(uint32_t)) == 0)
 		sna->kgem.nbatch = ls1;
 	else
 		sna->render_state.gen2.ls1 = ls1;
@@ -2428,9 +2440,9 @@ static void gen2_emit_fill_state(struct sna *sna,
 	BATCH(0);
 	BATCH(S3_CULLMODE_NONE | S3_VERTEXHAS_XY);
 	BATCH(S8_ENABLE_COLOR_BUFFER_WRITE);
-	if (memcmp (sna->kgem.batch + sna->render_state.gen2.ls1,
-		    sna->kgem.batch + ls1,
-		    4 * sizeof(uint32_t)) == 0)
+	if (memcmp(sna->kgem.batch + sna->render_state.gen2.ls1 + 1,
+		   sna->kgem.batch + ls1 + 1,
+		   3 * sizeof(uint32_t)) == 0)
 		sna->kgem.nbatch = ls1;
 	else
 		sna->render_state.gen2.ls1 = ls1;
@@ -2700,9 +2712,9 @@ gen2_emit_copy_pipeline(struct sna *sna, const struct sna_composite_op *op)
 		blend |= TB0A_ARG1_SEL_TEXEL0;
 	BATCH(blend);
 
-	if (memcmp (sna->kgem.batch + sna->render_state.gen2.ls2 + 1,
-		    sna->kgem.batch + unwind + 1,
-		    2 * sizeof(uint32_t)) == 0)
+	if (memcmp(sna->kgem.batch + sna->render_state.gen2.ls2 + 1,
+		   sna->kgem.batch + unwind + 1,
+		   2 * sizeof(uint32_t)) == 0)
 		sna->kgem.nbatch = unwind;
 	else
 		sna->render_state.gen2.ls2 = unwind;
@@ -2721,9 +2733,9 @@ static void gen2_emit_copy_state(struct sna *sna, const struct sna_composite_op
 	BATCH(1<<12);
 	BATCH(S3_CULLMODE_NONE | S3_VERTEXHAS_XY);
 	BATCH(S8_ENABLE_COLOR_BUFFER_WRITE);
-	if (memcmp (sna->kgem.batch + sna->render_state.gen2.ls1,
-		    sna->kgem.batch + ls1,
-		    4 * sizeof(uint32_t)) == 0)
+	if (memcmp(sna->kgem.batch + sna->render_state.gen2.ls1 + 1,
+		   sna->kgem.batch + ls1 + 1,
+		   3 * sizeof(uint32_t)) == 0)
 		sna->kgem.nbatch = ls1;
 	else
 		sna->render_state.gen2.ls1 = ls1;
@@ -2942,7 +2954,7 @@ 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.logic_op_enabled = 0;
 	sna->render_state.gen2.vertex_offset = 0;
 	sna->render_state.gen2.target = 0;
 
diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c
index c4d8a58..d39aa16 100644
--- a/src/sna/sna_render.c
+++ b/src/sna/sna_render.c
@@ -466,10 +466,10 @@ sna_render_pixmap_bo(struct sna *sna,
 	BoxRec box;
 
 	DBG(("%s (%d, %d)x(%d, %d)/(%d, %d)\n", __FUNCTION__,
-	     x, y, w,h, pixmap->drawable.height, pixmap->drawable.width));
+	     x, y, w,h, pixmap->drawable.width, pixmap->drawable.height));
 
-	channel->height = pixmap->drawable.height;
 	channel->width  = pixmap->drawable.width;
+	channel->height = pixmap->drawable.height;
 	channel->scale[0] = 1.f / pixmap->drawable.width;
 	channel->scale[1] = 1.f / pixmap->drawable.height;
 	channel->offset[0] = x - dst_x;
diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h
index dfaa606..f780428 100644
--- a/src/sna/sna_render.h
+++ b/src/sna/sna_render.h
@@ -280,7 +280,7 @@ struct sna_render {
 struct gen2_render_state {
 	uint32_t target;
 	Bool need_invariant;
-	Bool logic_op_enabled;
+	uint32_t logic_op_enabled;
 	uint32_t ls1, ls2, vft;
 	uint32_t diffuse;
 	uint32_t specular;
commit d65b7f9cf46a48e3bfb37c0b75df55aa1e7bff41
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon Jan 9 21:58:03 2012 +0000

    sna/blt: Rearrange to reduce a out-of-bounds copy to a clear
    
    If we asked to use the BLT, try to avoid trigging a context switch for
    a trivial case where we sample outside of a NONE source and so can
    reduce the operation to a clear.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_blt.c b/src/sna/sna_blt.c
index dfc4b43..64fcd06 100644
--- a/src/sna/sna_blt.c
+++ b/src/sna/sna_blt.c
@@ -1595,6 +1595,24 @@ sna_blt_composite(struct sna *sna,
 		return FALSE;
 	}
 
+	if (!sna_transform_is_integer_translation(src->transform, &tx, &ty)) {
+		DBG(("%s: source transform is not an integer translation\n",
+		     __FUNCTION__));
+		return FALSE;
+	}
+	x += tx;
+	y += ty;
+
+	if ((x > src->pDrawable->width ||
+	     y > src->pDrawable->height ||
+	     x + width < 0 ||
+	     y + height < 0) &&
+	    (!src->repeat || src->repeatType == RepeatNone)) {
+		DBG(("%s: source is outside of valid area, converting to clear\n",
+		     __FUNCTION__));
+		return prepare_blt_clear(sna, tmp);
+	}
+
 	alpha_fixup = 0;
 	if (!(dst->format == src_format ||
 	      dst->format == alphaless(src_format) ||
@@ -1607,14 +1625,6 @@ sna_blt_composite(struct sna *sna,
 		return FALSE;
 	}
 
-	if (!sna_transform_is_integer_translation(src->transform, &tx, &ty)) {
-		DBG(("%s: source transform is not an integer translation\n",
-		     __FUNCTION__));
-		return FALSE;
-	}
-	x += tx;
-	y += ty;
-
 	/* XXX tiling? */
 	if (x < 0 || y < 0 ||
 	    x + width > src->pDrawable->width ||
commit 09e54c553680cbc2f3b4319cdab0f3d1af1574a8
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Mon Jan 9 14:04:41 2012 +0000

    sna/gen2: Add poor-man's linear gradient support
    
    Convert the linear gradient to a texture ramp and compute the texture
    coordinates in the standard manner.
    
    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 9771693..674b41e 100644
--- a/src/sna/gen2_render.c
+++ b/src/sna/gen2_render.c
@@ -60,19 +60,6 @@
 #define BATCH_F(v) batch_emit_float(sna, v)
 #define VERTEX(v) batch_emit_float(sna, v)
 
-/* TODO: Remaining items for the sufficiently motivated reader
- *
- * - Linear gradients (radial do require pixel shaders)
- *   - generate 1-d ramp for texture
- *   - compute 1-d texture coordinate using a linear projection matrix
- *   - issues? 1-stop, degenerate, fallback.
- *
- * - vmap
- *   - the texture sampler can use any type of memory apparently.
- *
- * - memory compaction?
- */
-
 static const struct blendinfo {
 	Bool dst_alpha;
 	Bool src_alpha;
@@ -262,9 +249,9 @@ gen2_emit_texture(struct sna *sna,
 		  const struct sna_composite_channel *channel,
 		  int unit)
 {
-	uint32_t filter;
-	uint32_t wrap_mode;
+	uint32_t wrap_mode_u, wrap_mode_v;
 	uint32_t texcoordtype;
+	uint32_t filter;
 
 	if (channel->is_affine)
 		texcoordtype = TEXCOORDTYPE_CARTESIAN;
@@ -275,18 +262,22 @@ gen2_emit_texture(struct sna *sna,
 	default:
 		assert(0);
 	case RepeatNone:
-		wrap_mode = TEXCOORDMODE_CLAMP_BORDER;
+		wrap_mode_u = TEXCOORDMODE_CLAMP_BORDER;
 		break;
 	case RepeatNormal:
-		wrap_mode = TEXCOORDMODE_WRAP;
+		wrap_mode_u = TEXCOORDMODE_WRAP;
 		break;
 	case RepeatPad:
-		wrap_mode = TEXCOORDMODE_CLAMP;
+		wrap_mode_u = TEXCOORDMODE_CLAMP;
 		break;
 	case RepeatReflect:
-		wrap_mode = TEXCOORDMODE_MIRROR;
+		wrap_mode_u = TEXCOORDMODE_MIRROR;
 		break;
 	}
+	if (channel->is_linear)
+		wrap_mode_v = TEXCOORDMODE_WRAP;
+	else
+		wrap_mode_v = wrap_mode_u;
 
 	switch (channel->filter) {
 	default:
@@ -309,7 +300,7 @@ gen2_emit_texture(struct sna *sna,
 			     I915_GEM_DOMAIN_SAMPLER << 16,
 			     0));
 	BATCH(((channel->height - 1) << TM0S1_HEIGHT_SHIFT) |
-	      ((channel->width - 1) << TM0S1_WIDTH_SHIFT) |
+	      ((channel->width - 1)  << TM0S1_WIDTH_SHIFT) |
 	      gen2_get_card_format(sna, channel->pict_format) |
 	      gen2_sampler_tiling_bits(channel->bo->tiling));
 	BATCH((channel->bo->pitch / 4 - 1) << TM0S2_PITCH_SHIFT | TM0S2_MAP_2D);
@@ -317,10 +308,9 @@ gen2_emit_texture(struct sna *sna,
 	BATCH(0);	/* default color */
 
 	BATCH(_3DSTATE_MAP_COORD_SET_CMD | TEXCOORD_SET(unit) |
-	      ENABLE_TEXCOORD_PARAMS | TEXCOORDS_ARE_NORMAL |
-	      texcoordtype |
-	      ENABLE_ADDR_V_CNTL | TEXCOORD_ADDR_V_MODE(wrap_mode) |
-	      ENABLE_ADDR_U_CNTL | TEXCOORD_ADDR_U_MODE(wrap_mode));
+	      ENABLE_TEXCOORD_PARAMS | TEXCOORDS_ARE_NORMAL | texcoordtype |
+	      ENABLE_ADDR_V_CNTL | TEXCOORD_ADDR_V_MODE(wrap_mode_v) |
+	      ENABLE_ADDR_U_CNTL | TEXCOORD_ADDR_U_MODE(wrap_mode_u));
 }
 
 static void
@@ -693,6 +683,21 @@ gen2_emit_composite_dstcoord(struct sna *sna, int dstX, int dstY)
 	VERTEX(dstY);
 }
 
+inline static void
+gen2_emit_composite_linear(struct sna *sna,
+			   const struct sna_composite_channel *channel,
+			   int16_t x, int16_t y)
+{
+	float v;
+
+	v = (x * channel->u.gen2.linear_dx +
+	     y * channel->u.gen2.linear_dy +
+	     channel->u.gen2.linear_offset);
+	DBG(("%s: (%d, %d) -> %f\n", __FUNCTION__, x, y, v));
+	VERTEX(v);
+	VERTEX(v);
+}
+
 static void
 gen2_emit_composite_texcoord(struct sna *sna,
 			     const struct sna_composite_channel *channel,
@@ -727,9 +732,14 @@ gen2_emit_composite_vertex(struct sna *sna,
 			   int16_t dstX, int16_t dstY)
 {
 	gen2_emit_composite_dstcoord(sna, dstX, dstY);
-	if (!op->src.is_solid)
+	if (op->src.is_linear)
+		gen2_emit_composite_linear(sna, &op->src, srcX, srcY);
+	else if (!op->src.is_solid)
 		gen2_emit_composite_texcoord(sna, &op->src, srcX, srcY);
-	if (op->mask.bo)
+
+	if (op->mask.is_linear)
+		gen2_emit_composite_linear(sna, &op->mask, mskX, mskY);
+	else if (op->mask.bo)
 		gen2_emit_composite_texcoord(sna, &op->mask, mskX, mskY);
 }
 
@@ -775,6 +785,27 @@ gen2_emit_composite_primitive_constant(struct sna *sna,
 }
 
 fastcall static void
+gen2_emit_composite_primitive_linear(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_linear(sna, &op->src,
+				   r->src.x + r->width, r->src.y + r->height);
+
+	gen2_emit_composite_dstcoord(sna, dst_x, dst_y + r->height);
+	gen2_emit_composite_linear(sna, &op->src,
+				   r->src.x, r->src.y + r->height);
+
+	gen2_emit_composite_dstcoord(sna, dst_x, dst_y);
+	gen2_emit_composite_linear(sna, &op->src,
+				   r->src.x, r->src.y);
+}
+
+fastcall static void
 gen2_emit_composite_primitive_identity(struct sna *sna,
 				       const struct sna_composite_op *op,
 				       const struct sna_composite_rectangles *r)
@@ -862,7 +893,8 @@ gen2_emit_composite_primitive_constant_identity_mask(struct sna *sna,
 static void gen2_magic_ca_pass(struct sna *sna,
 			       const struct sna_composite_op *op)
 {
-	uint32_t ablend, cblend;
+	uint32_t ablend, cblend, *src, *dst;
+	int n;
 
 	if (!op->need_magic_ca_pass)
 		return;
@@ -880,10 +912,12 @@ static void gen2_magic_ca_pass(struct sna *sna,
 	BATCH(ablend);
 	sna->render_state.gen2.ls2 = 0;
 
-	memcpy(sna->kgem.batch + sna->kgem.nbatch,
-	       sna->kgem.batch + sna->render_state.gen2.vertex_offset,
-	       (1 + sna->render.vertex_index)*sizeof(uint32_t));
-	sna->kgem.nbatch += 1 + sna->render.vertex_index;
+	src = sna->kgem.batch + sna->render_state.gen2.vertex_offset;
+	dst = sna->kgem.batch + sna->kgem.nbatch;
+	n = 1 + sna->render.vertex_index;
+	sna->kgem.nbatch += n;
+	while (n--)
+		*dst++ = *src++;
 }
 
 static void gen2_vertex_flush(struct sna *sna)
@@ -1044,6 +1078,7 @@ gen2_composite_solid_init(struct sna *sna,
 	channel->repeat = RepeatNormal;
 	channel->is_affine = TRUE;
 	channel->is_solid  = TRUE;
+	channel->is_linear = FALSE;
 	channel->transform = NULL;
 	channel->width  = 1;
 	channel->height = 1;
@@ -1057,6 +1092,118 @@ gen2_composite_solid_init(struct sna *sna,
 	return channel->bo != NULL;
 }
 
+#define xFixedToDouble(f) pixman_fixed_to_double(f)
+
+static Bool
+gen2_composite_linear_init(struct sna *sna,
+			   PicturePtr picture,
+			   struct sna_composite_channel *channel,
+			   int x, int y,
+			   int w, int h,
+			   int dst_x, int dst_y)
+{
+	PictLinearGradient *linear =
+		(PictLinearGradient *)picture->pSourcePict;
+	pixman_fixed_t tx, ty;
+	float x0, y0, sf;
+	float dx, dy;
+
+	DBG(("%s: p1=(%f, %f), p2=(%f, %f)\n",
+	     __FUNCTION__,
+	     xFixedToDouble(linear->p1.x), xFixedToDouble(linear->p1.y),
+	     xFixedToDouble(linear->p2.x), xFixedToDouble(linear->p2.y)));
+
+	if (linear->p2.x == linear->p1.x && linear->p2.y == linear->p1.y)
+		return 0;
+
+	if (!sna_transform_is_affine(picture->transform)) {
+		DBG(("%s: fallback due to projective transform\n",
+		     __FUNCTION__));
+		return sna_render_picture_fixup(sna, picture, channel,
+						x, y, w, h, dst_x, dst_y);
+	}
+
+	channel->bo = sna_render_get_gradient(sna, (PictGradient *)linear);
+	if (!channel->bo)
+		return 0;
+
+	channel->filter = PictFilterNearest;
+	channel->repeat = picture->repeat ? picture->repeatType : RepeatNone;
+	channel->is_affine = TRUE;
+	channel->is_opaque = FALSE;
+	channel->is_solid  = FALSE;
+	channel->is_linear = TRUE;
+	channel->transform = NULL;
+	channel->width  = channel->bo->pitch / 4;
+	channel->height = 1;
+	channel->pict_format = PICT_a8r8g8b8;
+
+	channel->scale[0]  = channel->scale[1]  = 1;
+	channel->offset[0] = channel->offset[1] = 0;
+
+	if (sna_transform_is_translation(picture->transform, &tx, &ty)) {
+		dx = xFixedToDouble(linear->p2.x - linear->p1.x);
+		dy = xFixedToDouble(linear->p2.y - linear->p1.y);
+
+		x0 = xFixedToDouble(linear->p1.x);
+		y0 = xFixedToDouble(linear->p1.y);
+
+		if (tx | ty) {
+			x0 -= pixman_fixed_to_double(tx);
+			y0 -= pixman_fixed_to_double(ty);
+		}
+	} else {
+		struct pixman_f_vector p1, p2;
+		struct pixman_f_transform m, inv;
+
+		DBG(("%s: transform = [%f %f %f, %f %f %f, %f %f %f]\n",
+		     __FUNCTION__,
+		     pixman_fixed_to_double(picture->transform->matrix[0][0]),
+		     pixman_fixed_to_double(picture->transform->matrix[0][1]),
+		     pixman_fixed_to_double(picture->transform->matrix[0][2]),
+		     pixman_fixed_to_double(picture->transform->matrix[1][0]),
+		     pixman_fixed_to_double(picture->transform->matrix[1][1]),
+		     pixman_fixed_to_double(picture->transform->matrix[1][2]),
+		     pixman_fixed_to_double(picture->transform->matrix[2][0]),
+		     pixman_fixed_to_double(picture->transform->matrix[2][1]),
+		     pixman_fixed_to_double(picture->transform->matrix[2][2])));
+
+		pixman_f_transform_from_pixman_transform(&m,
+							 picture->transform);
+		if (!pixman_f_transform_invert(&inv, &m))
+			return 0;
+
+		p1.v[0] = linear->p1.x;
+		p1.v[1] = linear->p1.y;
+		p1.v[2] = pixman_fixed_1;
+		pixman_f_transform_point(&inv, &p1);
+
+		p2.v[0] = linear->p2.x;
+		p2.v[1] = linear->p2.y;
+		p2.v[2] = pixman_fixed_1;
+		pixman_f_transform_point(&inv, &p2);
+
+		dx = p2.v[0] - p1.v[0];
+		dy = p2.v[1] - p1.v[1];
+
+		x0 = p1.v[0];
+		y0 = p1.v[1];
+	}
+
+	sf = dx*dx + dy*dy;
+	dx /= sf;
+	dy /= sf;
+
+	channel->u.gen2.linear_dx = dx;
+	channel->u.gen2.linear_dy = dy;
+	channel->u.gen2.linear_offset = -dx*(x0+x-dst_x) + -dy*(y0+y-dst_y);
+
+	DBG(("%s: dx=%f, dy=%f, offset=%f\n",
+	     __FUNCTION__, dx, dy, channel->u.gen2.linear_offset));
+
+	return channel->bo != NULL;
+}
+
 static Bool source_is_covered(PicturePtr picture,
 			      int x, int y,
 			      int width, int height)
@@ -1115,7 +1262,7 @@ gen2_check_card_format(struct sna *sna,
 			if (sna->kgem.gen >= 21)
 				return TRUE;
 
-			if ( source_is_covered(picture, x, y, w,h)) {
+			if (source_is_covered(picture, x, y, w,h)) {
 				channel->is_opaque = true;
 				return TRUE;
 			}
@@ -1143,34 +1290,40 @@ gen2_composite_picture(struct sna *sna,
 	     __FUNCTION__, x, y, w, h, dst_x, dst_y));
 
 	channel->is_solid = FALSE;
-	channel->card_format = -1;
+	channel->is_linear = FALSE;
 
 	if (sna_picture_is_solid(picture, &color))
 		return gen2_composite_solid_init(sna, channel, color);
 
-	if (picture->pDrawable == NULL) {
-		DBG(("%s -- fallback, unhandled source %d\n",
-		     __FUNCTION__, picture->pSourcePict->type));
+	if (!gen2_check_repeat(picture)) {
+		DBG(("%s -- fallback, unhandled repeat %d\n",
+		     __FUNCTION__, picture->repeat));
 		return sna_render_picture_fixup(sna, picture, channel,
 						x, y, w, h, dst_x, dst_y);
 	}
 
-	if (picture->alphaMap) {
-		DBG(("%s -- fallback, alphamap\n", __FUNCTION__));
+	if (!gen2_check_filter(picture)) {
+		DBG(("%s -- fallback, unhandled filter %d\n",
+		     __FUNCTION__, picture->filter));
 		return sna_render_picture_fixup(sna, picture, channel,
 						x, y, w, h, dst_x, dst_y);
 	}
 
-	if (!gen2_check_repeat(picture)) {
-		DBG(("%s -- fallback, unhandled repeat %d\n",
-		     __FUNCTION__, picture->repeat));
+	if (picture->pDrawable == NULL) {
+		if (picture->pSourcePict->type == SourcePictTypeLinear)
+			return gen2_composite_linear_init(sna, picture, channel,
+							  x, y,
+							  w, h,
+							  dst_x, dst_y);
+
+		DBG(("%s -- fallback, unhandled source %d\n",
+		     __FUNCTION__, picture->pSourcePict->type));
 		return sna_render_picture_fixup(sna, picture, channel,
 						x, y, w, h, dst_x, dst_y);
 	}
 
-	if (!gen2_check_filter(picture)) {
-		DBG(("%s -- fallback, unhandled filter %d\n",
-		     __FUNCTION__, picture->filter));
+	if (picture->alphaMap) {
+		DBG(("%s -- fallback, alphamap\n", __FUNCTION__));
 		return sna_render_picture_fixup(sna, picture, channel,
 						x, y, w, h, dst_x, dst_y);
 	}
@@ -1301,12 +1454,18 @@ is_solid(PicturePtr picture)
 }
 
 static bool
-is_gradient(PicturePtr picture)
+is_unhandled_gradient(PicturePtr picture)
 {
 	if (picture->pDrawable)
 		return FALSE;
 
-	return picture->pSourcePict->type != SourcePictTypeSolidFill;
+	switch (picture->pSourcePict->type) {
+	case SourcePictTypeSolidFill:
+	case SourcePictTypeLinear:
+		return FALSE;
+	default:
+		return TRUE;
+	}
 }
 
 static bool
@@ -1318,7 +1477,10 @@ has_alphamap(PicturePtr p)
 static bool
 source_fallback(PicturePtr p)
 {
-	return has_alphamap(p) || is_gradient(p) || !gen2_check_filter(p) || !gen2_check_repeat(p);
+	return (has_alphamap(p) ||
+		is_unhandled_gradient(p) ||
+		!gen2_check_filter(p) ||
+		!gen2_check_repeat(p));
 }
 
 static bool
@@ -1578,6 +1740,8 @@ gen2_render_composite(struct sna *sna,
 	} else {
 		if (tmp->src.is_solid)
 			tmp->prim_emit = gen2_emit_composite_primitive_constant;
+		else if (tmp->src.is_linear)
+			tmp->prim_emit = gen2_emit_composite_primitive_linear;
 		else if (tmp->src.transform == NULL)
 			tmp->prim_emit = gen2_emit_composite_primitive_identity;
 		else if (tmp->src.is_affine)
@@ -1644,6 +1808,38 @@ gen2_emit_composite_spans_primitive_constant(struct sna *sna,
 }
 
 fastcall static void
+gen2_emit_composite_spans_primitive_linear(struct sna *sna,
+					     const struct sna_composite_spans_op *op,
+					     const BoxRec *box,
+					     float opacity)
+{
+	union {
+		float f;
+		uint32_t u;
+	} alpha;
+
+	alpha.u = (uint8_t)(255 * opacity) << 24;
+
+	gen2_emit_composite_dstcoord(sna,
+				     op->base.dst.x + box->x2,
+				     op->base.dst.y + box->y2);
+	VERTEX(alpha.f);
+	gen2_emit_composite_linear(sna, &op->base.src, box->x2, box->y2);
+
+	gen2_emit_composite_dstcoord(sna,
+				     op->base.dst.x + box->x1,
+				     op->base.dst.y + box->y2);
+	VERTEX(alpha.f);
+	gen2_emit_composite_linear(sna, &op->base.src, box->x1, box->y2);
+
+	gen2_emit_composite_dstcoord(sna,
+				     op->base.dst.x + box->x1,
+				     op->base.dst.y + box->y1);
+	VERTEX(alpha.f);
+	gen2_emit_composite_linear(sna, &op->base.src, box->x1, box->y1);
+}
+
+fastcall static void
 gen2_emit_composite_spans_primitive_identity_source(struct sna *sna,
 						    const struct sna_composite_spans_op *op,
 						    const BoxRec *box,
@@ -1723,7 +1919,11 @@ gen2_emit_composite_spans_vertex(struct sna *sna,
 {
 	gen2_emit_composite_dstcoord(sna, x + op->base.dst.x, y + op->base.dst.y);
 	BATCH((uint8_t)(opacity * 255) << 24);
-	gen2_emit_composite_texcoord(sna, &op->base.src, x, y);
+	assert(!op->base.src.is_solid);
+	if (op->base.src.is_linear)
+		gen2_emit_composite_linear(sna, &op->base.src, x, y);
+	else
+		gen2_emit_composite_texcoord(sna, &op->base.src, x, y);
 }
 
 fastcall static void
@@ -1746,7 +1946,7 @@ gen2_emit_spans_pipeline(struct sna *sna,
 
 	cblend =
 		TB0C_LAST_STAGE | TB0C_RESULT_SCALE_1X | TB0C_OP_MODULATE |
-	       	TB0C_ARG1_SEL_DIFFUSE | TB0C_ARG1_REPLICATE_ALPHA |
+		TB0C_ARG1_SEL_DIFFUSE | TB0C_ARG1_REPLICATE_ALPHA |
 		TB0C_OUTPUT_WRITE_CURRENT;
 	ablend =
 		TB0A_RESULT_SCALE_1X | TB0A_OP_MODULATE |
@@ -1962,6 +2162,9 @@ gen2_render_composite_spans(struct sna *sna,
 	tmp->base.floats_per_vertex = 3;
 	if (tmp->base.src.is_solid) {
 		tmp->prim_emit = gen2_emit_composite_spans_primitive_constant;
+	} else if (tmp->base.src.is_linear) {
+		tmp->base.floats_per_vertex += 2;
+		tmp->prim_emit = gen2_emit_composite_spans_primitive_linear;
 	} else {
 		assert(tmp->base.src.bo);
 		tmp->base.floats_per_vertex += tmp->base.src.is_affine ? 2 : 3;
diff --git a/src/sna/sna_gradient.c b/src/sna/sna_gradient.c
index c870076..2aa9bbd 100644
--- a/src/sna/sna_gradient.c
+++ b/src/sna/sna_gradient.c
@@ -104,7 +104,7 @@ sna_render_get_gradient(struct sna *sna,
 	int i, width;
 	struct kgem_bo *bo;
 
-	DBG(("%s: %dx[%f:%x...%f:%x...%f:%x]\n", __FUNCTION__,
+	DBG(("%s: %dx[%f:%x ... %f:%x ... %f:%x]\n", __FUNCTION__,
 	     pattern->nstops,
 	     pattern->stops[0].x / 65536.,
 	     pattern->stops[0].color.alpha >> 8 << 24 |
diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h
index 2229c18..dfaa606 100644
--- a/src/sna/sna_render.h
+++ b/src/sna/sna_render.h
@@ -50,6 +50,7 @@ struct sna_composite_op {
 		uint32_t repeat;
 		uint32_t is_affine : 1;
 		uint32_t is_solid : 1;
+		uint32_t is_linear : 1;
 		uint32_t is_opaque : 1;
 		uint32_t alpha_fixup : 1;
 		uint32_t rb_reversed : 1;
@@ -59,6 +60,9 @@ struct sna_composite_op {
 		union {
 			struct {
 				uint32_t pixel;
+				float linear_dx;
+				float linear_dy;
+				float linear_offset;
 			} gen2;
 			struct gen3_shader_channel {
 				int type;


More information about the xorg-commit mailing list