xf86-video-intel: 6 commits - configure.ac src/sna/gen4_render.c src/sna/gen5_render.c src/sna/gen6_render.c src/sna/gen6_render.h src/sna/gen7_render.c src/sna/kgem.c src/sna/kgem.h src/sna/sna_dri.c src/sna/sna_render.h src/sna/sna_trapezoids.c

Chris Wilson ickle at kemper.freedesktop.org
Wed Jul 18 14:37:20 PDT 2012


 configure.ac             |   10 
 src/sna/gen4_render.c    |    4 
 src/sna/gen5_render.c    |    4 
 src/sna/gen6_render.c    |  670 ++++++++++++++++++++++-------------------------
 src/sna/gen6_render.h    |    4 
 src/sna/gen7_render.c    |  596 +++++++++++++++++++----------------------
 src/sna/kgem.c           |   54 +--
 src/sna/kgem.h           |    2 
 src/sna/sna_dri.c        |    3 
 src/sna/sna_render.h     |   11 
 src/sna/sna_trapezoids.c |   50 ++-
 11 files changed, 670 insertions(+), 738 deletions(-)

New commits:
commit 558c8251299b786cab1ac83dbd35f077224b5950
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jul 18 22:00:30 2012 +0100

    sna/gen4+: Drop unsupported source formats
    
    Once again I've confused existence of the enum with the ability of the
    sampler to read that format.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/gen4_render.c b/src/sna/gen4_render.c
index c985c8d..4a67728 100644
--- a/src/sna/gen4_render.c
+++ b/src/sna/gen4_render.c
@@ -527,14 +527,10 @@ static uint32_t gen4_get_card_format(PictFormat format)
 		return GEN4_SURFACEFORMAT_B10G10R10A2_UNORM;
 	case PICT_x2r10g10b10:
 		return GEN4_SURFACEFORMAT_B10G10R10X2_UNORM;
-	case PICT_a2b10g10r10:
-		return GEN4_SURFACEFORMAT_R10G10B10A2_UNORM;
 	case PICT_r8g8b8:
 		return GEN4_SURFACEFORMAT_R8G8B8_UNORM;
 	case PICT_r5g6b5:
 		return GEN4_SURFACEFORMAT_B5G6R5_UNORM;
-	case PICT_x1r5g5b5:
-		return GEN4_SURFACEFORMAT_B5G5R5X1_UNORM;
 	case PICT_a1r5g5b5:
 		return GEN4_SURFACEFORMAT_B5G5R5A1_UNORM;
 	case PICT_a8:
diff --git a/src/sna/gen5_render.c b/src/sna/gen5_render.c
index f611a51..51614d4 100644
--- a/src/sna/gen5_render.c
+++ b/src/sna/gen5_render.c
@@ -521,14 +521,10 @@ static uint32_t gen5_get_card_format(PictFormat format)
 		return GEN5_SURFACEFORMAT_B10G10R10A2_UNORM;
 	case PICT_x2r10g10b10:
 		return GEN5_SURFACEFORMAT_B10G10R10X2_UNORM;
-	case PICT_a2b10g10r10:
-		return GEN5_SURFACEFORMAT_R10G10B10A2_UNORM;
 	case PICT_r8g8b8:
 		return GEN5_SURFACEFORMAT_R8G8B8_UNORM;
 	case PICT_r5g6b5:
 		return GEN5_SURFACEFORMAT_B5G6R5_UNORM;
-	case PICT_x1r5g5b5:
-		return GEN5_SURFACEFORMAT_B5G5R5X1_UNORM;
 	case PICT_a1r5g5b5:
 		return GEN5_SURFACEFORMAT_B5G5R5A1_UNORM;
 	case PICT_a8:
diff --git a/src/sna/gen6_render.c b/src/sna/gen6_render.c
index 1ff54ac..834cab3 100644
--- a/src/sna/gen6_render.c
+++ b/src/sna/gen6_render.c
@@ -284,14 +284,10 @@ static uint32_t gen6_get_card_format(PictFormat format)
 		return GEN6_SURFACEFORMAT_B10G10R10A2_UNORM;
 	case PICT_x2r10g10b10:
 		return GEN6_SURFACEFORMAT_B10G10R10X2_UNORM;
-	case PICT_a2b10g10r10:
-		return GEN6_SURFACEFORMAT_R10G10B10A2_UNORM;
 	case PICT_r8g8b8:
 		return GEN6_SURFACEFORMAT_R8G8B8_UNORM;
 	case PICT_r5g6b5:
 		return GEN6_SURFACEFORMAT_B5G6R5_UNORM;
-	case PICT_x1r5g5b5:
-		return GEN6_SURFACEFORMAT_B5G5R5X1_UNORM;
 	case PICT_a1r5g5b5:
 		return GEN6_SURFACEFORMAT_B5G5R5A1_UNORM;
 	case PICT_a8:
diff --git a/src/sna/gen7_render.c b/src/sna/gen7_render.c
index cb497b9..aedc934 100644
--- a/src/sna/gen7_render.c
+++ b/src/sna/gen7_render.c
@@ -316,14 +316,10 @@ static uint32_t gen7_get_card_format(PictFormat format)
 		return GEN7_SURFACEFORMAT_B10G10R10A2_UNORM;
 	case PICT_x2r10g10b10:
 		return GEN7_SURFACEFORMAT_B10G10R10X2_UNORM;
-	case PICT_a2b10g10r10:
-		return GEN7_SURFACEFORMAT_R10G10B10A2_UNORM;
 	case PICT_r8g8b8:
 		return GEN7_SURFACEFORMAT_R8G8B8_UNORM;
 	case PICT_r5g6b5:
 		return GEN7_SURFACEFORMAT_B5G6R5_UNORM;
-	case PICT_x1r5g5b5:
-		return GEN7_SURFACEFORMAT_B5G5R5X1_UNORM;
 	case PICT_a1r5g5b5:
 		return GEN7_SURFACEFORMAT_B5G5R5A1_UNORM;
 	case PICT_a8:
commit 9f3b3098c9f870d303a9de2b9c0db119eff5a865
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jul 18 21:39:47 2012 +0100

    sna/dri: Allow DRI2 to be loaded even if we are wedged
    
    Just because the GPU is spitting EIO at us does not necessarily imply
    that a DRI client will also suffer. Spit out a warning for later bug
    reporting and let them find out for themselves!
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index 65c3550..4ced0eb 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -2146,8 +2146,7 @@ bool sna_dri_open(struct sna *sna, ScreenPtr screen)
 
 	if (wedged(sna)) {
 		xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
-			   "cannot enable DRI2 whilst the GPU is wedged\n");
-		return false;
+			   "loading DRI2 whilst the GPU is wedged.\n");
 	}
 
 	if (xf86LoaderCheckSymbol("DRI2Version"))
commit 15b7191fd363e9e6083844a218e25419695d55f1
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jul 18 12:59:41 2012 +0100

    sna/gen6: Micro-optimise render copy emission
    
    Backport of the changes made for IVB.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/gen6_render.c b/src/sna/gen6_render.c
index c635f4d..1ff54ac 100644
--- a/src/sna/gen6_render.c
+++ b/src/sna/gen6_render.c
@@ -48,7 +48,8 @@
 #define NO_COPY_BOXES 0
 #define NO_FILL 0
 #define NO_FILL_BOXES 0
-#define NO_CLEAR 0
+#define NO_FILL_ONE 0
+#define NO_FILL_CLEAR 0
 
 #define NO_RING_SWITCH 0
 
@@ -134,28 +135,29 @@ static const uint32_t ps_kernel_planar[][4] = {
 #include "exa_wm_write.g6b"
 };
 
-#define KERNEL(kernel_enum, kernel, masked) \
-    [GEN6_WM_KERNEL_##kernel_enum] = {#kernel_enum, kernel, sizeof(kernel), masked}
+#define KERNEL(kernel_enum, kernel, ns, ni) \
+    [GEN6_WM_KERNEL_##kernel_enum] = {#kernel_enum, kernel, sizeof(kernel), ns, ni}
 static const struct wm_kernel_info {
 	const char *name;
 	const void *data;
 	unsigned int size;
-	bool has_mask;
+	unsigned int num_surfaces;
+	unsigned int num_inputs;
 } wm_kernels[] = {
-	KERNEL(NOMASK, ps_kernel_nomask_affine, false),
-	KERNEL(NOMASK_PROJECTIVE, ps_kernel_nomask_projective, false),
+	KERNEL(NOMASK, ps_kernel_nomask_affine, 2, 1),
+	KERNEL(NOMASK_PROJECTIVE, ps_kernel_nomask_projective, 2, 1),
 
-	KERNEL(MASK, ps_kernel_masknoca_affine, true),
-	KERNEL(MASK_PROJECTIVE, ps_kernel_masknoca_projective, true),
+	KERNEL(MASK, ps_kernel_masknoca_affine, 3, 2),
+	KERNEL(MASK_PROJECTIVE, ps_kernel_masknoca_projective, 3, 2),
 
-	KERNEL(MASKCA, ps_kernel_maskca_affine, true),
-	KERNEL(MASKCA_PROJECTIVE, ps_kernel_maskca_projective, true),
+	KERNEL(MASKCA, ps_kernel_maskca_affine, 3, 2),
+	KERNEL(MASKCA_PROJECTIVE, ps_kernel_maskca_projective, 3, 2),
 
-	KERNEL(MASKCA_SRCALPHA, ps_kernel_maskca_srcalpha_affine, true),
-	KERNEL(MASKCA_SRCALPHA_PROJECTIVE, ps_kernel_maskca_srcalpha_projective, true),
+	KERNEL(MASKCA_SRCALPHA, ps_kernel_maskca_srcalpha_affine, 3, 2),
+	KERNEL(MASKCA_SRCALPHA_PROJECTIVE, ps_kernel_maskca_srcalpha_projective, 3, 2),
 
-	KERNEL(VIDEO_PLANAR, ps_kernel_planar, false),
-	KERNEL(VIDEO_PACKED, ps_kernel_packed, false),
+	KERNEL(VIDEO_PLANAR, ps_kernel_planar, 7, 1),
+	KERNEL(VIDEO_PACKED, ps_kernel_packed, 2, 1),
 };
 #undef KERNEL
 
@@ -193,8 +195,32 @@ static const struct blendinfo {
 #define BLEND_OFFSET(s, d) \
 	(((s) * GEN6_BLENDFACTOR_COUNT + (d)) * GEN6_BLEND_STATE_PADDED_SIZE)
 
+#define NO_BLEND BLEND_OFFSET(GEN6_BLENDFACTOR_ONE, GEN6_BLENDFACTOR_ZERO)
+#define CLEAR BLEND_OFFSET(GEN6_BLENDFACTOR_ZERO, GEN6_BLENDFACTOR_ZERO)
+
 #define SAMPLER_OFFSET(sf, se, mf, me) \
-	(((((sf) * EXTEND_COUNT + (se)) * FILTER_COUNT + (mf)) * EXTEND_COUNT + (me)) * 2 * sizeof(struct gen6_sampler_state))
+	(((((sf) * EXTEND_COUNT + (se)) * FILTER_COUNT + (mf)) * EXTEND_COUNT + (me) + 2) * 2 * sizeof(struct gen6_sampler_state))
+
+#define VERTEX_2s2s 4
+
+#define COPY_SAMPLER 0
+#define COPY_VERTEX VERTEX_2s2s
+#define COPY_FLAGS(a) GEN6_SET_FLAGS(COPY_SAMPLER, (a) == GXcopy ? NO_BLEND : CLEAR, GEN6_WM_KERNEL_NOMASK, COPY_VERTEX)
+
+#define FILL_SAMPLER (2 * sizeof(struct gen6_sampler_state))
+#define FILL_VERTEX VERTEX_2s2s
+#define FILL_FLAGS(op, format) GEN6_SET_FLAGS(FILL_SAMPLER, gen6_get_blend((op), false, (format)), GEN6_WM_KERNEL_NOMASK, FILL_VERTEX)
+#define FILL_FLAGS_NOBLEND GEN6_SET_FLAGS(FILL_SAMPLER, NO_BLEND, GEN6_WM_KERNEL_NOMASK, FILL_VERTEX)
+
+#define VIDEO_SAMPLER \
+	SAMPLER_OFFSET(SAMPLER_FILTER_BILINEAR, SAMPLER_EXTEND_PAD, \
+		       SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE)
+
+#define GEN6_SAMPLER(f) (((f) >> 16) & 0xfff0)
+#define GEN6_BLEND(f) (((f) >> 0) & 0xfff0)
+#define GEN6_KERNEL(f) (((f) >> 16) & 0xf)
+#define GEN6_VERTEX(f) (((f) >> 0) & 0xf)
+#define GEN6_SET_FLAGS(S, B, K, V)  (((S) | (K)) << 16 | ((B) | (V)))
 
 #define OUT_BATCH(v) batch_emit(sna, v)
 #define OUT_VERTEX(x,y) vertex_emit_2s(sna, x,y)
@@ -545,20 +571,14 @@ gen6_emit_invariant(struct sna *sna)
 }
 
 static bool
-gen6_emit_cc(struct sna *sna,
-	     int op, bool has_component_alpha, uint32_t dst_format)
+gen6_emit_cc(struct sna *sna, int blend)
 {
 	struct gen6_render_state *render = &sna->render_state.gen6;
-	uint32_t blend;
-
-	blend = gen6_get_blend(op, has_component_alpha, dst_format);
 
-	DBG(("%s(op=%d, ca=%d, format=%x): new=%x, current=%x\n",
-	     __FUNCTION__,
-	     op, has_component_alpha, dst_format,
-	     blend, render->blend));
 	if (render->blend == blend)
-		return op <= PictOpSrc;
+		return blend != NO_BLEND;
+
+	DBG(("%s: blend = %x\n", __FUNCTION__, blend));
 
 	OUT_BATCH(GEN6_3DSTATE_CC_STATE_POINTERS | (4 - 2));
 	OUT_BATCH((render->cc_blend + blend) | 1);
@@ -571,22 +591,19 @@ gen6_emit_cc(struct sna *sna,
 	}
 
 	render->blend = blend;
-	return op <= PictOpSrc;
+	return blend != NO_BLEND;
 }
 
 static void
 gen6_emit_sampler(struct sna *sna, uint32_t state)
 {
-	assert(state <
-	       2 * sizeof(struct gen6_sampler_state) *
-	       FILTER_COUNT * EXTEND_COUNT *
-	       FILTER_COUNT * EXTEND_COUNT);
-
 	if (sna->render_state.gen6.samplers == state)
 		return;
 
 	sna->render_state.gen6.samplers = state;
 
+	DBG(("%s: sampler = %x\n", __FUNCTION__, state));
+
 	OUT_BATCH(GEN6_3DSTATE_SAMPLER_STATE_POINTERS |
 		  GEN6_3DSTATE_SAMPLER_STATE_MODIFY_PS |
 		  (4 - 2));
@@ -633,25 +650,28 @@ gen6_emit_sf(struct sna *sna, bool has_mask)
 }
 
 static void
-gen6_emit_wm(struct sna *sna, unsigned int kernel, int nr_surfaces, int nr_inputs)
+gen6_emit_wm(struct sna *sna, unsigned int kernel)
 {
 	if (sna->render_state.gen6.kernel == kernel)
 		return;
 
 	sna->render_state.gen6.kernel = kernel;
 
-	DBG(("%s: switching to %s\n", __FUNCTION__, wm_kernels[kernel].name));
+	DBG(("%s: switching to %s, num_surfaces=%d\n",
+	     __FUNCTION__,
+	     wm_kernels[kernel].name,
+	     wm_kernels[kernel].num_surfaces));
 
 	OUT_BATCH(GEN6_3DSTATE_WM | (9 - 2));
 	OUT_BATCH(sna->render_state.gen6.wm_kernel[kernel]);
 	OUT_BATCH(1 << GEN6_3DSTATE_WM_SAMPLER_COUNT_SHIFT |
-		  nr_surfaces << GEN6_3DSTATE_WM_BINDING_TABLE_ENTRY_COUNT_SHIFT);
+		  wm_kernels[kernel].num_surfaces << GEN6_3DSTATE_WM_BINDING_TABLE_ENTRY_COUNT_SHIFT);
 	OUT_BATCH(0);
 	OUT_BATCH(6 << GEN6_3DSTATE_WM_DISPATCH_START_GRF_0_SHIFT); /* DW4 */
 	OUT_BATCH((40 - 1) << GEN6_3DSTATE_WM_MAX_THREADS_SHIFT |
 		  GEN6_3DSTATE_WM_DISPATCH_ENABLE |
 		  GEN6_3DSTATE_WM_16_DISPATCH_ENABLE);
-	OUT_BATCH(nr_inputs << GEN6_3DSTATE_WM_NUM_SF_OUTPUTS_SHIFT |
+	OUT_BATCH(wm_kernels[kernel].num_inputs << GEN6_3DSTATE_WM_NUM_SF_OUTPUTS_SHIFT |
 		  GEN6_3DSTATE_WM_PERSPECTIVE_PIXEL_BARYCENTRIC);
 	OUT_BATCH(0);
 	OUT_BATCH(0);
@@ -737,22 +757,59 @@ gen6_emit_vertex_elements(struct sna *sna,
 	 *    texture coordinate 1 if (has_mask is true): same as above
 	 */
 	struct gen6_render_state *render = &sna->render_state.gen6;
-	int nelem = op->mask.bo ? 2 : 1;
-	int selem = op->is_affine ? 2 : 3;
+	int nelem, selem;
 	uint32_t w_component;
 	uint32_t src_format;
-	int id = op->u.gen6.ve_id;
+	int id = GEN6_VERTEX(op->u.gen6.flags);
 
 	if (render->ve_id == id)
 		return;
 	render->ve_id = id;
 
+	switch (id) {
+	case VERTEX_2s2s:
+		DBG(("%s: setup COPY\n", __FUNCTION__));
+
+		OUT_BATCH(GEN6_3DSTATE_VERTEX_ELEMENTS |
+			  ((2 * (1 + 2)) + 1 - 2));
+
+		OUT_BATCH(id << VE0_VERTEX_BUFFER_INDEX_SHIFT | VE0_VALID |
+			  GEN6_SURFACEFORMAT_R32G32B32A32_FLOAT << VE0_FORMAT_SHIFT |
+			  0 << VE0_OFFSET_SHIFT);
+		OUT_BATCH(GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_0_SHIFT |
+			  GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_1_SHIFT |
+			  GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_2_SHIFT |
+			  GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_3_SHIFT);
+
+		/* x,y */
+		OUT_BATCH(id << VE0_VERTEX_BUFFER_INDEX_SHIFT | VE0_VALID |
+			  GEN6_SURFACEFORMAT_R16G16_SSCALED << VE0_FORMAT_SHIFT |
+			  0 << VE0_OFFSET_SHIFT); /* offsets vb in bytes */
+		OUT_BATCH(GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT |
+			  GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT |
+			  GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_2_SHIFT |
+			  GEN6_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT);
+
+		/* u0, v0, w0 */
+		OUT_BATCH(id << VE0_VERTEX_BUFFER_INDEX_SHIFT | VE0_VALID |
+			  GEN6_SURFACEFORMAT_R16G16_SSCALED << VE0_FORMAT_SHIFT |
+			  4 << VE0_OFFSET_SHIFT);	/* offset vb in bytes */
+		OUT_BATCH(GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT |
+			  GEN6_VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT |
+			  GEN6_VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_2_SHIFT |
+			  GEN6_VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT);
+		return;
+	}
+
+	nelem = op->mask.bo ? 2 : 1;
 	if (op->is_affine) {
 		src_format = GEN6_SURFACEFORMAT_R32G32_FLOAT;
 		w_component = GEN6_VFCOMPONENT_STORE_1_FLT;
+		selem = 2;
 	} else {
 		src_format = GEN6_SURFACEFORMAT_R32G32B32_FLOAT;
 		w_component = GEN6_VFCOMPONENT_STORE_SRC;
+		selem = 3;
 	}
 
 	/* The VUE layout
@@ -822,19 +879,13 @@ gen6_emit_state(struct sna *sna,
 {
 	bool need_stall = wm_binding_table & 1;
 
-	if (gen6_emit_cc(sna, op->op, op->has_component_alpha, op->dst.format))
+	if (gen6_emit_cc(sna, GEN6_BLEND(op->u.gen6.flags)))
 		need_stall = false;
-	gen6_emit_sampler(sna,
-			  SAMPLER_OFFSET(op->src.filter,
-					 op->src.repeat,
-					 op->mask.filter,
-					 op->mask.repeat));
+	gen6_emit_sampler(sna, GEN6_SAMPLER(op->u.gen6.flags));
 	gen6_emit_sf(sna, op->mask.bo != NULL);
-	gen6_emit_wm(sna,
-		     op->u.gen6.wm_kernel,
-		     op->u.gen6.nr_surfaces,
-		     op->u.gen6.nr_inputs);
+	gen6_emit_wm(sna, GEN6_KERNEL(op->u.gen6.flags));
 	gen6_emit_vertex_elements(sna, op);
+
 	need_stall |= gen6_emit_binding_table(sna, wm_binding_table & ~1);
 	if (gen6_emit_drawing_rectangle(sna, op))
 		need_stall = false;
@@ -867,12 +918,11 @@ static void gen6_magic_ca_pass(struct sna *sna,
 
 	gen6_emit_flush(sna);
 
-	gen6_emit_cc(sna, PictOpAdd, true, op->dst.format);
+	gen6_emit_cc(sna, gen6_get_blend(PictOpAdd, true, op->dst.format));
 	gen6_emit_wm(sna,
 		     gen6_choose_composite_kernel(PictOpAdd,
 						  true, true,
-						  op->is_affine),
-		     3, 2);
+						  op->is_affine));
 
 	OUT_BATCH(GEN6_3DPRIMITIVE |
 		  GEN6_3DPRIMITIVE_VERTEX_SEQUENTIAL |
@@ -932,7 +982,7 @@ static int gen6_vertex_finish(struct sna *sna)
 						       sna->render.vertex_reloc[i]+1,
 						       bo,
 						       I915_GEM_DOMAIN_VERTEX << 16,
-						       0 + sna->render.vertex_used * 4 - 1);
+						       sna->render.vertex_used * 4 - 1);
 				sna->render.vertex_reloc[i] = 0;
 			}
 		}
@@ -1116,6 +1166,24 @@ sampler_state_init(struct gen6_sampler_state *sampler_state,
 	}
 }
 
+static void
+sampler_copy_init(struct gen6_sampler_state *ss)
+{
+	sampler_state_init(ss, SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE);
+	ss->ss3.non_normalized_coord = 1;
+
+	sampler_state_init(ss+1, SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE);
+}
+
+static void
+sampler_fill_init(struct gen6_sampler_state *ss)
+{
+	sampler_state_init(ss, SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_REPEAT);
+	ss->ss3.non_normalized_coord = 1;
+
+	sampler_state_init(ss+1, SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE);
+}
+
 static uint32_t gen6_create_cc_viewport(struct sna_static_stream *stream)
 {
 	struct gen6_cc_viewport vp;
@@ -1291,7 +1359,6 @@ gen6_emit_composite_primitive_simple_source(struct sna *sna,
 	v[8] = ((r->src.y + ty) * yy + y0) * sy;
 }
 
-
 fastcall static void
 gen6_emit_composite_primitive_affine_source(struct sna *sna,
 					    const struct sna_composite_op *op,
@@ -1444,7 +1511,7 @@ gen6_emit_composite_primitive(struct sna *sna,
 static void gen6_emit_vertex_buffer(struct sna *sna,
 				    const struct sna_composite_op *op)
 {
-	int id = op->u.gen6.ve_id;
+	int id = GEN6_VERTEX(op->u.gen6.flags);
 
 	OUT_BATCH(GEN6_3DSTATE_VERTEX_BUFFERS | 3);
 	OUT_BATCH(id << VB0_BUFFER_INDEX_SHIFT | VB0_VERTEXDATA |
@@ -1489,7 +1556,7 @@ static void gen6_emit_primitive(struct sna *sna)
 static bool gen6_rectangle_begin(struct sna *sna,
 				 const struct sna_composite_op *op)
 {
-	int id = 1 << op->u.gen6.ve_id;
+	int id = 1 << GEN6_VERTEX(op->u.gen6.flags);
 	int ndwords;
 
 	ndwords = op->need_magic_ca_pass ? 60 : 6;
@@ -1892,7 +1959,6 @@ gen6_render_video(struct sna *sna,
 
 	memset(&tmp, 0, sizeof(tmp));
 
-	tmp.op = PictOpSrc;
 	tmp.dst.pixmap = pixmap;
 	tmp.dst.width  = pixmap->drawable.width;
 	tmp.dst.height = pixmap->drawable.height;
@@ -1900,24 +1966,17 @@ gen6_render_video(struct sna *sna,
 	tmp.dst.bo = priv->gpu_bo;
 
 	tmp.src.bo = frame->bo;
-	tmp.src.filter = SAMPLER_FILTER_BILINEAR;
-	tmp.src.repeat = SAMPLER_EXTEND_PAD;
-
 	tmp.mask.bo = NULL;
 
-	tmp.is_affine = true;
 	tmp.floats_per_vertex = 3;
 	tmp.floats_per_rect = 9;
 
-	if (is_planar_fourcc(frame->id)) {
-		tmp.u.gen6.wm_kernel = GEN6_WM_KERNEL_VIDEO_PLANAR;
-		tmp.u.gen6.nr_surfaces = 7;
-	} else {
-		tmp.u.gen6.wm_kernel = GEN6_WM_KERNEL_VIDEO_PACKED;
-		tmp.u.gen6.nr_surfaces = 2;
-	}
-	tmp.u.gen6.nr_inputs = 1;
-	tmp.u.gen6.ve_id = 1;
+	tmp.u.gen6.flags =
+		GEN6_SET_FLAGS(VIDEO_SAMPLER, NO_BLEND,
+			       is_planar_fourcc(frame->id) ?
+			       GEN6_WM_KERNEL_VIDEO_PLANAR :
+			       GEN6_WM_KERNEL_VIDEO_PACKED,
+			       1);
 	tmp.priv = frame;
 
 	kgem_set_mode(&sna->kgem, KGEM_RENDER);
@@ -2568,17 +2627,6 @@ gen6_render_composite(struct sna *sna,
 	if (op >= ARRAY_SIZE(gen6_blend_op))
 		return false;
 
-#if NO_COMPOSITE
-	if (mask)
-		return false;
-
-	return sna_blt_composite(sna, op,
-				 src, dst,
-				 src_x, src_y,
-				 dst_x, dst_y,
-				 width, height, tmp);
-#endif
-
 	DBG(("%s: %dx%d, current mode=%d\n", __FUNCTION__,
 	     width, height, sna->kgem.ring));
 
@@ -2734,14 +2782,19 @@ gen6_render_composite(struct sna *sna,
 	}
 	tmp->floats_per_rect = 3 * tmp->floats_per_vertex;
 
-	tmp->u.gen6.wm_kernel =
-		gen6_choose_composite_kernel(tmp->op,
-					     tmp->mask.bo != NULL,
-					     tmp->has_component_alpha,
-					     tmp->is_affine);
-	tmp->u.gen6.nr_surfaces = 2 + (tmp->mask.bo != NULL);
-	tmp->u.gen6.nr_inputs = 1 + (tmp->mask.bo != NULL);
-	tmp->u.gen6.ve_id = gen6_choose_composite_vertex_buffer(tmp);
+	tmp->u.gen6.flags =
+		GEN6_SET_FLAGS(SAMPLER_OFFSET(tmp->src.filter,
+					      tmp->src.repeat,
+					      tmp->mask.filter,
+					      tmp->mask.repeat),
+			       gen6_get_blend(tmp->op,
+					      tmp->has_component_alpha,
+					      tmp->dst.format),
+			       gen6_choose_composite_kernel(tmp->op,
+							    tmp->mask.bo != NULL,
+							    tmp->has_component_alpha,
+							    tmp->is_affine),
+			       gen6_choose_composite_vertex_buffer(tmp));
 
 	tmp->blt   = gen6_render_composite_blt;
 	tmp->box   = gen6_render_composite_box;
@@ -2784,8 +2837,6 @@ gen6_composite_alpha_gradient_init(struct sna *sna,
 {
 	DBG(("%s\n", __FUNCTION__));
 
-	channel->filter = PictFilterNearest;
-	channel->repeat = RepeatPad;
 	channel->is_affine = true;
 	channel->is_solid  = false;
 	channel->transform = NULL;
@@ -3100,13 +3151,11 @@ gen6_render_composite_spans(struct sna *sna,
 		break;
 	}
 
-	tmp->base.mask.bo = NULL;
-
 	tmp->base.is_affine = tmp->base.src.is_affine;
-	tmp->base.has_component_alpha = false;
 	tmp->base.need_magic_ca_pass = false;
 
-	gen6_composite_alpha_gradient_init(sna, &tmp->base.mask);
+	if (!gen6_composite_alpha_gradient_init(sna, &tmp->base.mask))
+		goto cleanup_src;
 
 	tmp->prim_emit = gen6_emit_composite_spans_primitive;
 	if (tmp->base.src.is_solid) {
@@ -3125,13 +3174,16 @@ gen6_render_composite_spans(struct sna *sna,
 	tmp->base.floats_per_vertex = 5 + 2*!tmp->base.is_affine;
 	tmp->base.floats_per_rect = 3 * tmp->base.floats_per_vertex;
 
-	tmp->base.u.gen6.wm_kernel =
-		gen6_choose_composite_kernel(tmp->base.op,
-					     true, false,
-					     tmp->base.is_affine);
-	tmp->base.u.gen6.nr_surfaces = 3;
-	tmp->base.u.gen6.nr_inputs = 2;
-	tmp->base.u.gen6.ve_id = 1 << 1 | tmp->base.is_affine;
+	tmp->base.u.gen6.flags =
+		GEN6_SET_FLAGS(SAMPLER_OFFSET(tmp->base.src.filter,
+					      tmp->base.src.repeat,
+					      SAMPLER_FILTER_NEAREST,
+					      SAMPLER_EXTEND_PAD),
+			       gen6_get_blend(tmp->base.op, false, tmp->base.dst.format),
+			       gen6_choose_composite_kernel(tmp->base.op,
+							    true, false,
+							    tmp->base.is_affine),
+			       1 << 1 | tmp->base.is_affine);
 
 	tmp->box   = gen6_render_composite_spans_box;
 	tmp->boxes = gen6_render_composite_spans_boxes;
@@ -3258,17 +3310,6 @@ gen6_render_copy_boxes(struct sna *sna, uint8_t alu,
 {
 	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, alu=%x, self-copy=%d, overlaps? %d\n",
 	     __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy, n, alu,
 	     src_bo == dst_bo,
@@ -3309,7 +3350,6 @@ fallback_blt:
 	if (!gen6_check_format(tmp.src.pict_format))
 		goto fallback_blt;
 
-	tmp.op = alu == GXcopy ? PictOpSrc : PictOpClear;
 	tmp.dst.pixmap = dst;
 	tmp.dst.width  = dst->drawable.width;
 	tmp.dst.height = dst->drawable.height;
@@ -3333,16 +3373,20 @@ fallback_blt:
 			if (box[i].y2 > extents.y2)
 				extents.y2 = box[i].y2;
 		}
+
 		if (!sna_render_composite_redirect(sna, &tmp,
 						   extents.x1 + dst_dx,
 						   extents.y1 + dst_dy,
 						   extents.x2 - extents.x1,
 						   extents.y2 - extents.y1))
 			goto fallback_tiled;
+
+		dst_dx += tmp.dst.x;
+		dst_dy += tmp.dst.y;
+
+		tmp.dst.x = tmp.dst.y = 0;
 	}
 
-	tmp.src.filter = SAMPLER_FILTER_NEAREST;
-	tmp.src.repeat = SAMPLER_EXTEND_NONE;
 	tmp.src.card_format = gen6_get_card_format(tmp.src.pict_format);
 	if (too_large(src->drawable.width, src->drawable.height)) {
 		BoxRec extents = box[0];
@@ -3368,34 +3412,30 @@ fallback_blt:
 			DBG(("%s: unable to extract partial pixmap\n", __FUNCTION__));
 			goto fallback_tiled_dst;
 		}
+
+		src_dx += tmp.src.offset[0];
+		src_dy += tmp.src.offset[1];
 	} else {
-		tmp.src.bo = kgem_bo_reference(src_bo);
+		tmp.src.bo = src_bo;
 		tmp.src.width  = src->drawable.width;
 		tmp.src.height = src->drawable.height;
-		tmp.src.offset[0] = tmp.src.offset[1] = 0;
-		tmp.src.scale[0] = 1.f/src->drawable.width;
-		tmp.src.scale[1] = 1.f/src->drawable.height;
 	}
 
 	tmp.mask.bo = NULL;
-	tmp.mask.filter = SAMPLER_FILTER_NEAREST;
-	tmp.mask.repeat = SAMPLER_EXTEND_NONE;
 
-	tmp.is_affine = true;
-	tmp.floats_per_vertex = 3;
-	tmp.floats_per_rect = 9;
-	tmp.has_component_alpha = 0;
+	tmp.floats_per_vertex = 2;
+	tmp.floats_per_rect = 6;
 	tmp.need_magic_ca_pass = 0;
 
-	tmp.u.gen6.wm_kernel = GEN6_WM_KERNEL_NOMASK;
-	tmp.u.gen6.nr_surfaces = 2;
-	tmp.u.gen6.nr_inputs = 1;
-	tmp.u.gen6.ve_id = 1;
+	tmp.u.gen6.flags = COPY_FLAGS(alu);
+	assert(GEN6_KERNEL(tmp.u.gen6.flags) == GEN6_WM_KERNEL_NOMASK);
+	assert(GEN6_SAMPLER(tmp.u.gen6.flags) == COPY_SAMPLER);
+	assert(GEN6_VERTEX(tmp.u.gen6.flags) == COPY_VERTEX);
 
 	kgem_set_mode(&sna->kgem, KGEM_RENDER);
-	if (!kgem_check_bo(&sna->kgem, dst_bo, src_bo, NULL)) {
+	if (!kgem_check_bo(&sna->kgem, tmp.dst.bo, tmp.src.bo, NULL)) {
 		kgem_submit(&sna->kgem);
-		if (!kgem_check_bo(&sna->kgem, dst_bo, src_bo, NULL)) {
+		if (!kgem_check_bo(&sna->kgem, tmp.dst.bo, tmp.src.bo, NULL)) {
 			DBG(("%s: too large for a single operation\n",
 			     __FUNCTION__));
 			goto fallback_tiled_src;
@@ -3403,52 +3443,47 @@ fallback_blt:
 		_kgem_set_mode(&sna->kgem, KGEM_RENDER);
 	}
 
-	dst_dx += tmp.dst.x;
-	dst_dy += tmp.dst.y;
-	tmp.dst.x = tmp.dst.y = 0;
-
-	src_dx += tmp.src.offset[0];
-	src_dy += tmp.src.offset[1];
-
 	gen6_emit_copy_state(sna, &tmp);
 	gen6_align_vertex(sna, &tmp);
 
 	do {
-		float *v;
-		int n_this_time = gen6_get_rectangles(sna, &tmp, n,
-						      gen6_emit_copy_state);
+		int16_t *v;
+		int n_this_time;
+
+		n_this_time = gen6_get_rectangles(sna, &tmp, n,
+						  gen6_emit_copy_state);
 		n -= n_this_time;
 
-		v = sna->render.vertices + sna->render.vertex_used;
-		sna->render.vertex_used += 9 * n_this_time;
+		v = (int16_t *)(sna->render.vertices + sna->render.vertex_used);
+		sna->render.vertex_used += 6 * n_this_time;
+		assert(sna->render.vertex_used <= sna->render.vertex_size);
 		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));
-			v[0] = pack_2s(box->x2 + dst_dx, box->y2 + dst_dy);
-			v[3] = pack_2s(box->x1 + dst_dx, box->y2 + dst_dy);
-			v[6] = pack_2s(box->x1 + dst_dx, box->y1 + dst_dy);
-
-			v[1] = (box->x2 + src_dx) * tmp.src.scale[0];
-			v[7] = v[4] = (box->x1 + src_dx) * tmp.src.scale[0];
-
-			v[5] = v[2] = (box->y2 + src_dy) * tmp.src.scale[1];
-			v[8] = (box->y1 + src_dy) * tmp.src.scale[1];
-
-			v += 9;
-			box++;
+			v[0] = box->x2 + dst_dx;
+			v[2] = box->x2 + src_dx;
+			v[1]  = v[5] = box->y2 + dst_dy;
+			v[3]  = v[7] = box->y2 + src_dy;
+			v[8]  = v[4] = box->x1 + dst_dx;
+			v[10] = v[6] = box->x1 + src_dx;
+			v[9]  = box->y1 + dst_dy;
+			v[11] = box->y1 + src_dy;
+			v += 12; box++;
 		} while (--n_this_time);
 	} while (n);
 
 	gen6_vertex_flush(sna);
 	sna_render_composite_redirect_done(sna, &tmp);
-	kgem_bo_destroy(&sna->kgem, tmp.src.bo);
+	if (tmp.src.bo != src_bo)
+		kgem_bo_destroy(&sna->kgem, tmp.src.bo);
 	return true;
 
 fallback_tiled_src:
-	kgem_bo_destroy(&sna->kgem, tmp.src.bo);
+	if (tmp.src.bo != src_bo)
+		kgem_bo_destroy(&sna->kgem, tmp.src.bo);
 fallback_tiled_dst:
 	if (tmp.redirect.real_bo)
 		kgem_bo_destroy(&sna->kgem, tmp.dst.bo);
@@ -3466,19 +3501,20 @@ gen6_render_copy_blt(struct sna *sna,
 		     int16_t w,  int16_t h,
 		     int16_t dx, int16_t dy)
 {
-	gen6_get_rectangles(sna, &op->base, 1, gen6_emit_copy_state);
+	int16_t *v;
 
-	OUT_VERTEX(dx+w, dy+h);
-	OUT_VERTEX_F((sx+w)*op->base.src.scale[0]);
-	OUT_VERTEX_F((sy+h)*op->base.src.scale[1]);
+	gen6_get_rectangles(sna, &op->base, 1, gen6_emit_copy_state);
 
-	OUT_VERTEX(dx, dy+h);
-	OUT_VERTEX_F(sx*op->base.src.scale[0]);
-	OUT_VERTEX_F((sy+h)*op->base.src.scale[1]);
+	v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
+	sna->render.vertex_used += 6;
+	assert(sna->render.vertex_used <= sna->render.vertex_size);
 
-	OUT_VERTEX(dx, dy);
-	OUT_VERTEX_F(sx*op->base.src.scale[0]);
-	OUT_VERTEX_F(sy*op->base.src.scale[1]);
+	v[0]  = dx+w; v[1]  = dy+h;
+	v[2]  = sx+w; v[3]  = sy+h;
+	v[4]  = dx;   v[5]  = dy+h;
+	v[6]  = sx;   v[7]  = sy+h;
+	v[8]  = dx;   v[9]  = dy;
+	v[10] = sx;   v[11] = sy;
 }
 
 static void
@@ -3496,16 +3532,6 @@ gen6_render_copy(struct sna *sna, uint8_t alu,
 		 PixmapPtr dst, struct kgem_bo *dst_bo,
 		 struct sna_copy_op *op)
 {
-#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,
-			    op);
-#endif
-
 	DBG(("%s (alu=%d, src=(%dx%d), dst=(%dx%d))\n",
 	     __FUNCTION__, alu,
 	     src->drawable.width, src->drawable.height,
@@ -3541,8 +3567,6 @@ fallback:
 	if (!gen6_check_format(op->base.src.pict_format))
 		goto fallback;
 
-	op->base.op = PictOpSrc;
-
 	op->base.dst.pixmap = dst;
 	op->base.dst.width  = dst->drawable.width;
 	op->base.dst.height = dst->drawable.height;
@@ -3553,21 +3577,16 @@ fallback:
 		gen6_get_card_format(op->base.src.pict_format);
 	op->base.src.width  = src->drawable.width;
 	op->base.src.height = src->drawable.height;
-	op->base.src.scale[0] = 1.f/src->drawable.width;
-	op->base.src.scale[1] = 1.f/src->drawable.height;
-	op->base.src.filter = SAMPLER_FILTER_NEAREST;
-	op->base.src.repeat = SAMPLER_EXTEND_NONE;
 
 	op->base.mask.bo = NULL;
 
-	op->base.is_affine = true;
-	op->base.floats_per_vertex = 3;
-	op->base.floats_per_rect = 9;
+	op->base.floats_per_vertex = 2;
+	op->base.floats_per_rect = 6;
 
-	op->base.u.gen6.wm_kernel = GEN6_WM_KERNEL_NOMASK;
-	op->base.u.gen6.nr_surfaces = 2;
-	op->base.u.gen6.nr_inputs = 1;
-	op->base.u.gen6.ve_id = 1;
+	op->base.u.gen6.flags = COPY_FLAGS(alu);
+	assert(GEN6_KERNEL(op->base.u.gen6.flags) == GEN6_WM_KERNEL_NOMASK);
+	assert(GEN6_SAMPLER(op->base.u.gen6.flags) == COPY_SAMPLER);
+	assert(GEN6_VERTEX(op->base.u.gen6.flags) == COPY_VERTEX);
 
 	kgem_set_mode(&sna->kgem, KGEM_RENDER);
 	if (!kgem_check_bo(&sna->kgem, dst_bo, src_bo, NULL)) {
@@ -3678,27 +3697,21 @@ gen6_render_fill_boxes(struct sna *sna,
 						     dst, dst_bo, box, n);
 	}
 
-#if NO_FILL_BOXES
-	return false;
-#endif
-
 	if (op == PictOpClear) {
 		pixel = 0;
 		op = PictOpSrc;
 	} else if (!sna_get_pixel_from_rgba(&pixel,
-				     color->red,
-				     color->green,
-				     color->blue,
-				     color->alpha,
-				     PICT_a8r8g8b8))
+					    color->red,
+					    color->green,
+					    color->blue,
+					    color->alpha,
+					    PICT_a8r8g8b8))
 		return false;
 
 	DBG(("%s(%08x x %d [(%d, %d), (%d, %d) ...])\n",
 	     __FUNCTION__, pixel, n,
 	     box[0].x1, box[0].y1, box[0].x2, box[0].y2));
 
-	tmp.op = op;
-
 	tmp.dst.pixmap = dst;
 	tmp.dst.width  = dst->drawable.width;
 	tmp.dst.height = dst->drawable.height;
@@ -3707,23 +3720,16 @@ gen6_render_fill_boxes(struct sna *sna,
 	tmp.dst.x = tmp.dst.y = 0;
 
 	tmp.src.bo = sna_render_get_solid(sna, pixel);
-	tmp.src.filter = SAMPLER_FILTER_NEAREST;
-	tmp.src.repeat = SAMPLER_EXTEND_REPEAT;
-
 	tmp.mask.bo = NULL;
-	tmp.mask.filter = SAMPLER_FILTER_NEAREST;
-	tmp.mask.repeat = SAMPLER_EXTEND_NONE;
 
-	tmp.is_affine = true;
-	tmp.floats_per_vertex = 3;
-	tmp.floats_per_rect = 9;
-	tmp.has_component_alpha = false;
+	tmp.floats_per_vertex = 2;
+	tmp.floats_per_rect = 6;
 	tmp.need_magic_ca_pass = false;
 
-	tmp.u.gen6.wm_kernel = GEN6_WM_KERNEL_NOMASK;
-	tmp.u.gen6.nr_surfaces = 2;
-	tmp.u.gen6.nr_inputs = 1;
-	tmp.u.gen6.ve_id = 1;
+	tmp.u.gen6.flags = FILL_FLAGS(op, format);
+	assert(GEN6_KERNEL(tmp.u.gen6.flags) == GEN6_WM_KERNEL_NOMASK);
+	assert(GEN6_SAMPLER(tmp.u.gen6.flags) == FILL_SAMPLER);
+	assert(GEN6_VERTEX(tmp.u.gen6.flags) == FILL_VERTEX);
 
 	if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
 		kgem_submit(&sna->kgem);
@@ -3734,25 +3740,27 @@ gen6_render_fill_boxes(struct sna *sna,
 	gen6_align_vertex(sna, &tmp);
 
 	do {
-		int n_this_time = gen6_get_rectangles(sna, &tmp, n,
-						      gen6_emit_fill_state);
+		int n_this_time;
+		int16_t *v;
+
+		n_this_time = gen6_get_rectangles(sna, &tmp, n,
+						  gen6_emit_fill_state);
 		n -= n_this_time;
+
+		v = (int16_t *)(sna->render.vertices + sna->render.vertex_used);
+		sna->render.vertex_used += 6 * n_this_time;
+		assert(sna->render.vertex_used <= sna->render.vertex_size);
 		do {
 			DBG(("	(%d, %d), (%d, %d)\n",
 			     box->x1, box->y1, box->x2, box->y2));
-			OUT_VERTEX(box->x2, box->y2);
-			OUT_VERTEX_F(1);
-			OUT_VERTEX_F(1);
-
-			OUT_VERTEX(box->x1, box->y2);
-			OUT_VERTEX_F(0);
-			OUT_VERTEX_F(1);
 
-			OUT_VERTEX(box->x1, box->y1);
-			OUT_VERTEX_F(0);
-			OUT_VERTEX_F(0);
-
-			box++;
+			v[0] = box->x2;
+			v[5] = v[1] = box->y2;
+			v[8] = v[4] = box->x1;
+			v[9] = box->y1;
+			v[2] = v[3]  = v[7]  = 1;
+			v[6] = v[10] = v[11] = 0;
+			v += 12; box++;
 		} while (--n_this_time);
 	} while (n);
 
@@ -3766,21 +3774,23 @@ gen6_render_op_fill_blt(struct sna *sna,
 			const struct sna_fill_op *op,
 			int16_t x, int16_t y, int16_t w, int16_t h)
 {
+	int16_t *v;
+
 	DBG(("%s: (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
 
 	gen6_get_rectangles(sna, &op->base, 1, gen6_emit_fill_state);
 
-	OUT_VERTEX(x+w, y+h);
-	OUT_VERTEX_F(1);
-	OUT_VERTEX_F(1);
+	v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
+	sna->render.vertex_used += 6;
+	assert(sna->render.vertex_used <= sna->render.vertex_size);
 
-	OUT_VERTEX(x, y+h);
-	OUT_VERTEX_F(0);
-	OUT_VERTEX_F(1);
+	v[0] = x+w;
+	v[4] = v[8] = x;
+	v[1] = v[5] = y+h;
+	v[9] = y;
 
-	OUT_VERTEX(x, y);
-	OUT_VERTEX_F(0);
-	OUT_VERTEX_F(0);
+	v[2] = v[3]  = v[7]  = 1;
+	v[6] = v[10] = v[11] = 0;
 }
 
 fastcall static void
@@ -3788,22 +3798,24 @@ gen6_render_op_fill_box(struct sna *sna,
 			const struct sna_fill_op *op,
 			const BoxRec *box)
 {
+	int16_t *v;
+
 	DBG(("%s: (%d, %d),(%d, %d)\n", __FUNCTION__,
 	     box->x1, box->y1, box->x2, box->y2));
 
 	gen6_get_rectangles(sna, &op->base, 1, gen6_emit_fill_state);
 
-	OUT_VERTEX(box->x2, box->y2);
-	OUT_VERTEX_F(1);
-	OUT_VERTEX_F(1);
+	v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
+	sna->render.vertex_used += 6;
+	assert(sna->render.vertex_used <= sna->render.vertex_size);
 
-	OUT_VERTEX(box->x1, box->y2);
-	OUT_VERTEX_F(0);
-	OUT_VERTEX_F(1);
+	v[0] = box->x2;
+	v[8] = v[4] = box->x1;
+	v[5] = v[1] = box->y2;
+	v[9] = box->y1;
 
-	OUT_VERTEX(box->x1, box->y1);
-	OUT_VERTEX_F(0);
-	OUT_VERTEX_F(0);
+	v[7] = v[2]  = v[3]  = 1;
+	v[6] = v[10] = v[11] = 0;
 }
 
 fastcall static void
@@ -3817,24 +3829,24 @@ gen6_render_op_fill_boxes(struct sna *sna,
 
 	do {
 		int nbox_this_time;
+		int16_t *v;
 
 		nbox_this_time = gen6_get_rectangles(sna, &op->base, nbox,
 						     gen6_emit_fill_state);
 		nbox -= nbox_this_time;
 
-		do {
-			OUT_VERTEX(box->x2, box->y2);
-			OUT_VERTEX_F(1);
-			OUT_VERTEX_F(1);
-
-			OUT_VERTEX(box->x1, box->y2);
-			OUT_VERTEX_F(0);
-			OUT_VERTEX_F(1);
+		v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
+		sna->render.vertex_used += 6 * nbox_this_time;
+		assert(sna->render.vertex_used <= sna->render.vertex_size);
 
-			OUT_VERTEX(box->x1, box->y1);
-			OUT_VERTEX_F(0);
-			OUT_VERTEX_F(0);
-			box++;
+		do {
+			v[0] = box->x2;
+			v[8] = v[4] = box->x1;
+			v[5] = v[1] = box->y2;
+			v[9] = box->y1;
+			v[7] = v[2]  = v[3]  = 1;
+			v[6] = v[10] = v[11] = 0;
+			box++; v += 12;
 		} while (--nbox_this_time);
 	} while (nbox);
 }
@@ -3857,13 +3869,6 @@ gen6_render_fill(struct sna *sna, uint8_t alu,
 {
 	DBG(("%s: (alu=%d, color=%x)\n", __FUNCTION__, alu, color));
 
-#if NO_FILL
-	return sna_blt_fill(sna, alu,
-			    dst_bo, dst->drawable.bitsPerPixel,
-			    color,
-			    op);
-#endif
-
 	if (prefer_blt_fill(sna, dst_bo) &&
 	    sna_blt_fill(sna, alu,
 			 dst_bo, dst->drawable.bitsPerPixel,
@@ -3881,8 +3886,6 @@ gen6_render_fill(struct sna *sna, uint8_t alu,
 	if (alu == GXclear)
 		color = 0;
 
-	op->base.op = PictOpSrc;
-
 	op->base.dst.pixmap = dst;
 	op->base.dst.width  = dst->drawable.width;
 	op->base.dst.height = dst->drawable.height;
@@ -3894,23 +3897,16 @@ gen6_render_fill(struct sna *sna, uint8_t alu,
 		sna_render_get_solid(sna,
 				     sna_rgba_for_color(color,
 							dst->drawable.depth));
-	op->base.src.filter = SAMPLER_FILTER_NEAREST;
-	op->base.src.repeat = SAMPLER_EXTEND_REPEAT;
-
 	op->base.mask.bo = NULL;
-	op->base.mask.filter = SAMPLER_FILTER_NEAREST;
-	op->base.mask.repeat = SAMPLER_EXTEND_NONE;
 
-	op->base.is_affine = true;
-	op->base.has_component_alpha = false;
 	op->base.need_magic_ca_pass = false;
-	op->base.floats_per_vertex = 3;
-	op->base.floats_per_rect = 9;
+	op->base.floats_per_vertex = 2;
+	op->base.floats_per_rect = 6;
 
-	op->base.u.gen6.wm_kernel = GEN6_WM_KERNEL_NOMASK;
-	op->base.u.gen6.nr_surfaces = 2;
-	op->base.u.gen6.nr_inputs = 1;
-	op->base.u.gen6.ve_id = 1;
+	op->base.u.gen6.flags = FILL_FLAGS_NOBLEND;
+	assert(GEN6_KERNEL(op->base.u.gen6.flags) == GEN6_WM_KERNEL_NOMASK);
+	assert(GEN6_SAMPLER(op->base.u.gen6.flags) == FILL_SAMPLER);
+	assert(GEN6_VERTEX(op->base.u.gen6.flags) == FILL_VERTEX);
 
 	if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
 		kgem_submit(&sna->kgem);
@@ -3953,11 +3949,7 @@ gen6_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
 		     uint8_t alu)
 {
 	struct sna_composite_op tmp;
-
-#if NO_FILL_BOXES
-	return gen6_render_fill_one_try_blt(sna, dst, bo, color,
-					    x1, y1, x2, y2, alu);
-#endif
+	int16_t *v;
 
 	/* Prefer to use the BLT if already engaged */
 	if (prefer_blt_fill(sna, bo) &&
@@ -3974,8 +3966,6 @@ gen6_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
 	if (alu == GXclear)
 		color = 0;
 
-	tmp.op = PictOpSrc;
-
 	tmp.dst.pixmap = dst;
 	tmp.dst.width  = dst->drawable.width;
 	tmp.dst.height = dst->drawable.height;
@@ -3987,23 +3977,16 @@ gen6_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
 		sna_render_get_solid(sna,
 				     sna_rgba_for_color(color,
 							dst->drawable.depth));
-	tmp.src.filter = SAMPLER_FILTER_NEAREST;
-	tmp.src.repeat = SAMPLER_EXTEND_REPEAT;
-
 	tmp.mask.bo = NULL;
-	tmp.mask.filter = SAMPLER_FILTER_NEAREST;
-	tmp.mask.repeat = SAMPLER_EXTEND_NONE;
 
-	tmp.is_affine = true;
-	tmp.floats_per_vertex = 3;
-	tmp.floats_per_rect = 9;
-	tmp.has_component_alpha = 0;
+	tmp.floats_per_vertex = 2;
+	tmp.floats_per_rect = 6;
 	tmp.need_magic_ca_pass = false;
 
-	tmp.u.gen6.wm_kernel = GEN6_WM_KERNEL_NOMASK;
-	tmp.u.gen6.nr_surfaces = 2;
-	tmp.u.gen6.nr_inputs = 1;
-	tmp.u.gen6.ve_id = 1;
+	tmp.u.gen6.flags = FILL_FLAGS_NOBLEND;
+	assert(GEN6_KERNEL(tmp.u.gen6.flags) == GEN6_WM_KERNEL_NOMASK);
+	assert(GEN6_SAMPLER(tmp.u.gen6.flags) == FILL_SAMPLER);
+	assert(GEN6_VERTEX(tmp.u.gen6.flags) == FILL_VERTEX);
 
 	if (!kgem_check_bo(&sna->kgem, bo, NULL)) {
 		_kgem_submit(&sna->kgem);
@@ -4016,17 +3999,17 @@ gen6_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
 	gen6_get_rectangles(sna, &tmp, 1, gen6_emit_fill_state);
 
 	DBG(("	(%d, %d), (%d, %d)\n", x1, y1, x2, y2));
-	OUT_VERTEX(x2, y2);
-	OUT_VERTEX_F(1);
-	OUT_VERTEX_F(1);
 
-	OUT_VERTEX(x1, y2);
-	OUT_VERTEX_F(0);
-	OUT_VERTEX_F(1);
+	v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
+	sna->render.vertex_used += 6;
+	assert(sna->render.vertex_used <= sna->render.vertex_size);
 
-	OUT_VERTEX(x1, y1);
-	OUT_VERTEX_F(0);
-	OUT_VERTEX_F(0);
+	v[0] = x2;
+	v[8] = v[4] = x1;
+	v[5] = v[1] = y2;
+	v[9] = y1;
+	v[7] = v[2]  = v[3]  = 1;
+	v[6] = v[10] = v[11] = 0;
 
 	gen6_vertex_flush(sna);
 	kgem_bo_destroy(&sna->kgem, tmp.src.bo);
@@ -4053,10 +4036,7 @@ static bool
 gen6_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
 {
 	struct sna_composite_op tmp;
-
-#if NO_CLEAR
-	return gen6_render_clear_try_blt(sna, dst, bo);
-#endif
+	int16_t *v;
 
 	DBG(("%s: %dx%d\n",
 	     __FUNCTION__,
@@ -4072,8 +4052,6 @@ gen6_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
 	if (too_large(dst->drawable.width, dst->drawable.height))
 		return gen6_render_clear_try_blt(sna, dst, bo);
 
-	tmp.op = PictOpSrc;
-
 	tmp.dst.pixmap = dst;
 	tmp.dst.width  = dst->drawable.width;
 	tmp.dst.height = dst->drawable.height;
@@ -4082,23 +4060,16 @@ gen6_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
 	tmp.dst.x = tmp.dst.y = 0;
 
 	tmp.src.bo = sna_render_get_solid(sna, 0);
-	tmp.src.filter = SAMPLER_FILTER_NEAREST;
-	tmp.src.repeat = SAMPLER_EXTEND_REPEAT;
-
 	tmp.mask.bo = NULL;
-	tmp.mask.filter = SAMPLER_FILTER_NEAREST;
-	tmp.mask.repeat = SAMPLER_EXTEND_NONE;
 
-	tmp.is_affine = true;
-	tmp.floats_per_vertex = 3;
-	tmp.floats_per_rect = 9;
-	tmp.has_component_alpha = 0;
+	tmp.floats_per_vertex = 2;
+	tmp.floats_per_rect = 6;
 	tmp.need_magic_ca_pass = false;
 
-	tmp.u.gen6.wm_kernel = GEN6_WM_KERNEL_NOMASK;
-	tmp.u.gen6.nr_surfaces = 2;
-	tmp.u.gen6.nr_inputs = 1;
-	tmp.u.gen6.ve_id = 1;
+	tmp.u.gen6.flags = FILL_FLAGS_NOBLEND;
+	assert(GEN6_KERNEL(tmp.u.gen6.flags) == GEN6_WM_KERNEL_NOMASK);
+	assert(GEN6_SAMPLER(tmp.u.gen6.flags) == FILL_SAMPLER);
+	assert(GEN6_VERTEX(tmp.u.gen6.flags) == FILL_VERTEX);
 
 	if (!kgem_check_bo(&sna->kgem, bo, NULL)) {
 		_kgem_submit(&sna->kgem);
@@ -4110,17 +4081,17 @@ gen6_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
 
 	gen6_get_rectangles(sna, &tmp, 1, gen6_emit_fill_state);
 
-	OUT_VERTEX(dst->drawable.width, dst->drawable.height);
-	OUT_VERTEX_F(1);
-	OUT_VERTEX_F(1);
+	v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
+	sna->render.vertex_used += 6;
+	assert(sna->render.vertex_used <= sna->render.vertex_size);
 
-	OUT_VERTEX(0, dst->drawable.height);
-	OUT_VERTEX_F(0);
-	OUT_VERTEX_F(1);
+	v[0] = dst->drawable.width;
+	v[5] = v[1] = dst->drawable.height;
+	v[8] = v[4] = 0;
+	v[9] = 0;
 
-	OUT_VERTEX(0, 0);
-	OUT_VERTEX_F(0);
-	OUT_VERTEX_F(0);
+	v[7] = v[2]  = v[3]  = 1;
+	v[6] = v[10] = v[11] = 0;
 
 	gen6_vertex_flush(sna);
 	kgem_bo_destroy(&sna->kgem, tmp.src.bo);
@@ -4227,10 +4198,13 @@ static bool gen6_render_setup(struct sna *sna)
 
 	ss = sna_static_stream_map(&general,
 				   2 * sizeof(*ss) *
-				   FILTER_COUNT * EXTEND_COUNT *
-				   FILTER_COUNT * EXTEND_COUNT,
+				   (2 +
+				    FILTER_COUNT * EXTEND_COUNT *
+				    FILTER_COUNT * EXTEND_COUNT),
 				   32);
 	state->wm_state = sna_static_stream_offsetof(&general, ss);
+	sampler_copy_init(ss); ss += 2;
+	sampler_fill_init(ss); ss += 2;
 	for (i = 0; i < FILTER_COUNT; i++) {
 		for (j = 0; j < EXTEND_COUNT; j++) {
 			for (k = 0; k < FILTER_COUNT; k++) {
@@ -4258,19 +4232,33 @@ bool gen6_render_init(struct sna *sna)
 	sna->kgem.retire = gen6_render_retire;
 	sna->kgem.expire = gen6_render_expire;
 
+#if !NO_COMPOSITE
 	sna->render.composite = gen6_render_composite;
+#endif
 #if !NO_COMPOSITE_SPANS
 	sna->render.composite_spans = gen6_render_composite_spans;
 #endif
 	sna->render.video = gen6_render_video;
 
+#if !NO_COPY_BOXES
 	sna->render.copy_boxes = gen6_render_copy_boxes;
+#endif
+#if !NO_COPY
 	sna->render.copy = gen6_render_copy;
+#endif
 
+#if !NO_FILL_BOXES
 	sna->render.fill_boxes = gen6_render_fill_boxes;
+#endif
+#if !NO_FILL
 	sna->render.fill = gen6_render_fill;
+#endif
+#if !NO_FILL_ONE
 	sna->render.fill_one = gen6_render_fill_one;
+#endif
+#if !NO_FILL_CLEAR
 	sna->render.clear = gen6_render_clear;
+#endif
 
 	sna->render.flush = gen6_render_flush;
 	sna->render.reset = gen6_render_reset;
diff --git a/src/sna/gen6_render.h b/src/sna/gen6_render.h
index eded2b7..b0331ec 100644
--- a/src/sna/gen6_render.h
+++ b/src/sna/gen6_render.h
@@ -1350,7 +1350,9 @@ struct gen6_sampler_state {
    } ss2;
 
    struct {
-      uint32_t pad:19;
+      uint32_t non_normalized_coord:1;
+      uint32_t pad:12;
+      uint32_t address_round:6;
       uint32_t max_aniso:3;
       uint32_t chroma_key_mode:1;
       uint32_t chroma_key_index:2;
diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h
index 15d882f..41cb02b 100644
--- a/src/sna/sna_render.h
+++ b/src/sna/sna_render.h
@@ -126,10 +126,7 @@ struct sna_composite_op {
 		} gen5;
 
 		struct {
-			int wm_kernel;
-			int nr_surfaces;
-			int nr_inputs;
-			int ve_id;
+			uint32_t flags;
 		} gen6;
 
 		struct {
commit 4eea9ac0035dd72f3c637adc39eeaeda46472e9e
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jul 18 12:59:41 2012 +0100

    sna/gen7: Micro-optimise render copy emission
    
    The goal is bring the overhead down to that of using the blitter. Tricky
    given the number of steps to using the 3D pipeline compared to the
    BLT...
    
    A stretch goal would be to make IVB GPU bound for -copywinpix10!
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/gen7_render.c b/src/sna/gen7_render.c
index f8036fb..cb497b9 100644
--- a/src/sna/gen7_render.c
+++ b/src/sna/gen7_render.c
@@ -48,7 +48,8 @@
 #define NO_COPY_BOXES 0
 #define NO_FILL 0
 #define NO_FILL_BOXES 0
-#define NO_CLEAR 0
+#define NO_FILL_ONE 0
+#define NO_FILL_CLEAR 0
 
 #define NO_RING_SWITCH 0
 
@@ -167,28 +168,28 @@ static const uint32_t ps_kernel_planar[][4] = {
 #include "exa_wm_write.g7b"
 };
 
-#define KERNEL(kernel_enum, kernel, masked) \
-    [GEN7_WM_KERNEL_##kernel_enum] = {#kernel_enum, kernel, sizeof(kernel), masked}
+#define KERNEL(kernel_enum, kernel, num_surfaces) \
+    [GEN7_WM_KERNEL_##kernel_enum] = {#kernel_enum, kernel, sizeof(kernel), num_surfaces}
 static const struct wm_kernel_info {
 	const char *name;
 	const void *data;
 	unsigned int size;
-	bool has_mask;
+	int num_surfaces;
 } wm_kernels[] = {
-	KERNEL(NOMASK, ps_kernel_nomask_affine, false),
-	KERNEL(NOMASK_PROJECTIVE, ps_kernel_nomask_projective, false),
+	KERNEL(NOMASK, ps_kernel_nomask_affine, 2),
+	KERNEL(NOMASK_PROJECTIVE, ps_kernel_nomask_projective, 2),
 
-	KERNEL(MASK, ps_kernel_masknoca_affine, true),
-	KERNEL(MASK_PROJECTIVE, ps_kernel_masknoca_projective, true),
+	KERNEL(MASK, ps_kernel_masknoca_affine, 3),
+	KERNEL(MASK_PROJECTIVE, ps_kernel_masknoca_projective, 3),
 
-	KERNEL(MASKCA, ps_kernel_maskca_affine, true),
-	KERNEL(MASKCA_PROJECTIVE, ps_kernel_maskca_projective, true),
+	KERNEL(MASKCA, ps_kernel_maskca_affine, 3),
+	KERNEL(MASKCA_PROJECTIVE, ps_kernel_maskca_projective, 3),
 
-	KERNEL(MASKCA_SRCALPHA, ps_kernel_maskca_srcalpha_affine, true),
-	KERNEL(MASKCA_SRCALPHA_PROJECTIVE, ps_kernel_maskca_srcalpha_projective, true),
+	KERNEL(MASKCA_SRCALPHA, ps_kernel_maskca_srcalpha_affine, 3),
+	KERNEL(MASKCA_SRCALPHA_PROJECTIVE, ps_kernel_maskca_srcalpha_projective, 3),
 
-	KERNEL(VIDEO_PLANAR, ps_kernel_planar, false),
-	KERNEL(VIDEO_PACKED, ps_kernel_packed, false),
+	KERNEL(VIDEO_PLANAR, ps_kernel_planar, 7),
+	KERNEL(VIDEO_PACKED, ps_kernel_packed, 2),
 };
 #undef KERNEL
 
@@ -226,21 +227,32 @@ static const struct blendinfo {
 #define BLEND_OFFSET(s, d) \
 	(((s) * GEN7_BLENDFACTOR_COUNT + (d)) * GEN7_BLEND_STATE_PADDED_SIZE)
 
+#define NO_BLEND BLEND_OFFSET(GEN7_BLENDFACTOR_ONE, GEN7_BLENDFACTOR_ZERO)
+#define CLEAR BLEND_OFFSET(GEN7_BLENDFACTOR_ZERO, GEN7_BLENDFACTOR_ZERO)
+
 #define SAMPLER_OFFSET(sf, se, mf, me) \
-	(((((sf) * EXTEND_COUNT + (se)) * FILTER_COUNT + (mf)) * EXTEND_COUNT + (me)) * 2 * sizeof(struct gen7_sampler_state))
+	((((((sf) * EXTEND_COUNT + (se)) * FILTER_COUNT + (mf)) * EXTEND_COUNT + (me)) + 2) * 2 * sizeof(struct gen7_sampler_state))
 
-#define FILL_SAMPLER \
-	SAMPLER_OFFSET(SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_REPEAT, \
-		       SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE)
+#define VERTEX_2s2s 4
 
-#define COPY_SAMPLER \
-	SAMPLER_OFFSET(SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE, \
-		       SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE)
+#define COPY_SAMPLER 0
+#define COPY_VERTEX VERTEX_2s2s
+#define COPY_FLAGS(a) GEN7_SET_FLAGS(COPY_SAMPLER, (a) == GXcopy ? NO_BLEND : CLEAR, GEN7_WM_KERNEL_NOMASK, COPY_VERTEX)
+
+#define FILL_SAMPLER (2 * sizeof(struct gen7_sampler_state))
+#define FILL_VERTEX VERTEX_2s2s
+#define FILL_FLAGS(op, format) GEN7_SET_FLAGS(FILL_SAMPLER, gen7_get_blend((op), false, (format)), GEN7_WM_KERNEL_NOMASK, FILL_VERTEX)
+#define FILL_FLAGS_NOBLEND GEN7_SET_FLAGS(FILL_SAMPLER, NO_BLEND, GEN7_WM_KERNEL_NOMASK, FILL_VERTEX)
 
 #define VIDEO_SAMPLER \
 	SAMPLER_OFFSET(SAMPLER_FILTER_BILINEAR, SAMPLER_EXTEND_PAD, \
 		       SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE)
 
+#define GEN7_SAMPLER(f) (((f) >> 16) & 0xfff0)
+#define GEN7_BLEND(f) (((f) >> 0) & 0xfff0)
+#define GEN7_KERNEL(f) (((f) >> 16) & 0xf)
+#define GEN7_VERTEX(f) (((f) >> 0) & 0xf)
+#define GEN7_SET_FLAGS(S, B, K, V)  (((S) | (K)) << 16 | ((B) | (V)))
 
 #define OUT_BATCH(v) batch_emit(sna, v)
 #define OUT_VERTEX(x,y) vertex_emit_2s(sna, x,y)
@@ -748,6 +760,8 @@ gen7_emit_cc(struct sna *sna, uint32_t blend_offset)
 	if (render->blend == blend_offset)
 		return;
 
+	DBG(("%s: blend = %x\n", __FUNCTION__, blend_offset));
+
 	/* XXX can have upto 8 blend states preload, selectable via
 	 * Render Target Index. What other side-effects of Render Target Index?
 	 */
@@ -762,16 +776,13 @@ gen7_emit_cc(struct sna *sna, uint32_t blend_offset)
 static void
 gen7_emit_sampler(struct sna *sna, uint32_t state)
 {
-	assert(state <
-	       2 * sizeof(struct gen7_sampler_state) *
-	       FILTER_COUNT * EXTEND_COUNT *
-	       FILTER_COUNT * EXTEND_COUNT);
-
 	if (sna->render_state.gen7.samplers == state)
 		return;
 
 	sna->render_state.gen7.samplers = state;
 
+	DBG(("%s: sampler = %x\n", __FUNCTION__, state));
+
 	assert (is_aligned(sna->render_state.gen7.wm_state + state, 32));
 	OUT_BATCH(GEN7_3DSTATE_SAMPLER_STATE_POINTERS_PS | (2 - 2));
 	OUT_BATCH(sna->render_state.gen7.wm_state + state);
@@ -809,19 +820,22 @@ gen7_emit_sf(struct sna *sna, bool has_mask)
 }
 
 static void
-gen7_emit_wm(struct sna *sna, unsigned int kernel, int nr_surfaces, int nr_inputs)
+gen7_emit_wm(struct sna *sna, int kernel)
 {
 	if (sna->render_state.gen7.kernel == kernel)
 		return;
 
 	sna->render_state.gen7.kernel = kernel;
 
-	DBG(("%s: switching to %s\n", __FUNCTION__, wm_kernels[kernel].name));
+	DBG(("%s: switching to %s, num_surfaces=%d\n",
+	     __FUNCTION__,
+	     wm_kernels[kernel].name,
+	     wm_kernels[kernel].num_surfaces));
 
 	OUT_BATCH(GEN7_3DSTATE_PS | (8 - 2));
 	OUT_BATCH(sna->render_state.gen7.wm_kernel[kernel]);
 	OUT_BATCH(1 << GEN7_PS_SAMPLER_COUNT_SHIFT |
-		  nr_surfaces << GEN7_PS_BINDING_TABLE_ENTRY_COUNT_SHIFT);
+		  wm_kernels[kernel].num_surfaces << GEN7_PS_BINDING_TABLE_ENTRY_COUNT_SHIFT);
 	OUT_BATCH(0); /* scratch address */
 	OUT_BATCH((sna->render_state.gen7.info->max_wm_threads - 1) << GEN7_PS_MAX_THREADS_SHIFT |
 		  GEN7_PS_ATTRIBUTE_ENABLE |
@@ -881,22 +895,58 @@ gen7_emit_vertex_elements(struct sna *sna,
 	 *    texture coordinate 1 if (has_mask is true): same as above
 	 */
 	struct gen7_render_state *render = &sna->render_state.gen7;
-	int nelem = op->mask.bo ? 2 : 1;
-	int selem = op->is_affine ? 2 : 3;
+	int nelem, selem;
 	uint32_t w_component;
 	uint32_t src_format;
-	int id = op->u.gen7.ve_id;
+	int id = GEN7_VERTEX(op->u.gen7.flags);
 
 	if (render->ve_id == id)
 		return;
 	render->ve_id = id;
 
+	switch (id) {
+	case VERTEX_2s2s:
+		DBG(("%s: setup COPY\n", __FUNCTION__));
+
+		OUT_BATCH(GEN7_3DSTATE_VERTEX_ELEMENTS |
+			  ((2 * (1 + 2)) + 1 - 2));
+
+		OUT_BATCH(id << GEN7_VE0_VERTEX_BUFFER_INDEX_SHIFT | GEN7_VE0_VALID |
+			  GEN7_SURFACEFORMAT_R32G32B32A32_FLOAT << GEN7_VE0_FORMAT_SHIFT |
+			  0 << GEN7_VE0_OFFSET_SHIFT);
+		OUT_BATCH(GEN7_VFCOMPONENT_STORE_0 << GEN7_VE1_VFCOMPONENT_0_SHIFT |
+			  GEN7_VFCOMPONENT_STORE_0 << GEN7_VE1_VFCOMPONENT_1_SHIFT |
+			  GEN7_VFCOMPONENT_STORE_0 << GEN7_VE1_VFCOMPONENT_2_SHIFT |
+			  GEN7_VFCOMPONENT_STORE_0 << GEN7_VE1_VFCOMPONENT_3_SHIFT);
+
+		/* x,y */
+		OUT_BATCH(id << GEN7_VE0_VERTEX_BUFFER_INDEX_SHIFT | GEN7_VE0_VALID |
+			  GEN7_SURFACEFORMAT_R16G16_SSCALED << GEN7_VE0_FORMAT_SHIFT |
+			  0 << GEN7_VE0_OFFSET_SHIFT); /* offsets vb in bytes */
+		OUT_BATCH(GEN7_VFCOMPONENT_STORE_SRC << GEN7_VE1_VFCOMPONENT_0_SHIFT |
+			  GEN7_VFCOMPONENT_STORE_SRC << GEN7_VE1_VFCOMPONENT_1_SHIFT |
+			  GEN7_VFCOMPONENT_STORE_0 << GEN7_VE1_VFCOMPONENT_2_SHIFT |
+			  GEN7_VFCOMPONENT_STORE_1_FLT << GEN7_VE1_VFCOMPONENT_3_SHIFT);
+
+		OUT_BATCH(id << GEN7_VE0_VERTEX_BUFFER_INDEX_SHIFT | GEN7_VE0_VALID |
+			  GEN7_SURFACEFORMAT_R16G16_SSCALED << GEN7_VE0_FORMAT_SHIFT |
+			  4 << GEN7_VE0_OFFSET_SHIFT);	/* offset vb in bytes */
+		OUT_BATCH(GEN7_VFCOMPONENT_STORE_SRC << GEN7_VE1_VFCOMPONENT_0_SHIFT |
+			  GEN7_VFCOMPONENT_STORE_SRC << GEN7_VE1_VFCOMPONENT_1_SHIFT |
+			  GEN7_VFCOMPONENT_STORE_0 << GEN7_VE1_VFCOMPONENT_2_SHIFT |
+			  GEN7_VFCOMPONENT_STORE_1_FLT << GEN7_VE1_VFCOMPONENT_3_SHIFT);
+		return;
+	}
+
+	nelem = op->mask.bo ? 2 : 1;
 	if (op->is_affine) {
 		src_format = GEN7_SURFACEFORMAT_R32G32_FLOAT;
 		w_component = GEN7_VFCOMPONENT_STORE_0;
+		selem = 2;
 	} else {
 		src_format = GEN7_SURFACEFORMAT_R32G32B32_FLOAT;
 		w_component = GEN7_VFCOMPONENT_STORE_SRC;
+		selem = 3;
 	}
 
 	/* The VUE layout
@@ -990,17 +1040,10 @@ gen7_emit_state(struct sna *sna,
 	if (sna->render_state.gen7.emit_flush)
 		gen7_emit_pipe_flush(sna);
 
-	gen7_emit_cc(sna,
-		     gen7_get_blend(op->op,
-				    op->has_component_alpha,
-				    op->dst.format));
-
-	gen7_emit_sampler(sna, op->u.gen7.sampler);
+	gen7_emit_cc(sna, GEN7_BLEND(op->u.gen7.flags));
+	gen7_emit_sampler(sna, GEN7_SAMPLER(op->u.gen7.flags));
 	gen7_emit_sf(sna, op->mask.bo != NULL);
-	gen7_emit_wm(sna,
-		     op->u.gen7.wm_kernel,
-		     op->u.gen7.nr_surfaces,
-		     op->u.gen7.nr_inputs);
+	gen7_emit_wm(sna, GEN7_KERNEL(op->u.gen7.flags));
 	gen7_emit_vertex_elements(sna, op);
 
 	need_stall |= gen7_emit_binding_table(sna, wm_binding_table);
@@ -1015,7 +1058,8 @@ gen7_emit_state(struct sna *sna,
 	if (need_stall)
 		gen7_emit_pipe_stall(sna);
 
-	sna->render_state.gen7.emit_flush = op->op > PictOpSrc;
+	sna->render_state.gen7.emit_flush =
+		GEN7_BLEND(op->u.gen7.flags) != NO_BLEND;
 }
 
 static void gen7_magic_ca_pass(struct sna *sna,
@@ -1035,8 +1079,7 @@ static void gen7_magic_ca_pass(struct sna *sna,
 	gen7_emit_wm(sna,
 		     gen7_choose_composite_kernel(PictOpAdd,
 						  true, true,
-						  op->is_affine),
-		     3, 2);
+						  op->is_affine));
 
 	OUT_BATCH(GEN7_3DPRIMITIVE | (7- 2));
 	OUT_BATCH(GEN7_3DPRIMITIVE_VERTEX_SEQUENTIAL | _3DPRIM_RECTLIST);
@@ -1256,6 +1299,24 @@ sampler_state_init(struct gen7_sampler_state *sampler_state,
 	}
 }
 
+static void
+sampler_copy_init(struct gen7_sampler_state *ss)
+{
+	sampler_state_init(ss, SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE);
+	ss->ss3.non_normalized_coord = 1;
+
+	sampler_state_init(ss+1, SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE);
+}
+
+static void
+sampler_fill_init(struct gen7_sampler_state *ss)
+{
+	sampler_state_init(ss, SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_REPEAT);
+	ss->ss3.non_normalized_coord = 1;
+
+	sampler_state_init(ss+1, SAMPLER_FILTER_NEAREST, SAMPLER_EXTEND_NONE);
+}
+
 static uint32_t gen7_create_cc_viewport(struct sna_static_stream *stream)
 {
 	struct gen7_cc_viewport vp;
@@ -1576,7 +1637,7 @@ gen7_emit_composite_primitive(struct sna *sna,
 static void gen7_emit_vertex_buffer(struct sna *sna,
 				    const struct sna_composite_op *op)
 {
-	int id = op->u.gen7.ve_id;
+	int id = GEN7_VERTEX(op->u.gen7.flags);
 
 	OUT_BATCH(GEN7_3DSTATE_VERTEX_BUFFERS | (5 - 2));
 	OUT_BATCH(id << GEN7_VB0_BUFFER_INDEX_SHIFT |
@@ -1614,7 +1675,7 @@ static void gen7_emit_primitive(struct sna *sna)
 static bool gen7_rectangle_begin(struct sna *sna,
 				 const struct sna_composite_op *op)
 {
-	int id = 1 << op->u.gen7.ve_id;
+	int id = 1 << GEN7_VERTEX(op->u.gen7.flags);
 	int ndwords;
 
 	ndwords = op->need_magic_ca_pass ? 60 : 6;
@@ -2010,7 +2071,6 @@ gen7_render_video(struct sna *sna,
 
 	memset(&tmp, 0, sizeof(tmp));
 
-	tmp.op = PictOpSrc;
 	tmp.dst.pixmap = pixmap;
 	tmp.dst.width  = pixmap->drawable.width;
 	tmp.dst.height = pixmap->drawable.height;
@@ -2020,20 +2080,15 @@ gen7_render_video(struct sna *sna,
 	tmp.src.bo = frame->bo;
 	tmp.mask.bo = NULL;
 
-	tmp.is_affine = true;
 	tmp.floats_per_vertex = 3;
 	tmp.floats_per_rect = 9;
 
-	if (is_planar_fourcc(frame->id)) {
-		tmp.u.gen7.wm_kernel = GEN7_WM_KERNEL_VIDEO_PLANAR;
-		tmp.u.gen7.nr_surfaces = 7;
-	} else {
-		tmp.u.gen7.wm_kernel = GEN7_WM_KERNEL_VIDEO_PACKED;
-		tmp.u.gen7.nr_surfaces = 2;
-	}
-	tmp.u.gen7.nr_inputs = 1;
-	tmp.u.gen7.ve_id = 1;
-	tmp.u.gen7.sampler = VIDEO_SAMPLER;
+	tmp.u.gen7.flags =
+		GEN7_SET_FLAGS(VIDEO_SAMPLER, NO_BLEND,
+			       is_planar_fourcc(frame->id) ?
+			       GEN7_WM_KERNEL_VIDEO_PLANAR :
+			       GEN7_WM_KERNEL_VIDEO_PACKED,
+			       1);
 	tmp.priv = frame;
 
 	kgem_set_mode(&sna->kgem, KGEM_RENDER);
@@ -2663,17 +2718,6 @@ gen7_render_composite(struct sna *sna,
 	if (op >= ARRAY_SIZE(gen7_blend_op))
 		return false;
 
-#if NO_COMPOSITE
-	if (mask)
-		return false;
-
-	return sna_blt_composite(sna, op,
-				 src, dst,
-				 src_x, src_y,
-				 dst_x, dst_y,
-				 width, height, tmp);
-#endif
-
 	DBG(("%s: %dx%d, current mode=%d\n", __FUNCTION__,
 	     width, height, sna->kgem.ring));
 
@@ -2820,18 +2864,19 @@ gen7_render_composite(struct sna *sna,
 	}
 	tmp->floats_per_rect = 3 * tmp->floats_per_vertex;
 
-	tmp->u.gen7.wm_kernel =
-		gen7_choose_composite_kernel(tmp->op,
-					     tmp->mask.bo != NULL,
-					     tmp->has_component_alpha,
-					     tmp->is_affine);
-	tmp->u.gen7.nr_surfaces = 2 + (tmp->mask.bo != NULL);
-	tmp->u.gen7.nr_inputs = 1 + (tmp->mask.bo != NULL);
-	tmp->u.gen7.ve_id = gen7_choose_composite_vertex_buffer(tmp);
-	tmp->u.gen7.sampler = SAMPLER_OFFSET(tmp->src.filter,
-					     tmp->src.repeat,
-					     tmp->mask.filter,
-					     tmp->mask.repeat);
+	tmp->u.gen7.flags =
+		GEN7_SET_FLAGS(SAMPLER_OFFSET(tmp->src.filter,
+					      tmp->src.repeat,
+					      tmp->mask.filter,
+					      tmp->mask.repeat),
+			       gen7_get_blend(tmp->op,
+					      tmp->has_component_alpha,
+					      tmp->dst.format),
+			       gen7_choose_composite_kernel(tmp->op,
+							    tmp->mask.bo != NULL,
+							    tmp->has_component_alpha,
+							    tmp->is_affine),
+			       gen7_choose_composite_vertex_buffer(tmp));
 
 	tmp->blt   = gen7_render_composite_blt;
 	tmp->box   = gen7_render_composite_box;
@@ -3186,7 +3231,6 @@ gen7_render_composite_spans(struct sna *sna,
 	}
 
 	tmp->base.is_affine = tmp->base.src.is_affine;
-	tmp->base.has_component_alpha = false;
 	tmp->base.need_magic_ca_pass = false;
 
 	if (!gen7_composite_alpha_gradient_init(sna, &tmp->base.mask))
@@ -3209,17 +3253,16 @@ gen7_render_composite_spans(struct sna *sna,
 	tmp->base.floats_per_vertex = 5 + 2*!tmp->base.is_affine;
 	tmp->base.floats_per_rect = 3 * tmp->base.floats_per_vertex;
 
-	tmp->base.u.gen7.wm_kernel =
-		gen7_choose_composite_kernel(tmp->base.op,
-					     true, false,
-					     tmp->base.is_affine);
-	tmp->base.u.gen7.nr_surfaces = 3;
-	tmp->base.u.gen7.nr_inputs = 2;
-	tmp->base.u.gen7.ve_id = 1 << 1 | tmp->base.is_affine;
-	tmp->base.u.gen7.sampler = SAMPLER_OFFSET(tmp->base.src.filter,
-						  tmp->base.src.repeat,
-						  SAMPLER_FILTER_NEAREST,
-						  SAMPLER_EXTEND_PAD);
+	tmp->base.u.gen7.flags =
+		GEN7_SET_FLAGS(SAMPLER_OFFSET(tmp->base.src.filter,
+					      tmp->base.src.repeat,
+					      SAMPLER_FILTER_NEAREST,
+					      SAMPLER_EXTEND_PAD),
+			       gen7_get_blend(tmp->base.op, false, tmp->base.dst.format),
+			       gen7_choose_composite_kernel(tmp->base.op,
+							    true, false,
+							    tmp->base.is_affine),
+			       1 << 1 | tmp->base.is_affine);
 
 	tmp->box   = gen7_render_composite_spans_box;
 	tmp->boxes = gen7_render_composite_spans_boxes;
@@ -3344,17 +3387,6 @@ gen7_render_copy_boxes(struct sna *sna, uint8_t alu,
 {
 	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, alu=%x, self-copy=%d, overlaps? %d\n",
 	     __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy, n, alu,
 	     src_bo == dst_bo,
@@ -3420,8 +3452,6 @@ fallback_blt:
 	if (!gen7_check_format(tmp.src.pict_format))
 		goto fallback_blt;
 
-	tmp.op = alu == GXcopy ? PictOpSrc : PictOpClear;
-
 	tmp.dst.pixmap = dst;
 	tmp.dst.width  = dst->drawable.width;
 	tmp.dst.height = dst->drawable.height;
@@ -3452,6 +3482,11 @@ fallback_blt:
 						   extents.x2 - extents.x1,
 						   extents.y2 - extents.y1))
 			goto fallback_tiled;
+
+		dst_dx += tmp.dst.x;
+		dst_dy += tmp.dst.y;
+
+		tmp.dst.x = tmp.dst.y = 0;
 	}
 
 	tmp.src.card_format = gen7_get_card_format(tmp.src.pict_format);
@@ -3477,85 +3512,72 @@ fallback_blt:
 					       extents.x2 - extents.x1,
 					       extents.y2 - extents.y1))
 			goto fallback_tiled_dst;
+
+		src_dx += tmp.src.offset[0];
+		src_dy += tmp.src.offset[1];
 	} else {
-		tmp.src.bo = kgem_bo_reference(src_bo);
+		tmp.src.bo = src_bo;
 		tmp.src.width  = src->drawable.width;
 		tmp.src.height = src->drawable.height;
-		tmp.src.offset[0] = tmp.src.offset[1] = 0;
-		tmp.src.scale[0] = 1.f/src->drawable.width;
-		tmp.src.scale[1] = 1.f/src->drawable.height;
 	}
 
 	tmp.mask.bo = NULL;
 
-	tmp.is_affine = true;
-	tmp.floats_per_vertex = 3;
-	tmp.floats_per_rect = 9;
-	tmp.has_component_alpha = 0;
+	tmp.floats_per_vertex = 2;
+	tmp.floats_per_rect = 6;
 	tmp.need_magic_ca_pass = 0;
 
-	tmp.u.gen7.wm_kernel = GEN7_WM_KERNEL_NOMASK;
-	tmp.u.gen7.nr_surfaces = 2;
-	tmp.u.gen7.nr_inputs = 1;
-	tmp.u.gen7.ve_id = 1;
-	tmp.u.gen7.sampler = COPY_SAMPLER;
+	tmp.u.gen7.flags = COPY_FLAGS(alu);
 
 	kgem_set_mode(&sna->kgem, KGEM_RENDER);
-	if (!kgem_check_bo(&sna->kgem, dst_bo, src_bo, NULL)) {
+	if (!kgem_check_bo(&sna->kgem, tmp.dst.bo, tmp.src.bo, NULL)) {
 		kgem_submit(&sna->kgem);
-		if (!kgem_check_bo(&sna->kgem, dst_bo, src_bo, NULL))
+		if (!kgem_check_bo(&sna->kgem, tmp.dst.bo, tmp.src.bo, NULL))
 			goto fallback_tiled_src;
 		_kgem_set_mode(&sna->kgem, KGEM_RENDER);
 	}
 
-	dst_dx += tmp.dst.x;
-	dst_dy += tmp.dst.y;
-	tmp.dst.x = tmp.dst.y = 0;
-
-	src_dx += tmp.src.offset[0];
-	src_dy += tmp.src.offset[1];
-
 	gen7_emit_copy_state(sna, &tmp);
 	gen7_align_vertex(sna, &tmp);
 
 	do {
-		float *v;
+		int16_t *v;
 		int n_this_time;
 
 		n_this_time = gen7_get_rectangles(sna, &tmp, n,
 						  gen7_emit_copy_state);
 		n -= n_this_time;
 
-		v = sna->render.vertices + sna->render.vertex_used;
-		sna->render.vertex_used += 9 * n_this_time;
+		v = (int16_t *)(sna->render.vertices + sna->render.vertex_used);
+		sna->render.vertex_used += 6 * n_this_time;
+		assert(sna->render.vertex_used <= sna->render.vertex_size);
 		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));
-			v[0] = pack_2s(box->x2 + dst_dx, box->y2 + dst_dy);
-			v[3] = pack_2s(box->x1 + dst_dx, box->y2 + dst_dy);
-			v[6] = pack_2s(box->x1 + dst_dx, box->y1 + dst_dy);
-
-			v[1] = (box->x2 + src_dx) * tmp.src.scale[0];
-			v[7] = v[4] = (box->x1 + src_dx) * tmp.src.scale[0];
-
-			v[5] = v[2] = (box->y2 + src_dy) * tmp.src.scale[1];
-			v[8] = (box->y1 + src_dy) * tmp.src.scale[1];
-
-			v += 9;
-			box++;
+			v[0] = box->x2 + dst_dx;
+			v[2] = box->x2 + src_dx;
+			v[1]  = v[5] = box->y2 + dst_dy;
+			v[3]  = v[7] = box->y2 + src_dy;
+			v[8]  = v[4] = box->x1 + dst_dx;
+			v[10] = v[6] = box->x1 + src_dx;
+			v[9]  = box->y1 + dst_dy;
+			v[11] = box->y1 + src_dy;
+			v += 12; box++;
 		} while (--n_this_time);
 	} while (n);
 
 	gen7_vertex_flush(sna);
 	sna_render_composite_redirect_done(sna, &tmp);
-	kgem_bo_destroy(&sna->kgem, tmp.src.bo);
+	if (tmp.src.bo != src_bo)
+		kgem_bo_destroy(&sna->kgem, tmp.src.bo);
 	return true;
 
 fallback_tiled_src:
-	kgem_bo_destroy(&sna->kgem, tmp.src.bo);
+	if (tmp.src.bo != src_bo)
+		kgem_bo_destroy(&sna->kgem, tmp.src.bo);
 fallback_tiled_dst:
 	if (tmp.redirect.real_bo)
 		kgem_bo_destroy(&sna->kgem, tmp.dst.bo);
@@ -3573,19 +3595,20 @@ gen7_render_copy_blt(struct sna *sna,
 		     int16_t w,  int16_t h,
 		     int16_t dx, int16_t dy)
 {
-	gen7_get_rectangles(sna, &op->base, 1, gen7_emit_copy_state);
+	int16_t *v;
 
-	OUT_VERTEX(dx+w, dy+h);
-	OUT_VERTEX_F((sx+w)*op->base.src.scale[0]);
-	OUT_VERTEX_F((sy+h)*op->base.src.scale[1]);
+	gen7_get_rectangles(sna, &op->base, 1, gen7_emit_copy_state);
 
-	OUT_VERTEX(dx, dy+h);
-	OUT_VERTEX_F(sx*op->base.src.scale[0]);
-	OUT_VERTEX_F((sy+h)*op->base.src.scale[1]);
+	v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
+	sna->render.vertex_used += 6;
+	assert(sna->render.vertex_used <= sna->render.vertex_size);
 
-	OUT_VERTEX(dx, dy);
-	OUT_VERTEX_F(sx*op->base.src.scale[0]);
-	OUT_VERTEX_F(sy*op->base.src.scale[1]);
+	v[0]  = dx+w; v[1]  = dy+h;
+	v[2]  = sx+w; v[3]  = sy+h;
+	v[4]  = dx;   v[5]  = dy+h;
+	v[6]  = sx;   v[7]  = sy+h;
+	v[8]  = dx;   v[9]  = dy;
+	v[10] = sx;   v[11] = sy;
 }
 
 static void
@@ -3601,16 +3624,6 @@ gen7_render_copy(struct sna *sna, uint8_t alu,
 		 PixmapPtr dst, struct kgem_bo *dst_bo,
 		 struct sna_copy_op *op)
 {
-#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,
-			    op);
-#endif
-
 	DBG(("%s (alu=%d, src=(%dx%d), dst=(%dx%d))\n",
 	     __FUNCTION__, alu,
 	     src->drawable.width, src->drawable.height,
@@ -3646,8 +3659,6 @@ fallback:
 	if (!gen7_check_format(op->base.src.pict_format))
 		goto fallback;
 
-	op->base.op = PictOpSrc;
-
 	op->base.dst.pixmap = dst;
 	op->base.dst.width  = dst->drawable.width;
 	op->base.dst.height = dst->drawable.height;
@@ -3658,20 +3669,13 @@ fallback:
 		gen7_get_card_format(op->base.src.pict_format);
 	op->base.src.width  = src->drawable.width;
 	op->base.src.height = src->drawable.height;
-	op->base.src.scale[0] = 1.f/src->drawable.width;
-	op->base.src.scale[1] = 1.f/src->drawable.height;
 
 	op->base.mask.bo = NULL;
 
-	op->base.is_affine = true;
-	op->base.floats_per_vertex = 3;
-	op->base.floats_per_rect = 9;
+	op->base.floats_per_vertex = 2;
+	op->base.floats_per_rect = 6;
 
-	op->base.u.gen7.wm_kernel = GEN7_WM_KERNEL_NOMASK;
-	op->base.u.gen7.nr_surfaces = 2;
-	op->base.u.gen7.nr_inputs = 1;
-	op->base.u.gen7.ve_id = 1;
-	op->base.u.gen7.sampler = COPY_SAMPLER;
+	op->base.u.gen7.flags = COPY_FLAGS(alu);
 
 	kgem_set_mode(&sna->kgem, KGEM_RENDER);
 	if (!kgem_check_bo(&sna->kgem, dst_bo, src_bo, NULL)) {
@@ -3784,27 +3788,21 @@ gen7_render_fill_boxes(struct sna *sna,
 						     dst, dst_bo, box, n);
 	}
 
-#if NO_FILL_BOXES
-	return false;
-#endif
-
 	if (op == PictOpClear) {
 		pixel = 0;
 		op = PictOpSrc;
 	} else if (!sna_get_pixel_from_rgba(&pixel,
-				     color->red,
-				     color->green,
-				     color->blue,
-				     color->alpha,
-				     PICT_a8r8g8b8))
+					    color->red,
+					    color->green,
+					    color->blue,
+					    color->alpha,
+					    PICT_a8r8g8b8))
 		return false;
 
 	DBG(("%s(%08x x %d [(%d, %d), (%d, %d) ...])\n",
 	     __FUNCTION__, pixel, n,
 	     box[0].x1, box[0].y1, box[0].x2, box[0].y2));
 
-	tmp.op = op;
-
 	tmp.dst.pixmap = dst;
 	tmp.dst.width  = dst->drawable.width;
 	tmp.dst.height = dst->drawable.height;
@@ -3815,17 +3813,11 @@ gen7_render_fill_boxes(struct sna *sna,
 	tmp.src.bo = sna_render_get_solid(sna, pixel);
 	tmp.mask.bo = NULL;
 
-	tmp.is_affine = true;
-	tmp.floats_per_vertex = 3;
-	tmp.floats_per_rect = 9;
-	tmp.has_component_alpha = false;
+	tmp.floats_per_vertex = 2;
+	tmp.floats_per_rect = 6;
 	tmp.need_magic_ca_pass = false;
 
-	tmp.u.gen7.wm_kernel = GEN7_WM_KERNEL_NOMASK;
-	tmp.u.gen7.nr_surfaces = 2;
-	tmp.u.gen7.nr_inputs = 1;
-	tmp.u.gen7.ve_id = 1;
-	tmp.u.gen7.sampler = FILL_SAMPLER;
+	tmp.u.gen7.flags = FILL_FLAGS(op, format);
 
 	if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
 		kgem_submit(&sna->kgem);
@@ -3837,27 +3829,26 @@ gen7_render_fill_boxes(struct sna *sna,
 
 	do {
 		int n_this_time;
+		int16_t *v;
 
 		n_this_time = gen7_get_rectangles(sna, &tmp, n,
 						  gen7_emit_fill_state);
 		n -= n_this_time;
 
+		v = (int16_t *)(sna->render.vertices + sna->render.vertex_used);
+		sna->render.vertex_used += 6 * n_this_time;
+		assert(sna->render.vertex_used <= sna->render.vertex_size);
 		do {
 			DBG(("	(%d, %d), (%d, %d)\n",
 			     box->x1, box->y1, box->x2, box->y2));
-			OUT_VERTEX(box->x2, box->y2);
-			OUT_VERTEX_F(1);
-			OUT_VERTEX_F(1);
-
-			OUT_VERTEX(box->x1, box->y2);
-			OUT_VERTEX_F(0);
-			OUT_VERTEX_F(1);
 
-			OUT_VERTEX(box->x1, box->y1);
-			OUT_VERTEX_F(0);
-			OUT_VERTEX_F(0);
-
-			box++;
+			v[0] = box->x2;
+			v[5] = v[1] = box->y2;
+			v[8] = v[4] = box->x1;
+			v[9] = box->y1;
+			v[2] = v[3]  = v[7]  = 1;
+			v[6] = v[10] = v[11] = 0;
+			v += 12; box++;
 		} while (--n_this_time);
 	} while (n);
 
@@ -3871,21 +3862,23 @@ gen7_render_fill_op_blt(struct sna *sna,
 			const struct sna_fill_op *op,
 			int16_t x, int16_t y, int16_t w, int16_t h)
 {
+	int16_t *v;
+
 	DBG(("%s: (%d, %d)x(%d, %d)\n", __FUNCTION__, x, y, w, h));
 
 	gen7_get_rectangles(sna, &op->base, 1, gen7_emit_fill_state);
 
-	OUT_VERTEX(x+w, y+h);
-	OUT_VERTEX_F(1);
-	OUT_VERTEX_F(1);
+	v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
+	sna->render.vertex_used += 6;
+	assert(sna->render.vertex_used <= sna->render.vertex_size);
 
-	OUT_VERTEX(x, y+h);
-	OUT_VERTEX_F(0);
-	OUT_VERTEX_F(1);
+	v[0] = x+w;
+	v[4] = v[8] = x;
+	v[1] = v[5] = y+h;
+	v[9] = y;
 
-	OUT_VERTEX(x, y);
-	OUT_VERTEX_F(0);
-	OUT_VERTEX_F(0);
+	v[2] = v[3]  = v[7]  = 1;
+	v[6] = v[10] = v[11] = 0;
 }
 
 fastcall static void
@@ -3893,22 +3886,24 @@ gen7_render_fill_op_box(struct sna *sna,
 			const struct sna_fill_op *op,
 			const BoxRec *box)
 {
+	int16_t *v;
+
 	DBG(("%s: (%d, %d),(%d, %d)\n", __FUNCTION__,
 	     box->x1, box->y1, box->x2, box->y2));
 
 	gen7_get_rectangles(sna, &op->base, 1, gen7_emit_fill_state);
 
-	OUT_VERTEX(box->x2, box->y2);
-	OUT_VERTEX_F(1);
-	OUT_VERTEX_F(1);
+	v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
+	sna->render.vertex_used += 6;
+	assert(sna->render.vertex_used <= sna->render.vertex_size);
 
-	OUT_VERTEX(box->x1, box->y2);
-	OUT_VERTEX_F(0);
-	OUT_VERTEX_F(1);
+	v[0] = box->x2;
+	v[8] = v[4] = box->x1;
+	v[5] = v[1] = box->y2;
+	v[9] = box->y1;
 
-	OUT_VERTEX(box->x1, box->y1);
-	OUT_VERTEX_F(0);
-	OUT_VERTEX_F(0);
+	v[7] = v[2]  = v[3]  = 1;
+	v[6] = v[10] = v[11] = 0;
 }
 
 fastcall static void
@@ -3922,24 +3917,24 @@ gen7_render_fill_op_boxes(struct sna *sna,
 
 	do {
 		int nbox_this_time;
+		int16_t *v;
 
 		nbox_this_time = gen7_get_rectangles(sna, &op->base, nbox,
 						     gen7_emit_fill_state);
 		nbox -= nbox_this_time;
 
-		do {
-			OUT_VERTEX(box->x2, box->y2);
-			OUT_VERTEX_F(1);
-			OUT_VERTEX_F(1);
-
-			OUT_VERTEX(box->x1, box->y2);
-			OUT_VERTEX_F(0);
-			OUT_VERTEX_F(1);
+		v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
+		sna->render.vertex_used += 6 * nbox_this_time;
+		assert(sna->render.vertex_used <= sna->render.vertex_size);
 
-			OUT_VERTEX(box->x1, box->y1);
-			OUT_VERTEX_F(0);
-			OUT_VERTEX_F(0);
-			box++;
+		do {
+			v[0] = box->x2;
+			v[8] = v[4] = box->x1;
+			v[5] = v[1] = box->y2;
+			v[9] = box->y1;
+			v[7] = v[2]  = v[3]  = 1;
+			v[6] = v[10] = v[11] = 0;
+			box++; v += 12;
 		} while (--nbox_this_time);
 	} while (nbox);
 }
@@ -3960,13 +3955,6 @@ gen7_render_fill(struct sna *sna, uint8_t alu,
 {
 	DBG(("%s: (alu=%d, color=%x)\n", __FUNCTION__, alu, color));
 
-#if NO_FILL
-	return sna_blt_fill(sna, alu,
-			    dst_bo, dst->drawable.bitsPerPixel,
-			    color,
-			    op);
-#endif
-
 	if (prefer_blt_fill(sna, dst_bo) &&
 	    sna_blt_fill(sna, alu,
 			 dst_bo, dst->drawable.bitsPerPixel,
@@ -3984,8 +3972,6 @@ gen7_render_fill(struct sna *sna, uint8_t alu,
 	if (alu == GXclear)
 		color = 0;
 
-	op->base.op = PictOpSrc;
-
 	op->base.dst.pixmap = dst;
 	op->base.dst.width  = dst->drawable.width;
 	op->base.dst.height = dst->drawable.height;
@@ -3999,17 +3985,11 @@ gen7_render_fill(struct sna *sna, uint8_t alu,
 							dst->drawable.depth));
 	op->base.mask.bo = NULL;
 
-	op->base.is_affine = true;
-	op->base.has_component_alpha = false;
 	op->base.need_magic_ca_pass = false;
-	op->base.floats_per_vertex = 3;
-	op->base.floats_per_rect = 9;
+	op->base.floats_per_vertex = 2;
+	op->base.floats_per_rect = 6;
 
-	op->base.u.gen7.wm_kernel = GEN7_WM_KERNEL_NOMASK;
-	op->base.u.gen7.nr_surfaces = 2;
-	op->base.u.gen7.nr_inputs = 1;
-	op->base.u.gen7.ve_id = 1;
-	op->base.u.gen7.sampler = FILL_SAMPLER;
+	op->base.u.gen7.flags = FILL_FLAGS_NOBLEND;
 
 	if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
 		kgem_submit(&sna->kgem);
@@ -4052,11 +4032,7 @@ gen7_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
 		     uint8_t alu)
 {
 	struct sna_composite_op tmp;
-
-#if NO_FILL_BOXES
-	return gen7_render_fill_one_try_blt(sna, dst, bo, color,
-					    x1, y1, x2, y2, alu);
-#endif
+	int16_t *v;
 
 	/* Prefer to use the BLT if already engaged */
 	if (prefer_blt_fill(sna, bo) &&
@@ -4073,8 +4049,6 @@ gen7_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
 	if (alu == GXclear)
 		color = 0;
 
-	tmp.op = PictOpSrc;
-
 	tmp.dst.pixmap = dst;
 	tmp.dst.width  = dst->drawable.width;
 	tmp.dst.height = dst->drawable.height;
@@ -4088,17 +4062,11 @@ gen7_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
 							dst->drawable.depth));
 	tmp.mask.bo = NULL;
 
-	tmp.is_affine = true;
-	tmp.floats_per_vertex = 3;
-	tmp.floats_per_rect = 9;
-	tmp.has_component_alpha = 0;
+	tmp.floats_per_vertex = 2;
+	tmp.floats_per_rect = 6;
 	tmp.need_magic_ca_pass = false;
 
-	tmp.u.gen7.wm_kernel = GEN7_WM_KERNEL_NOMASK;
-	tmp.u.gen7.nr_surfaces = 2;
-	tmp.u.gen7.nr_inputs = 1;
-	tmp.u.gen7.ve_id = 1;
-	tmp.u.gen7.sampler = FILL_SAMPLER;
+	tmp.u.gen7.flags = FILL_FLAGS_NOBLEND;
 
 	if (!kgem_check_bo(&sna->kgem, bo, NULL)) {
 		_kgem_submit(&sna->kgem);
@@ -4111,17 +4079,17 @@ gen7_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
 	gen7_get_rectangles(sna, &tmp, 1, gen7_emit_fill_state);
 
 	DBG(("	(%d, %d), (%d, %d)\n", x1, y1, x2, y2));
-	OUT_VERTEX(x2, y2);
-	OUT_VERTEX_F(1);
-	OUT_VERTEX_F(1);
 
-	OUT_VERTEX(x1, y2);
-	OUT_VERTEX_F(0);
-	OUT_VERTEX_F(1);
+	v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
+	sna->render.vertex_used += 6;
+	assert(sna->render.vertex_used <= sna->render.vertex_size);
 
-	OUT_VERTEX(x1, y1);
-	OUT_VERTEX_F(0);
-	OUT_VERTEX_F(0);
+	v[0] = x2;
+	v[8] = v[4] = x1;
+	v[5] = v[1] = y2;
+	v[9] = y1;
+	v[7] = v[2]  = v[3]  = 1;
+	v[6] = v[10] = v[11] = 0;
 
 	gen7_vertex_flush(sna);
 	kgem_bo_destroy(&sna->kgem, tmp.src.bo);
@@ -4148,10 +4116,7 @@ static bool
 gen7_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
 {
 	struct sna_composite_op tmp;
-
-#if NO_CLEAR
-	return gen7_render_clear_try_blt(sna, dst, bo);
-#endif
+	int16_t *v;
 
 	DBG(("%s: %dx%d\n",
 	     __FUNCTION__,
@@ -4167,8 +4132,6 @@ gen7_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
 	if (too_large(dst->drawable.width, dst->drawable.height))
 		return gen7_render_clear_try_blt(sna, dst, bo);
 
-	tmp.op = PictOpSrc;
-
 	tmp.dst.pixmap = dst;
 	tmp.dst.width  = dst->drawable.width;
 	tmp.dst.height = dst->drawable.height;
@@ -4179,17 +4142,11 @@ gen7_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
 	tmp.src.bo = sna_render_get_solid(sna, 0);
 	tmp.mask.bo = NULL;
 
-	tmp.is_affine = true;
-	tmp.floats_per_vertex = 3;
-	tmp.floats_per_rect = 9;
-	tmp.has_component_alpha = 0;
+	tmp.floats_per_vertex = 2;
+	tmp.floats_per_rect = 6;
 	tmp.need_magic_ca_pass = false;
 
-	tmp.u.gen7.wm_kernel = GEN7_WM_KERNEL_NOMASK;
-	tmp.u.gen7.nr_surfaces = 2;
-	tmp.u.gen7.nr_inputs = 1;
-	tmp.u.gen7.ve_id = 1;
-	tmp.u.gen7.sampler = FILL_SAMPLER;
+	tmp.u.gen7.flags = FILL_FLAGS_NOBLEND;
 
 	if (!kgem_check_bo(&sna->kgem, bo, NULL)) {
 		_kgem_submit(&sna->kgem);
@@ -4201,17 +4158,17 @@ gen7_render_clear(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo)
 
 	gen7_get_rectangles(sna, &tmp, 1, gen7_emit_fill_state);
 
-	OUT_VERTEX(dst->drawable.width, dst->drawable.height);
-	OUT_VERTEX_F(1);
-	OUT_VERTEX_F(1);
+	v = (int16_t *)&sna->render.vertices[sna->render.vertex_used];
+	sna->render.vertex_used += 6;
+	assert(sna->render.vertex_used <= sna->render.vertex_size);
 
-	OUT_VERTEX(0, dst->drawable.height);
-	OUT_VERTEX_F(0);
-	OUT_VERTEX_F(1);
+	v[0] = dst->drawable.width;
+	v[5] = v[1] = dst->drawable.height;
+	v[8] = v[4] = 0;
+	v[9] = 0;
 
-	OUT_VERTEX(0, 0);
-	OUT_VERTEX_F(0);
-	OUT_VERTEX_F(0);
+	v[7] = v[2]  = v[3]  = 1;
+	v[6] = v[10] = v[11] = 0;
 
 	gen7_vertex_flush(sna);
 	kgem_bo_destroy(&sna->kgem, tmp.src.bo);
@@ -4322,10 +4279,13 @@ static bool gen7_render_setup(struct sna *sna)
 
 	ss = sna_static_stream_map(&general,
 				   2 * sizeof(*ss) *
-				   FILTER_COUNT * EXTEND_COUNT *
-				   FILTER_COUNT * EXTEND_COUNT,
+				   (2 +
+				    FILTER_COUNT * EXTEND_COUNT *
+				    FILTER_COUNT * EXTEND_COUNT),
 				   32);
 	state->wm_state = sna_static_stream_offsetof(&general, ss);
+	sampler_copy_init(ss); ss += 2;
+	sampler_fill_init(ss); ss += 2;
 	for (i = 0; i < FILTER_COUNT; i++) {
 		for (j = 0; j < EXTEND_COUNT; j++) {
 			for (k = 0; k < FILTER_COUNT; k++) {
@@ -4353,19 +4313,33 @@ bool gen7_render_init(struct sna *sna)
 	sna->kgem.retire = gen7_render_retire;
 	sna->kgem.expire = gen7_render_expire;
 
+#if !NO_COMPOSITE
 	sna->render.composite = gen7_render_composite;
+#endif
 #if !NO_COMPOSITE_SPANS
 	sna->render.composite_spans = gen7_render_composite_spans;
 #endif
 	sna->render.video = gen7_render_video;
 
+#if !NO_COPY_BOXES
 	sna->render.copy_boxes = gen7_render_copy_boxes;
+#endif
+#if !NO_COPY
 	sna->render.copy = gen7_render_copy;
+#endif
 
+#if !NO_FILL_BOXES
 	sna->render.fill_boxes = gen7_render_fill_boxes;
+#endif
+#if !NO_FILL
 	sna->render.fill = gen7_render_fill;
+#endif
+#if !NO_FILL_ONE
 	sna->render.fill_one = gen7_render_fill_one;
+#endif
+#if !NO_FILL_CLEAR
 	sna->render.clear = gen7_render_clear;
+#endif
 
 	sna->render.flush = gen7_render_flush;
 	sna->render.reset = gen7_render_reset;
diff --git a/src/sna/sna_render.h b/src/sna/sna_render.h
index 0f96ace..15d882f 100644
--- a/src/sna/sna_render.h
+++ b/src/sna/sna_render.h
@@ -133,11 +133,7 @@ struct sna_composite_op {
 		} gen6;
 
 		struct {
-			int wm_kernel;
-			int nr_surfaces;
-			int nr_inputs;
-			int ve_id;
-			int sampler;
+			uint32_t flags;
 		} gen7;
 	} u;
 
commit 267429bbb146449ee4d3b88fa8e23c5b1d53470a
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jul 18 19:24:44 2012 +0100

    sna: Enable runtime detection of set-cacheing ioctl
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/configure.ac b/configure.ac
index 90dae7e..b3a786d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -247,16 +247,6 @@ if test "x$accel" = xno; then
 	AC_MSG_ERROR([No default acceleration option])
 fi
 
-AC_ARG_ENABLE(cache-level,
-	      AS_HELP_STRING([--enable-cache-level],
-			     [Enable use of cache level ioctl (experimental) [default=no]]),
-	      [CACHE_LEVEL="$enableval"],
-	      [CACHE_LEVEL=no])
-AM_CONDITIONAL(USE_CACHE_LEVEL, test x$CACHE_LEVEL = xyes)
-if test "x$CACHE_LEVEL" = xyes; then
-	AC_DEFINE(USE_CACHE_LEVEL,1,[Assume DRM_I915_GEM_SET_CACHE_LEVEL_IOCTL support])
-fi
-
 AC_ARG_ENABLE(vmap,
 	      AS_HELP_STRING([--enable-vmap],
 			     [Enable use of vmap (experimental) [default=no]]),
diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index 6327e49..e5c97f6 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -104,22 +104,16 @@ struct drm_i915_gem_vmap {
 };
 #endif
 
-#if !defined(DRM_I915_GEM_SET_CACHE_LEVEL)
-#define I915_CACHE_NONE		0
-#define I915_CACHE_LLC		1
-#define I915_CACHE_LLC_MLC	2 /* gen6+ */
+#define UNCACHED	0
+#define SNOOPED		1
 
-struct drm_i915_gem_cache_level {
-	/** Handle of the buffer to check for busy */
-	__u32 handle;
-
-	/** Cache level to apply or return value */
-	__u32 cache_level;
+struct local_i915_gem_cacheing {
+	uint32_t handle;
+	uint32_t cacheing;
 };
 
-#define DRM_I915_GEM_SET_CACHE_LEVEL	0x2f
-#define DRM_IOCTL_I915_GEM_SET_CACHE_LEVEL		DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_SET_CACHE_LEVEL, struct drm_i915_gem_cache_level)
-#endif
+#define LOCAL_I915_GEM_SET_CACHEING	0x2f
+#define LOCAL_IOCTL_I915_GEM_SET_CACHEING DRM_IOW(DRM_COMMAND_BASE + LOCAL_I915_GEM_SET_CACHEING, struct local_i915_gem_cacheing)
 
 struct kgem_partial_bo {
 	struct kgem_bo base;
@@ -193,14 +187,14 @@ static int gem_set_tiling(int fd, uint32_t handle, int tiling, int stride)
 	return set_tiling.tiling_mode;
 }
 
-static bool gem_set_cache_level(int fd, uint32_t handle, int cache_level)
+static bool gem_set_cacheing(int fd, uint32_t handle, int cacheing)
 {
-	struct drm_i915_gem_cache_level arg;
+	struct local_i915_gem_cacheing arg;
 
 	VG_CLEAR(arg);
 	arg.handle = handle;
-	arg.cache_level = cache_level;
-	return drmIoctl(fd, DRM_IOCTL_I915_GEM_SET_CACHE_LEVEL, &arg) == 0;
+	arg.cacheing = cacheing;
+	return drmIoctl(fd, LOCAL_IOCTL_I915_GEM_SET_CACHEING, &arg) == 0;
 }
 
 static bool __kgem_throttle_retire(struct kgem *kgem, unsigned flags)
@@ -681,9 +675,8 @@ static bool test_has_llc(struct kgem *kgem)
 	return has_llc;
 }
 
-static bool test_has_cache_level(struct kgem *kgem)
+static bool test_has_cacheing(struct kgem *kgem)
 {
-#if defined(USE_CACHE_LEVEL)
 	uint32_t handle;
 	bool ret;
 
@@ -698,12 +691,9 @@ static bool test_has_cache_level(struct kgem *kgem)
 	if (handle == 0)
 		return false;
 
-	ret = gem_set_cache_level(kgem->fd, handle, I915_CACHE_NONE);
+	ret = gem_set_cacheing(kgem->fd, handle, UNCACHED);
 	gem_close(kgem->fd, handle);
 	return ret;
-#else
-	return false;
-#endif
 }
 
 static bool test_has_vmap(struct kgem *kgem)
@@ -759,9 +749,9 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, int gen)
 	DBG(("%s: has shared last-level-cache? %d\n", __FUNCTION__,
 	     kgem->has_llc));
 
-	kgem->has_cache_level = test_has_cache_level(kgem);
+	kgem->has_cacheing = test_has_cacheing(kgem);
 	DBG(("%s: has set-cache-level? %d\n", __FUNCTION__,
-	     kgem->has_cache_level));
+	     kgem->has_cacheing));
 
 	kgem->has_vmap = test_has_vmap(kgem);
 	DBG(("%s: has vmap? %d\n", __FUNCTION__,
@@ -830,8 +820,8 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, int gen)
 	kgem->next_request = __kgem_request_alloc();
 
 	DBG(("%s: cpu bo enabled %d: llc? %d, set-cache-level? %d, vmap? %d\n", __FUNCTION__,
-	     kgem->has_llc | kgem->has_vmap | kgem->has_cache_level,
-	     kgem->has_llc, kgem->has_cache_level, kgem->has_vmap));
+	     kgem->has_llc | kgem->has_vmap | kgem->has_cacheing,
+	     kgem->has_llc, kgem->has_cacheing, kgem->has_vmap));
 
 	VG_CLEAR(aperture);
 	aperture.aper_size = 64*1024*1024;
@@ -902,7 +892,7 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, int gen)
 	kgem->large_object_size = MAX_CACHE_SIZE;
 	if (kgem->large_object_size > kgem->max_gpu_size)
 		kgem->large_object_size = kgem->max_gpu_size;
-	if (kgem->has_llc | kgem->has_cache_level | kgem->has_vmap) {
+	if (kgem->has_llc | kgem->has_cacheing | kgem->has_vmap) {
 		if (kgem->large_object_size > kgem->max_cpu_size)
 			kgem->large_object_size = kgem->max_cpu_size;
 	} else
@@ -3249,7 +3239,7 @@ struct kgem_bo *kgem_create_cpu_2d(struct kgem *kgem,
 		return bo;
 	}
 
-	if (kgem->has_cache_level) {
+	if (kgem->has_cacheing) {
 		bo = kgem_create_linear(kgem, size, flags);
 		if (bo == NULL)
 			return NULL;
@@ -3258,7 +3248,7 @@ struct kgem_bo *kgem_create_cpu_2d(struct kgem *kgem,
 
 		bo->reusable = false;
 		bo->vmap = true;
-		if (!gem_set_cache_level(kgem->fd, bo->handle, I915_CACHE_LLC) ||
+		if (!gem_set_cacheing(kgem->fd, bo->handle, SNOOPED) ||
 		    kgem_bo_map__cpu(kgem, bo) == NULL) {
 			kgem_bo_destroy(kgem, bo);
 			return NULL;
@@ -4004,14 +3994,14 @@ create_snoopable_buffer(struct kgem *kgem, unsigned alloc)
 {
 	struct kgem_partial_bo *bo;
 
-	if (kgem->has_cache_level) {
+	if (kgem->has_cacheing) {
 		uint32_t handle;
 
 		handle = gem_create(kgem->fd, alloc);
 		if (handle == 0)
 			return NULL;
 
-		if (!gem_set_cache_level(kgem->fd, handle, I915_CACHE_LLC)) {
+		if (!gem_set_cacheing(kgem->fd, handle, SNOOPED)) {
 			gem_close(kgem->fd, handle);
 			return NULL;
 		}
diff --git a/src/sna/kgem.h b/src/sna/kgem.h
index b8d755c..b038bb1 100644
--- a/src/sna/kgem.h
+++ b/src/sna/kgem.h
@@ -158,7 +158,7 @@ struct kgem {
 	uint32_t has_relaxed_fencing :1;
 	uint32_t has_relaxed_delta :1;
 	uint32_t has_semaphores :1;
-	uint32_t has_cache_level :1;
+	uint32_t has_cacheing :1;
 	uint32_t has_llc :1;
 
 	uint32_t can_blt_cpu :1;
commit c0b3674d042ff55d64ad1fd0d64926e1967be323
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Wed Jul 18 20:48:27 2012 +0100

    sna/trapezoids: Only reduce bounded operators to a single pass
    
    Only for a few operators can we replace the opacity mask by
    premultiplying into the source.
    
    Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

diff --git a/src/sna/sna_trapezoids.c b/src/sna/sna_trapezoids.c
index 7124baf..c3a5447 100644
--- a/src/sna/sna_trapezoids.c
+++ b/src/sna/sna_trapezoids.c
@@ -4873,11 +4873,36 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
 {
 	struct tor tor;
 	span_func_t span;
+	uint32_t color;
+	bool lerp;
 	RegionRec region;
 	int16_t dst_x, dst_y;
 	int dx, dy;
 	int n;
 
+	lerp = false;
+	if (sna_picture_is_solid(src, &color)) {
+		if (op == PictOpOver && (color >> 24) == 0xff)
+			op = PictOpSrc;
+		if (op == PictOpOver && sna_drawable_is_clear(dst->pDrawable))
+			op = PictOpSrc;
+		lerp = op == PictOpSrc;
+	}
+	if (!lerp) {
+		switch (op) {
+		case PictOpOver:
+		case PictOpAdd:
+		case PictOpOutReverse:
+			break;
+		case PictOpSrc:
+			if (!sna_drawable_is_clear(dst->pDrawable))
+				return false;
+			break;
+		default:
+			return false;
+		}
+	}
+
 	if (maskFormat == NULL && ntrap > 1) {
 		DBG(("%s: individual rasterisation requested\n",
 		     __FUNCTION__));
@@ -4902,8 +4927,8 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
 	     region.extents.x2, region.extents.y2));
 
 	if (!sna_compute_composite_extents(&region.extents,
-					   NULL, NULL, dst,
-					   0, 0,
+					   src, NULL, dst,
+					   src_x, src_y,
 					   0, 0,
 					   region.extents.x1, region.extents.y1,
 					   region.extents.x2 - region.extents.x1,
@@ -4940,26 +4965,14 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
 	if (sna_drawable_move_region_to_cpu(dst->pDrawable, &region,
 					    MOVE_WRITE | MOVE_READ)) {
 		PixmapPtr pixmap;
-		uint32_t color;
 
 		pixmap = get_drawable_pixmap(dst->pDrawable);
 		get_drawable_deltas(dst->pDrawable, pixmap, &dst_x, &dst_y);
 
-		if (!sna_picture_is_solid(src, &color))
-			goto pixman;
-
-		if (op == PictOpOver && (color >> 24) == 0xff)
-			op = PictOpSrc;
-		if (op == PictOpOver) {
-			struct sna_pixmap *priv = sna_pixmap_from_drawable(dst->pDrawable);
-			if (priv && priv->clear && priv->clear_color == 0)
-				op = PictOpSrc;
-		}
-
 		DBG(("%s: format=%x, op=%d, color=%x\n",
 		     __FUNCTION__, dst->format, op, color));
 
-		if (op == PictOpSrc) {
+		if (lerp) {
 			struct inplace inplace;
 
 			inplace.ptr = pixmap->devPrivate.ptr;
@@ -4981,11 +4994,10 @@ trapezoid_span_inplace__x8r8g8b8(CARD8 op,
 		} else {
 			struct pixman_inplace pi;
 
-pixman:
 			pi.image = image_from_pict(dst, false, &pi.dx, &pi.dy);
 			pi.source = image_from_pict(src, false, &pi.sx, &pi.sy);
-			pi.sx += src_x;
-			pi.sy += src_y;
+			pi.sx += src_x - pixman_fixed_to_int(traps[0].left.p1.x);
+			pi.sy += src_y - pixman_fixed_to_int(traps[0].left.p1.y);
 			pi.mask = pixman_image_create_bits(PIXMAN_a8, 1, 1, NULL, 0);
 			pixman_image_set_repeat(pi.mask, PIXMAN_REPEAT_NORMAL);
 			pi.bits = pixman_image_get_data(pi.mask);
@@ -4998,7 +5010,7 @@ pixman:
 
 			tor_render(NULL, &tor, (void*)&pi,
 				   dst->pCompositeClip, span,
-				   operator_is_bounded(op));
+				   false);
 			tor_fini(&tor);
 
 			pixman_image_unref(pi.mask);


More information about the xorg-commit mailing list