1428d7b3dSmrg/*
2428d7b3dSmrg * Copyright © 2006,2008,2011 Intel Corporation
3428d7b3dSmrg * Copyright © 2007 Red Hat, Inc.
4428d7b3dSmrg *
5428d7b3dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
6428d7b3dSmrg * copy of this software and associated documentation files (the "Software"),
7428d7b3dSmrg * to deal in the Software without restriction, including without limitation
8428d7b3dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9428d7b3dSmrg * and/or sell copies of the Software, and to permit persons to whom the
10428d7b3dSmrg * Software is furnished to do so, subject to the following conditions:
11428d7b3dSmrg *
12428d7b3dSmrg * The above copyright notice and this permission notice (including the next
13428d7b3dSmrg * paragraph) shall be included in all copies or substantial portions of the
14428d7b3dSmrg * Software.
15428d7b3dSmrg *
16428d7b3dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17428d7b3dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18428d7b3dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19428d7b3dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20428d7b3dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21428d7b3dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22428d7b3dSmrg * SOFTWARE.
23428d7b3dSmrg *
24428d7b3dSmrg * Authors:
25428d7b3dSmrg *    Wang Zhenyu <zhenyu.z.wang@sna.com>
26428d7b3dSmrg *    Eric Anholt <eric@anholt.net>
27428d7b3dSmrg *    Carl Worth <cworth@redhat.com>
28428d7b3dSmrg *    Keith Packard <keithp@keithp.com>
29428d7b3dSmrg *    Chris Wilson <chris@chris-wilson.co.uk>
30428d7b3dSmrg *
31428d7b3dSmrg */
32428d7b3dSmrg
33428d7b3dSmrg#ifdef HAVE_CONFIG_H
34428d7b3dSmrg#include "config.h"
35428d7b3dSmrg#endif
36428d7b3dSmrg
37428d7b3dSmrg#include "sna.h"
38428d7b3dSmrg#include "sna_reg.h"
39428d7b3dSmrg#include "sna_render.h"
40428d7b3dSmrg#include "sna_render_inline.h"
41428d7b3dSmrg#include "sna_video.h"
42428d7b3dSmrg
43428d7b3dSmrg#include "brw/brw.h"
44428d7b3dSmrg#include "gen5_render.h"
45428d7b3dSmrg#include "gen4_common.h"
46428d7b3dSmrg#include "gen4_source.h"
47428d7b3dSmrg#include "gen4_vertex.h"
48428d7b3dSmrg
49428d7b3dSmrg#define NO_COMPOSITE 0
50428d7b3dSmrg#define NO_COMPOSITE_SPANS 0
51428d7b3dSmrg
52428d7b3dSmrg#define PREFER_BLT_FILL 1
53428d7b3dSmrg
54428d7b3dSmrg#define DBG_NO_STATE_CACHE 0
55428d7b3dSmrg#define DBG_NO_SURFACE_CACHE 0
56428d7b3dSmrg
57428d7b3dSmrg#define ALWAYS_FLUSH 0
58428d7b3dSmrg
59428d7b3dSmrg#define MAX_3D_SIZE 8192
60428d7b3dSmrg
61428d7b3dSmrg#define GEN5_GRF_BLOCKS(nreg)    ((nreg + 15) / 16 - 1)
62428d7b3dSmrg
63428d7b3dSmrg/* Set up a default static partitioning of the URB, which is supposed to
64428d7b3dSmrg * allow anything we would want to do, at potentially lower performance.
65428d7b3dSmrg */
66428d7b3dSmrg#define URB_CS_ENTRY_SIZE     1
67428d7b3dSmrg#define URB_CS_ENTRIES	      0
68428d7b3dSmrg
69428d7b3dSmrg#define URB_VS_ENTRY_SIZE     1
70428d7b3dSmrg#define URB_VS_ENTRIES	      256 /* minimum of 8 */
71428d7b3dSmrg
72428d7b3dSmrg#define URB_GS_ENTRY_SIZE     0
73428d7b3dSmrg#define URB_GS_ENTRIES	      0
74428d7b3dSmrg
75428d7b3dSmrg#define URB_CLIP_ENTRY_SIZE   0
76428d7b3dSmrg#define URB_CLIP_ENTRIES      0
77428d7b3dSmrg
78428d7b3dSmrg#define URB_SF_ENTRY_SIZE     2
79428d7b3dSmrg#define URB_SF_ENTRIES	      64
80428d7b3dSmrg
81428d7b3dSmrg/*
82428d7b3dSmrg * this program computes dA/dx and dA/dy for the texture coordinates along
83428d7b3dSmrg * with the base texture coordinate. It was extracted from the Mesa driver
84428d7b3dSmrg */
85428d7b3dSmrg
86428d7b3dSmrg#define SF_KERNEL_NUM_GRF  16
87428d7b3dSmrg#define SF_MAX_THREADS	   48
88428d7b3dSmrg
89428d7b3dSmrg#define PS_KERNEL_NUM_GRF   32
90428d7b3dSmrg#define PS_MAX_THREADS	    72
91428d7b3dSmrg
92428d7b3dSmrgstatic const uint32_t ps_kernel_packed_static[][4] = {
93428d7b3dSmrg#include "exa_wm_xy.g5b"
94428d7b3dSmrg#include "exa_wm_src_affine.g5b"
95428d7b3dSmrg#include "exa_wm_src_sample_argb.g5b"
96428d7b3dSmrg#include "exa_wm_yuv_rgb.g5b"
97428d7b3dSmrg#include "exa_wm_write.g5b"
98428d7b3dSmrg};
99428d7b3dSmrg
100428d7b3dSmrgstatic const uint32_t ps_kernel_planar_static[][4] = {
101428d7b3dSmrg#include "exa_wm_xy.g5b"
102428d7b3dSmrg#include "exa_wm_src_affine.g5b"
103428d7b3dSmrg#include "exa_wm_src_sample_planar.g5b"
104428d7b3dSmrg#include "exa_wm_yuv_rgb.g5b"
105428d7b3dSmrg#include "exa_wm_write.g5b"
106428d7b3dSmrg};
107428d7b3dSmrg
108428d7b3dSmrg#define NOKERNEL(kernel_enum, func, masked) \
109428d7b3dSmrg    [kernel_enum] = {func, 0, masked}
110428d7b3dSmrg#define KERNEL(kernel_enum, kernel, masked) \
111428d7b3dSmrg    [kernel_enum] = {&kernel, sizeof(kernel), masked}
112428d7b3dSmrgstatic const struct wm_kernel_info {
113428d7b3dSmrg	const void *data;
114428d7b3dSmrg	unsigned int size;
115428d7b3dSmrg	bool has_mask;
116428d7b3dSmrg} wm_kernels[] = {
117428d7b3dSmrg	NOKERNEL(WM_KERNEL, brw_wm_kernel__affine, false),
118428d7b3dSmrg	NOKERNEL(WM_KERNEL_P, brw_wm_kernel__projective, false),
119428d7b3dSmrg
120428d7b3dSmrg	NOKERNEL(WM_KERNEL_MASK, brw_wm_kernel__affine_mask, true),
121428d7b3dSmrg	NOKERNEL(WM_KERNEL_MASK_P, brw_wm_kernel__projective_mask, true),
122428d7b3dSmrg
123428d7b3dSmrg	NOKERNEL(WM_KERNEL_MASKCA, brw_wm_kernel__affine_mask_ca, true),
124428d7b3dSmrg	NOKERNEL(WM_KERNEL_MASKCA_P, brw_wm_kernel__projective_mask_ca, true),
125428d7b3dSmrg
126428d7b3dSmrg	NOKERNEL(WM_KERNEL_MASKSA, brw_wm_kernel__affine_mask_sa, true),
127428d7b3dSmrg	NOKERNEL(WM_KERNEL_MASKSA_P, brw_wm_kernel__projective_mask_sa, true),
128428d7b3dSmrg
129428d7b3dSmrg	NOKERNEL(WM_KERNEL_OPACITY, brw_wm_kernel__affine_opacity, true),
130428d7b3dSmrg	NOKERNEL(WM_KERNEL_OPACITY_P, brw_wm_kernel__projective_opacity, true),
131428d7b3dSmrg
132428d7b3dSmrg	KERNEL(WM_KERNEL_VIDEO_PLANAR, ps_kernel_planar_static, false),
133428d7b3dSmrg	KERNEL(WM_KERNEL_VIDEO_PACKED, ps_kernel_packed_static, false),
134428d7b3dSmrg};
135428d7b3dSmrg#undef KERNEL
136428d7b3dSmrg
137428d7b3dSmrgstatic const struct blendinfo {
138428d7b3dSmrg	bool src_alpha;
139428d7b3dSmrg	uint32_t src_blend;
140428d7b3dSmrg	uint32_t dst_blend;
141428d7b3dSmrg} gen5_blend_op[] = {
142428d7b3dSmrg	/* Clear */	{0, GEN5_BLENDFACTOR_ZERO, GEN5_BLENDFACTOR_ZERO},
143428d7b3dSmrg	/* Src */	{0, GEN5_BLENDFACTOR_ONE, GEN5_BLENDFACTOR_ZERO},
144428d7b3dSmrg	/* Dst */	{0, GEN5_BLENDFACTOR_ZERO, GEN5_BLENDFACTOR_ONE},
145428d7b3dSmrg	/* Over */	{1, GEN5_BLENDFACTOR_ONE, GEN5_BLENDFACTOR_INV_SRC_ALPHA},
146428d7b3dSmrg	/* OverReverse */ {0, GEN5_BLENDFACTOR_INV_DST_ALPHA, GEN5_BLENDFACTOR_ONE},
147428d7b3dSmrg	/* In */	{0, GEN5_BLENDFACTOR_DST_ALPHA, GEN5_BLENDFACTOR_ZERO},
148428d7b3dSmrg	/* InReverse */	{1, GEN5_BLENDFACTOR_ZERO, GEN5_BLENDFACTOR_SRC_ALPHA},
149428d7b3dSmrg	/* Out */	{0, GEN5_BLENDFACTOR_INV_DST_ALPHA, GEN5_BLENDFACTOR_ZERO},
150428d7b3dSmrg	/* OutReverse */ {1, GEN5_BLENDFACTOR_ZERO, GEN5_BLENDFACTOR_INV_SRC_ALPHA},
151428d7b3dSmrg	/* Atop */	{1, GEN5_BLENDFACTOR_DST_ALPHA, GEN5_BLENDFACTOR_INV_SRC_ALPHA},
152428d7b3dSmrg	/* AtopReverse */ {1, GEN5_BLENDFACTOR_INV_DST_ALPHA, GEN5_BLENDFACTOR_SRC_ALPHA},
153428d7b3dSmrg	/* Xor */	{1, GEN5_BLENDFACTOR_INV_DST_ALPHA, GEN5_BLENDFACTOR_INV_SRC_ALPHA},
154428d7b3dSmrg	/* Add */	{0, GEN5_BLENDFACTOR_ONE, GEN5_BLENDFACTOR_ONE},
155428d7b3dSmrg};
156428d7b3dSmrg
157428d7b3dSmrg/**
158428d7b3dSmrg * Highest-valued BLENDFACTOR used in gen5_blend_op.
159428d7b3dSmrg *
160428d7b3dSmrg * This leaves out GEN5_BLENDFACTOR_INV_DST_COLOR,
161428d7b3dSmrg * GEN5_BLENDFACTOR_INV_CONST_{COLOR,ALPHA},
162428d7b3dSmrg * GEN5_BLENDFACTOR_INV_SRC1_{COLOR,ALPHA}
163428d7b3dSmrg */
164428d7b3dSmrg#define GEN5_BLENDFACTOR_COUNT (GEN5_BLENDFACTOR_INV_DST_ALPHA + 1)
165428d7b3dSmrg
166428d7b3dSmrg#define BLEND_OFFSET(s, d) \
167428d7b3dSmrg	(((s) * GEN5_BLENDFACTOR_COUNT + (d)) * 64)
168428d7b3dSmrg
169428d7b3dSmrg#define SAMPLER_OFFSET(sf, se, mf, me, k) \
170428d7b3dSmrg	((((((sf) * EXTEND_COUNT + (se)) * FILTER_COUNT + (mf)) * EXTEND_COUNT + (me)) * KERNEL_COUNT + (k)) * 64)
171428d7b3dSmrg
172428d7b3dSmrgstatic bool
173428d7b3dSmrggen5_emit_pipelined_pointers(struct sna *sna,
174428d7b3dSmrg			     const struct sna_composite_op *op,
175428d7b3dSmrg			     int blend, int kernel);
176428d7b3dSmrg
177428d7b3dSmrg#define OUT_BATCH(v) batch_emit(sna, v)
178428d7b3dSmrg#define OUT_VERTEX(x,y) vertex_emit_2s(sna, x,y)
179428d7b3dSmrg#define OUT_VERTEX_F(v) vertex_emit(sna, v)
180428d7b3dSmrg
181428d7b3dSmrgstatic inline bool too_large(int width, int height)
182428d7b3dSmrg{
183428d7b3dSmrg	return width > MAX_3D_SIZE || height > MAX_3D_SIZE;
184428d7b3dSmrg}
185428d7b3dSmrg
186428d7b3dSmrgstatic int
187428d7b3dSmrggen5_choose_composite_kernel(int op, bool has_mask, bool is_ca, bool is_affine)
188428d7b3dSmrg{
189428d7b3dSmrg	int base;
190428d7b3dSmrg
191428d7b3dSmrg	if (has_mask) {
192428d7b3dSmrg		if (is_ca) {
193428d7b3dSmrg			if (gen5_blend_op[op].src_alpha)
194428d7b3dSmrg				base = WM_KERNEL_MASKSA;
195428d7b3dSmrg			else
196428d7b3dSmrg				base = WM_KERNEL_MASKCA;
197428d7b3dSmrg		} else
198428d7b3dSmrg			base = WM_KERNEL_MASK;
199428d7b3dSmrg	} else
200428d7b3dSmrg		base = WM_KERNEL;
201428d7b3dSmrg
202428d7b3dSmrg	return base + !is_affine;
203428d7b3dSmrg}
204428d7b3dSmrg
205428d7b3dSmrgstatic bool gen5_magic_ca_pass(struct sna *sna,
206428d7b3dSmrg			       const struct sna_composite_op *op)
207428d7b3dSmrg{
208428d7b3dSmrg	struct gen5_render_state *state = &sna->render_state.gen5;
209428d7b3dSmrg
210428d7b3dSmrg	if (!op->need_magic_ca_pass)
211428d7b3dSmrg		return false;
212428d7b3dSmrg
213428d7b3dSmrg	assert(sna->render.vertex_index > sna->render.vertex_start);
214428d7b3dSmrg
215428d7b3dSmrg	DBG(("%s: CA fixup\n", __FUNCTION__));
216428d7b3dSmrg	assert(op->mask.bo != NULL);
217428d7b3dSmrg	assert(op->has_component_alpha);
218428d7b3dSmrg
219428d7b3dSmrg	gen5_emit_pipelined_pointers
220428d7b3dSmrg		(sna, op, PictOpAdd,
221428d7b3dSmrg		 gen5_choose_composite_kernel(PictOpAdd,
222428d7b3dSmrg					      true, true, op->is_affine));
223428d7b3dSmrg
224428d7b3dSmrg	OUT_BATCH(GEN5_3DPRIMITIVE |
225428d7b3dSmrg		  GEN5_3DPRIMITIVE_VERTEX_SEQUENTIAL |
226428d7b3dSmrg		  (_3DPRIM_RECTLIST << GEN5_3DPRIMITIVE_TOPOLOGY_SHIFT) |
227428d7b3dSmrg		  (0 << 9) |
228428d7b3dSmrg		  4);
229428d7b3dSmrg	OUT_BATCH(sna->render.vertex_index - sna->render.vertex_start);
230428d7b3dSmrg	OUT_BATCH(sna->render.vertex_start);
231428d7b3dSmrg	OUT_BATCH(1);	/* single instance */
232428d7b3dSmrg	OUT_BATCH(0);	/* start instance location */
233428d7b3dSmrg	OUT_BATCH(0);	/* index buffer offset, ignored */
234428d7b3dSmrg
235428d7b3dSmrg	state->last_primitive = sna->kgem.nbatch;
236428d7b3dSmrg	return true;
237428d7b3dSmrg}
238428d7b3dSmrg
239428d7b3dSmrgstatic uint32_t gen5_get_blend(int op,
240428d7b3dSmrg			       bool has_component_alpha,
241428d7b3dSmrg			       uint32_t dst_format)
242428d7b3dSmrg{
243428d7b3dSmrg	uint32_t src, dst;
244428d7b3dSmrg
245428d7b3dSmrg	src = gen5_blend_op[op].src_blend;
246428d7b3dSmrg	dst = gen5_blend_op[op].dst_blend;
247428d7b3dSmrg
248428d7b3dSmrg	/* If there's no dst alpha channel, adjust the blend op so that we'll treat
249428d7b3dSmrg	 * it as always 1.
250428d7b3dSmrg	 */
251428d7b3dSmrg	if (PICT_FORMAT_A(dst_format) == 0) {
252428d7b3dSmrg		if (src == GEN5_BLENDFACTOR_DST_ALPHA)
253428d7b3dSmrg			src = GEN5_BLENDFACTOR_ONE;
254428d7b3dSmrg		else if (src == GEN5_BLENDFACTOR_INV_DST_ALPHA)
255428d7b3dSmrg			src = GEN5_BLENDFACTOR_ZERO;
256428d7b3dSmrg	}
257428d7b3dSmrg
258428d7b3dSmrg	/* If the source alpha is being used, then we should only be in a
259428d7b3dSmrg	 * case where the source blend factor is 0, and the source blend
260428d7b3dSmrg	 * value is the mask channels multiplied by the source picture's alpha.
261428d7b3dSmrg	 */
262428d7b3dSmrg	if (has_component_alpha && gen5_blend_op[op].src_alpha) {
263428d7b3dSmrg		if (dst == GEN5_BLENDFACTOR_SRC_ALPHA)
264428d7b3dSmrg			dst = GEN5_BLENDFACTOR_SRC_COLOR;
265428d7b3dSmrg		else if (dst == GEN5_BLENDFACTOR_INV_SRC_ALPHA)
266428d7b3dSmrg			dst = GEN5_BLENDFACTOR_INV_SRC_COLOR;
267428d7b3dSmrg	}
268428d7b3dSmrg
269428d7b3dSmrg	DBG(("blend op=%d, dst=%x [A=%d] => src=%d, dst=%d => offset=%x\n",
270428d7b3dSmrg	     op, dst_format, PICT_FORMAT_A(dst_format),
271428d7b3dSmrg	     src, dst, BLEND_OFFSET(src, dst)));
272428d7b3dSmrg	return BLEND_OFFSET(src, dst);
273428d7b3dSmrg}
274428d7b3dSmrg
275428d7b3dSmrgstatic uint32_t gen5_get_card_format(PictFormat format)
276428d7b3dSmrg{
277428d7b3dSmrg	switch (format) {
278428d7b3dSmrg	default:
279428d7b3dSmrg		return -1;
280428d7b3dSmrg	case PICT_a8r8g8b8:
281428d7b3dSmrg		return GEN5_SURFACEFORMAT_B8G8R8A8_UNORM;
282428d7b3dSmrg	case PICT_x8r8g8b8:
283428d7b3dSmrg		return GEN5_SURFACEFORMAT_B8G8R8X8_UNORM;
284428d7b3dSmrg	case PICT_a8b8g8r8:
285428d7b3dSmrg		return GEN5_SURFACEFORMAT_R8G8B8A8_UNORM;
286428d7b3dSmrg	case PICT_x8b8g8r8:
287428d7b3dSmrg		return GEN5_SURFACEFORMAT_R8G8B8X8_UNORM;
288428d7b3dSmrg#ifdef PICT_a2r10g10b10
289428d7b3dSmrg	case PICT_a2r10g10b10:
290428d7b3dSmrg		return GEN5_SURFACEFORMAT_B10G10R10A2_UNORM;
291428d7b3dSmrg	case PICT_x2r10g10b10:
292428d7b3dSmrg		return GEN5_SURFACEFORMAT_B10G10R10X2_UNORM;
293428d7b3dSmrg#endif
294428d7b3dSmrg	case PICT_r8g8b8:
295428d7b3dSmrg		return GEN5_SURFACEFORMAT_R8G8B8_UNORM;
296428d7b3dSmrg	case PICT_r5g6b5:
297428d7b3dSmrg		return GEN5_SURFACEFORMAT_B5G6R5_UNORM;
298428d7b3dSmrg	case PICT_a1r5g5b5:
299428d7b3dSmrg		return GEN5_SURFACEFORMAT_B5G5R5A1_UNORM;
300428d7b3dSmrg	case PICT_a8:
301428d7b3dSmrg		return GEN5_SURFACEFORMAT_A8_UNORM;
302428d7b3dSmrg	case PICT_a4r4g4b4:
303428d7b3dSmrg		return GEN5_SURFACEFORMAT_B4G4R4A4_UNORM;
304428d7b3dSmrg	}
305428d7b3dSmrg}
306428d7b3dSmrg
307428d7b3dSmrgstatic uint32_t gen5_get_dest_format(PictFormat format)
308428d7b3dSmrg{
309428d7b3dSmrg	switch (format) {
310428d7b3dSmrg	default:
311428d7b3dSmrg		return -1;
312428d7b3dSmrg	case PICT_a8r8g8b8:
313428d7b3dSmrg	case PICT_x8r8g8b8:
314428d7b3dSmrg		return GEN5_SURFACEFORMAT_B8G8R8A8_UNORM;
315428d7b3dSmrg	case PICT_a8b8g8r8:
316428d7b3dSmrg	case PICT_x8b8g8r8:
317428d7b3dSmrg		return GEN5_SURFACEFORMAT_R8G8B8A8_UNORM;
318428d7b3dSmrg#ifdef PICT_a2r10g10b10
319428d7b3dSmrg	case PICT_a2r10g10b10:
320428d7b3dSmrg	case PICT_x2r10g10b10:
321428d7b3dSmrg		return GEN5_SURFACEFORMAT_B10G10R10A2_UNORM;
322428d7b3dSmrg#endif
323428d7b3dSmrg	case PICT_r5g6b5:
324428d7b3dSmrg		return GEN5_SURFACEFORMAT_B5G6R5_UNORM;
325428d7b3dSmrg	case PICT_x1r5g5b5:
326428d7b3dSmrg	case PICT_a1r5g5b5:
327428d7b3dSmrg		return GEN5_SURFACEFORMAT_B5G5R5A1_UNORM;
328428d7b3dSmrg	case PICT_a8:
329428d7b3dSmrg		return GEN5_SURFACEFORMAT_A8_UNORM;
330428d7b3dSmrg	case PICT_a4r4g4b4:
331428d7b3dSmrg	case PICT_x4r4g4b4:
332428d7b3dSmrg		return GEN5_SURFACEFORMAT_B4G4R4A4_UNORM;
333428d7b3dSmrg	}
334428d7b3dSmrg}
335428d7b3dSmrg
336428d7b3dSmrgstatic bool gen5_check_dst_format(PictFormat format)
337428d7b3dSmrg{
338428d7b3dSmrg	if (gen5_get_dest_format(format) != -1)
339428d7b3dSmrg		return true;
340428d7b3dSmrg
341428d7b3dSmrg	DBG(("%s: unhandled format: %x\n", __FUNCTION__, (int)format));
342428d7b3dSmrg	return false;
343428d7b3dSmrg}
344428d7b3dSmrg
345428d7b3dSmrgstatic bool gen5_check_format(uint32_t format)
346428d7b3dSmrg{
347428d7b3dSmrg	if (gen5_get_card_format(format) != -1)
348428d7b3dSmrg		return true;
349428d7b3dSmrg
350428d7b3dSmrg	DBG(("%s: unhandled format: %x\n", __FUNCTION__, (int)format));
351428d7b3dSmrg	return false;
352428d7b3dSmrg}
353428d7b3dSmrg
354428d7b3dSmrgtypedef struct gen5_surface_state_padded {
355428d7b3dSmrg	struct gen5_surface_state state;
356428d7b3dSmrg	char pad[32 - sizeof(struct gen5_surface_state)];
357428d7b3dSmrg} gen5_surface_state_padded;
358428d7b3dSmrg
359428d7b3dSmrgstatic void null_create(struct sna_static_stream *stream)
360428d7b3dSmrg{
361428d7b3dSmrg	/* A bunch of zeros useful for legacy border color and depth-stencil */
362428d7b3dSmrg	sna_static_stream_map(stream, 64, 64);
363428d7b3dSmrg}
364428d7b3dSmrg
365428d7b3dSmrgstatic void
366428d7b3dSmrgsampler_state_init(struct gen5_sampler_state *sampler_state,
367428d7b3dSmrg		   sampler_filter_t filter,
368428d7b3dSmrg		   sampler_extend_t extend)
369428d7b3dSmrg{
370428d7b3dSmrg	sampler_state->ss0.lod_preclamp = 1;	/* GL mode */
371428d7b3dSmrg
372428d7b3dSmrg	/* We use the legacy mode to get the semantics specified by
373428d7b3dSmrg	 * the Render extension. */
374428d7b3dSmrg	sampler_state->ss0.border_color_mode = GEN5_BORDER_COLOR_MODE_LEGACY;
375428d7b3dSmrg
376428d7b3dSmrg	switch (filter) {
377428d7b3dSmrg	default:
378428d7b3dSmrg	case SAMPLER_FILTER_NEAREST:
379428d7b3dSmrg		sampler_state->ss0.min_filter = GEN5_MAPFILTER_NEAREST;
380428d7b3dSmrg		sampler_state->ss0.mag_filter = GEN5_MAPFILTER_NEAREST;
381428d7b3dSmrg		break;
382428d7b3dSmrg	case SAMPLER_FILTER_BILINEAR:
383428d7b3dSmrg		sampler_state->ss0.min_filter = GEN5_MAPFILTER_LINEAR;
384428d7b3dSmrg		sampler_state->ss0.mag_filter = GEN5_MAPFILTER_LINEAR;
385428d7b3dSmrg		break;
386428d7b3dSmrg	}
387428d7b3dSmrg
388428d7b3dSmrg	switch (extend) {
389428d7b3dSmrg	default:
390428d7b3dSmrg	case SAMPLER_EXTEND_NONE:
391428d7b3dSmrg		sampler_state->ss1.r_wrap_mode = GEN5_TEXCOORDMODE_CLAMP_BORDER;
392428d7b3dSmrg		sampler_state->ss1.s_wrap_mode = GEN5_TEXCOORDMODE_CLAMP_BORDER;
393428d7b3dSmrg		sampler_state->ss1.t_wrap_mode = GEN5_TEXCOORDMODE_CLAMP_BORDER;
394428d7b3dSmrg		break;
395428d7b3dSmrg	case SAMPLER_EXTEND_REPEAT:
396428d7b3dSmrg		sampler_state->ss1.r_wrap_mode = GEN5_TEXCOORDMODE_WRAP;
397428d7b3dSmrg		sampler_state->ss1.s_wrap_mode = GEN5_TEXCOORDMODE_WRAP;
398428d7b3dSmrg		sampler_state->ss1.t_wrap_mode = GEN5_TEXCOORDMODE_WRAP;
399428d7b3dSmrg		break;
400428d7b3dSmrg	case SAMPLER_EXTEND_PAD:
401428d7b3dSmrg		sampler_state->ss1.r_wrap_mode = GEN5_TEXCOORDMODE_CLAMP;
402428d7b3dSmrg		sampler_state->ss1.s_wrap_mode = GEN5_TEXCOORDMODE_CLAMP;
403428d7b3dSmrg		sampler_state->ss1.t_wrap_mode = GEN5_TEXCOORDMODE_CLAMP;
404428d7b3dSmrg		break;
405428d7b3dSmrg	case SAMPLER_EXTEND_REFLECT:
406428d7b3dSmrg		sampler_state->ss1.r_wrap_mode = GEN5_TEXCOORDMODE_MIRROR;
407428d7b3dSmrg		sampler_state->ss1.s_wrap_mode = GEN5_TEXCOORDMODE_MIRROR;
408428d7b3dSmrg		sampler_state->ss1.t_wrap_mode = GEN5_TEXCOORDMODE_MIRROR;
409428d7b3dSmrg		break;
410428d7b3dSmrg	}
411428d7b3dSmrg}
412428d7b3dSmrg
413428d7b3dSmrgstatic uint32_t gen5_filter(uint32_t filter)
414428d7b3dSmrg{
415428d7b3dSmrg	switch (filter) {
416428d7b3dSmrg	default:
417428d7b3dSmrg		assert(0);
418428d7b3dSmrg	case PictFilterNearest:
419428d7b3dSmrg		return SAMPLER_FILTER_NEAREST;
420428d7b3dSmrg	case PictFilterBilinear:
421428d7b3dSmrg		return SAMPLER_FILTER_BILINEAR;
422428d7b3dSmrg	}
423428d7b3dSmrg}
424428d7b3dSmrg
425428d7b3dSmrgstatic uint32_t gen5_check_filter(PicturePtr picture)
426428d7b3dSmrg{
427428d7b3dSmrg	switch (picture->filter) {
428428d7b3dSmrg	case PictFilterNearest:
429428d7b3dSmrg	case PictFilterBilinear:
430428d7b3dSmrg		return true;
431428d7b3dSmrg	default:
432428d7b3dSmrg		DBG(("%s: unknown filter: %x\n", __FUNCTION__, picture->filter));
433428d7b3dSmrg		return false;
434428d7b3dSmrg	}
435428d7b3dSmrg}
436428d7b3dSmrg
437428d7b3dSmrgstatic uint32_t gen5_repeat(uint32_t repeat)
438428d7b3dSmrg{
439428d7b3dSmrg	switch (repeat) {
440428d7b3dSmrg	default:
441428d7b3dSmrg		assert(0);
442428d7b3dSmrg	case RepeatNone:
443428d7b3dSmrg		return SAMPLER_EXTEND_NONE;
444428d7b3dSmrg	case RepeatNormal:
445428d7b3dSmrg		return SAMPLER_EXTEND_REPEAT;
446428d7b3dSmrg	case RepeatPad:
447428d7b3dSmrg		return SAMPLER_EXTEND_PAD;
448428d7b3dSmrg	case RepeatReflect:
449428d7b3dSmrg		return SAMPLER_EXTEND_REFLECT;
450428d7b3dSmrg	}
451428d7b3dSmrg}
452428d7b3dSmrg
453428d7b3dSmrgstatic bool gen5_check_repeat(PicturePtr picture)
454428d7b3dSmrg{
455428d7b3dSmrg	if (!picture->repeat)
456428d7b3dSmrg		return true;
457428d7b3dSmrg
458428d7b3dSmrg	switch (picture->repeatType) {
459428d7b3dSmrg	case RepeatNone:
460428d7b3dSmrg	case RepeatNormal:
461428d7b3dSmrg	case RepeatPad:
462428d7b3dSmrg	case RepeatReflect:
463428d7b3dSmrg		return true;
464428d7b3dSmrg	default:
465428d7b3dSmrg		DBG(("%s: unknown repeat: %x\n",
466428d7b3dSmrg		     __FUNCTION__, picture->repeatType));
467428d7b3dSmrg		return false;
468428d7b3dSmrg	}
469428d7b3dSmrg}
470428d7b3dSmrg
471428d7b3dSmrgstatic uint32_t
472428d7b3dSmrggen5_tiling_bits(uint32_t tiling)
473428d7b3dSmrg{
474428d7b3dSmrg	switch (tiling) {
475428d7b3dSmrg	default: assert(0);
476428d7b3dSmrg	case I915_TILING_NONE: return 0;
477428d7b3dSmrg	case I915_TILING_X: return GEN5_SURFACE_TILED;
478428d7b3dSmrg	case I915_TILING_Y: return GEN5_SURFACE_TILED | GEN5_SURFACE_TILED_Y;
479428d7b3dSmrg	}
480428d7b3dSmrg}
481428d7b3dSmrg
482428d7b3dSmrg/**
483428d7b3dSmrg * Sets up the common fields for a surface state buffer for the given
484428d7b3dSmrg * picture in the given surface state buffer.
485428d7b3dSmrg */
486428d7b3dSmrgstatic uint32_t
487428d7b3dSmrggen5_bind_bo(struct sna *sna,
488428d7b3dSmrg	     struct kgem_bo *bo,
489428d7b3dSmrg	     uint32_t width,
490428d7b3dSmrg	     uint32_t height,
491428d7b3dSmrg	     uint32_t format,
492428d7b3dSmrg	     bool is_dst)
493428d7b3dSmrg{
494428d7b3dSmrg	uint32_t domains;
495428d7b3dSmrg	uint16_t offset;
496428d7b3dSmrg	uint32_t *ss;
497428d7b3dSmrg
498428d7b3dSmrg	/* After the first bind, we manage the cache domains within the batch */
499428d7b3dSmrg	if (!DBG_NO_SURFACE_CACHE) {
500428d7b3dSmrg		offset = kgem_bo_get_binding(bo, format | is_dst << 31);
501428d7b3dSmrg		if (offset) {
502428d7b3dSmrg			if (is_dst)
503428d7b3dSmrg				kgem_bo_mark_dirty(bo);
504428d7b3dSmrg			assert(offset >= sna->kgem.surface);
505428d7b3dSmrg			return offset * sizeof(uint32_t);
506428d7b3dSmrg		}
507428d7b3dSmrg	}
508428d7b3dSmrg
509428d7b3dSmrg	offset = sna->kgem.surface -=
510428d7b3dSmrg		sizeof(struct gen5_surface_state_padded) / sizeof(uint32_t);
511428d7b3dSmrg	ss = sna->kgem.batch + offset;
512428d7b3dSmrg
513428d7b3dSmrg	ss[0] = (GEN5_SURFACE_2D << GEN5_SURFACE_TYPE_SHIFT |
514428d7b3dSmrg		 GEN5_SURFACE_BLEND_ENABLED |
515428d7b3dSmrg		 format << GEN5_SURFACE_FORMAT_SHIFT);
516428d7b3dSmrg
517428d7b3dSmrg	if (is_dst) {
518428d7b3dSmrg		ss[0] |= GEN5_SURFACE_RC_READ_WRITE;
519428d7b3dSmrg		domains = I915_GEM_DOMAIN_RENDER << 16 | I915_GEM_DOMAIN_RENDER;
520428d7b3dSmrg	} else
521428d7b3dSmrg		domains = I915_GEM_DOMAIN_SAMPLER << 16;
522428d7b3dSmrg	ss[1] = kgem_add_reloc(&sna->kgem, offset + 1, bo, domains, 0);
523428d7b3dSmrg
524428d7b3dSmrg	ss[2] = ((width - 1)  << GEN5_SURFACE_WIDTH_SHIFT |
525428d7b3dSmrg		 (height - 1) << GEN5_SURFACE_HEIGHT_SHIFT);
526428d7b3dSmrg	ss[3] = (gen5_tiling_bits(bo->tiling) |
527428d7b3dSmrg		 (bo->pitch - 1) << GEN5_SURFACE_PITCH_SHIFT);
528428d7b3dSmrg	ss[4] = 0;
529428d7b3dSmrg	ss[5] = 0;
530428d7b3dSmrg
531428d7b3dSmrg	kgem_bo_set_binding(bo, format | is_dst << 31, offset);
532428d7b3dSmrg
533428d7b3dSmrg	DBG(("[%x] bind bo(handle=%d, addr=%d), format=%d, width=%d, height=%d, pitch=%d, tiling=%d -> %s\n",
534428d7b3dSmrg	     offset, bo->handle, ss[1],
535428d7b3dSmrg	     format, width, height, bo->pitch, bo->tiling,
536428d7b3dSmrg	     domains & 0xffff ? "render" : "sampler"));
537428d7b3dSmrg
538428d7b3dSmrg	return offset * sizeof(uint32_t);
539428d7b3dSmrg}
540428d7b3dSmrg
541428d7b3dSmrgstatic void gen5_emit_vertex_buffer(struct sna *sna,
542428d7b3dSmrg				    const struct sna_composite_op *op)
543428d7b3dSmrg{
544428d7b3dSmrg	int id = op->u.gen5.ve_id;
545428d7b3dSmrg
546428d7b3dSmrg	assert((sna->render.vb_id & (1 << id)) == 0);
547428d7b3dSmrg
548428d7b3dSmrg	OUT_BATCH(GEN5_3DSTATE_VERTEX_BUFFERS | 3);
549428d7b3dSmrg	OUT_BATCH(id << VB0_BUFFER_INDEX_SHIFT | VB0_VERTEXDATA |
550428d7b3dSmrg		  (4*op->floats_per_vertex << VB0_BUFFER_PITCH_SHIFT));
551428d7b3dSmrg	assert(sna->render.nvertex_reloc < ARRAY_SIZE(sna->render.vertex_reloc));
552428d7b3dSmrg	sna->render.vertex_reloc[sna->render.nvertex_reloc++] = sna->kgem.nbatch;
553428d7b3dSmrg	OUT_BATCH(0);
554428d7b3dSmrg	OUT_BATCH(~0); /* max address: disabled */
555428d7b3dSmrg	OUT_BATCH(0);
556428d7b3dSmrg
557428d7b3dSmrg	sna->render.vb_id |= 1 << id;
558428d7b3dSmrg}
559428d7b3dSmrg
560428d7b3dSmrgstatic void gen5_emit_primitive(struct sna *sna)
561428d7b3dSmrg{
562428d7b3dSmrg	if (sna->kgem.nbatch == sna->render_state.gen5.last_primitive) {
563428d7b3dSmrg		sna->render.vertex_offset = sna->kgem.nbatch - 5;
564428d7b3dSmrg		return;
565428d7b3dSmrg	}
566428d7b3dSmrg
567428d7b3dSmrg	OUT_BATCH(GEN5_3DPRIMITIVE |
568428d7b3dSmrg		  GEN5_3DPRIMITIVE_VERTEX_SEQUENTIAL |
569428d7b3dSmrg		  (_3DPRIM_RECTLIST << GEN5_3DPRIMITIVE_TOPOLOGY_SHIFT) |
570428d7b3dSmrg		  (0 << 9) |
571428d7b3dSmrg		  4);
572428d7b3dSmrg	sna->render.vertex_offset = sna->kgem.nbatch;
573428d7b3dSmrg	OUT_BATCH(0);	/* vertex count, to be filled in later */
574428d7b3dSmrg	OUT_BATCH(sna->render.vertex_index);
575428d7b3dSmrg	OUT_BATCH(1);	/* single instance */
576428d7b3dSmrg	OUT_BATCH(0);	/* start instance location */
577428d7b3dSmrg	OUT_BATCH(0);	/* index buffer offset, ignored */
578428d7b3dSmrg	sna->render.vertex_start = sna->render.vertex_index;
579428d7b3dSmrg
580428d7b3dSmrg	sna->render_state.gen5.last_primitive = sna->kgem.nbatch;
581428d7b3dSmrg}
582428d7b3dSmrg
583428d7b3dSmrgstatic bool gen5_rectangle_begin(struct sna *sna,
584428d7b3dSmrg				 const struct sna_composite_op *op)
585428d7b3dSmrg{
586428d7b3dSmrg	int id = op->u.gen5.ve_id;
587428d7b3dSmrg	int ndwords;
588428d7b3dSmrg
589428d7b3dSmrg	if (sna_vertex_wait__locked(&sna->render) && sna->render.vertex_offset)
590428d7b3dSmrg		return true;
591428d7b3dSmrg
592428d7b3dSmrg	ndwords = op->need_magic_ca_pass ? 20 : 6;
593428d7b3dSmrg	if ((sna->render.vb_id & (1 << id)) == 0)
594428d7b3dSmrg		ndwords += 5;
595428d7b3dSmrg
596428d7b3dSmrg	if (!kgem_check_batch(&sna->kgem, ndwords))
597428d7b3dSmrg		return false;
598428d7b3dSmrg
599428d7b3dSmrg	if ((sna->render.vb_id & (1 << id)) == 0)
600428d7b3dSmrg		gen5_emit_vertex_buffer(sna, op);
601428d7b3dSmrg	if (sna->render.vertex_offset == 0)
602428d7b3dSmrg		gen5_emit_primitive(sna);
603428d7b3dSmrg
604428d7b3dSmrg	return true;
605428d7b3dSmrg}
606428d7b3dSmrg
607428d7b3dSmrgstatic int gen5_get_rectangles__flush(struct sna *sna,
608428d7b3dSmrg				      const struct sna_composite_op *op)
609428d7b3dSmrg{
610428d7b3dSmrg	/* Preventing discarding new vbo after lock contention */
611428d7b3dSmrg	if (sna_vertex_wait__locked(&sna->render)) {
612428d7b3dSmrg		int rem = vertex_space(sna);
613428d7b3dSmrg		if (rem > op->floats_per_rect)
614428d7b3dSmrg			return rem;
615428d7b3dSmrg	}
616428d7b3dSmrg
617428d7b3dSmrg	if (!kgem_check_batch(&sna->kgem, op->need_magic_ca_pass ? 40 : 6))
618428d7b3dSmrg		return 0;
619428d7b3dSmrg	if (!kgem_check_reloc_and_exec(&sna->kgem, 2))
620428d7b3dSmrg		return 0;
621428d7b3dSmrg
622428d7b3dSmrg	if (sna->render.vertex_offset) {
623428d7b3dSmrg		gen4_vertex_flush(sna);
624428d7b3dSmrg		if (gen5_magic_ca_pass(sna, op))
625428d7b3dSmrg			gen5_emit_pipelined_pointers(sna, op, op->op,
626428d7b3dSmrg						     op->u.gen5.wm_kernel);
627428d7b3dSmrg	}
628428d7b3dSmrg
629428d7b3dSmrg	return gen4_vertex_finish(sna);
630428d7b3dSmrg}
631428d7b3dSmrg
632428d7b3dSmrginline static int gen5_get_rectangles(struct sna *sna,
633428d7b3dSmrg				      const struct sna_composite_op *op,
634428d7b3dSmrg				      int want,
635428d7b3dSmrg				      void (*emit_state)(struct sna *sna,
636428d7b3dSmrg							 const struct sna_composite_op *op))
637428d7b3dSmrg{
638428d7b3dSmrg	int rem;
639428d7b3dSmrg
640428d7b3dSmrg	assert(want);
641428d7b3dSmrg
642428d7b3dSmrgstart:
643428d7b3dSmrg	rem = vertex_space(sna);
644428d7b3dSmrg	if (unlikely(rem < op->floats_per_rect)) {
645428d7b3dSmrg		DBG(("flushing vbo for %s: %d < %d\n",
646428d7b3dSmrg		     __FUNCTION__, rem, op->floats_per_rect));
647428d7b3dSmrg		rem = gen5_get_rectangles__flush(sna, op);
648428d7b3dSmrg		if (unlikely (rem == 0))
649428d7b3dSmrg			goto flush;
650428d7b3dSmrg	}
651428d7b3dSmrg
652428d7b3dSmrg	if (unlikely(sna->render.vertex_offset == 0)) {
653428d7b3dSmrg		if (!gen5_rectangle_begin(sna, op))
654428d7b3dSmrg			goto flush;
655428d7b3dSmrg		else
656428d7b3dSmrg			goto start;
657428d7b3dSmrg	}
658428d7b3dSmrg
659428d7b3dSmrg	assert(rem <= vertex_space(sna));
660428d7b3dSmrg	assert(op->floats_per_rect <= rem);
661428d7b3dSmrg	if (want > 1 && want * op->floats_per_rect > rem)
662428d7b3dSmrg		want = rem / op->floats_per_rect;
663428d7b3dSmrg
664428d7b3dSmrg	sna->render.vertex_index += 3*want;
665428d7b3dSmrg	return want;
666428d7b3dSmrg
667428d7b3dSmrgflush:
668428d7b3dSmrg	if (sna->render.vertex_offset) {
669428d7b3dSmrg		gen4_vertex_flush(sna);
670428d7b3dSmrg		gen5_magic_ca_pass(sna, op);
671428d7b3dSmrg	}
672428d7b3dSmrg	sna_vertex_wait__locked(&sna->render);
673428d7b3dSmrg	_kgem_submit(&sna->kgem);
674428d7b3dSmrg	emit_state(sna, op);
675428d7b3dSmrg	goto start;
676428d7b3dSmrg}
677428d7b3dSmrg
678428d7b3dSmrgstatic uint32_t *
679428d7b3dSmrggen5_composite_get_binding_table(struct sna *sna,
680428d7b3dSmrg				 uint16_t *offset)
681428d7b3dSmrg{
682428d7b3dSmrg	sna->kgem.surface -=
683428d7b3dSmrg		sizeof(struct gen5_surface_state_padded) / sizeof(uint32_t);
684428d7b3dSmrg
685428d7b3dSmrg	DBG(("%s(%x)\n", __FUNCTION__, 4*sna->kgem.surface));
686428d7b3dSmrg
687428d7b3dSmrg	/* Clear all surplus entries to zero in case of prefetch */
688428d7b3dSmrg	*offset = sna->kgem.surface;
689428d7b3dSmrg	return memset(sna->kgem.batch + sna->kgem.surface,
690428d7b3dSmrg		      0, sizeof(struct gen5_surface_state_padded));
691428d7b3dSmrg}
692428d7b3dSmrg
693428d7b3dSmrgstatic void
694428d7b3dSmrggen5_emit_urb(struct sna *sna)
695428d7b3dSmrg{
696428d7b3dSmrg	int urb_vs_start, urb_vs_size;
697428d7b3dSmrg	int urb_gs_start, urb_gs_size;
698428d7b3dSmrg	int urb_clip_start, urb_clip_size;
699428d7b3dSmrg	int urb_sf_start, urb_sf_size;
700428d7b3dSmrg	int urb_cs_start, urb_cs_size;
701428d7b3dSmrg
702428d7b3dSmrg	urb_vs_start = 0;
703428d7b3dSmrg	urb_vs_size = URB_VS_ENTRIES * URB_VS_ENTRY_SIZE;
704428d7b3dSmrg	urb_gs_start = urb_vs_start + urb_vs_size;
705428d7b3dSmrg	urb_gs_size = URB_GS_ENTRIES * URB_GS_ENTRY_SIZE;
706428d7b3dSmrg	urb_clip_start = urb_gs_start + urb_gs_size;
707428d7b3dSmrg	urb_clip_size = URB_CLIP_ENTRIES * URB_CLIP_ENTRY_SIZE;
708428d7b3dSmrg	urb_sf_start = urb_clip_start + urb_clip_size;
709428d7b3dSmrg	urb_sf_size = URB_SF_ENTRIES * URB_SF_ENTRY_SIZE;
710428d7b3dSmrg	urb_cs_start = urb_sf_start + urb_sf_size;
711428d7b3dSmrg	urb_cs_size = URB_CS_ENTRIES * URB_CS_ENTRY_SIZE;
712428d7b3dSmrg
713428d7b3dSmrg	OUT_BATCH(GEN5_URB_FENCE |
714428d7b3dSmrg		  UF0_CS_REALLOC |
715428d7b3dSmrg		  UF0_SF_REALLOC |
716428d7b3dSmrg		  UF0_CLIP_REALLOC |
717428d7b3dSmrg		  UF0_GS_REALLOC |
718428d7b3dSmrg		  UF0_VS_REALLOC |
719428d7b3dSmrg		  1);
720428d7b3dSmrg	OUT_BATCH(((urb_clip_start + urb_clip_size) << UF1_CLIP_FENCE_SHIFT) |
721428d7b3dSmrg		  ((urb_gs_start + urb_gs_size) << UF1_GS_FENCE_SHIFT) |
722428d7b3dSmrg		  ((urb_vs_start + urb_vs_size) << UF1_VS_FENCE_SHIFT));
723428d7b3dSmrg	OUT_BATCH(((urb_cs_start + urb_cs_size) << UF2_CS_FENCE_SHIFT) |
724428d7b3dSmrg		  ((urb_sf_start + urb_sf_size) << UF2_SF_FENCE_SHIFT));
725428d7b3dSmrg
726428d7b3dSmrg	/* Constant buffer state */
727428d7b3dSmrg	OUT_BATCH(GEN5_CS_URB_STATE | 0);
728428d7b3dSmrg	OUT_BATCH((URB_CS_ENTRY_SIZE - 1) << 4 | URB_CS_ENTRIES << 0);
729428d7b3dSmrg}
730428d7b3dSmrg
731428d7b3dSmrgstatic void
732428d7b3dSmrggen5_emit_state_base_address(struct sna *sna)
733428d7b3dSmrg{
734428d7b3dSmrg	assert(sna->render_state.gen5.general_bo->proxy == NULL);
735428d7b3dSmrg	OUT_BATCH(GEN5_STATE_BASE_ADDRESS | 6);
736428d7b3dSmrg	OUT_BATCH(kgem_add_reloc(&sna->kgem, /* general */
737428d7b3dSmrg				 sna->kgem.nbatch,
738428d7b3dSmrg				 sna->render_state.gen5.general_bo,
739428d7b3dSmrg				 I915_GEM_DOMAIN_INSTRUCTION << 16,
740428d7b3dSmrg				 BASE_ADDRESS_MODIFY));
741428d7b3dSmrg	OUT_BATCH(kgem_add_reloc(&sna->kgem, /* surface */
742428d7b3dSmrg				 sna->kgem.nbatch,
743428d7b3dSmrg				 NULL,
744428d7b3dSmrg				 I915_GEM_DOMAIN_INSTRUCTION << 16,
745428d7b3dSmrg				 BASE_ADDRESS_MODIFY));
746428d7b3dSmrg	OUT_BATCH(0); /* media */
747428d7b3dSmrg	OUT_BATCH(kgem_add_reloc(&sna->kgem, /* instruction */
748428d7b3dSmrg				 sna->kgem.nbatch,
749428d7b3dSmrg				 sna->render_state.gen5.general_bo,
750428d7b3dSmrg				 I915_GEM_DOMAIN_INSTRUCTION << 16,
751428d7b3dSmrg				 BASE_ADDRESS_MODIFY));
752428d7b3dSmrg
753428d7b3dSmrg	/* upper bounds, all disabled */
754428d7b3dSmrg	OUT_BATCH(BASE_ADDRESS_MODIFY);
755428d7b3dSmrg	OUT_BATCH(0);
756428d7b3dSmrg	OUT_BATCH(BASE_ADDRESS_MODIFY);
757428d7b3dSmrg}
758428d7b3dSmrg
759428d7b3dSmrgstatic void
760428d7b3dSmrggen5_emit_invariant(struct sna *sna)
761428d7b3dSmrg{
762428d7b3dSmrg	/* Ironlake errata workaround: Before disabling the clipper,
763428d7b3dSmrg	 * you have to MI_FLUSH to get the pipeline idle.
764428d7b3dSmrg	 *
765428d7b3dSmrg	 * However, the kernel flushes the pipeline between batches,
766428d7b3dSmrg	 * so we should be safe....
767428d7b3dSmrg	 *
768428d7b3dSmrg	 * On the other hand, after using BLT we must use a non-pipelined
769428d7b3dSmrg	 * operation...
770428d7b3dSmrg	 */
771428d7b3dSmrg	if (sna->kgem.nreloc)
772428d7b3dSmrg		OUT_BATCH(MI_FLUSH | MI_INHIBIT_RENDER_CACHE_FLUSH);
773428d7b3dSmrg
774428d7b3dSmrg	OUT_BATCH(GEN5_PIPELINE_SELECT | PIPELINE_SELECT_3D);
775428d7b3dSmrg
776428d7b3dSmrg	gen5_emit_state_base_address(sna);
777428d7b3dSmrg
778428d7b3dSmrg	sna->render_state.gen5.needs_invariant = false;
779428d7b3dSmrg}
780428d7b3dSmrg
781428d7b3dSmrgstatic void
782428d7b3dSmrggen5_get_batch(struct sna *sna, const struct sna_composite_op *op)
783428d7b3dSmrg{
784428d7b3dSmrg	kgem_set_mode(&sna->kgem, KGEM_RENDER, op->dst.bo);
785428d7b3dSmrg
786428d7b3dSmrg	if (!kgem_check_batch_with_surfaces(&sna->kgem, 150, 4)) {
787428d7b3dSmrg		DBG(("%s: flushing batch: %d < %d+%d\n",
788428d7b3dSmrg		     __FUNCTION__, sna->kgem.surface - sna->kgem.nbatch,
789428d7b3dSmrg		     150, 4*8));
790428d7b3dSmrg		kgem_submit(&sna->kgem);
791428d7b3dSmrg		_kgem_set_mode(&sna->kgem, KGEM_RENDER);
792428d7b3dSmrg	}
793428d7b3dSmrg
794428d7b3dSmrg	if (sna->render_state.gen5.needs_invariant)
795428d7b3dSmrg		gen5_emit_invariant(sna);
796428d7b3dSmrg}
797428d7b3dSmrg
798428d7b3dSmrgstatic void
799428d7b3dSmrggen5_align_vertex(struct sna *sna, const struct sna_composite_op *op)
800428d7b3dSmrg{
801428d7b3dSmrg	assert(op->floats_per_rect == 3*op->floats_per_vertex);
802428d7b3dSmrg	if (op->floats_per_vertex != sna->render_state.gen5.floats_per_vertex) {
803428d7b3dSmrg		DBG(("aligning vertex: was %d, now %d floats per vertex\n",
804428d7b3dSmrg		     sna->render_state.gen5.floats_per_vertex,
805428d7b3dSmrg		     op->floats_per_vertex));
806428d7b3dSmrg		gen4_vertex_align(sna, op);
807428d7b3dSmrg		sna->render_state.gen5.floats_per_vertex = op->floats_per_vertex;
808428d7b3dSmrg	}
809428d7b3dSmrg}
810428d7b3dSmrg
811428d7b3dSmrgstatic void
812428d7b3dSmrggen5_emit_binding_table(struct sna *sna, uint16_t offset)
813428d7b3dSmrg{
814428d7b3dSmrg	if (!DBG_NO_STATE_CACHE &&
815428d7b3dSmrg	    sna->render_state.gen5.surface_table == offset)
816428d7b3dSmrg		return;
817428d7b3dSmrg
818428d7b3dSmrg	sna->render_state.gen5.surface_table = offset;
819428d7b3dSmrg
820428d7b3dSmrg	/* Binding table pointers */
821428d7b3dSmrg	OUT_BATCH(GEN5_3DSTATE_BINDING_TABLE_POINTERS | 4);
822428d7b3dSmrg	OUT_BATCH(0);		/* vs */
823428d7b3dSmrg	OUT_BATCH(0);		/* gs */
824428d7b3dSmrg	OUT_BATCH(0);		/* clip */
825428d7b3dSmrg	OUT_BATCH(0);		/* sf */
826428d7b3dSmrg	/* Only the PS uses the binding table */
827428d7b3dSmrg	OUT_BATCH(offset*4);
828428d7b3dSmrg}
829428d7b3dSmrg
830428d7b3dSmrgstatic bool
831428d7b3dSmrggen5_emit_pipelined_pointers(struct sna *sna,
832428d7b3dSmrg			     const struct sna_composite_op *op,
833428d7b3dSmrg			     int blend, int kernel)
834428d7b3dSmrg{
835428d7b3dSmrg	uint16_t sp, bp;
836428d7b3dSmrg	uint32_t key;
837428d7b3dSmrg
838428d7b3dSmrg	DBG(("%s: has_mask=%d, src=(%d, %d), mask=(%d, %d),kernel=%d, blend=%d, ca=%d, format=%x\n",
839428d7b3dSmrg	     __FUNCTION__, op->u.gen5.ve_id & 2,
840428d7b3dSmrg	     op->src.filter, op->src.repeat,
841428d7b3dSmrg	     op->mask.filter, op->mask.repeat,
842428d7b3dSmrg	     kernel, blend, op->has_component_alpha, (int)op->dst.format));
843428d7b3dSmrg
844428d7b3dSmrg	sp = SAMPLER_OFFSET(op->src.filter, op->src.repeat,
845428d7b3dSmrg			    op->mask.filter, op->mask.repeat,
846428d7b3dSmrg			    kernel);
847428d7b3dSmrg	bp = gen5_get_blend(blend, op->has_component_alpha, op->dst.format);
848428d7b3dSmrg
849428d7b3dSmrg	key = sp | (uint32_t)bp << 16 | (op->mask.bo != NULL) << 31;
850428d7b3dSmrg	DBG(("%s: sp=%d, bp=%d, key=%08x (current sp=%d, bp=%d, key=%08x)\n",
851428d7b3dSmrg	     __FUNCTION__, sp, bp, key,
852428d7b3dSmrg	     sna->render_state.gen5.last_pipelined_pointers & 0xffff,
853428d7b3dSmrg	     (sna->render_state.gen5.last_pipelined_pointers >> 16) & 0x7fff,
854428d7b3dSmrg	     sna->render_state.gen5.last_pipelined_pointers));
855428d7b3dSmrg	if (key == sna->render_state.gen5.last_pipelined_pointers)
856428d7b3dSmrg		return false;
857428d7b3dSmrg
858428d7b3dSmrg	OUT_BATCH(GEN5_3DSTATE_PIPELINED_POINTERS | 5);
859428d7b3dSmrg	OUT_BATCH(sna->render_state.gen5.vs);
860428d7b3dSmrg	OUT_BATCH(GEN5_GS_DISABLE); /* passthrough */
861428d7b3dSmrg	OUT_BATCH(GEN5_CLIP_DISABLE); /* passthrough */
862428d7b3dSmrg	OUT_BATCH(sna->render_state.gen5.sf[op->mask.bo != NULL]);
863428d7b3dSmrg	OUT_BATCH(sna->render_state.gen5.wm + sp);
864428d7b3dSmrg	OUT_BATCH(sna->render_state.gen5.cc + bp);
865428d7b3dSmrg
866428d7b3dSmrg	bp = (sna->render_state.gen5.last_pipelined_pointers & 0x7fff0000) != ((uint32_t)bp << 16);
867428d7b3dSmrg	sna->render_state.gen5.last_pipelined_pointers = key;
868428d7b3dSmrg
869428d7b3dSmrg	gen5_emit_urb(sna);
870428d7b3dSmrg
871428d7b3dSmrg	return bp;
872428d7b3dSmrg}
873428d7b3dSmrg
874428d7b3dSmrgstatic bool
875428d7b3dSmrggen5_emit_drawing_rectangle(struct sna *sna, const struct sna_composite_op *op)
876428d7b3dSmrg{
877428d7b3dSmrg	uint32_t limit = (op->dst.height - 1) << 16 | (op->dst.width - 1);
878428d7b3dSmrg	uint32_t offset = (uint16_t)op->dst.y << 16 | (uint16_t)op->dst.x;
879428d7b3dSmrg
880428d7b3dSmrg	assert(!too_large(abs(op->dst.x), abs(op->dst.y)));
881428d7b3dSmrg	assert(!too_large(op->dst.width, op->dst.height));
882428d7b3dSmrg
883428d7b3dSmrg	if (!DBG_NO_STATE_CACHE &&
884428d7b3dSmrg	    sna->render_state.gen5.drawrect_limit == limit &&
885428d7b3dSmrg	    sna->render_state.gen5.drawrect_offset == offset)
886428d7b3dSmrg		return false;
887428d7b3dSmrg
888428d7b3dSmrg	sna->render_state.gen5.drawrect_offset = offset;
889428d7b3dSmrg	sna->render_state.gen5.drawrect_limit = limit;
890428d7b3dSmrg
891428d7b3dSmrg	OUT_BATCH(GEN5_3DSTATE_DRAWING_RECTANGLE | (4 - 2));
892428d7b3dSmrg	OUT_BATCH(0x00000000);
893428d7b3dSmrg	OUT_BATCH(limit);
894428d7b3dSmrg	OUT_BATCH(offset);
895428d7b3dSmrg	return true;
896428d7b3dSmrg}
897428d7b3dSmrg
898428d7b3dSmrgstatic void
899428d7b3dSmrggen5_emit_vertex_elements(struct sna *sna,
900428d7b3dSmrg			  const struct sna_composite_op *op)
901428d7b3dSmrg{
902428d7b3dSmrg	/*
903428d7b3dSmrg	 * vertex data in vertex buffer
904428d7b3dSmrg	 *    position: (x, y)
905428d7b3dSmrg	 *    texture coordinate 0: (u0, v0) if (is_affine is true) else (u0, v0, w0)
906428d7b3dSmrg	 *    texture coordinate 1 if (has_mask is true): same as above
907428d7b3dSmrg	 */
908428d7b3dSmrg	struct gen5_render_state *render = &sna->render_state.gen5;
909428d7b3dSmrg	int id = op->u.gen5.ve_id;
910428d7b3dSmrg	bool has_mask = id >> 2;
911428d7b3dSmrg	uint32_t format, dw;
912428d7b3dSmrg
913428d7b3dSmrg	if (!DBG_NO_STATE_CACHE && render->ve_id == id)
914428d7b3dSmrg		return;
915428d7b3dSmrg
916428d7b3dSmrg	DBG(("%s: changing %d -> %d\n", __FUNCTION__, render->ve_id, id));
917428d7b3dSmrg	render->ve_id = id;
918428d7b3dSmrg
919428d7b3dSmrg	/* The VUE layout
920428d7b3dSmrg	 *    dword 0-3: pad (0.0, 0.0, 0.0. 0.0)
921428d7b3dSmrg	 *    dword 4-7: position (x, y, 1.0, 1.0),
922428d7b3dSmrg	 *    dword 8-11: texture coordinate 0 (u0, v0, w0, 1.0)
923428d7b3dSmrg	 *    dword 12-15: texture coordinate 1 (u1, v1, w1, 1.0)
924428d7b3dSmrg	 *
925428d7b3dSmrg	 * dword 4-15 are fetched from vertex buffer
926428d7b3dSmrg	 */
927428d7b3dSmrg	OUT_BATCH(GEN5_3DSTATE_VERTEX_ELEMENTS |
928428d7b3dSmrg		((2 * (has_mask ? 4 : 3)) + 1 - 2));
929428d7b3dSmrg
930428d7b3dSmrg	OUT_BATCH((id << VE0_VERTEX_BUFFER_INDEX_SHIFT) | VE0_VALID |
931428d7b3dSmrg		  (GEN5_SURFACEFORMAT_R32G32B32A32_FLOAT << VE0_FORMAT_SHIFT) |
932428d7b3dSmrg		  (0 << VE0_OFFSET_SHIFT));
933428d7b3dSmrg	OUT_BATCH((VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_0_SHIFT) |
934428d7b3dSmrg		  (VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_1_SHIFT) |
935428d7b3dSmrg		  (VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_2_SHIFT) |
936428d7b3dSmrg		  (VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_3_SHIFT));
937428d7b3dSmrg
938428d7b3dSmrg	/* x,y */
939428d7b3dSmrg	OUT_BATCH(id << VE0_VERTEX_BUFFER_INDEX_SHIFT | VE0_VALID |
940428d7b3dSmrg		  GEN5_SURFACEFORMAT_R16G16_SSCALED << VE0_FORMAT_SHIFT |
941428d7b3dSmrg		  0 << VE0_OFFSET_SHIFT);
942428d7b3dSmrg	OUT_BATCH(VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT |
943428d7b3dSmrg		  VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT |
944428d7b3dSmrg		  VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_2_SHIFT |
945428d7b3dSmrg		  VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT);
946428d7b3dSmrg
947428d7b3dSmrg	/* u0, v0, w0 */
948428d7b3dSmrg	DBG(("%s: id=%d, first channel %d floats, offset=4b\n", __FUNCTION__,
949428d7b3dSmrg	     id, id & 3));
950428d7b3dSmrg	dw = VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT;
951428d7b3dSmrg	switch (id & 3) {
952428d7b3dSmrg	default:
953428d7b3dSmrg		assert(0);
954428d7b3dSmrg	case 0:
955428d7b3dSmrg		format = GEN5_SURFACEFORMAT_R16G16_SSCALED << VE0_FORMAT_SHIFT;
956428d7b3dSmrg		dw |= VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT;
957428d7b3dSmrg		dw |= VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT;
958428d7b3dSmrg		dw |= VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_2_SHIFT;
959428d7b3dSmrg		break;
960428d7b3dSmrg	case 1:
961428d7b3dSmrg		format = GEN5_SURFACEFORMAT_R32_FLOAT << VE0_FORMAT_SHIFT;
962428d7b3dSmrg		dw |= VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT;
963428d7b3dSmrg		dw |= VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_1_SHIFT;
964428d7b3dSmrg		dw |= VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_2_SHIFT;
965428d7b3dSmrg		break;
966428d7b3dSmrg	case 2:
967428d7b3dSmrg		format = GEN5_SURFACEFORMAT_R32G32_FLOAT << VE0_FORMAT_SHIFT;
968428d7b3dSmrg		dw |= VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT;
969428d7b3dSmrg		dw |= VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT;
970428d7b3dSmrg		dw |= VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_2_SHIFT;
971428d7b3dSmrg		break;
972428d7b3dSmrg	case 3:
973428d7b3dSmrg		format = GEN5_SURFACEFORMAT_R32G32B32_FLOAT << VE0_FORMAT_SHIFT;
974428d7b3dSmrg		dw |= VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT;
975428d7b3dSmrg		dw |= VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT;
976428d7b3dSmrg		dw |= VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_2_SHIFT;
977428d7b3dSmrg		break;
978428d7b3dSmrg	}
979428d7b3dSmrg	OUT_BATCH(id << VE0_VERTEX_BUFFER_INDEX_SHIFT | VE0_VALID |
980428d7b3dSmrg		  format | 4 << VE0_OFFSET_SHIFT);
981428d7b3dSmrg	OUT_BATCH(dw);
982428d7b3dSmrg
983428d7b3dSmrg	/* u1, v1, w1 */
984428d7b3dSmrg	if (has_mask) {
985428d7b3dSmrg		unsigned offset = 4 + ((id & 3) ?: 1) * sizeof(float);
986428d7b3dSmrg		DBG(("%s: id=%x, second channel %d floats, offset=%db\n", __FUNCTION__,
987428d7b3dSmrg		     id, id >> 2, offset));
988428d7b3dSmrg		dw = VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_3_SHIFT;
989428d7b3dSmrg		switch (id >> 2) {
990428d7b3dSmrg		case 1:
991428d7b3dSmrg			format = GEN5_SURFACEFORMAT_R32_FLOAT << VE0_FORMAT_SHIFT;
992428d7b3dSmrg			dw |= VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT;
993428d7b3dSmrg			dw |= VFCOMPONENT_STORE_0 << VE1_VFCOMPONENT_1_SHIFT;
994428d7b3dSmrg			dw |= VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_2_SHIFT;
995428d7b3dSmrg			break;
996428d7b3dSmrg		default:
997428d7b3dSmrg			assert(0);
998428d7b3dSmrg		case 2:
999428d7b3dSmrg			format = GEN5_SURFACEFORMAT_R32G32_FLOAT << VE0_FORMAT_SHIFT;
1000428d7b3dSmrg			dw |= VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT;
1001428d7b3dSmrg			dw |= VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT;
1002428d7b3dSmrg			dw |= VFCOMPONENT_STORE_1_FLT << VE1_VFCOMPONENT_2_SHIFT;
1003428d7b3dSmrg			break;
1004428d7b3dSmrg		case 3:
1005428d7b3dSmrg			format = GEN5_SURFACEFORMAT_R32G32B32_FLOAT << VE0_FORMAT_SHIFT;
1006428d7b3dSmrg			dw |= VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_0_SHIFT;
1007428d7b3dSmrg			dw |= VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_1_SHIFT;
1008428d7b3dSmrg			dw |= VFCOMPONENT_STORE_SRC << VE1_VFCOMPONENT_2_SHIFT;
1009428d7b3dSmrg			break;
1010428d7b3dSmrg		}
1011428d7b3dSmrg		OUT_BATCH(id << VE0_VERTEX_BUFFER_INDEX_SHIFT | VE0_VALID |
1012428d7b3dSmrg			  format | offset << VE0_OFFSET_SHIFT);
1013428d7b3dSmrg		OUT_BATCH(dw);
1014428d7b3dSmrg	}
1015428d7b3dSmrg}
1016428d7b3dSmrg
1017428d7b3dSmrginline static void
1018428d7b3dSmrggen5_emit_pipe_flush(struct sna *sna)
1019428d7b3dSmrg{
1020428d7b3dSmrg#if 1
1021428d7b3dSmrg	OUT_BATCH(GEN5_PIPE_CONTROL |
1022428d7b3dSmrg		  GEN5_PIPE_CONTROL_WC_FLUSH |
1023428d7b3dSmrg		  (4 - 2));
1024428d7b3dSmrg	OUT_BATCH(0);
1025428d7b3dSmrg	OUT_BATCH(0);
1026428d7b3dSmrg	OUT_BATCH(0);
1027428d7b3dSmrg#else
1028428d7b3dSmrg	OUT_BATCH(MI_FLUSH | MI_INHIBIT_RENDER_CACHE_FLUSH);
1029428d7b3dSmrg#endif
1030428d7b3dSmrg}
1031428d7b3dSmrg
1032428d7b3dSmrgstatic void
1033428d7b3dSmrggen5_emit_state(struct sna *sna,
1034428d7b3dSmrg		const struct sna_composite_op *op,
1035428d7b3dSmrg		uint16_t offset)
1036428d7b3dSmrg{
1037428d7b3dSmrg	bool flush = false;
1038428d7b3dSmrg
1039428d7b3dSmrg	assert(op->dst.bo->exec);
1040428d7b3dSmrg
1041428d7b3dSmrg	/* drawrect must be first for Ironlake BLT workaround */
1042428d7b3dSmrg	if (gen5_emit_drawing_rectangle(sna, op))
1043428d7b3dSmrg		offset &= ~1;
1044428d7b3dSmrg	gen5_emit_binding_table(sna, offset & ~1);
1045428d7b3dSmrg	if (gen5_emit_pipelined_pointers(sna, op, op->op, op->u.gen5.wm_kernel)){
1046428d7b3dSmrg		DBG(("%s: changed blend state, flush required? %d\n",
1047428d7b3dSmrg		     __FUNCTION__, (offset & 1) && op->op > PictOpSrc));
1048428d7b3dSmrg		flush = (offset & 1) && op->op > PictOpSrc;
1049428d7b3dSmrg	}
1050428d7b3dSmrg	gen5_emit_vertex_elements(sna, op);
1051428d7b3dSmrg
1052428d7b3dSmrg	if (ALWAYS_FLUSH || kgem_bo_is_dirty(op->src.bo) || kgem_bo_is_dirty(op->mask.bo)) {
1053428d7b3dSmrg		DBG(("%s: flushing dirty (%d, %d)\n", __FUNCTION__,
1054428d7b3dSmrg		     kgem_bo_is_dirty(op->src.bo),
1055428d7b3dSmrg		     kgem_bo_is_dirty(op->mask.bo)));
1056428d7b3dSmrg		OUT_BATCH(MI_FLUSH);
1057428d7b3dSmrg		kgem_clear_dirty(&sna->kgem);
1058428d7b3dSmrg		kgem_bo_mark_dirty(op->dst.bo);
1059428d7b3dSmrg		flush = false;
1060428d7b3dSmrg	}
1061428d7b3dSmrg	if (flush) {
1062428d7b3dSmrg		DBG(("%s: forcing flush\n", __FUNCTION__));
1063428d7b3dSmrg		gen5_emit_pipe_flush(sna);
1064428d7b3dSmrg	}
1065428d7b3dSmrg}
1066428d7b3dSmrg
1067428d7b3dSmrgstatic void gen5_bind_surfaces(struct sna *sna,
1068428d7b3dSmrg			       const struct sna_composite_op *op)
1069428d7b3dSmrg{
1070428d7b3dSmrg	bool dirty = kgem_bo_is_dirty(op->dst.bo);
1071428d7b3dSmrg	uint32_t *binding_table;
1072428d7b3dSmrg	uint16_t offset;
1073428d7b3dSmrg
1074428d7b3dSmrg	gen5_get_batch(sna, op);
1075428d7b3dSmrg
1076428d7b3dSmrg	binding_table = gen5_composite_get_binding_table(sna, &offset);
1077428d7b3dSmrg
1078428d7b3dSmrg	binding_table[0] =
1079428d7b3dSmrg		gen5_bind_bo(sna,
1080428d7b3dSmrg			    op->dst.bo, op->dst.width, op->dst.height,
1081428d7b3dSmrg			    gen5_get_dest_format(op->dst.format),
1082428d7b3dSmrg			    true);
1083428d7b3dSmrg	binding_table[1] =
1084428d7b3dSmrg		gen5_bind_bo(sna,
1085428d7b3dSmrg			     op->src.bo, op->src.width, op->src.height,
1086428d7b3dSmrg			     op->src.card_format,
1087428d7b3dSmrg			     false);
1088428d7b3dSmrg	if (op->mask.bo) {
1089428d7b3dSmrg		assert(op->u.gen5.ve_id >> 2);
1090428d7b3dSmrg		binding_table[2] =
1091428d7b3dSmrg			gen5_bind_bo(sna,
1092428d7b3dSmrg				     op->mask.bo,
1093428d7b3dSmrg				     op->mask.width,
1094428d7b3dSmrg				     op->mask.height,
1095428d7b3dSmrg				     op->mask.card_format,
1096428d7b3dSmrg				     false);
1097428d7b3dSmrg	}
1098428d7b3dSmrg
1099428d7b3dSmrg	if (sna->kgem.surface == offset &&
1100428d7b3dSmrg	    *(uint64_t *)(sna->kgem.batch + sna->render_state.gen5.surface_table) == *(uint64_t*)binding_table &&
1101428d7b3dSmrg	    (op->mask.bo == NULL ||
1102428d7b3dSmrg	     sna->kgem.batch[sna->render_state.gen5.surface_table+2] == binding_table[2])) {
1103428d7b3dSmrg		sna->kgem.surface += sizeof(struct gen5_surface_state_padded) / sizeof(uint32_t);
1104428d7b3dSmrg		offset = sna->render_state.gen5.surface_table;
1105428d7b3dSmrg	}
1106428d7b3dSmrg
1107428d7b3dSmrg	gen5_emit_state(sna, op, offset | dirty);
1108428d7b3dSmrg}
1109428d7b3dSmrg
1110428d7b3dSmrgfastcall static void
1111428d7b3dSmrggen5_render_composite_blt(struct sna *sna,
1112428d7b3dSmrg			  const struct sna_composite_op *op,
1113428d7b3dSmrg			  const struct sna_composite_rectangles *r)
1114428d7b3dSmrg{
1115428d7b3dSmrg	DBG(("%s: src=(%d, %d)+(%d, %d), mask=(%d, %d)+(%d, %d), dst=(%d, %d)+(%d, %d), size=(%d, %d)\n",
1116428d7b3dSmrg	     __FUNCTION__,
1117428d7b3dSmrg	     r->src.x, r->src.y, op->src.offset[0], op->src.offset[1],
1118428d7b3dSmrg	     r->mask.x, r->mask.y, op->mask.offset[0], op->mask.offset[1],
1119428d7b3dSmrg	     r->dst.x, r->dst.y, op->dst.x, op->dst.y,
1120428d7b3dSmrg	     r->width, r->height));
1121428d7b3dSmrg
1122428d7b3dSmrg	gen5_get_rectangles(sna, op, 1, gen5_bind_surfaces);
1123428d7b3dSmrg	op->prim_emit(sna, op, r);
1124428d7b3dSmrg}
1125428d7b3dSmrg
1126428d7b3dSmrgfastcall static void
1127428d7b3dSmrggen5_render_composite_box(struct sna *sna,
1128428d7b3dSmrg			  const struct sna_composite_op *op,
1129428d7b3dSmrg			  const BoxRec *box)
1130428d7b3dSmrg{
1131428d7b3dSmrg	struct sna_composite_rectangles r;
1132428d7b3dSmrg
1133428d7b3dSmrg	DBG(("  %s: (%d, %d), (%d, %d)\n",
1134428d7b3dSmrg	     __FUNCTION__,
1135428d7b3dSmrg	     box->x1, box->y1, box->x2, box->y2));
1136428d7b3dSmrg
1137428d7b3dSmrg	gen5_get_rectangles(sna, op, 1, gen5_bind_surfaces);
1138428d7b3dSmrg
1139428d7b3dSmrg	r.dst.x = box->x1;
1140428d7b3dSmrg	r.dst.y = box->y1;
1141428d7b3dSmrg	r.width  = box->x2 - box->x1;
1142428d7b3dSmrg	r.height = box->y2 - box->y1;
1143428d7b3dSmrg	r.mask = r.src = r.dst;
1144428d7b3dSmrg
1145428d7b3dSmrg	op->prim_emit(sna, op, &r);
1146428d7b3dSmrg}
1147428d7b3dSmrg
1148428d7b3dSmrgstatic void
1149428d7b3dSmrggen5_render_composite_boxes__blt(struct sna *sna,
1150428d7b3dSmrg				 const struct sna_composite_op *op,
1151428d7b3dSmrg				 const BoxRec *box, int nbox)
1152428d7b3dSmrg{
1153428d7b3dSmrg	DBG(("%s(%d) delta=(%d, %d), src=(%d, %d)/(%d, %d), mask=(%d, %d)/(%d, %d)\n",
1154428d7b3dSmrg	     __FUNCTION__, nbox, op->dst.x, op->dst.y,
1155428d7b3dSmrg	     op->src.offset[0], op->src.offset[1],
1156428d7b3dSmrg	     op->src.width, op->src.height,
1157428d7b3dSmrg	     op->mask.offset[0], op->mask.offset[1],
1158428d7b3dSmrg	     op->mask.width, op->mask.height));
1159428d7b3dSmrg
1160428d7b3dSmrg	do {
1161428d7b3dSmrg		int nbox_this_time;
1162428d7b3dSmrg
1163428d7b3dSmrg		nbox_this_time = gen5_get_rectangles(sna, op, nbox,
1164428d7b3dSmrg						     gen5_bind_surfaces);
1165428d7b3dSmrg		nbox -= nbox_this_time;
1166428d7b3dSmrg
1167428d7b3dSmrg		do {
1168428d7b3dSmrg			struct sna_composite_rectangles r;
1169428d7b3dSmrg
1170428d7b3dSmrg			DBG(("  %s: (%d, %d), (%d, %d)\n",
1171428d7b3dSmrg			     __FUNCTION__,
1172428d7b3dSmrg			     box->x1, box->y1, box->x2, box->y2));
1173428d7b3dSmrg
1174428d7b3dSmrg			r.dst.x = box->x1;
1175428d7b3dSmrg			r.dst.y = box->y1;
1176428d7b3dSmrg			r.width  = box->x2 - box->x1;
1177428d7b3dSmrg			r.height = box->y2 - box->y1;
1178428d7b3dSmrg			r.mask = r.src = r.dst;
1179428d7b3dSmrg			op->prim_emit(sna, op, &r);
1180428d7b3dSmrg			box++;
1181428d7b3dSmrg		} while (--nbox_this_time);
1182428d7b3dSmrg	} while (nbox);
1183428d7b3dSmrg}
1184428d7b3dSmrg
1185428d7b3dSmrgstatic void
1186428d7b3dSmrggen5_render_composite_boxes(struct sna *sna,
1187428d7b3dSmrg			    const struct sna_composite_op *op,
1188428d7b3dSmrg			    const BoxRec *box, int nbox)
1189428d7b3dSmrg{
1190428d7b3dSmrg	DBG(("%s: nbox=%d\n", __FUNCTION__, nbox));
1191428d7b3dSmrg
1192428d7b3dSmrg	do {
1193428d7b3dSmrg		int nbox_this_time;
1194428d7b3dSmrg		float *v;
1195428d7b3dSmrg
1196428d7b3dSmrg		nbox_this_time = gen5_get_rectangles(sna, op, nbox,
1197428d7b3dSmrg						     gen5_bind_surfaces);
1198428d7b3dSmrg		assert(nbox_this_time);
1199428d7b3dSmrg		nbox -= nbox_this_time;
1200428d7b3dSmrg
1201428d7b3dSmrg		v = sna->render.vertices + sna->render.vertex_used;
1202428d7b3dSmrg		sna->render.vertex_used += nbox_this_time * op->floats_per_rect;
1203428d7b3dSmrg
1204428d7b3dSmrg		op->emit_boxes(op, box, nbox_this_time, v);
1205428d7b3dSmrg		box += nbox_this_time;
1206428d7b3dSmrg	} while (nbox);
1207428d7b3dSmrg}
1208428d7b3dSmrg
1209428d7b3dSmrgstatic void
1210428d7b3dSmrggen5_render_composite_boxes__thread(struct sna *sna,
1211428d7b3dSmrg				    const struct sna_composite_op *op,
1212428d7b3dSmrg				    const BoxRec *box, int nbox)
1213428d7b3dSmrg{
1214428d7b3dSmrg	DBG(("%s: nbox=%d\n", __FUNCTION__, nbox));
1215428d7b3dSmrg
1216428d7b3dSmrg	sna_vertex_lock(&sna->render);
1217428d7b3dSmrg	do {
1218428d7b3dSmrg		int nbox_this_time;
1219428d7b3dSmrg		float *v;
1220428d7b3dSmrg
1221428d7b3dSmrg		nbox_this_time = gen5_get_rectangles(sna, op, nbox,
1222428d7b3dSmrg						     gen5_bind_surfaces);
1223428d7b3dSmrg		assert(nbox_this_time);
1224428d7b3dSmrg		nbox -= nbox_this_time;
1225428d7b3dSmrg
1226428d7b3dSmrg		v = sna->render.vertices + sna->render.vertex_used;
1227428d7b3dSmrg		sna->render.vertex_used += nbox_this_time * op->floats_per_rect;
1228428d7b3dSmrg
1229428d7b3dSmrg		sna_vertex_acquire__locked(&sna->render);
1230428d7b3dSmrg		sna_vertex_unlock(&sna->render);
1231428d7b3dSmrg
1232428d7b3dSmrg		op->emit_boxes(op, box, nbox_this_time, v);
1233428d7b3dSmrg		box += nbox_this_time;
1234428d7b3dSmrg
1235428d7b3dSmrg		sna_vertex_lock(&sna->render);
1236428d7b3dSmrg		sna_vertex_release__locked(&sna->render);
1237428d7b3dSmrg	} while (nbox);
1238428d7b3dSmrg	sna_vertex_unlock(&sna->render);
1239428d7b3dSmrg}
1240428d7b3dSmrg
1241428d7b3dSmrg#ifndef MAX
1242428d7b3dSmrg#define MAX(a,b) ((a) > (b) ? (a) : (b))
1243428d7b3dSmrg#endif
1244428d7b3dSmrg
1245428d7b3dSmrgstatic uint32_t gen5_bind_video_source(struct sna *sna,
1246428d7b3dSmrg				       struct kgem_bo *src_bo,
1247428d7b3dSmrg				       uint32_t src_offset,
1248428d7b3dSmrg				       int src_width,
1249428d7b3dSmrg				       int src_height,
1250428d7b3dSmrg				       int src_pitch,
1251428d7b3dSmrg				       uint32_t src_surf_format)
1252428d7b3dSmrg{
1253428d7b3dSmrg	struct gen5_surface_state *ss;
1254428d7b3dSmrg
1255428d7b3dSmrg	sna->kgem.surface -= sizeof(struct gen5_surface_state_padded) / sizeof(uint32_t);
1256428d7b3dSmrg
1257428d7b3dSmrg	ss = memset(sna->kgem.batch + sna->kgem.surface, 0, sizeof(*ss));
1258428d7b3dSmrg	ss->ss0.surface_type = GEN5_SURFACE_2D;
1259428d7b3dSmrg	ss->ss0.surface_format = src_surf_format;
1260428d7b3dSmrg	ss->ss0.color_blend = 1;
1261428d7b3dSmrg
1262428d7b3dSmrg	ss->ss1.base_addr =
1263428d7b3dSmrg		kgem_add_reloc(&sna->kgem,
1264428d7b3dSmrg			       sna->kgem.surface + 1,
1265428d7b3dSmrg			       src_bo,
1266428d7b3dSmrg			       I915_GEM_DOMAIN_SAMPLER << 16,
1267428d7b3dSmrg			       src_offset);
1268428d7b3dSmrg
1269428d7b3dSmrg	ss->ss2.width  = src_width - 1;
1270428d7b3dSmrg	ss->ss2.height = src_height - 1;
1271428d7b3dSmrg	ss->ss3.pitch  = src_pitch - 1;
1272428d7b3dSmrg
1273428d7b3dSmrg	return sna->kgem.surface * sizeof(uint32_t);
1274428d7b3dSmrg}
1275428d7b3dSmrg
1276428d7b3dSmrgstatic void gen5_video_bind_surfaces(struct sna *sna,
1277428d7b3dSmrg				     const struct sna_composite_op *op)
1278428d7b3dSmrg{
1279428d7b3dSmrg	bool dirty = kgem_bo_is_dirty(op->dst.bo);
1280428d7b3dSmrg	struct sna_video_frame *frame = op->priv;
1281428d7b3dSmrg	uint32_t src_surf_format;
1282428d7b3dSmrg	uint32_t src_surf_base[6];
1283428d7b3dSmrg	int src_width[6];
1284428d7b3dSmrg	int src_height[6];
1285428d7b3dSmrg	int src_pitch[6];
1286428d7b3dSmrg	uint32_t *binding_table;
1287428d7b3dSmrg	uint16_t offset;
1288428d7b3dSmrg	int n_src, n;
1289428d7b3dSmrg
1290428d7b3dSmrg	src_surf_base[0] = 0;
1291428d7b3dSmrg	src_surf_base[1] = 0;
1292428d7b3dSmrg	src_surf_base[2] = frame->VBufOffset;
1293428d7b3dSmrg	src_surf_base[3] = frame->VBufOffset;
1294428d7b3dSmrg	src_surf_base[4] = frame->UBufOffset;
1295428d7b3dSmrg	src_surf_base[5] = frame->UBufOffset;
1296428d7b3dSmrg
1297428d7b3dSmrg	if (is_planar_fourcc(frame->id)) {
1298428d7b3dSmrg		src_surf_format = GEN5_SURFACEFORMAT_R8_UNORM;
1299428d7b3dSmrg		src_width[1]  = src_width[0]  = frame->width;
1300428d7b3dSmrg		src_height[1] = src_height[0] = frame->height;
1301428d7b3dSmrg		src_pitch[1]  = src_pitch[0]  = frame->pitch[1];
1302428d7b3dSmrg		src_width[4]  = src_width[5]  = src_width[2]  = src_width[3] =
1303428d7b3dSmrg			frame->width / 2;
1304428d7b3dSmrg		src_height[4] = src_height[5] = src_height[2] = src_height[3] =
1305428d7b3dSmrg			frame->height / 2;
1306428d7b3dSmrg		src_pitch[4]  = src_pitch[5]  = src_pitch[2]  = src_pitch[3] =
1307428d7b3dSmrg			frame->pitch[0];
1308428d7b3dSmrg		n_src = 6;
1309428d7b3dSmrg	} else {
1310428d7b3dSmrg		if (frame->id == FOURCC_UYVY)
1311428d7b3dSmrg			src_surf_format = GEN5_SURFACEFORMAT_YCRCB_SWAPY;
1312428d7b3dSmrg		else
1313428d7b3dSmrg			src_surf_format = GEN5_SURFACEFORMAT_YCRCB_NORMAL;
1314428d7b3dSmrg
1315428d7b3dSmrg		src_width[0]  = frame->width;
1316428d7b3dSmrg		src_height[0] = frame->height;
1317428d7b3dSmrg		src_pitch[0]  = frame->pitch[0];
1318428d7b3dSmrg		n_src = 1;
1319428d7b3dSmrg	}
1320428d7b3dSmrg
1321428d7b3dSmrg	gen5_get_batch(sna, op);
1322428d7b3dSmrg
1323428d7b3dSmrg	binding_table = gen5_composite_get_binding_table(sna, &offset);
1324428d7b3dSmrg	binding_table[0] =
1325428d7b3dSmrg		gen5_bind_bo(sna,
1326428d7b3dSmrg			     op->dst.bo, op->dst.width, op->dst.height,
1327428d7b3dSmrg			     gen5_get_dest_format(op->dst.format),
1328428d7b3dSmrg			     true);
1329428d7b3dSmrg	for (n = 0; n < n_src; n++) {
1330428d7b3dSmrg		binding_table[1+n] =
1331428d7b3dSmrg			gen5_bind_video_source(sna,
1332428d7b3dSmrg					       frame->bo,
1333428d7b3dSmrg					       src_surf_base[n],
1334428d7b3dSmrg					       src_width[n],
1335428d7b3dSmrg					       src_height[n],
1336428d7b3dSmrg					       src_pitch[n],
1337428d7b3dSmrg					       src_surf_format);
1338428d7b3dSmrg	}
1339428d7b3dSmrg
1340428d7b3dSmrg	gen5_emit_state(sna, op, offset | dirty);
1341428d7b3dSmrg}
1342428d7b3dSmrg
1343428d7b3dSmrgstatic bool
1344428d7b3dSmrggen5_render_video(struct sna *sna,
1345428d7b3dSmrg		  struct sna_video *video,
1346428d7b3dSmrg		  struct sna_video_frame *frame,
1347428d7b3dSmrg		  RegionPtr dstRegion,
1348428d7b3dSmrg		  PixmapPtr pixmap)
1349428d7b3dSmrg{
1350428d7b3dSmrg	struct sna_composite_op tmp;
1351428d7b3dSmrg	struct sna_pixmap *priv = sna_pixmap(pixmap);
1352428d7b3dSmrg	int dst_width = dstRegion->extents.x2 - dstRegion->extents.x1;
1353428d7b3dSmrg	int dst_height = dstRegion->extents.y2 - dstRegion->extents.y1;
1354428d7b3dSmrg	int src_width = frame->src.x2 - frame->src.x1;
1355428d7b3dSmrg	int src_height = frame->src.y2 - frame->src.y1;
1356428d7b3dSmrg	float src_offset_x, src_offset_y;
1357428d7b3dSmrg	float src_scale_x, src_scale_y;
1358428d7b3dSmrg	int nbox, pix_xoff, pix_yoff;
1359428d7b3dSmrg	const BoxRec *box;
1360428d7b3dSmrg
1361428d7b3dSmrg	DBG(("%s: %dx%d -> %dx%d\n", __FUNCTION__,
1362428d7b3dSmrg	     src_width, src_height, dst_width, dst_height));
1363428d7b3dSmrg
1364428d7b3dSmrg	assert(priv->gpu_bo);
1365428d7b3dSmrg	memset(&tmp, 0, sizeof(tmp));
1366428d7b3dSmrg
1367428d7b3dSmrg	tmp.op = PictOpSrc;
1368428d7b3dSmrg	tmp.dst.pixmap = pixmap;
1369428d7b3dSmrg	tmp.dst.width  = pixmap->drawable.width;
1370428d7b3dSmrg	tmp.dst.height = pixmap->drawable.height;
1371428d7b3dSmrg	tmp.dst.format = sna_format_for_depth(pixmap->drawable.depth);
1372428d7b3dSmrg	tmp.dst.bo = priv->gpu_bo;
1373428d7b3dSmrg
1374428d7b3dSmrg	if (src_width == dst_width && src_height == dst_height)
1375428d7b3dSmrg		tmp.src.filter = SAMPLER_FILTER_NEAREST;
1376428d7b3dSmrg	else
1377428d7b3dSmrg		tmp.src.filter = SAMPLER_FILTER_BILINEAR;
1378428d7b3dSmrg	tmp.src.repeat = SAMPLER_EXTEND_PAD;
1379428d7b3dSmrg	tmp.src.bo = frame->bo;
1380428d7b3dSmrg	tmp.mask.bo = NULL;
1381428d7b3dSmrg	tmp.u.gen5.wm_kernel =
1382428d7b3dSmrg		is_planar_fourcc(frame->id) ? WM_KERNEL_VIDEO_PLANAR : WM_KERNEL_VIDEO_PACKED;
1383428d7b3dSmrg	tmp.u.gen5.ve_id = 2;
1384428d7b3dSmrg	tmp.is_affine = true;
1385428d7b3dSmrg	tmp.floats_per_vertex = 3;
1386428d7b3dSmrg	tmp.floats_per_rect = 9;
1387428d7b3dSmrg	tmp.priv = frame;
1388428d7b3dSmrg
1389428d7b3dSmrg	if (!kgem_check_bo(&sna->kgem, tmp.dst.bo, frame->bo, NULL)) {
1390428d7b3dSmrg		kgem_submit(&sna->kgem);
1391428d7b3dSmrg		if (!kgem_check_bo(&sna->kgem, tmp.dst.bo, frame->bo, NULL))
1392428d7b3dSmrg			return false;
1393428d7b3dSmrg	}
1394428d7b3dSmrg
1395428d7b3dSmrg	gen5_align_vertex(sna, &tmp);
1396428d7b3dSmrg	gen5_video_bind_surfaces(sna, &tmp);
1397428d7b3dSmrg
1398428d7b3dSmrg	/* Set up the offset for translating from the given region (in screen
1399428d7b3dSmrg	 * coordinates) to the backing pixmap.
1400428d7b3dSmrg	 */
1401428d7b3dSmrg#ifdef COMPOSITE
1402428d7b3dSmrg	pix_xoff = -pixmap->screen_x + pixmap->drawable.x;
1403428d7b3dSmrg	pix_yoff = -pixmap->screen_y + pixmap->drawable.y;
1404428d7b3dSmrg#else
1405428d7b3dSmrg	pix_xoff = 0;
1406428d7b3dSmrg	pix_yoff = 0;
1407428d7b3dSmrg#endif
1408428d7b3dSmrg
1409428d7b3dSmrg	src_scale_x = (float)src_width / dst_width / frame->width;
1410428d7b3dSmrg	src_offset_x = (float)frame->src.x1 / frame->width - dstRegion->extents.x1 * src_scale_x;
1411428d7b3dSmrg
1412428d7b3dSmrg	src_scale_y = (float)src_height / dst_height / frame->height;
1413428d7b3dSmrg	src_offset_y = (float)frame->src.y1 / frame->height - dstRegion->extents.y1 * src_scale_y;
1414428d7b3dSmrg
1415428d7b3dSmrg	box = region_rects(dstRegion);
1416428d7b3dSmrg	nbox = region_num_rects(dstRegion);
1417428d7b3dSmrg	while (nbox--) {
1418428d7b3dSmrg		BoxRec r;
1419428d7b3dSmrg
1420428d7b3dSmrg		r.x1 = box->x1 + pix_xoff;
1421428d7b3dSmrg		r.x2 = box->x2 + pix_xoff;
1422428d7b3dSmrg		r.y1 = box->y1 + pix_yoff;
1423428d7b3dSmrg		r.y2 = box->y2 + pix_yoff;
1424428d7b3dSmrg
1425428d7b3dSmrg		gen5_get_rectangles(sna, &tmp, 1, gen5_video_bind_surfaces);
1426428d7b3dSmrg
1427428d7b3dSmrg		OUT_VERTEX(r.x2, r.y2);
1428428d7b3dSmrg		OUT_VERTEX_F(box->x2 * src_scale_x + src_offset_x);
1429428d7b3dSmrg		OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
1430428d7b3dSmrg
1431428d7b3dSmrg		OUT_VERTEX(r.x1, r.y2);
1432428d7b3dSmrg		OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
1433428d7b3dSmrg		OUT_VERTEX_F(box->y2 * src_scale_y + src_offset_y);
1434428d7b3dSmrg
1435428d7b3dSmrg		OUT_VERTEX(r.x1, r.y1);
1436428d7b3dSmrg		OUT_VERTEX_F(box->x1 * src_scale_x + src_offset_x);
1437428d7b3dSmrg		OUT_VERTEX_F(box->y1 * src_scale_y + src_offset_y);
1438428d7b3dSmrg
1439428d7b3dSmrg		if (!DAMAGE_IS_ALL(priv->gpu_damage)) {
1440428d7b3dSmrg			sna_damage_add_box(&priv->gpu_damage, &r);
1441428d7b3dSmrg			sna_damage_subtract_box(&priv->cpu_damage, &r);
1442428d7b3dSmrg		}
1443428d7b3dSmrg		box++;
1444428d7b3dSmrg	}
1445428d7b3dSmrg
1446428d7b3dSmrg	gen4_vertex_flush(sna);
1447428d7b3dSmrg	return true;
1448428d7b3dSmrg}
1449428d7b3dSmrg
1450428d7b3dSmrgstatic int
1451428d7b3dSmrggen5_composite_picture(struct sna *sna,
1452428d7b3dSmrg		       PicturePtr picture,
1453428d7b3dSmrg		       struct sna_composite_channel *channel,
1454428d7b3dSmrg		       int x, int y,
1455428d7b3dSmrg		       int w, int h,
1456428d7b3dSmrg		       int dst_x, int dst_y,
1457428d7b3dSmrg		       bool precise)
1458428d7b3dSmrg{
1459428d7b3dSmrg	PixmapPtr pixmap;
1460428d7b3dSmrg	uint32_t color;
1461428d7b3dSmrg	int16_t dx, dy;
1462428d7b3dSmrg
1463428d7b3dSmrg	DBG(("%s: (%d, %d)x(%d, %d), dst=(%d, %d)\n",
1464428d7b3dSmrg	     __FUNCTION__, x, y, w, h, dst_x, dst_y));
1465428d7b3dSmrg
1466428d7b3dSmrg	channel->is_solid = false;
1467428d7b3dSmrg	channel->card_format = -1;
1468428d7b3dSmrg
1469428d7b3dSmrg	if (sna_picture_is_solid(picture, &color))
1470428d7b3dSmrg		return gen4_channel_init_solid(sna, channel, color);
1471428d7b3dSmrg
1472428d7b3dSmrg	if (picture->pDrawable == NULL) {
1473428d7b3dSmrg		int ret;
1474428d7b3dSmrg
1475428d7b3dSmrg		if (picture->pSourcePict->type == SourcePictTypeLinear)
1476428d7b3dSmrg			return gen4_channel_init_linear(sna, picture, channel,
1477428d7b3dSmrg							x, y,
1478428d7b3dSmrg							w, h,
1479428d7b3dSmrg							dst_x, dst_y);
1480428d7b3dSmrg
1481428d7b3dSmrg		DBG(("%s -- fixup, gradient\n", __FUNCTION__));
1482428d7b3dSmrg		ret = -1;
1483428d7b3dSmrg		if (!precise)
1484428d7b3dSmrg			ret = sna_render_picture_approximate_gradient(sna, picture, channel,
1485428d7b3dSmrg								      x, y, w, h, dst_x, dst_y);
1486428d7b3dSmrg		if (ret == -1)
1487428d7b3dSmrg			ret = sna_render_picture_fixup(sna, picture, channel,
1488428d7b3dSmrg						       x, y, w, h, dst_x, dst_y);
1489428d7b3dSmrg		return ret;
1490428d7b3dSmrg	}
1491428d7b3dSmrg
1492428d7b3dSmrg	if (picture->alphaMap) {
1493428d7b3dSmrg		DBG(("%s -- fallback, alphamap\n", __FUNCTION__));
1494428d7b3dSmrg		return sna_render_picture_fixup(sna, picture, channel,
1495428d7b3dSmrg						x, y, w, h, dst_x, dst_y);
1496428d7b3dSmrg	}
1497428d7b3dSmrg
1498428d7b3dSmrg	if (!gen5_check_repeat(picture))
1499428d7b3dSmrg		return sna_render_picture_fixup(sna, picture, channel,
1500428d7b3dSmrg						x, y, w, h, dst_x, dst_y);
1501428d7b3dSmrg
1502428d7b3dSmrg	if (!gen5_check_filter(picture))
1503428d7b3dSmrg		return sna_render_picture_fixup(sna, picture, channel,
1504428d7b3dSmrg						x, y, w, h, dst_x, dst_y);
1505428d7b3dSmrg
1506428d7b3dSmrg	channel->repeat = picture->repeat ? picture->repeatType : RepeatNone;
1507428d7b3dSmrg	channel->filter = picture->filter;
1508428d7b3dSmrg
1509428d7b3dSmrg	pixmap = get_drawable_pixmap(picture->pDrawable);
1510428d7b3dSmrg	get_drawable_deltas(picture->pDrawable, pixmap, &dx, &dy);
1511428d7b3dSmrg
1512428d7b3dSmrg	x += dx + picture->pDrawable->x;
1513428d7b3dSmrg	y += dy + picture->pDrawable->y;
1514428d7b3dSmrg
1515428d7b3dSmrg	channel->is_affine = sna_transform_is_affine(picture->transform);
1516428d7b3dSmrg	if (sna_transform_is_imprecise_integer_translation(picture->transform, picture->filter, precise, &dx, &dy)) {
1517428d7b3dSmrg		DBG(("%s: integer translation (%d, %d), removing\n",
1518428d7b3dSmrg		     __FUNCTION__, dx, dy));
1519428d7b3dSmrg		x += dx;
1520428d7b3dSmrg		y += dy;
1521428d7b3dSmrg		channel->transform = NULL;
1522428d7b3dSmrg		channel->filter = PictFilterNearest;
1523428d7b3dSmrg
1524428d7b3dSmrg		if (channel->repeat ||
1525428d7b3dSmrg		    (x >= 0 &&
1526428d7b3dSmrg		     y >= 0 &&
1527428d7b3dSmrg		     x + w < pixmap->drawable.width &&
1528428d7b3dSmrg		     y + h < pixmap->drawable.height)) {
1529428d7b3dSmrg			struct sna_pixmap *priv = sna_pixmap(pixmap);
1530428d7b3dSmrg			if (priv && priv->clear) {
1531428d7b3dSmrg				DBG(("%s: converting large pixmap source into solid [%08x]\n", __FUNCTION__, priv->clear_color));
1532428d7b3dSmrg				return gen4_channel_init_solid(sna, channel, priv->clear_color);
1533428d7b3dSmrg			}
1534428d7b3dSmrg		}
1535428d7b3dSmrg	} else
1536428d7b3dSmrg		channel->transform = picture->transform;
1537428d7b3dSmrg
1538428d7b3dSmrg	channel->pict_format = picture->format;
1539428d7b3dSmrg	channel->card_format = gen5_get_card_format(picture->format);
1540428d7b3dSmrg	if (channel->card_format == -1)
1541428d7b3dSmrg		return sna_render_picture_convert(sna, picture, channel, pixmap,
1542428d7b3dSmrg						  x, y, w, h, dst_x, dst_y,
1543428d7b3dSmrg						  false);
1544428d7b3dSmrg
1545428d7b3dSmrg	if (too_large(pixmap->drawable.width, pixmap->drawable.height))
1546428d7b3dSmrg		return sna_render_picture_extract(sna, picture, channel,
1547428d7b3dSmrg						  x, y, w, h, dst_x, dst_y);
1548428d7b3dSmrg
1549428d7b3dSmrg	DBG(("%s: pixmap, repeat=%d, filter=%d, transform?=%d [affine? %d], format=%08x\n",
1550428d7b3dSmrg	     __FUNCTION__,
1551428d7b3dSmrg	     channel->repeat, channel->filter,
1552428d7b3dSmrg	     channel->transform != NULL, channel->is_affine,
1553428d7b3dSmrg	     channel->pict_format));
1554428d7b3dSmrg	if (channel->transform) {
1555428d7b3dSmrg		DBG(("%s: transform=[%f %f %f, %f %f %f, %f %f %f]\n",
1556428d7b3dSmrg		     __FUNCTION__,
1557428d7b3dSmrg		     channel->transform->matrix[0][0] / 65536.,
1558428d7b3dSmrg		     channel->transform->matrix[0][1] / 65536.,
1559428d7b3dSmrg		     channel->transform->matrix[0][2] / 65536.,
1560428d7b3dSmrg		     channel->transform->matrix[1][0] / 65536.,
1561428d7b3dSmrg		     channel->transform->matrix[1][1] / 65536.,
1562428d7b3dSmrg		     channel->transform->matrix[1][2] / 65536.,
1563428d7b3dSmrg		     channel->transform->matrix[2][0] / 65536.,
1564428d7b3dSmrg		     channel->transform->matrix[2][1] / 65536.,
1565428d7b3dSmrg		     channel->transform->matrix[2][2] / 65536.));
1566428d7b3dSmrg	}
1567428d7b3dSmrg
1568428d7b3dSmrg	return sna_render_pixmap_bo(sna, channel, pixmap,
1569428d7b3dSmrg				    x, y, w, h, dst_x, dst_y);
1570428d7b3dSmrg}
1571428d7b3dSmrg
1572428d7b3dSmrgstatic void gen5_composite_channel_convert(struct sna_composite_channel *channel)
1573428d7b3dSmrg{
1574428d7b3dSmrg	channel->repeat = gen5_repeat(channel->repeat);
1575428d7b3dSmrg	channel->filter = gen5_filter(channel->filter);
1576428d7b3dSmrg	if (channel->card_format == (unsigned)-1)
1577428d7b3dSmrg		channel->card_format = gen5_get_card_format(channel->pict_format);
1578428d7b3dSmrg}
1579428d7b3dSmrg
1580428d7b3dSmrgstatic void
1581428d7b3dSmrggen5_render_composite_done(struct sna *sna,
1582428d7b3dSmrg			   const struct sna_composite_op *op)
1583428d7b3dSmrg{
1584428d7b3dSmrg	if (sna->render.vertex_offset) {
1585428d7b3dSmrg		gen4_vertex_flush(sna);
1586428d7b3dSmrg		gen5_magic_ca_pass(sna,op);
1587428d7b3dSmrg	}
1588428d7b3dSmrg
1589428d7b3dSmrg	DBG(("%s()\n", __FUNCTION__));
1590428d7b3dSmrg
1591428d7b3dSmrg	if (op->mask.bo)
1592428d7b3dSmrg		kgem_bo_destroy(&sna->kgem, op->mask.bo);
1593428d7b3dSmrg	if (op->src.bo)
1594428d7b3dSmrg		kgem_bo_destroy(&sna->kgem, op->src.bo);
1595428d7b3dSmrg
1596428d7b3dSmrg	sna_render_composite_redirect_done(sna, op);
1597428d7b3dSmrg}
1598428d7b3dSmrg
1599428d7b3dSmrgstatic bool
1600428d7b3dSmrggen5_composite_set_target(struct sna *sna,
1601428d7b3dSmrg			  struct sna_composite_op *op,
1602428d7b3dSmrg			  PicturePtr dst,
1603428d7b3dSmrg			  int x, int y, int w, int h,
1604428d7b3dSmrg			  bool partial)
1605428d7b3dSmrg{
1606428d7b3dSmrg	BoxRec box;
1607428d7b3dSmrg	unsigned hint;
1608428d7b3dSmrg
1609428d7b3dSmrg	op->dst.pixmap = get_drawable_pixmap(dst->pDrawable);
1610428d7b3dSmrg	op->dst.width  = op->dst.pixmap->drawable.width;
1611428d7b3dSmrg	op->dst.height = op->dst.pixmap->drawable.height;
1612428d7b3dSmrg	op->dst.format = dst->format;
1613428d7b3dSmrg	if (w && h) {
1614428d7b3dSmrg		box.x1 = x;
1615428d7b3dSmrg		box.y1 = y;
1616428d7b3dSmrg		box.x2 = x + w;
1617428d7b3dSmrg		box.y2 = y + h;
1618428d7b3dSmrg	} else
1619428d7b3dSmrg		sna_render_picture_extents(dst, &box);
1620428d7b3dSmrg
1621428d7b3dSmrg	hint = PREFER_GPU | FORCE_GPU | RENDER_GPU;
1622428d7b3dSmrg	if (!partial) {
1623428d7b3dSmrg		hint |= IGNORE_DAMAGE;
1624428d7b3dSmrg		if (w == op->dst.width && h == op->dst.height)
1625428d7b3dSmrg			hint |= REPLACES;
1626428d7b3dSmrg	}
1627428d7b3dSmrg
1628428d7b3dSmrg	op->dst.bo = sna_drawable_use_bo(dst->pDrawable, hint, &box, &op->damage);
1629428d7b3dSmrg	if (op->dst.bo == NULL)
1630428d7b3dSmrg		return false;
1631428d7b3dSmrg
1632428d7b3dSmrg	if (hint & REPLACES) {
1633428d7b3dSmrg		struct sna_pixmap *priv = sna_pixmap(op->dst.pixmap);
1634428d7b3dSmrg		kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
1635428d7b3dSmrg	}
1636428d7b3dSmrg
1637428d7b3dSmrg	get_drawable_deltas(dst->pDrawable, op->dst.pixmap,
1638428d7b3dSmrg			    &op->dst.x, &op->dst.y);
1639428d7b3dSmrg
1640428d7b3dSmrg	DBG(("%s: pixmap=%ld, format=%08x, size=%dx%d, pitch=%d, delta=(%d,%d),damage=%p\n",
1641428d7b3dSmrg	     __FUNCTION__,
1642428d7b3dSmrg	     op->dst.pixmap->drawable.serialNumber, (int)op->dst.format,
1643428d7b3dSmrg	     op->dst.width, op->dst.height,
1644428d7b3dSmrg	     op->dst.bo->pitch,
1645428d7b3dSmrg	     op->dst.x, op->dst.y,
1646428d7b3dSmrg	     op->damage ? *op->damage : (void *)-1));
1647428d7b3dSmrg
1648428d7b3dSmrg	assert(op->dst.bo->proxy == NULL);
1649428d7b3dSmrg
1650428d7b3dSmrg	if (too_large(op->dst.width, op->dst.height) &&
1651428d7b3dSmrg	    !sna_render_composite_redirect(sna, op, x, y, w, h, partial))
1652428d7b3dSmrg		return false;
1653428d7b3dSmrg
1654428d7b3dSmrg	return true;
1655428d7b3dSmrg}
1656428d7b3dSmrg
1657428d7b3dSmrgstatic bool
1658428d7b3dSmrgis_gradient(PicturePtr picture, bool precise)
1659428d7b3dSmrg{
1660428d7b3dSmrg	if (picture->pDrawable)
1661428d7b3dSmrg		return false;
1662428d7b3dSmrg
1663428d7b3dSmrg	switch (picture->pSourcePict->type) {
1664428d7b3dSmrg	case SourcePictTypeSolidFill:
1665428d7b3dSmrg	case SourcePictTypeLinear:
1666428d7b3dSmrg		return false;
1667428d7b3dSmrg	default:
1668428d7b3dSmrg		return precise;
1669428d7b3dSmrg	}
1670428d7b3dSmrg}
1671428d7b3dSmrg
1672428d7b3dSmrgstatic bool
1673428d7b3dSmrghas_alphamap(PicturePtr p)
1674428d7b3dSmrg{
1675428d7b3dSmrg	return p->alphaMap != NULL;
1676428d7b3dSmrg}
1677428d7b3dSmrg
1678428d7b3dSmrgstatic bool
1679428d7b3dSmrgneed_upload(struct sna *sna, PicturePtr p)
1680428d7b3dSmrg{
1681428d7b3dSmrg	return p->pDrawable && untransformed(p) &&
1682428d7b3dSmrg		!is_gpu(sna, p->pDrawable, PREFER_GPU_RENDER);
1683428d7b3dSmrg}
1684428d7b3dSmrg
1685428d7b3dSmrgstatic bool
1686428d7b3dSmrgsource_is_busy(PixmapPtr pixmap)
1687428d7b3dSmrg{
1688428d7b3dSmrg	struct sna_pixmap *priv = sna_pixmap(pixmap);
1689428d7b3dSmrg	if (priv == NULL)
1690428d7b3dSmrg		return false;
1691428d7b3dSmrg
1692428d7b3dSmrg	if (priv->clear)
1693428d7b3dSmrg		return false;
1694428d7b3dSmrg
1695428d7b3dSmrg	if (priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo))
1696428d7b3dSmrg		return true;
1697428d7b3dSmrg
1698428d7b3dSmrg	if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo))
1699428d7b3dSmrg		return true;
1700428d7b3dSmrg
1701428d7b3dSmrg	return priv->gpu_damage && !priv->cpu_damage;
1702428d7b3dSmrg}
1703428d7b3dSmrg
1704428d7b3dSmrgstatic bool
1705428d7b3dSmrgsource_fallback(struct sna *sna, PicturePtr p, PixmapPtr pixmap, bool precise)
1706428d7b3dSmrg{
1707428d7b3dSmrg	if (sna_picture_is_solid(p, NULL))
1708428d7b3dSmrg		return false;
1709428d7b3dSmrg
1710428d7b3dSmrg	if (is_gradient(p, precise) ||
1711428d7b3dSmrg	    !gen5_check_repeat(p) ||
1712428d7b3dSmrg	    !gen5_check_format(p->format))
1713428d7b3dSmrg		return true;
1714428d7b3dSmrg
1715428d7b3dSmrg	if (pixmap && source_is_busy(pixmap))
1716428d7b3dSmrg		return false;
1717428d7b3dSmrg
1718428d7b3dSmrg	return has_alphamap(p) || !gen5_check_filter(p) || need_upload(sna, p);
1719428d7b3dSmrg}
1720428d7b3dSmrg
1721428d7b3dSmrgstatic bool
1722428d7b3dSmrggen5_composite_fallback(struct sna *sna,
1723428d7b3dSmrg			PicturePtr src,
1724428d7b3dSmrg			PicturePtr mask,
1725428d7b3dSmrg			PicturePtr dst)
1726428d7b3dSmrg{
1727428d7b3dSmrg	PixmapPtr src_pixmap;
1728428d7b3dSmrg	PixmapPtr mask_pixmap;
1729428d7b3dSmrg	PixmapPtr dst_pixmap;
1730428d7b3dSmrg	bool src_fallback, mask_fallback;
1731428d7b3dSmrg
1732428d7b3dSmrg	if (!gen5_check_dst_format(dst->format)) {
1733428d7b3dSmrg		DBG(("%s: unknown destination format: %d\n",
1734428d7b3dSmrg		     __FUNCTION__, dst->format));
1735428d7b3dSmrg		return true;
1736428d7b3dSmrg	}
1737428d7b3dSmrg
1738428d7b3dSmrg	dst_pixmap = get_drawable_pixmap(dst->pDrawable);
1739428d7b3dSmrg
1740428d7b3dSmrg	src_pixmap = src->pDrawable ? get_drawable_pixmap(src->pDrawable) : NULL;
1741428d7b3dSmrg	src_fallback = source_fallback(sna, src, src_pixmap,
1742428d7b3dSmrg				       dst->polyMode == PolyModePrecise);
1743428d7b3dSmrg
1744428d7b3dSmrg	if (mask) {
1745428d7b3dSmrg		mask_pixmap = mask->pDrawable ? get_drawable_pixmap(mask->pDrawable) : NULL;
1746428d7b3dSmrg		mask_fallback = source_fallback(sna, mask, mask_pixmap,
1747428d7b3dSmrg						dst->polyMode == PolyModePrecise);
1748428d7b3dSmrg	} else {
1749428d7b3dSmrg		mask_pixmap = NULL;
1750428d7b3dSmrg		mask_fallback = false;
1751428d7b3dSmrg	}
1752428d7b3dSmrg
1753428d7b3dSmrg	/* If we are using the destination as a source and need to
1754428d7b3dSmrg	 * readback in order to upload the source, do it all
1755428d7b3dSmrg	 * on the cpu.
1756428d7b3dSmrg	 */
1757428d7b3dSmrg	if (src_pixmap == dst_pixmap && src_fallback) {
1758428d7b3dSmrg		DBG(("%s: src is dst and will fallback\n",__FUNCTION__));
1759428d7b3dSmrg		return true;
1760428d7b3dSmrg	}
1761428d7b3dSmrg	if (mask_pixmap == dst_pixmap && mask_fallback) {
1762428d7b3dSmrg		DBG(("%s: mask is dst and will fallback\n",__FUNCTION__));
1763428d7b3dSmrg		return true;
1764428d7b3dSmrg	}
1765428d7b3dSmrg
1766428d7b3dSmrg	/* If anything is on the GPU, push everything out to the GPU */
1767428d7b3dSmrg	if (dst_use_gpu(dst_pixmap)) {
1768428d7b3dSmrg		DBG(("%s: dst is already on the GPU, try to use GPU\n",
1769428d7b3dSmrg		     __FUNCTION__));
1770428d7b3dSmrg		return false;
1771428d7b3dSmrg	}
1772428d7b3dSmrg
1773428d7b3dSmrg	if (src_pixmap && !src_fallback) {
1774428d7b3dSmrg		DBG(("%s: src is already on the GPU, try to use GPU\n",
1775428d7b3dSmrg		     __FUNCTION__));
1776428d7b3dSmrg		return false;
1777428d7b3dSmrg	}
1778428d7b3dSmrg	if (mask_pixmap && !mask_fallback) {
1779428d7b3dSmrg		DBG(("%s: mask is already on the GPU, try to use GPU\n",
1780428d7b3dSmrg		     __FUNCTION__));
1781428d7b3dSmrg		return false;
1782428d7b3dSmrg	}
1783428d7b3dSmrg
1784428d7b3dSmrg	/* However if the dst is not on the GPU and we need to
1785428d7b3dSmrg	 * render one of the sources using the CPU, we may
1786428d7b3dSmrg	 * as well do the entire operation in place onthe CPU.
1787428d7b3dSmrg	 */
1788428d7b3dSmrg	if (src_fallback) {
1789428d7b3dSmrg		DBG(("%s: dst is on the CPU and src will fallback\n",
1790428d7b3dSmrg		     __FUNCTION__));
1791428d7b3dSmrg		return true;
1792428d7b3dSmrg	}
1793428d7b3dSmrg
1794428d7b3dSmrg	if (mask_fallback) {
1795428d7b3dSmrg		DBG(("%s: dst is on the CPU and mask will fallback\n",
1796428d7b3dSmrg		     __FUNCTION__));
1797428d7b3dSmrg		return true;
1798428d7b3dSmrg	}
1799428d7b3dSmrg
1800428d7b3dSmrg	if (too_large(dst_pixmap->drawable.width,
1801428d7b3dSmrg		      dst_pixmap->drawable.height) &&
1802428d7b3dSmrg	    dst_is_cpu(dst_pixmap)) {
1803428d7b3dSmrg		DBG(("%s: dst is on the CPU and too large\n", __FUNCTION__));
1804428d7b3dSmrg		return true;
1805428d7b3dSmrg	}
1806428d7b3dSmrg
1807428d7b3dSmrg	DBG(("%s: dst is not on the GPU and the operation should not fallback\n",
1808428d7b3dSmrg	     __FUNCTION__));
1809428d7b3dSmrg	return dst_use_cpu(dst_pixmap);
1810428d7b3dSmrg}
1811428d7b3dSmrg
1812428d7b3dSmrgstatic int
1813428d7b3dSmrgreuse_source(struct sna *sna,
1814428d7b3dSmrg	     PicturePtr src, struct sna_composite_channel *sc, int src_x, int src_y,
1815428d7b3dSmrg	     PicturePtr mask, struct sna_composite_channel *mc, int msk_x, int msk_y)
1816428d7b3dSmrg{
1817428d7b3dSmrg	uint32_t color;
1818428d7b3dSmrg
1819428d7b3dSmrg	if (src_x != msk_x || src_y != msk_y)
1820428d7b3dSmrg		return false;
1821428d7b3dSmrg
1822428d7b3dSmrg	if (src == mask) {
1823428d7b3dSmrg		DBG(("%s: mask is source\n", __FUNCTION__));
1824428d7b3dSmrg		*mc = *sc;
1825428d7b3dSmrg		mc->bo = kgem_bo_reference(mc->bo);
1826428d7b3dSmrg		return true;
1827428d7b3dSmrg	}
1828428d7b3dSmrg
1829428d7b3dSmrg	if (sna_picture_is_solid(mask, &color))
1830428d7b3dSmrg		return gen4_channel_init_solid(sna, mc, color);
1831428d7b3dSmrg
1832428d7b3dSmrg	if (sc->is_solid)
1833428d7b3dSmrg		return false;
1834428d7b3dSmrg
1835428d7b3dSmrg	if (src->pDrawable == NULL || mask->pDrawable != src->pDrawable)
1836428d7b3dSmrg		return false;
1837428d7b3dSmrg
1838428d7b3dSmrg	DBG(("%s: mask reuses source drawable\n", __FUNCTION__));
1839428d7b3dSmrg
1840428d7b3dSmrg	if (!sna_transform_equal(src->transform, mask->transform))
1841428d7b3dSmrg		return false;
1842428d7b3dSmrg
1843428d7b3dSmrg	if (!sna_picture_alphamap_equal(src, mask))
1844428d7b3dSmrg		return false;
1845428d7b3dSmrg
1846428d7b3dSmrg	if (!gen5_check_repeat(mask))
1847428d7b3dSmrg		return false;
1848428d7b3dSmrg
1849428d7b3dSmrg	if (!gen5_check_filter(mask))
1850428d7b3dSmrg		return false;
1851428d7b3dSmrg
1852428d7b3dSmrg	if (!gen5_check_format(mask->format))
1853428d7b3dSmrg		return false;
1854428d7b3dSmrg
1855428d7b3dSmrg	DBG(("%s: reusing source channel for mask with a twist\n",
1856428d7b3dSmrg	     __FUNCTION__));
1857428d7b3dSmrg
1858428d7b3dSmrg	*mc = *sc;
1859428d7b3dSmrg	mc->repeat = gen5_repeat(mask->repeat ? mask->repeatType : RepeatNone);
1860428d7b3dSmrg	mc->filter = gen5_filter(mask->filter);
1861428d7b3dSmrg	mc->pict_format = mask->format;
1862428d7b3dSmrg	mc->card_format = gen5_get_card_format(mask->format);
1863428d7b3dSmrg	mc->bo = kgem_bo_reference(mc->bo);
1864428d7b3dSmrg	return true;
1865428d7b3dSmrg}
1866428d7b3dSmrg
1867428d7b3dSmrgstatic bool
1868428d7b3dSmrggen5_render_composite(struct sna *sna,
1869428d7b3dSmrg		      uint8_t op,
1870428d7b3dSmrg		      PicturePtr src,
1871428d7b3dSmrg		      PicturePtr mask,
1872428d7b3dSmrg		      PicturePtr dst,
1873428d7b3dSmrg		      int16_t src_x, int16_t src_y,
1874428d7b3dSmrg		      int16_t msk_x, int16_t msk_y,
1875428d7b3dSmrg		      int16_t dst_x, int16_t dst_y,
1876428d7b3dSmrg		      int16_t width, int16_t height,
1877428d7b3dSmrg		      unsigned flags,
1878428d7b3dSmrg		      struct sna_composite_op *tmp)
1879428d7b3dSmrg{
1880428d7b3dSmrg	DBG(("%s: %dx%d, current mode=%d\n", __FUNCTION__,
1881428d7b3dSmrg	     width, height, sna->kgem.mode));
1882428d7b3dSmrg
1883428d7b3dSmrg	if (op >= ARRAY_SIZE(gen5_blend_op)) {
1884428d7b3dSmrg		DBG(("%s: unhandled blend op %d\n", __FUNCTION__, op));
1885428d7b3dSmrg		return false;
1886428d7b3dSmrg	}
1887428d7b3dSmrg
1888428d7b3dSmrg	if (mask == NULL &&
1889428d7b3dSmrg	    sna_blt_composite(sna, op,
1890428d7b3dSmrg			      src, dst,
1891428d7b3dSmrg			      src_x, src_y,
1892428d7b3dSmrg			      dst_x, dst_y,
1893428d7b3dSmrg			      width, height,
1894428d7b3dSmrg			      flags, tmp))
1895428d7b3dSmrg		return true;
1896428d7b3dSmrg
1897428d7b3dSmrg	if (gen5_composite_fallback(sna, src, mask, dst))
1898428d7b3dSmrg		goto fallback;
1899428d7b3dSmrg
1900428d7b3dSmrg	if (need_tiling(sna, width, height))
1901428d7b3dSmrg		return sna_tiling_composite(op, src, mask, dst,
1902428d7b3dSmrg					    src_x, src_y,
1903428d7b3dSmrg					    msk_x, msk_y,
1904428d7b3dSmrg					    dst_x, dst_y,
1905428d7b3dSmrg					    width, height,
1906428d7b3dSmrg					    tmp);
1907428d7b3dSmrg
1908428d7b3dSmrg	if (!gen5_composite_set_target(sna, tmp, dst,
1909428d7b3dSmrg				       dst_x, dst_y, width, height,
1910428d7b3dSmrg				       flags & COMPOSITE_PARTIAL || op > PictOpSrc)) {
1911428d7b3dSmrg		DBG(("%s: failed to set composite target\n", __FUNCTION__));
1912428d7b3dSmrg		goto fallback;
1913428d7b3dSmrg	}
1914428d7b3dSmrg
1915428d7b3dSmrg	DBG(("%s: preparing source\n", __FUNCTION__));
1916428d7b3dSmrg	tmp->op = op;
1917428d7b3dSmrg	switch (gen5_composite_picture(sna, src, &tmp->src,
1918428d7b3dSmrg				       src_x, src_y,
1919428d7b3dSmrg				       width, height,
1920428d7b3dSmrg				       dst_x, dst_y,
1921428d7b3dSmrg				       dst->polyMode == PolyModePrecise)) {
1922428d7b3dSmrg	case -1:
1923428d7b3dSmrg		DBG(("%s: failed to prepare source picture\n", __FUNCTION__));
1924428d7b3dSmrg		goto cleanup_dst;
1925428d7b3dSmrg	case 0:
1926428d7b3dSmrg		if (!gen4_channel_init_solid(sna, &tmp->src, 0))
1927428d7b3dSmrg			goto cleanup_dst;
1928428d7b3dSmrg		/* fall through to fixup */
1929428d7b3dSmrg	case 1:
1930428d7b3dSmrg		if (mask == NULL &&
1931428d7b3dSmrg		    sna_blt_composite__convert(sna,
1932428d7b3dSmrg					       dst_x, dst_y, width, height,
1933428d7b3dSmrg					       tmp))
1934428d7b3dSmrg			return true;
1935428d7b3dSmrg
1936428d7b3dSmrg		gen5_composite_channel_convert(&tmp->src);
1937428d7b3dSmrg		break;
1938428d7b3dSmrg	}
1939428d7b3dSmrg
1940428d7b3dSmrg	tmp->is_affine = tmp->src.is_affine;
1941428d7b3dSmrg	tmp->has_component_alpha = false;
1942428d7b3dSmrg	tmp->need_magic_ca_pass = false;
1943428d7b3dSmrg
1944428d7b3dSmrg	if (mask) {
1945428d7b3dSmrg		if (mask->componentAlpha && PICT_FORMAT_RGB(mask->format)) {
1946428d7b3dSmrg			tmp->has_component_alpha = true;
1947428d7b3dSmrg
1948428d7b3dSmrg			/* Check if it's component alpha that relies on a source alpha and on
1949428d7b3dSmrg			 * the source value.  We can only get one of those into the single
1950428d7b3dSmrg			 * source value that we get to blend with.
1951428d7b3dSmrg			 */
1952428d7b3dSmrg			if (gen5_blend_op[op].src_alpha &&
1953428d7b3dSmrg			    (gen5_blend_op[op].src_blend != GEN5_BLENDFACTOR_ZERO)) {
1954428d7b3dSmrg				if (op != PictOpOver) {
1955428d7b3dSmrg					DBG(("%s: unhandled CA blend op %d\n", __FUNCTION__, op));
1956428d7b3dSmrg					goto cleanup_src;
1957428d7b3dSmrg				}
1958428d7b3dSmrg
1959428d7b3dSmrg				tmp->need_magic_ca_pass = true;
1960428d7b3dSmrg				tmp->op = PictOpOutReverse;
1961428d7b3dSmrg			}
1962428d7b3dSmrg		}
1963428d7b3dSmrg
1964428d7b3dSmrg		if (!reuse_source(sna,
1965428d7b3dSmrg				  src, &tmp->src, src_x, src_y,
1966428d7b3dSmrg				  mask, &tmp->mask, msk_x, msk_y)) {
1967428d7b3dSmrg			DBG(("%s: preparing mask\n", __FUNCTION__));
1968428d7b3dSmrg			switch (gen5_composite_picture(sna, mask, &tmp->mask,
1969428d7b3dSmrg						       msk_x, msk_y,
1970428d7b3dSmrg						       width, height,
1971428d7b3dSmrg						       dst_x, dst_y,
1972428d7b3dSmrg						       dst->polyMode == PolyModePrecise)) {
1973428d7b3dSmrg			case -1:
1974428d7b3dSmrg				DBG(("%s: failed to prepare mask picture\n", __FUNCTION__));
1975428d7b3dSmrg				goto cleanup_src;
1976428d7b3dSmrg			case 0:
1977428d7b3dSmrg				if (!gen4_channel_init_solid(sna, &tmp->mask, 0))
1978428d7b3dSmrg					goto cleanup_src;
1979428d7b3dSmrg				/* fall through to fixup */
1980428d7b3dSmrg			case 1:
1981428d7b3dSmrg				gen5_composite_channel_convert(&tmp->mask);
1982428d7b3dSmrg				break;
1983428d7b3dSmrg			}
1984428d7b3dSmrg		}
1985428d7b3dSmrg
1986428d7b3dSmrg		tmp->is_affine &= tmp->mask.is_affine;
1987428d7b3dSmrg	}
1988428d7b3dSmrg
1989428d7b3dSmrg	tmp->u.gen5.wm_kernel =
1990428d7b3dSmrg		gen5_choose_composite_kernel(tmp->op,
1991428d7b3dSmrg					     tmp->mask.bo != NULL,
1992428d7b3dSmrg					     tmp->has_component_alpha,
1993428d7b3dSmrg					     tmp->is_affine);
1994428d7b3dSmrg	tmp->u.gen5.ve_id = gen4_choose_composite_emitter(sna, tmp);
1995428d7b3dSmrg
1996428d7b3dSmrg	tmp->blt   = gen5_render_composite_blt;
1997428d7b3dSmrg	tmp->box   = gen5_render_composite_box;
1998428d7b3dSmrg	tmp->boxes = gen5_render_composite_boxes__blt;
1999428d7b3dSmrg	if (tmp->emit_boxes) {
2000428d7b3dSmrg		tmp->boxes = gen5_render_composite_boxes;
2001428d7b3dSmrg		tmp->thread_boxes = gen5_render_composite_boxes__thread;
2002428d7b3dSmrg	}
2003428d7b3dSmrg	tmp->done  = gen5_render_composite_done;
2004428d7b3dSmrg
2005428d7b3dSmrg	if (!kgem_check_bo(&sna->kgem,
2006428d7b3dSmrg			   tmp->dst.bo, tmp->src.bo, tmp->mask.bo, NULL)) {
2007428d7b3dSmrg		kgem_submit(&sna->kgem);
2008428d7b3dSmrg		if (!kgem_check_bo(&sna->kgem,
2009428d7b3dSmrg				   tmp->dst.bo, tmp->src.bo, tmp->mask.bo, NULL))
2010428d7b3dSmrg			goto cleanup_mask;
2011428d7b3dSmrg	}
2012428d7b3dSmrg
2013428d7b3dSmrg	gen5_align_vertex(sna, tmp);
2014428d7b3dSmrg	gen5_bind_surfaces(sna, tmp);
2015428d7b3dSmrg	return true;
2016428d7b3dSmrg
2017428d7b3dSmrgcleanup_mask:
2018428d7b3dSmrg	if (tmp->mask.bo) {
2019428d7b3dSmrg		kgem_bo_destroy(&sna->kgem, tmp->mask.bo);
2020428d7b3dSmrg		tmp->mask.bo = NULL;
2021428d7b3dSmrg	}
2022428d7b3dSmrgcleanup_src:
2023428d7b3dSmrg	if (tmp->src.bo) {
2024428d7b3dSmrg		kgem_bo_destroy(&sna->kgem, tmp->src.bo);
2025428d7b3dSmrg		tmp->src.bo = NULL;
2026428d7b3dSmrg	}
2027428d7b3dSmrgcleanup_dst:
2028428d7b3dSmrg	if (tmp->redirect.real_bo) {
2029428d7b3dSmrg		kgem_bo_destroy(&sna->kgem, tmp->dst.bo);
2030428d7b3dSmrg		tmp->redirect.real_bo = NULL;
2031428d7b3dSmrg	}
2032428d7b3dSmrgfallback:
2033428d7b3dSmrg	return (mask == NULL &&
2034428d7b3dSmrg		sna_blt_composite(sna, op,
2035428d7b3dSmrg				  src, dst,
2036428d7b3dSmrg				  src_x, src_y,
2037428d7b3dSmrg				  dst_x, dst_y,
2038428d7b3dSmrg				  width, height,
2039428d7b3dSmrg				  flags | COMPOSITE_FALLBACK, tmp));
2040428d7b3dSmrg}
2041428d7b3dSmrg
2042428d7b3dSmrg#if !NO_COMPOSITE_SPANS
2043428d7b3dSmrgfastcall static void
2044428d7b3dSmrggen5_render_composite_spans_box(struct sna *sna,
2045428d7b3dSmrg				const struct sna_composite_spans_op *op,
2046428d7b3dSmrg				const BoxRec *box, float opacity)
2047428d7b3dSmrg{
2048428d7b3dSmrg	DBG(("%s: src=+(%d, %d), opacity=%f, dst=+(%d, %d), box=(%d, %d) x (%d, %d)\n",
2049428d7b3dSmrg	     __FUNCTION__,
2050428d7b3dSmrg	     op->base.src.offset[0], op->base.src.offset[1],
2051428d7b3dSmrg	     opacity,
2052428d7b3dSmrg	     op->base.dst.x, op->base.dst.y,
2053428d7b3dSmrg	     box->x1, box->y1,
2054428d7b3dSmrg	     box->x2 - box->x1,
2055428d7b3dSmrg	     box->y2 - box->y1));
2056428d7b3dSmrg
2057428d7b3dSmrg	gen5_get_rectangles(sna, &op->base, 1, gen5_bind_surfaces);
2058428d7b3dSmrg	op->prim_emit(sna, op, box, opacity);
2059428d7b3dSmrg}
2060428d7b3dSmrg
2061428d7b3dSmrgstatic void
2062428d7b3dSmrggen5_render_composite_spans_boxes(struct sna *sna,
2063428d7b3dSmrg				  const struct sna_composite_spans_op *op,
2064428d7b3dSmrg				  const BoxRec *box, int nbox,
2065428d7b3dSmrg				  float opacity)
2066428d7b3dSmrg{
2067428d7b3dSmrg	DBG(("%s: nbox=%d, src=+(%d, %d), opacity=%f, dst=+(%d, %d)\n",
2068428d7b3dSmrg	     __FUNCTION__, nbox,
2069428d7b3dSmrg	     op->base.src.offset[0], op->base.src.offset[1],
2070428d7b3dSmrg	     opacity,
2071428d7b3dSmrg	     op->base.dst.x, op->base.dst.y));
2072428d7b3dSmrg
2073428d7b3dSmrg	do {
2074428d7b3dSmrg		int nbox_this_time;
2075428d7b3dSmrg
2076428d7b3dSmrg		nbox_this_time = gen5_get_rectangles(sna, &op->base, nbox,
2077428d7b3dSmrg						     gen5_bind_surfaces);
2078428d7b3dSmrg		nbox -= nbox_this_time;
2079428d7b3dSmrg
2080428d7b3dSmrg		do {
2081428d7b3dSmrg			DBG(("  %s: (%d, %d) x (%d, %d)\n", __FUNCTION__,
2082428d7b3dSmrg			     box->x1, box->y1,
2083428d7b3dSmrg			     box->x2 - box->x1,
2084428d7b3dSmrg			     box->y2 - box->y1));
2085428d7b3dSmrg
2086428d7b3dSmrg			op->prim_emit(sna, op, box++, opacity);
2087428d7b3dSmrg		} while (--nbox_this_time);
2088428d7b3dSmrg	} while (nbox);
2089428d7b3dSmrg}
2090428d7b3dSmrg
2091428d7b3dSmrgfastcall static void
2092428d7b3dSmrggen5_render_composite_spans_boxes__thread(struct sna *sna,
2093428d7b3dSmrg					  const struct sna_composite_spans_op *op,
2094428d7b3dSmrg					  const struct sna_opacity_box *box,
2095428d7b3dSmrg					  int nbox)
2096428d7b3dSmrg{
2097428d7b3dSmrg	DBG(("%s: nbox=%d, src=+(%d, %d), dst=+(%d, %d)\n",
2098428d7b3dSmrg	     __FUNCTION__, nbox,
2099428d7b3dSmrg	     op->base.src.offset[0], op->base.src.offset[1],
2100428d7b3dSmrg	     op->base.dst.x, op->base.dst.y));
2101428d7b3dSmrg
2102428d7b3dSmrg	sna_vertex_lock(&sna->render);
2103428d7b3dSmrg	do {
2104428d7b3dSmrg		int nbox_this_time;
2105428d7b3dSmrg		float *v;
2106428d7b3dSmrg
2107428d7b3dSmrg		nbox_this_time = gen5_get_rectangles(sna, &op->base, nbox,
2108428d7b3dSmrg						     gen5_bind_surfaces);
2109428d7b3dSmrg		assert(nbox_this_time);
2110428d7b3dSmrg		nbox -= nbox_this_time;
2111428d7b3dSmrg
2112428d7b3dSmrg		v = sna->render.vertices + sna->render.vertex_used;
2113428d7b3dSmrg		sna->render.vertex_used += nbox_this_time * op->base.floats_per_rect;
2114428d7b3dSmrg
2115428d7b3dSmrg		sna_vertex_acquire__locked(&sna->render);
2116428d7b3dSmrg		sna_vertex_unlock(&sna->render);
2117428d7b3dSmrg
2118428d7b3dSmrg		op->emit_boxes(op, box, nbox_this_time, v);
2119428d7b3dSmrg		box += nbox_this_time;
2120428d7b3dSmrg
2121428d7b3dSmrg		sna_vertex_lock(&sna->render);
2122428d7b3dSmrg		sna_vertex_release__locked(&sna->render);
2123428d7b3dSmrg	} while (nbox);
2124428d7b3dSmrg	sna_vertex_unlock(&sna->render);
2125428d7b3dSmrg}
2126428d7b3dSmrg
2127428d7b3dSmrgfastcall static void
2128428d7b3dSmrggen5_render_composite_spans_done(struct sna *sna,
2129428d7b3dSmrg				 const struct sna_composite_spans_op *op)
2130428d7b3dSmrg{
2131428d7b3dSmrg	if (sna->render.vertex_offset)
2132428d7b3dSmrg		gen4_vertex_flush(sna);
2133428d7b3dSmrg
2134428d7b3dSmrg	DBG(("%s()\n", __FUNCTION__));
2135428d7b3dSmrg
2136428d7b3dSmrg	kgem_bo_destroy(&sna->kgem, op->base.src.bo);
2137428d7b3dSmrg	sna_render_composite_redirect_done(sna, &op->base);
2138428d7b3dSmrg}
2139428d7b3dSmrg
2140428d7b3dSmrgstatic bool
2141428d7b3dSmrggen5_check_composite_spans(struct sna *sna,
2142428d7b3dSmrg			   uint8_t op, PicturePtr src, PicturePtr dst,
2143428d7b3dSmrg			   int16_t width, int16_t height,
2144428d7b3dSmrg			   unsigned flags)
2145428d7b3dSmrg{
2146428d7b3dSmrg	DBG(("%s: op=%d, width=%d, height=%d, flags=%x\n",
2147428d7b3dSmrg	     __FUNCTION__, op, width, height, flags));
2148428d7b3dSmrg
2149428d7b3dSmrg	if (op >= ARRAY_SIZE(gen5_blend_op))
2150428d7b3dSmrg		return false;
2151428d7b3dSmrg
2152428d7b3dSmrg	if (gen5_composite_fallback(sna, src, NULL, dst)) {
2153428d7b3dSmrg		DBG(("%s: operation would fallback\n", __FUNCTION__));
2154428d7b3dSmrg		return false;
2155428d7b3dSmrg	}
2156428d7b3dSmrg
2157428d7b3dSmrg	if (need_tiling(sna, width, height) &&
2158428d7b3dSmrg	    !is_gpu(sna, dst->pDrawable, PREFER_GPU_SPANS)) {
2159428d7b3dSmrg		DBG(("%s: fallback, tiled operation not on GPU\n",
2160428d7b3dSmrg		     __FUNCTION__));
2161428d7b3dSmrg		return false;
2162428d7b3dSmrg	}
2163428d7b3dSmrg
2164428d7b3dSmrg	if ((flags & COMPOSITE_SPANS_RECTILINEAR) == 0) {
2165428d7b3dSmrg		struct sna_pixmap *priv = sna_pixmap_from_drawable(dst->pDrawable);
2166428d7b3dSmrg		assert(priv);
2167428d7b3dSmrg
2168428d7b3dSmrg		if (priv->cpu_bo && kgem_bo_is_busy(priv->cpu_bo))
2169428d7b3dSmrg			return true;
2170428d7b3dSmrg
2171428d7b3dSmrg		if (flags & COMPOSITE_SPANS_INPLACE_HINT)
2172428d7b3dSmrg			return false;
2173428d7b3dSmrg
2174428d7b3dSmrg		if ((sna->render.prefer_gpu & PREFER_GPU_SPANS) == 0 &&
2175428d7b3dSmrg		    dst->format == PICT_a8)
2176428d7b3dSmrg			return false;
2177428d7b3dSmrg
2178428d7b3dSmrg		return priv->gpu_bo && kgem_bo_is_busy(priv->gpu_bo);
2179428d7b3dSmrg	}
2180428d7b3dSmrg
2181428d7b3dSmrg	return true;
2182428d7b3dSmrg}
2183428d7b3dSmrg
2184428d7b3dSmrgstatic bool
2185428d7b3dSmrggen5_render_composite_spans(struct sna *sna,
2186428d7b3dSmrg			    uint8_t op,
2187428d7b3dSmrg			    PicturePtr src,
2188428d7b3dSmrg			    PicturePtr dst,
2189428d7b3dSmrg			    int16_t src_x,  int16_t src_y,
2190428d7b3dSmrg			    int16_t dst_x,  int16_t dst_y,
2191428d7b3dSmrg			    int16_t width,  int16_t height,
2192428d7b3dSmrg			    unsigned flags,
2193428d7b3dSmrg			    struct sna_composite_spans_op *tmp)
2194428d7b3dSmrg{
2195428d7b3dSmrg	DBG(("%s: %dx%d with flags=%x, current mode=%d\n", __FUNCTION__,
2196428d7b3dSmrg	     width, height, flags, sna->kgem.ring));
2197428d7b3dSmrg
2198428d7b3dSmrg	assert(gen5_check_composite_spans(sna, op, src, dst, width, height, flags));
2199428d7b3dSmrg
2200428d7b3dSmrg	if (need_tiling(sna, width, height)) {
2201428d7b3dSmrg		DBG(("%s: tiling, operation (%dx%d) too wide for pipeline\n",
2202428d7b3dSmrg		     __FUNCTION__, width, height));
2203428d7b3dSmrg		return sna_tiling_composite_spans(op, src, dst,
2204428d7b3dSmrg						  src_x, src_y, dst_x, dst_y,
2205428d7b3dSmrg						  width, height, flags, tmp);
2206428d7b3dSmrg	}
2207428d7b3dSmrg
2208428d7b3dSmrg	tmp->base.op = op;
2209428d7b3dSmrg	if (!gen5_composite_set_target(sna, &tmp->base, dst,
2210428d7b3dSmrg				       dst_x, dst_y, width, height,
2211428d7b3dSmrg				       true))
2212428d7b3dSmrg		return false;
2213428d7b3dSmrg
2214428d7b3dSmrg	switch (gen5_composite_picture(sna, src, &tmp->base.src,
2215428d7b3dSmrg				       src_x, src_y,
2216428d7b3dSmrg				       width, height,
2217428d7b3dSmrg				       dst_x, dst_y,
2218428d7b3dSmrg				       dst->polyMode == PolyModePrecise)) {
2219428d7b3dSmrg	case -1:
2220428d7b3dSmrg		goto cleanup_dst;
2221428d7b3dSmrg	case 0:
2222428d7b3dSmrg		if (!gen4_channel_init_solid(sna, &tmp->base.src, 0))
2223428d7b3dSmrg			goto cleanup_dst;
2224428d7b3dSmrg		/* fall through to fixup */
2225428d7b3dSmrg	case 1:
2226428d7b3dSmrg		gen5_composite_channel_convert(&tmp->base.src);
2227428d7b3dSmrg		break;
2228428d7b3dSmrg	}
2229428d7b3dSmrg
2230428d7b3dSmrg	tmp->base.mask.bo = NULL;
2231428d7b3dSmrg
2232428d7b3dSmrg	tmp->base.is_affine = tmp->base.src.is_affine;
2233428d7b3dSmrg	tmp->base.has_component_alpha = false;
2234428d7b3dSmrg	tmp->base.need_magic_ca_pass = false;
2235428d7b3dSmrg
2236428d7b3dSmrg	tmp->base.u.gen5.ve_id = gen4_choose_spans_emitter(sna, tmp);
2237428d7b3dSmrg	tmp->base.u.gen5.wm_kernel = WM_KERNEL_OPACITY | !tmp->base.is_affine;
2238428d7b3dSmrg
2239428d7b3dSmrg	tmp->box   = gen5_render_composite_spans_box;
2240428d7b3dSmrg	tmp->boxes = gen5_render_composite_spans_boxes;
2241428d7b3dSmrg	if (tmp->emit_boxes)
2242428d7b3dSmrg		tmp->thread_boxes = gen5_render_composite_spans_boxes__thread;
2243428d7b3dSmrg	tmp->done  = gen5_render_composite_spans_done;
2244428d7b3dSmrg
2245428d7b3dSmrg	if (!kgem_check_bo(&sna->kgem,
2246428d7b3dSmrg			   tmp->base.dst.bo, tmp->base.src.bo,
2247428d7b3dSmrg			   NULL))  {
2248428d7b3dSmrg		kgem_submit(&sna->kgem);
2249428d7b3dSmrg		if (!kgem_check_bo(&sna->kgem,
2250428d7b3dSmrg				   tmp->base.dst.bo, tmp->base.src.bo,
2251428d7b3dSmrg				   NULL))
2252428d7b3dSmrg			goto cleanup_src;
2253428d7b3dSmrg	}
2254428d7b3dSmrg
2255428d7b3dSmrg	gen5_align_vertex(sna, &tmp->base);
2256428d7b3dSmrg	gen5_bind_surfaces(sna, &tmp->base);
2257428d7b3dSmrg	return true;
2258428d7b3dSmrg
2259428d7b3dSmrgcleanup_src:
2260428d7b3dSmrg	if (tmp->base.src.bo)
2261428d7b3dSmrg		kgem_bo_destroy(&sna->kgem, tmp->base.src.bo);
2262428d7b3dSmrgcleanup_dst:
2263428d7b3dSmrg	if (tmp->base.redirect.real_bo)
2264428d7b3dSmrg		kgem_bo_destroy(&sna->kgem, tmp->base.dst.bo);
2265428d7b3dSmrg	return false;
2266428d7b3dSmrg}
2267428d7b3dSmrg#endif
2268428d7b3dSmrg
2269428d7b3dSmrgstatic void
2270428d7b3dSmrggen5_copy_bind_surfaces(struct sna *sna,
2271428d7b3dSmrg			const struct sna_composite_op *op)
2272428d7b3dSmrg{
2273428d7b3dSmrg	bool dirty = kgem_bo_is_dirty(op->dst.bo);
2274428d7b3dSmrg	uint32_t *binding_table;
2275428d7b3dSmrg	uint16_t offset;
2276428d7b3dSmrg
2277428d7b3dSmrg	gen5_get_batch(sna, op);
2278428d7b3dSmrg
2279428d7b3dSmrg	binding_table = gen5_composite_get_binding_table(sna, &offset);
2280428d7b3dSmrg
2281428d7b3dSmrg	binding_table[0] =
2282428d7b3dSmrg		gen5_bind_bo(sna,
2283428d7b3dSmrg			     op->dst.bo, op->dst.width, op->dst.height,
2284428d7b3dSmrg			     gen5_get_dest_format(op->dst.format),
2285428d7b3dSmrg			     true);
2286428d7b3dSmrg	binding_table[1] =
2287428d7b3dSmrg		gen5_bind_bo(sna,
2288428d7b3dSmrg			     op->src.bo, op->src.width, op->src.height,
2289428d7b3dSmrg			     op->src.card_format,
2290428d7b3dSmrg			     false);
2291428d7b3dSmrg
2292428d7b3dSmrg	if (sna->kgem.surface == offset &&
2293428d7b3dSmrg	    *(uint64_t *)(sna->kgem.batch + sna->render_state.gen5.surface_table) == *(uint64_t*)binding_table) {
2294428d7b3dSmrg		sna->kgem.surface += sizeof(struct gen5_surface_state_padded) / sizeof(uint32_t);
2295428d7b3dSmrg		offset = sna->render_state.gen5.surface_table;
2296428d7b3dSmrg	}
2297428d7b3dSmrg
2298428d7b3dSmrg	gen5_emit_state(sna, op, offset | dirty);
2299428d7b3dSmrg}
2300428d7b3dSmrg
2301428d7b3dSmrgstatic bool
2302428d7b3dSmrggen5_render_copy_boxes(struct sna *sna, uint8_t alu,
2303428d7b3dSmrg		       const DrawableRec *src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
2304428d7b3dSmrg		       const DrawableRec *dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
2305428d7b3dSmrg		       const BoxRec *box, int n, unsigned flags)
2306428d7b3dSmrg{
2307428d7b3dSmrg	struct sna_composite_op tmp;
2308428d7b3dSmrg
2309428d7b3dSmrg	DBG(("%s alu=%d, src=%ld:handle=%d, dst=%ld:handle=%d boxes=%d x [((%d, %d), (%d, %d))...], flags=%x\n",
2310428d7b3dSmrg	     __FUNCTION__, alu,
2311428d7b3dSmrg	     src->serialNumber, src_bo->handle,
2312428d7b3dSmrg	     dst->serialNumber, dst_bo->handle,
2313428d7b3dSmrg	     n, box->x1, box->y1, box->x2, box->y2,
2314428d7b3dSmrg	     flags));
2315428d7b3dSmrg
2316428d7b3dSmrg	if (sna_blt_compare_depth(src, dst) &&
2317428d7b3dSmrg	    sna_blt_copy_boxes(sna, alu,
2318428d7b3dSmrg			       src_bo, src_dx, src_dy,
2319428d7b3dSmrg			       dst_bo, dst_dx, dst_dy,
2320428d7b3dSmrg			       dst->bitsPerPixel,
2321428d7b3dSmrg			       box, n))
2322428d7b3dSmrg		return true;
2323428d7b3dSmrg
2324428d7b3dSmrg	if (!(alu == GXcopy || alu == GXclear) || src_bo == dst_bo) {
2325428d7b3dSmrgfallback_blt:
2326428d7b3dSmrg		if (!sna_blt_compare_depth(src, dst))
2327428d7b3dSmrg			return false;
2328428d7b3dSmrg
2329428d7b3dSmrg		return sna_blt_copy_boxes_fallback(sna, alu,
2330428d7b3dSmrg						   src, src_bo, src_dx, src_dy,
2331428d7b3dSmrg						   dst, dst_bo, dst_dx, dst_dy,
2332428d7b3dSmrg						   box, n);
2333428d7b3dSmrg	}
2334428d7b3dSmrg
2335428d7b3dSmrg	memset(&tmp, 0, sizeof(tmp));
2336428d7b3dSmrg
2337428d7b3dSmrg	if (dst->depth == src->depth) {
2338428d7b3dSmrg		tmp.dst.format = sna_render_format_for_depth(dst->depth);
2339428d7b3dSmrg		tmp.src.pict_format = tmp.dst.format;
2340428d7b3dSmrg	} else {
2341428d7b3dSmrg		tmp.dst.format = sna_format_for_depth(dst->depth);
2342428d7b3dSmrg		tmp.src.pict_format = sna_format_for_depth(src->depth);
2343428d7b3dSmrg	}
2344428d7b3dSmrg	if (!gen5_check_format(tmp.src.pict_format)) {
2345428d7b3dSmrg		DBG(("%s: unsupported source format, %x, use BLT\n",
2346428d7b3dSmrg		     __FUNCTION__, tmp.src.pict_format));
2347428d7b3dSmrg		goto fallback_blt;
2348428d7b3dSmrg	}
2349428d7b3dSmrg
2350428d7b3dSmrg	DBG(("%s (%d, %d)->(%d, %d) x %d\n",
2351428d7b3dSmrg	     __FUNCTION__, src_dx, src_dy, dst_dx, dst_dy, n));
2352428d7b3dSmrg
2353428d7b3dSmrg	tmp.op = alu == GXcopy ? PictOpSrc : PictOpClear;
2354428d7b3dSmrg
2355428d7b3dSmrg	tmp.dst.pixmap = (PixmapPtr)dst;
2356428d7b3dSmrg	tmp.dst.width  = dst->width;
2357428d7b3dSmrg	tmp.dst.height = dst->height;
2358428d7b3dSmrg	tmp.dst.x = tmp.dst.y = 0;
2359428d7b3dSmrg	tmp.dst.bo = dst_bo;
2360428d7b3dSmrg	tmp.damage = NULL;
2361428d7b3dSmrg
2362428d7b3dSmrg	sna_render_composite_redirect_init(&tmp);
2363428d7b3dSmrg	if (too_large(tmp.dst.width, tmp.dst.height)) {
2364428d7b3dSmrg		BoxRec extents = box[0];
2365428d7b3dSmrg		int i;
2366428d7b3dSmrg
2367428d7b3dSmrg		for (i = 1; i < n; i++) {
2368428d7b3dSmrg			if (box[i].x1 < extents.x1)
2369428d7b3dSmrg				extents.x1 = box[i].x1;
2370428d7b3dSmrg			if (box[i].y1 < extents.y1)
2371428d7b3dSmrg				extents.y1 = box[i].y1;
2372428d7b3dSmrg
2373428d7b3dSmrg			if (box[i].x2 > extents.x2)
2374428d7b3dSmrg				extents.x2 = box[i].x2;
2375428d7b3dSmrg			if (box[i].y2 > extents.y2)
2376428d7b3dSmrg				extents.y2 = box[i].y2;
2377428d7b3dSmrg		}
2378428d7b3dSmrg		if (!sna_render_composite_redirect(sna, &tmp,
2379428d7b3dSmrg						   extents.x1 + dst_dx,
2380428d7b3dSmrg						   extents.y1 + dst_dy,
2381428d7b3dSmrg						   extents.x2 - extents.x1,
2382428d7b3dSmrg						   extents.y2 - extents.y1,
2383428d7b3dSmrg						   n > 1))
2384428d7b3dSmrg			goto fallback_tiled;
2385428d7b3dSmrg	}
2386428d7b3dSmrg
2387428d7b3dSmrg	tmp.src.filter = SAMPLER_FILTER_NEAREST;
2388428d7b3dSmrg	tmp.src.repeat = SAMPLER_EXTEND_NONE;
2389428d7b3dSmrg	tmp.src.card_format = gen5_get_card_format(tmp.src.pict_format);
2390428d7b3dSmrg	if (too_large(src->width, src->height)) {
2391428d7b3dSmrg		BoxRec extents = box[0];
2392428d7b3dSmrg		int i;
2393428d7b3dSmrg
2394428d7b3dSmrg		for (i = 1; i < n; i++) {
2395428d7b3dSmrg			if (box[i].x1 < extents.x1)
2396428d7b3dSmrg				extents.x1 = box[i].x1;
2397428d7b3dSmrg			if (box[i].y1 < extents.y1)
2398428d7b3dSmrg				extents.y1 = box[i].y1;
2399428d7b3dSmrg
2400428d7b3dSmrg			if (box[i].x2 > extents.x2)
2401428d7b3dSmrg				extents.x2 = box[i].x2;
2402428d7b3dSmrg			if (box[i].y2 > extents.y2)
2403428d7b3dSmrg				extents.y2 = box[i].y2;
2404428d7b3dSmrg		}
2405428d7b3dSmrg
2406428d7b3dSmrg		if (!sna_render_pixmap_partial(sna, src, src_bo, &tmp.src,
2407428d7b3dSmrg					       extents.x1 + src_dx,
2408428d7b3dSmrg					       extents.y1 + src_dy,
2409428d7b3dSmrg					       extents.x2 - extents.x1,
2410428d7b3dSmrg					       extents.y2 - extents.y1))
2411428d7b3dSmrg			goto fallback_tiled_dst;
2412428d7b3dSmrg	} else {
2413428d7b3dSmrg		tmp.src.bo = kgem_bo_reference(src_bo);
2414428d7b3dSmrg		tmp.src.width  = src->width;
2415428d7b3dSmrg		tmp.src.height = src->height;
2416428d7b3dSmrg		tmp.src.offset[0] = tmp.src.offset[1] = 0;
2417428d7b3dSmrg		tmp.src.scale[0] = 1.f/src->width;
2418428d7b3dSmrg		tmp.src.scale[1] = 1.f/src->height;
2419428d7b3dSmrg	}
2420428d7b3dSmrg
2421428d7b3dSmrg	tmp.is_affine = true;
2422428d7b3dSmrg	tmp.floats_per_vertex = 3;
2423428d7b3dSmrg	tmp.floats_per_rect = 9;
2424428d7b3dSmrg	tmp.u.gen5.wm_kernel = WM_KERNEL;
2425428d7b3dSmrg	tmp.u.gen5.ve_id = 2;
2426428d7b3dSmrg
2427428d7b3dSmrg	if (!kgem_check_bo(&sna->kgem, dst_bo, src_bo, NULL)) {
2428428d7b3dSmrg		kgem_submit(&sna->kgem);
2429428d7b3dSmrg		if (!kgem_check_bo(&sna->kgem, dst_bo, src_bo, NULL)) {
2430428d7b3dSmrg			DBG(("%s: aperture check failed\n", __FUNCTION__));
2431428d7b3dSmrg			kgem_bo_destroy(&sna->kgem, tmp.src.bo);
2432428d7b3dSmrg			if (tmp.redirect.real_bo)
2433428d7b3dSmrg				kgem_bo_destroy(&sna->kgem, tmp.dst.bo);
2434428d7b3dSmrg
2435428d7b3dSmrg			goto fallback_blt;
2436428d7b3dSmrg		}
2437428d7b3dSmrg	}
2438428d7b3dSmrg
2439428d7b3dSmrg	dst_dx += tmp.dst.x;
2440428d7b3dSmrg	dst_dy += tmp.dst.y;
2441428d7b3dSmrg	tmp.dst.x = tmp.dst.y = 0;
2442428d7b3dSmrg
2443428d7b3dSmrg	src_dx += tmp.src.offset[0];
2444428d7b3dSmrg	src_dy += tmp.src.offset[1];
2445428d7b3dSmrg
2446428d7b3dSmrg	gen5_align_vertex(sna, &tmp);
2447428d7b3dSmrg	gen5_copy_bind_surfaces(sna, &tmp);
2448428d7b3dSmrg
2449428d7b3dSmrg	do {
2450428d7b3dSmrg		int n_this_time;
2451428d7b3dSmrg
2452428d7b3dSmrg		n_this_time = gen5_get_rectangles(sna, &tmp, n,
2453428d7b3dSmrg						  gen5_copy_bind_surfaces);
2454428d7b3dSmrg		n -= n_this_time;
2455428d7b3dSmrg
2456428d7b3dSmrg		do {
2457428d7b3dSmrg			DBG(("	(%d, %d) -> (%d, %d) + (%d, %d)\n",
2458428d7b3dSmrg			     box->x1 + src_dx, box->y1 + src_dy,
2459428d7b3dSmrg			     box->x1 + dst_dx, box->y1 + dst_dy,
2460428d7b3dSmrg			     box->x2 - box->x1, box->y2 - box->y1));
2461428d7b3dSmrg			OUT_VERTEX(box->x2 + dst_dx, box->y2 + dst_dy);
2462428d7b3dSmrg			OUT_VERTEX_F((box->x2 + src_dx) * tmp.src.scale[0]);
2463428d7b3dSmrg			OUT_VERTEX_F((box->y2 + src_dy) * tmp.src.scale[1]);
2464428d7b3dSmrg
2465428d7b3dSmrg			OUT_VERTEX(box->x1 + dst_dx, box->y2 + dst_dy);
2466428d7b3dSmrg			OUT_VERTEX_F((box->x1 + src_dx) * tmp.src.scale[0]);
2467428d7b3dSmrg			OUT_VERTEX_F((box->y2 + src_dy) * tmp.src.scale[1]);
2468428d7b3dSmrg
2469428d7b3dSmrg			OUT_VERTEX(box->x1 + dst_dx, box->y1 + dst_dy);
2470428d7b3dSmrg			OUT_VERTEX_F((box->x1 + src_dx) * tmp.src.scale[0]);
2471428d7b3dSmrg			OUT_VERTEX_F((box->y1 + src_dy) * tmp.src.scale[1]);
2472428d7b3dSmrg
2473428d7b3dSmrg			box++;
2474428d7b3dSmrg		} while (--n_this_time);
2475428d7b3dSmrg	} while (n);
2476428d7b3dSmrg
2477428d7b3dSmrg	gen4_vertex_flush(sna);
2478428d7b3dSmrg	sna_render_composite_redirect_done(sna, &tmp);
2479428d7b3dSmrg	kgem_bo_destroy(&sna->kgem, tmp.src.bo);
2480428d7b3dSmrg	return true;
2481428d7b3dSmrg
2482428d7b3dSmrgfallback_tiled_dst:
2483428d7b3dSmrg	if (tmp.redirect.real_bo)
2484428d7b3dSmrg		kgem_bo_destroy(&sna->kgem, tmp.dst.bo);
2485428d7b3dSmrgfallback_tiled:
2486428d7b3dSmrg	if (sna_blt_compare_depth(src, dst) &&
2487428d7b3dSmrg	    sna_blt_copy_boxes(sna, alu,
2488428d7b3dSmrg			       src_bo, src_dx, src_dy,
2489428d7b3dSmrg			       dst_bo, dst_dx, dst_dy,
2490428d7b3dSmrg			       dst->bitsPerPixel,
2491428d7b3dSmrg			       box, n))
2492428d7b3dSmrg		return true;
2493428d7b3dSmrg
2494428d7b3dSmrg	DBG(("%s: tiled fallback\n", __FUNCTION__));
2495428d7b3dSmrg	return sna_tiling_copy_boxes(sna, alu,
2496428d7b3dSmrg				     src, src_bo, src_dx, src_dy,
2497428d7b3dSmrg				     dst, dst_bo, dst_dx, dst_dy,
2498428d7b3dSmrg				     box, n);
2499428d7b3dSmrg}
2500428d7b3dSmrg
2501428d7b3dSmrgstatic void
2502428d7b3dSmrggen5_render_copy_blt(struct sna *sna,
2503428d7b3dSmrg		     const struct sna_copy_op *op,
2504428d7b3dSmrg		     int16_t sx, int16_t sy,
2505428d7b3dSmrg		     int16_t w,  int16_t h,
2506428d7b3dSmrg		     int16_t dx, int16_t dy)
2507428d7b3dSmrg{
2508428d7b3dSmrg	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n", __FUNCTION__,
2509428d7b3dSmrg	     sx, sy, dx, dy, w, h));
2510428d7b3dSmrg
2511428d7b3dSmrg	gen5_get_rectangles(sna, &op->base, 1, gen5_copy_bind_surfaces);
2512428d7b3dSmrg
2513428d7b3dSmrg	OUT_VERTEX(dx+w, dy+h);
2514428d7b3dSmrg	OUT_VERTEX_F((sx+w)*op->base.src.scale[0]);
2515428d7b3dSmrg	OUT_VERTEX_F((sy+h)*op->base.src.scale[1]);
2516428d7b3dSmrg
2517428d7b3dSmrg	OUT_VERTEX(dx, dy+h);
2518428d7b3dSmrg	OUT_VERTEX_F(sx*op->base.src.scale[0]);
2519428d7b3dSmrg	OUT_VERTEX_F((sy+h)*op->base.src.scale[1]);
2520428d7b3dSmrg
2521428d7b3dSmrg	OUT_VERTEX(dx, dy);
2522428d7b3dSmrg	OUT_VERTEX_F(sx*op->base.src.scale[0]);
2523428d7b3dSmrg	OUT_VERTEX_F(sy*op->base.src.scale[1]);
2524428d7b3dSmrg}
2525428d7b3dSmrg
2526428d7b3dSmrgstatic void
2527428d7b3dSmrggen5_render_copy_done(struct sna *sna,
2528428d7b3dSmrg		      const struct sna_copy_op *op)
2529428d7b3dSmrg{
2530428d7b3dSmrg	if (sna->render.vertex_offset)
2531428d7b3dSmrg		gen4_vertex_flush(sna);
2532428d7b3dSmrg
2533428d7b3dSmrg	DBG(("%s()\n", __FUNCTION__));
2534428d7b3dSmrg}
2535428d7b3dSmrg
2536428d7b3dSmrgstatic bool
2537428d7b3dSmrggen5_render_copy(struct sna *sna, uint8_t alu,
2538428d7b3dSmrg		 PixmapPtr src, struct kgem_bo *src_bo,
2539428d7b3dSmrg		 PixmapPtr dst, struct kgem_bo *dst_bo,
2540428d7b3dSmrg		 struct sna_copy_op *op)
2541428d7b3dSmrg{
2542428d7b3dSmrg	DBG(("%s (alu=%d)\n", __FUNCTION__, alu));
2543428d7b3dSmrg
2544428d7b3dSmrg	if (sna_blt_compare_depth(&src->drawable, &dst->drawable) &&
2545428d7b3dSmrg	    sna_blt_copy(sna, alu,
2546428d7b3dSmrg			 src_bo, dst_bo,
2547428d7b3dSmrg			 dst->drawable.bitsPerPixel,
2548428d7b3dSmrg			 op))
2549428d7b3dSmrg		return true;
2550428d7b3dSmrg
2551428d7b3dSmrg	if (!(alu == GXcopy || alu == GXclear) || src_bo == dst_bo ||
2552428d7b3dSmrg	    too_large(src->drawable.width, src->drawable.height) ||
2553428d7b3dSmrg	    too_large(dst->drawable.width, dst->drawable.height)) {
2554428d7b3dSmrgfallback:
2555428d7b3dSmrg		if (!sna_blt_compare_depth(&src->drawable, &dst->drawable))
2556428d7b3dSmrg			return false;
2557428d7b3dSmrg
2558428d7b3dSmrg		return sna_blt_copy(sna, alu, src_bo, dst_bo,
2559428d7b3dSmrg				    dst->drawable.bitsPerPixel,
2560428d7b3dSmrg				    op);
2561428d7b3dSmrg	}
2562428d7b3dSmrg
2563428d7b3dSmrg	if (dst->drawable.depth == src->drawable.depth) {
2564428d7b3dSmrg		op->base.dst.format = sna_render_format_for_depth(dst->drawable.depth);
2565428d7b3dSmrg		op->base.src.pict_format = op->base.dst.format;
2566428d7b3dSmrg	} else {
2567428d7b3dSmrg		op->base.dst.format = sna_format_for_depth(dst->drawable.depth);
2568428d7b3dSmrg		op->base.src.pict_format = sna_format_for_depth(src->drawable.depth);
2569428d7b3dSmrg	}
2570428d7b3dSmrg	if (!gen5_check_format(op->base.src.pict_format))
2571428d7b3dSmrg		goto fallback;
2572428d7b3dSmrg
2573428d7b3dSmrg	op->base.op = alu == GXcopy ? PictOpSrc : PictOpClear;
2574428d7b3dSmrg
2575428d7b3dSmrg	op->base.dst.pixmap = dst;
2576428d7b3dSmrg	op->base.dst.width  = dst->drawable.width;
2577428d7b3dSmrg	op->base.dst.height = dst->drawable.height;
2578428d7b3dSmrg	op->base.dst.bo = dst_bo;
2579428d7b3dSmrg
2580428d7b3dSmrg	op->base.src.bo = src_bo;
2581428d7b3dSmrg	op->base.src.card_format =
2582428d7b3dSmrg		gen5_get_card_format(op->base.src.pict_format);
2583428d7b3dSmrg	op->base.src.width  = src->drawable.width;
2584428d7b3dSmrg	op->base.src.height = src->drawable.height;
2585428d7b3dSmrg	op->base.src.scale[0] = 1.f/src->drawable.width;
2586428d7b3dSmrg	op->base.src.scale[1] = 1.f/src->drawable.height;
2587428d7b3dSmrg	op->base.src.filter = SAMPLER_FILTER_NEAREST;
2588428d7b3dSmrg	op->base.src.repeat = SAMPLER_EXTEND_NONE;
2589428d7b3dSmrg
2590428d7b3dSmrg	op->base.is_affine = true;
2591428d7b3dSmrg	op->base.floats_per_vertex = 3;
2592428d7b3dSmrg	op->base.floats_per_rect = 9;
2593428d7b3dSmrg	op->base.u.gen5.wm_kernel = WM_KERNEL;
2594428d7b3dSmrg	op->base.u.gen5.ve_id = 2;
2595428d7b3dSmrg
2596428d7b3dSmrg	if (!kgem_check_bo(&sna->kgem, dst_bo, src_bo, NULL)) {
2597428d7b3dSmrg		kgem_submit(&sna->kgem);
2598428d7b3dSmrg		if (!kgem_check_bo(&sna->kgem, dst_bo, src_bo, NULL))
2599428d7b3dSmrg			goto fallback;
2600428d7b3dSmrg	}
2601428d7b3dSmrg
2602428d7b3dSmrg	if (kgem_bo_is_dirty(src_bo)) {
2603428d7b3dSmrg		if (sna_blt_compare_depth(&src->drawable, &dst->drawable) &&
2604428d7b3dSmrg		    sna_blt_copy(sna, alu,
2605428d7b3dSmrg				 src_bo, dst_bo,
2606428d7b3dSmrg				 dst->drawable.bitsPerPixel,
2607428d7b3dSmrg				 op))
2608428d7b3dSmrg			return true;
2609428d7b3dSmrg	}
2610428d7b3dSmrg
2611428d7b3dSmrg	gen5_align_vertex(sna, &op->base);
2612428d7b3dSmrg	gen5_copy_bind_surfaces(sna, &op->base);
2613428d7b3dSmrg
2614428d7b3dSmrg	op->blt  = gen5_render_copy_blt;
2615428d7b3dSmrg	op->done = gen5_render_copy_done;
2616428d7b3dSmrg	return true;
2617428d7b3dSmrg}
2618428d7b3dSmrg
2619428d7b3dSmrgstatic void
2620428d7b3dSmrggen5_fill_bind_surfaces(struct sna *sna,
2621428d7b3dSmrg			const struct sna_composite_op *op)
2622428d7b3dSmrg{
2623428d7b3dSmrg	bool dirty = kgem_bo_is_dirty(op->dst.bo);
2624428d7b3dSmrg	uint32_t *binding_table;
2625428d7b3dSmrg	uint16_t offset;
2626428d7b3dSmrg
2627428d7b3dSmrg	gen5_get_batch(sna, op);
2628428d7b3dSmrg
2629428d7b3dSmrg	binding_table = gen5_composite_get_binding_table(sna, &offset);
2630428d7b3dSmrg
2631428d7b3dSmrg	binding_table[0] =
2632428d7b3dSmrg		gen5_bind_bo(sna,
2633428d7b3dSmrg			     op->dst.bo, op->dst.width, op->dst.height,
2634428d7b3dSmrg			     gen5_get_dest_format(op->dst.format),
2635428d7b3dSmrg			     true);
2636428d7b3dSmrg	binding_table[1] =
2637428d7b3dSmrg		gen5_bind_bo(sna,
2638428d7b3dSmrg			     op->src.bo, 1, 1,
2639428d7b3dSmrg			     GEN5_SURFACEFORMAT_B8G8R8A8_UNORM,
2640428d7b3dSmrg			     false);
2641428d7b3dSmrg
2642428d7b3dSmrg	if (sna->kgem.surface == offset &&
2643428d7b3dSmrg	    *(uint64_t *)(sna->kgem.batch + sna->render_state.gen5.surface_table) == *(uint64_t*)binding_table) {
2644428d7b3dSmrg		sna->kgem.surface +=
2645428d7b3dSmrg			sizeof(struct gen5_surface_state_padded)/sizeof(uint32_t);
2646428d7b3dSmrg		offset = sna->render_state.gen5.surface_table;
2647428d7b3dSmrg	}
2648428d7b3dSmrg
2649428d7b3dSmrg	gen5_emit_state(sna, op, offset | dirty);
2650428d7b3dSmrg}
2651428d7b3dSmrg
2652428d7b3dSmrgstatic inline bool prefer_blt_fill(struct sna *sna)
2653428d7b3dSmrg{
2654428d7b3dSmrg#if PREFER_BLT_FILL
2655428d7b3dSmrg	return true;
2656428d7b3dSmrg#else
2657428d7b3dSmrg	return sna->kgem.mode != KGEM_RENDER;
2658428d7b3dSmrg#endif
2659428d7b3dSmrg}
2660428d7b3dSmrg
2661428d7b3dSmrgstatic bool
2662428d7b3dSmrggen5_render_fill_boxes(struct sna *sna,
2663428d7b3dSmrg		       CARD8 op,
2664428d7b3dSmrg		       PictFormat format,
2665428d7b3dSmrg		       const xRenderColor *color,
2666428d7b3dSmrg		       const DrawableRec *dst, struct kgem_bo *dst_bo,
2667428d7b3dSmrg		       const BoxRec *box, int n)
2668428d7b3dSmrg{
2669428d7b3dSmrg	struct sna_composite_op tmp;
2670428d7b3dSmrg	uint32_t pixel;
2671428d7b3dSmrg
2672428d7b3dSmrg	DBG(("%s op=%x, color=(%04x,%04x,%04x,%04x), boxes=%d x [((%d, %d), (%d, %d))...]\n",
2673428d7b3dSmrg	     __FUNCTION__, op,
2674428d7b3dSmrg	     color->red, color->green, color->blue, color->alpha,
2675428d7b3dSmrg	     n, box->x1, box->y1, box->x2, box->y2));
2676428d7b3dSmrg
2677428d7b3dSmrg	if (op >= ARRAY_SIZE(gen5_blend_op)) {
2678428d7b3dSmrg		DBG(("%s: fallback due to unhandled blend op: %d\n",
2679428d7b3dSmrg		     __FUNCTION__, op));
2680428d7b3dSmrg		return false;
2681428d7b3dSmrg	}
2682428d7b3dSmrg
2683428d7b3dSmrg	if (op <= PictOpSrc &&
2684428d7b3dSmrg	    (prefer_blt_fill(sna) ||
2685428d7b3dSmrg	     too_large(dst->width, dst->height) ||
2686428d7b3dSmrg	     !gen5_check_dst_format(format))) {
2687428d7b3dSmrg		uint8_t alu = GXinvalid;
2688428d7b3dSmrg
2689428d7b3dSmrg		pixel = 0;
2690428d7b3dSmrg		if (op == PictOpClear)
2691428d7b3dSmrg			alu = GXclear;
2692428d7b3dSmrg		else if (sna_get_pixel_from_rgba(&pixel,
2693428d7b3dSmrg						 color->red,
2694428d7b3dSmrg						 color->green,
2695428d7b3dSmrg						 color->blue,
2696428d7b3dSmrg						 color->alpha,
2697428d7b3dSmrg						 format))
2698428d7b3dSmrg			alu = GXcopy;
2699428d7b3dSmrg
2700428d7b3dSmrg		if (alu != GXinvalid &&
2701428d7b3dSmrg		    sna_blt_fill_boxes(sna, alu,
2702428d7b3dSmrg				       dst_bo, dst->bitsPerPixel,
2703428d7b3dSmrg				       pixel, box, n))
2704428d7b3dSmrg			return true;
2705428d7b3dSmrg
2706428d7b3dSmrg		if (!gen5_check_dst_format(format))
2707428d7b3dSmrg			return false;
2708428d7b3dSmrg
2709428d7b3dSmrg		if (too_large(dst->width, dst->height))
2710428d7b3dSmrg			return sna_tiling_fill_boxes(sna, op, format, color,
2711428d7b3dSmrg						     dst, dst_bo, box, n);
2712428d7b3dSmrg	}
2713428d7b3dSmrg
2714428d7b3dSmrg	if (op == PictOpClear) {
2715428d7b3dSmrg		pixel = 0;
2716428d7b3dSmrg		op = PictOpSrc;
2717428d7b3dSmrg	} else if (!sna_get_pixel_from_rgba(&pixel,
2718428d7b3dSmrg					    color->red,
2719428d7b3dSmrg					    color->green,
2720428d7b3dSmrg					    color->blue,
2721428d7b3dSmrg					    color->alpha,
2722428d7b3dSmrg					    PICT_a8r8g8b8))
2723428d7b3dSmrg		return false;
2724428d7b3dSmrg
2725428d7b3dSmrg	DBG(("%s(%08x x %d)\n", __FUNCTION__, pixel, n));
2726428d7b3dSmrg
2727428d7b3dSmrg	memset(&tmp, 0, sizeof(tmp));
2728428d7b3dSmrg
2729428d7b3dSmrg	tmp.op = op;
2730428d7b3dSmrg
2731428d7b3dSmrg	tmp.dst.pixmap = (PixmapPtr)dst;
2732428d7b3dSmrg	tmp.dst.width  = dst->width;
2733428d7b3dSmrg	tmp.dst.height = dst->height;
2734428d7b3dSmrg	tmp.dst.format = format;
2735428d7b3dSmrg	tmp.dst.bo = dst_bo;
2736428d7b3dSmrg
2737428d7b3dSmrg	tmp.src.bo = sna_render_get_solid(sna, pixel);
2738428d7b3dSmrg	tmp.src.filter = SAMPLER_FILTER_NEAREST;
2739428d7b3dSmrg	tmp.src.repeat = SAMPLER_EXTEND_REPEAT;
2740428d7b3dSmrg
2741428d7b3dSmrg	tmp.is_affine = true;
2742428d7b3dSmrg	tmp.floats_per_vertex = 2;
2743428d7b3dSmrg	tmp.floats_per_rect = 6;
2744428d7b3dSmrg	tmp.u.gen5.wm_kernel = WM_KERNEL;
2745428d7b3dSmrg	tmp.u.gen5.ve_id = 1;
2746428d7b3dSmrg
2747428d7b3dSmrg	if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
2748428d7b3dSmrg		kgem_submit(&sna->kgem);
2749428d7b3dSmrg		if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
2750428d7b3dSmrg			kgem_bo_destroy(&sna->kgem, tmp.src.bo);
2751428d7b3dSmrg			return false;
2752428d7b3dSmrg		}
2753428d7b3dSmrg	}
2754428d7b3dSmrg
2755428d7b3dSmrg	gen5_align_vertex(sna, &tmp);
2756428d7b3dSmrg	gen5_fill_bind_surfaces(sna, &tmp);
2757428d7b3dSmrg
2758428d7b3dSmrg	do {
2759428d7b3dSmrg		int n_this_time;
2760428d7b3dSmrg
2761428d7b3dSmrg		n_this_time = gen5_get_rectangles(sna, &tmp, n,
2762428d7b3dSmrg						  gen5_fill_bind_surfaces);
2763428d7b3dSmrg		n -= n_this_time;
2764428d7b3dSmrg
2765428d7b3dSmrg		do {
2766428d7b3dSmrg			DBG(("	(%d, %d), (%d, %d)\n",
2767428d7b3dSmrg			     box->x1, box->y1, box->x2, box->y2));
2768428d7b3dSmrg			OUT_VERTEX(box->x2, box->y2);
2769428d7b3dSmrg			OUT_VERTEX_F(.5);
2770428d7b3dSmrg
2771428d7b3dSmrg			OUT_VERTEX(box->x1, box->y2);
2772428d7b3dSmrg			OUT_VERTEX_F(.5);
2773428d7b3dSmrg
2774428d7b3dSmrg			OUT_VERTEX(box->x1, box->y1);
2775428d7b3dSmrg			OUT_VERTEX_F(.5);
2776428d7b3dSmrg
2777428d7b3dSmrg			box++;
2778428d7b3dSmrg		} while (--n_this_time);
2779428d7b3dSmrg	} while (n);
2780428d7b3dSmrg
2781428d7b3dSmrg	gen4_vertex_flush(sna);
2782428d7b3dSmrg	kgem_bo_destroy(&sna->kgem, tmp.src.bo);
2783428d7b3dSmrg	return true;
2784428d7b3dSmrg}
2785428d7b3dSmrg
2786428d7b3dSmrgstatic void
2787428d7b3dSmrggen5_render_fill_op_blt(struct sna *sna,
2788428d7b3dSmrg			const struct sna_fill_op *op,
2789428d7b3dSmrg			int16_t x, int16_t y, int16_t w, int16_t h)
2790428d7b3dSmrg{
2791428d7b3dSmrg	DBG(("%s (%d, %d)x(%d, %d)\n", __FUNCTION__, x,y,w,h));
2792428d7b3dSmrg
2793428d7b3dSmrg	gen5_get_rectangles(sna, &op->base, 1, gen5_fill_bind_surfaces);
2794428d7b3dSmrg
2795428d7b3dSmrg	OUT_VERTEX(x+w, y+h);
2796428d7b3dSmrg	OUT_VERTEX_F(.5);
2797428d7b3dSmrg
2798428d7b3dSmrg	OUT_VERTEX(x, y+h);
2799428d7b3dSmrg	OUT_VERTEX_F(.5);
2800428d7b3dSmrg
2801428d7b3dSmrg	OUT_VERTEX(x, y);
2802428d7b3dSmrg	OUT_VERTEX_F(.5);
2803428d7b3dSmrg}
2804428d7b3dSmrg
2805428d7b3dSmrgfastcall static void
2806428d7b3dSmrggen5_render_fill_op_box(struct sna *sna,
2807428d7b3dSmrg			const struct sna_fill_op *op,
2808428d7b3dSmrg			const BoxRec *box)
2809428d7b3dSmrg{
2810428d7b3dSmrg	DBG(("%s: (%d, %d),(%d, %d)\n", __FUNCTION__,
2811428d7b3dSmrg	     box->x1, box->y1, box->x2, box->y2));
2812428d7b3dSmrg
2813428d7b3dSmrg	gen5_get_rectangles(sna, &op->base, 1, gen5_fill_bind_surfaces);
2814428d7b3dSmrg
2815428d7b3dSmrg	OUT_VERTEX(box->x2, box->y2);
2816428d7b3dSmrg	OUT_VERTEX_F(.5);
2817428d7b3dSmrg
2818428d7b3dSmrg	OUT_VERTEX(box->x1, box->y2);
2819428d7b3dSmrg	OUT_VERTEX_F(.5);
2820428d7b3dSmrg
2821428d7b3dSmrg	OUT_VERTEX(box->x1, box->y1);
2822428d7b3dSmrg	OUT_VERTEX_F(.5);
2823428d7b3dSmrg}
2824428d7b3dSmrg
2825428d7b3dSmrgfastcall static void
2826428d7b3dSmrggen5_render_fill_op_boxes(struct sna *sna,
2827428d7b3dSmrg			  const struct sna_fill_op *op,
2828428d7b3dSmrg			  const BoxRec *box,
2829428d7b3dSmrg			  int nbox)
2830428d7b3dSmrg{
2831428d7b3dSmrg	DBG(("%s: (%d, %d),(%d, %d)... x %d\n", __FUNCTION__,
2832428d7b3dSmrg	     box->x1, box->y1, box->x2, box->y2, nbox));
2833428d7b3dSmrg
2834428d7b3dSmrg	do {
2835428d7b3dSmrg		int nbox_this_time;
2836428d7b3dSmrg
2837428d7b3dSmrg		nbox_this_time = gen5_get_rectangles(sna, &op->base, nbox,
2838428d7b3dSmrg						     gen5_fill_bind_surfaces);
2839428d7b3dSmrg		nbox -= nbox_this_time;
2840428d7b3dSmrg
2841428d7b3dSmrg		do {
2842428d7b3dSmrg			OUT_VERTEX(box->x2, box->y2);
2843428d7b3dSmrg			OUT_VERTEX_F(.5);
2844428d7b3dSmrg
2845428d7b3dSmrg			OUT_VERTEX(box->x1, box->y2);
2846428d7b3dSmrg			OUT_VERTEX_F(.5);
2847428d7b3dSmrg
2848428d7b3dSmrg			OUT_VERTEX(box->x1, box->y1);
2849428d7b3dSmrg			OUT_VERTEX_F(.5);
2850428d7b3dSmrg			box++;
2851428d7b3dSmrg		} while (--nbox_this_time);
2852428d7b3dSmrg	} while (nbox);
2853428d7b3dSmrg}
2854428d7b3dSmrg
2855428d7b3dSmrgstatic void
2856428d7b3dSmrggen5_render_fill_op_done(struct sna *sna,
2857428d7b3dSmrg			 const struct sna_fill_op *op)
2858428d7b3dSmrg{
2859428d7b3dSmrg	if (sna->render.vertex_offset)
2860428d7b3dSmrg		gen4_vertex_flush(sna);
2861428d7b3dSmrg	kgem_bo_destroy(&sna->kgem, op->base.src.bo);
2862428d7b3dSmrg
2863428d7b3dSmrg	DBG(("%s()\n", __FUNCTION__));
2864428d7b3dSmrg}
2865428d7b3dSmrg
2866428d7b3dSmrgstatic bool
2867428d7b3dSmrggen5_render_fill(struct sna *sna, uint8_t alu,
2868428d7b3dSmrg		 PixmapPtr dst, struct kgem_bo *dst_bo,
2869428d7b3dSmrg		 uint32_t color, unsigned flags,
2870428d7b3dSmrg		 struct sna_fill_op *op)
2871428d7b3dSmrg{
2872428d7b3dSmrg	DBG(("%s(alu=%d, color=%08x)\n", __FUNCTION__, alu, color));
2873428d7b3dSmrg
2874428d7b3dSmrg	if (prefer_blt_fill(sna) &&
2875428d7b3dSmrg	    sna_blt_fill(sna, alu,
2876428d7b3dSmrg			 dst_bo, dst->drawable.bitsPerPixel,
2877428d7b3dSmrg			 color,
2878428d7b3dSmrg			 op))
2879428d7b3dSmrg		return true;
2880428d7b3dSmrg
2881428d7b3dSmrg	if (!(alu == GXcopy || alu == GXclear) ||
2882428d7b3dSmrg	    too_large(dst->drawable.width, dst->drawable.height))
2883428d7b3dSmrg		return sna_blt_fill(sna, alu,
2884428d7b3dSmrg				    dst_bo, dst->drawable.bitsPerPixel,
2885428d7b3dSmrg				    color,
2886428d7b3dSmrg				    op);
2887428d7b3dSmrg
2888428d7b3dSmrg	if (alu == GXclear)
2889428d7b3dSmrg		color = 0;
2890428d7b3dSmrg
2891428d7b3dSmrg	op->base.op = color == 0 ? PictOpClear : PictOpSrc;
2892428d7b3dSmrg
2893428d7b3dSmrg	op->base.dst.pixmap = dst;
2894428d7b3dSmrg	op->base.dst.width  = dst->drawable.width;
2895428d7b3dSmrg	op->base.dst.height = dst->drawable.height;
2896428d7b3dSmrg	op->base.dst.format = sna_format_for_depth(dst->drawable.depth);
2897428d7b3dSmrg	op->base.dst.bo = dst_bo;
2898428d7b3dSmrg	op->base.dst.x = op->base.dst.y = 0;
2899428d7b3dSmrg
2900428d7b3dSmrg	op->base.need_magic_ca_pass = 0;
2901428d7b3dSmrg	op->base.has_component_alpha = 0;
2902428d7b3dSmrg
2903428d7b3dSmrg	op->base.src.bo =
2904428d7b3dSmrg		sna_render_get_solid(sna,
2905428d7b3dSmrg				     sna_rgba_for_color(color,
2906428d7b3dSmrg							dst->drawable.depth));
2907428d7b3dSmrg	op->base.src.filter = SAMPLER_FILTER_NEAREST;
2908428d7b3dSmrg	op->base.src.repeat = SAMPLER_EXTEND_REPEAT;
2909428d7b3dSmrg
2910428d7b3dSmrg	op->base.mask.bo = NULL;
2911428d7b3dSmrg	op->base.mask.filter = SAMPLER_FILTER_NEAREST;
2912428d7b3dSmrg	op->base.mask.repeat = SAMPLER_EXTEND_NONE;
2913428d7b3dSmrg
2914428d7b3dSmrg	op->base.is_affine = true;
2915428d7b3dSmrg	op->base.floats_per_vertex = 2;
2916428d7b3dSmrg	op->base.floats_per_rect = 6;
2917428d7b3dSmrg	op->base.u.gen5.wm_kernel = WM_KERNEL;
2918428d7b3dSmrg	op->base.u.gen5.ve_id = 1;
2919428d7b3dSmrg
2920428d7b3dSmrg	if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
2921428d7b3dSmrg		kgem_submit(&sna->kgem);
2922428d7b3dSmrg		if (!kgem_check_bo(&sna->kgem, dst_bo, NULL)) {
2923428d7b3dSmrg			kgem_bo_destroy(&sna->kgem, op->base.src.bo);
2924428d7b3dSmrg			return false;
2925428d7b3dSmrg		}
2926428d7b3dSmrg	}
2927428d7b3dSmrg
2928428d7b3dSmrg	gen5_align_vertex(sna, &op->base);
2929428d7b3dSmrg	gen5_fill_bind_surfaces(sna, &op->base);
2930428d7b3dSmrg
2931428d7b3dSmrg	op->blt   = gen5_render_fill_op_blt;
2932428d7b3dSmrg	op->box   = gen5_render_fill_op_box;
2933428d7b3dSmrg	op->boxes = gen5_render_fill_op_boxes;
2934428d7b3dSmrg	op->points = NULL;
2935428d7b3dSmrg	op->done  = gen5_render_fill_op_done;
2936428d7b3dSmrg	return true;
2937428d7b3dSmrg}
2938428d7b3dSmrg
2939428d7b3dSmrgstatic bool
2940428d7b3dSmrggen5_render_fill_one_try_blt(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
2941428d7b3dSmrg			     uint32_t color,
2942428d7b3dSmrg			     int16_t x1, int16_t y1, int16_t x2, int16_t y2,
2943428d7b3dSmrg			     uint8_t alu)
2944428d7b3dSmrg{
2945428d7b3dSmrg	BoxRec box;
2946428d7b3dSmrg
2947428d7b3dSmrg	box.x1 = x1;
2948428d7b3dSmrg	box.y1 = y1;
2949428d7b3dSmrg	box.x2 = x2;
2950428d7b3dSmrg	box.y2 = y2;
2951428d7b3dSmrg
2952428d7b3dSmrg	return sna_blt_fill_boxes(sna, alu,
2953428d7b3dSmrg				  bo, dst->drawable.bitsPerPixel,
2954428d7b3dSmrg				  color, &box, 1);
2955428d7b3dSmrg}
2956428d7b3dSmrg
2957428d7b3dSmrgstatic bool
2958428d7b3dSmrggen5_render_fill_one(struct sna *sna, PixmapPtr dst, struct kgem_bo *bo,
2959428d7b3dSmrg		     uint32_t color,
2960428d7b3dSmrg		     int16_t x1, int16_t y1,
2961428d7b3dSmrg		     int16_t x2, int16_t y2,
2962428d7b3dSmrg		     uint8_t alu)
2963428d7b3dSmrg{
2964428d7b3dSmrg	struct sna_composite_op tmp;
2965428d7b3dSmrg
2966428d7b3dSmrg#if NO_FILL_ONE
2967428d7b3dSmrg	return gen5_render_fill_one_try_blt(sna, dst, bo, color,
2968428d7b3dSmrg					    x1, y1, x2, y2, alu);
2969428d7b3dSmrg#endif
2970428d7b3dSmrg
2971428d7b3dSmrg	/* Prefer to use the BLT if already engaged */
2972428d7b3dSmrg	if (prefer_blt_fill(sna) &&
2973428d7b3dSmrg	    gen5_render_fill_one_try_blt(sna, dst, bo, color,
2974428d7b3dSmrg					 x1, y1, x2, y2, alu))
2975428d7b3dSmrg		return true;
2976428d7b3dSmrg
2977428d7b3dSmrg	/* Must use the BLT if we can't RENDER... */
2978428d7b3dSmrg	if (!(alu == GXcopy || alu == GXclear) ||
2979428d7b3dSmrg	    too_large(dst->drawable.width, dst->drawable.height))
2980428d7b3dSmrg		return gen5_render_fill_one_try_blt(sna, dst, bo, color,
2981428d7b3dSmrg						    x1, y1, x2, y2, alu);
2982428d7b3dSmrg
2983428d7b3dSmrg	if (alu == GXclear)
2984428d7b3dSmrg		color = 0;
2985428d7b3dSmrg
2986428d7b3dSmrg	tmp.op = color == 0 ? PictOpClear : PictOpSrc;
2987428d7b3dSmrg
2988428d7b3dSmrg	tmp.dst.pixmap = dst;
2989428d7b3dSmrg	tmp.dst.width  = dst->drawable.width;
2990428d7b3dSmrg	tmp.dst.height = dst->drawable.height;
2991428d7b3dSmrg	tmp.dst.format = sna_format_for_depth(dst->drawable.depth);
2992428d7b3dSmrg	tmp.dst.bo = bo;
2993428d7b3dSmrg	tmp.dst.x = tmp.dst.y = 0;
2994428d7b3dSmrg
2995428d7b3dSmrg	tmp.src.bo =
2996428d7b3dSmrg		sna_render_get_solid(sna,
2997428d7b3dSmrg				     sna_rgba_for_color(color,
2998428d7b3dSmrg							dst->drawable.depth));
2999428d7b3dSmrg	tmp.src.filter = SAMPLER_FILTER_NEAREST;
3000428d7b3dSmrg	tmp.src.repeat = SAMPLER_EXTEND_REPEAT;
3001428d7b3dSmrg
3002428d7b3dSmrg	tmp.mask.bo = NULL;
3003428d7b3dSmrg	tmp.mask.filter = SAMPLER_FILTER_NEAREST;
3004428d7b3dSmrg	tmp.mask.repeat = SAMPLER_EXTEND_NONE;
3005428d7b3dSmrg
3006428d7b3dSmrg	tmp.is_affine = true;
3007428d7b3dSmrg	tmp.floats_per_vertex = 2;
3008428d7b3dSmrg	tmp.floats_per_rect = 6;
3009428d7b3dSmrg	tmp.has_component_alpha = 0;
3010428d7b3dSmrg	tmp.need_magic_ca_pass = false;
3011428d7b3dSmrg
3012428d7b3dSmrg	tmp.u.gen5.wm_kernel = WM_KERNEL;
3013428d7b3dSmrg	tmp.u.gen5.ve_id = 1;
3014428d7b3dSmrg
3015428d7b3dSmrg	if (!kgem_check_bo(&sna->kgem, bo, NULL)) {
3016428d7b3dSmrg		kgem_submit(&sna->kgem);
3017428d7b3dSmrg		if (!kgem_check_bo(&sna->kgem, bo, NULL)) {
3018428d7b3dSmrg			kgem_bo_destroy(&sna->kgem, tmp.src.bo);
3019428d7b3dSmrg			return false;
3020428d7b3dSmrg		}
3021428d7b3dSmrg	}
3022428d7b3dSmrg
3023428d7b3dSmrg	gen5_align_vertex(sna, &tmp);
3024428d7b3dSmrg	gen5_fill_bind_surfaces(sna, &tmp);
3025428d7b3dSmrg
3026428d7b3dSmrg	gen5_get_rectangles(sna, &tmp, 1, gen5_fill_bind_surfaces);
3027428d7b3dSmrg
3028428d7b3dSmrg	DBG(("	(%d, %d), (%d, %d)\n", x1, y1, x2, y2));
3029428d7b3dSmrg	OUT_VERTEX(x2, y2);
3030428d7b3dSmrg	OUT_VERTEX_F(.5);
3031428d7b3dSmrg
3032428d7b3dSmrg	OUT_VERTEX(x1, y2);
3033428d7b3dSmrg	OUT_VERTEX_F(.5);
3034428d7b3dSmrg
3035428d7b3dSmrg	OUT_VERTEX(x1, y1);
3036428d7b3dSmrg	OUT_VERTEX_F(.5);
3037428d7b3dSmrg
3038428d7b3dSmrg	gen4_vertex_flush(sna);
3039428d7b3dSmrg	kgem_bo_destroy(&sna->kgem, tmp.src.bo);
3040428d7b3dSmrg
3041428d7b3dSmrg	return true;
3042428d7b3dSmrg}
3043428d7b3dSmrgstatic void
3044428d7b3dSmrggen5_render_context_switch(struct kgem *kgem,
3045428d7b3dSmrg			   int new_mode)
3046428d7b3dSmrg{
3047428d7b3dSmrg	if (!kgem->nbatch)
3048428d7b3dSmrg		return;
3049428d7b3dSmrg
3050428d7b3dSmrg	/* WaNonPipelinedStateCommandFlush
3051428d7b3dSmrg	 *
3052428d7b3dSmrg	 * Ironlake has a limitation that a 3D or Media command can't
3053428d7b3dSmrg	 * be the first command after a BLT, unless it's
3054428d7b3dSmrg	 * non-pipelined.
3055428d7b3dSmrg	 *
3056428d7b3dSmrg	 * We do this by ensuring that the non-pipelined drawrect
3057428d7b3dSmrg	 * is always emitted first following a switch from BLT.
3058428d7b3dSmrg	 */
3059428d7b3dSmrg	if (kgem->mode == KGEM_BLT) {
3060428d7b3dSmrg		struct sna *sna = to_sna_from_kgem(kgem);
3061428d7b3dSmrg		DBG(("%s: forcing drawrect on next state emission\n",
3062428d7b3dSmrg		     __FUNCTION__));
3063428d7b3dSmrg		sna->render_state.gen5.drawrect_limit = -1;
3064428d7b3dSmrg	}
3065428d7b3dSmrg
3066428d7b3dSmrg	if (kgem_ring_is_idle(kgem, kgem->ring)) {
3067428d7b3dSmrg		DBG(("%s: GPU idle, flushing\n", __FUNCTION__));
3068428d7b3dSmrg		_kgem_submit(kgem);
3069428d7b3dSmrg	}
3070428d7b3dSmrg}
3071428d7b3dSmrg
3072428d7b3dSmrgstatic void gen5_render_reset(struct sna *sna)
3073428d7b3dSmrg{
3074428d7b3dSmrg	sna->render_state.gen5.needs_invariant = true;
3075428d7b3dSmrg	sna->render_state.gen5.ve_id = -1;
3076428d7b3dSmrg	sna->render_state.gen5.last_primitive = -1;
3077428d7b3dSmrg	sna->render_state.gen5.last_pipelined_pointers = 0;
3078428d7b3dSmrg
3079428d7b3dSmrg	sna->render_state.gen5.drawrect_offset = -1;
3080428d7b3dSmrg	sna->render_state.gen5.drawrect_limit = -1;
3081428d7b3dSmrg	sna->render_state.gen5.surface_table = -1;
3082428d7b3dSmrg
3083428d7b3dSmrg	if (sna->render.vbo && !kgem_bo_can_map(&sna->kgem, sna->render.vbo)) {
3084428d7b3dSmrg		DBG(("%s: discarding unmappable vbo\n", __FUNCTION__));
3085428d7b3dSmrg		discard_vbo(sna);
3086428d7b3dSmrg	}
3087428d7b3dSmrg
3088428d7b3dSmrg	sna->render.vertex_offset = 0;
3089428d7b3dSmrg	sna->render.nvertex_reloc = 0;
3090428d7b3dSmrg	sna->render.vb_id = 0;
3091428d7b3dSmrg}
3092428d7b3dSmrg
3093428d7b3dSmrgstatic void gen5_render_fini(struct sna *sna)
3094428d7b3dSmrg{
3095428d7b3dSmrg	kgem_bo_destroy(&sna->kgem, sna->render_state.gen5.general_bo);
3096428d7b3dSmrg}
3097428d7b3dSmrg
3098428d7b3dSmrgstatic uint32_t gen5_create_vs_unit_state(struct sna_static_stream *stream)
3099428d7b3dSmrg{
3100428d7b3dSmrg	struct gen5_vs_unit_state *vs = sna_static_stream_map(stream, sizeof(*vs), 32);
3101428d7b3dSmrg
3102428d7b3dSmrg	/* Set up the vertex shader to be disabled (passthrough) */
3103428d7b3dSmrg	vs->thread4.nr_urb_entries = URB_VS_ENTRIES >> 2;
3104428d7b3dSmrg	vs->thread4.urb_entry_allocation_size = URB_VS_ENTRY_SIZE - 1;
3105428d7b3dSmrg	vs->vs6.vs_enable = 0;
3106428d7b3dSmrg	vs->vs6.vert_cache_disable = 1;
3107428d7b3dSmrg
3108428d7b3dSmrg	return sna_static_stream_offsetof(stream, vs);
3109428d7b3dSmrg}
3110428d7b3dSmrg
3111428d7b3dSmrgstatic uint32_t gen5_create_sf_state(struct sna_static_stream *stream,
3112428d7b3dSmrg				     uint32_t kernel)
3113428d7b3dSmrg{
3114428d7b3dSmrg	struct gen5_sf_unit_state *sf_state;
3115428d7b3dSmrg
3116428d7b3dSmrg	sf_state = sna_static_stream_map(stream, sizeof(*sf_state), 32);
3117428d7b3dSmrg
3118428d7b3dSmrg	sf_state->thread0.grf_reg_count = GEN5_GRF_BLOCKS(SF_KERNEL_NUM_GRF);
3119428d7b3dSmrg	sf_state->thread0.kernel_start_pointer = kernel >> 6;
3120428d7b3dSmrg
3121428d7b3dSmrg	sf_state->thread3.const_urb_entry_read_length = 0;	/* no const URBs */
3122428d7b3dSmrg	sf_state->thread3.const_urb_entry_read_offset = 0;	/* no const URBs */
3123428d7b3dSmrg	sf_state->thread3.urb_entry_read_length = 1;	/* 1 URB per vertex */
3124428d7b3dSmrg	/* don't smash vertex header, read start from dw8 */
3125428d7b3dSmrg	sf_state->thread3.urb_entry_read_offset = 1;
3126428d7b3dSmrg	sf_state->thread3.dispatch_grf_start_reg = 3;
3127428d7b3dSmrg	sf_state->thread4.max_threads = SF_MAX_THREADS - 1;
3128428d7b3dSmrg	sf_state->thread4.urb_entry_allocation_size = URB_SF_ENTRY_SIZE - 1;
3129428d7b3dSmrg	sf_state->thread4.nr_urb_entries = URB_SF_ENTRIES;
3130428d7b3dSmrg	sf_state->sf5.viewport_transform = false;	/* skip viewport */
3131428d7b3dSmrg	sf_state->sf6.cull_mode = GEN5_CULLMODE_NONE;
3132428d7b3dSmrg	sf_state->sf6.scissor = 0;
3133428d7b3dSmrg	sf_state->sf7.trifan_pv = 2;
3134428d7b3dSmrg	sf_state->sf6.dest_org_vbias = 0x8;
3135428d7b3dSmrg	sf_state->sf6.dest_org_hbias = 0x8;
3136428d7b3dSmrg
3137428d7b3dSmrg	return sna_static_stream_offsetof(stream, sf_state);
3138428d7b3dSmrg}
3139428d7b3dSmrg
3140428d7b3dSmrgstatic uint32_t gen5_create_sampler_state(struct sna_static_stream *stream,
3141428d7b3dSmrg					  sampler_filter_t src_filter,
3142428d7b3dSmrg					  sampler_extend_t src_extend,
3143428d7b3dSmrg					  sampler_filter_t mask_filter,
3144428d7b3dSmrg					  sampler_extend_t mask_extend)
3145428d7b3dSmrg{
3146428d7b3dSmrg	struct gen5_sampler_state *sampler_state;
3147428d7b3dSmrg
3148428d7b3dSmrg	sampler_state = sna_static_stream_map(stream,
3149428d7b3dSmrg					      sizeof(struct gen5_sampler_state) * 2,
3150428d7b3dSmrg					      32);
3151428d7b3dSmrg	sampler_state_init(&sampler_state[0], src_filter, src_extend);
3152428d7b3dSmrg	sampler_state_init(&sampler_state[1], mask_filter, mask_extend);
3153428d7b3dSmrg
3154428d7b3dSmrg	return sna_static_stream_offsetof(stream, sampler_state);
3155428d7b3dSmrg}
3156428d7b3dSmrg
3157428d7b3dSmrgstatic void gen5_init_wm_state(struct gen5_wm_unit_state *state,
3158428d7b3dSmrg			       bool has_mask,
3159428d7b3dSmrg			       uint32_t kernel,
3160428d7b3dSmrg			       uint32_t sampler)
3161428d7b3dSmrg{
3162428d7b3dSmrg	state->thread0.grf_reg_count = GEN5_GRF_BLOCKS(PS_KERNEL_NUM_GRF);
3163428d7b3dSmrg	state->thread0.kernel_start_pointer = kernel >> 6;
3164428d7b3dSmrg
3165428d7b3dSmrg	state->thread1.single_program_flow = 0;
3166428d7b3dSmrg
3167428d7b3dSmrg	/* scratch space is not used in our kernel */
3168428d7b3dSmrg	state->thread2.scratch_space_base_pointer = 0;
3169428d7b3dSmrg	state->thread2.per_thread_scratch_space = 0;
3170428d7b3dSmrg
3171428d7b3dSmrg	state->thread3.const_urb_entry_read_length = 0;
3172428d7b3dSmrg	state->thread3.const_urb_entry_read_offset = 0;
3173428d7b3dSmrg
3174428d7b3dSmrg	state->thread3.urb_entry_read_offset = 0;
3175428d7b3dSmrg	/* wm kernel use urb from 3, see wm_program in compiler module */
3176428d7b3dSmrg	state->thread3.dispatch_grf_start_reg = 3;	/* must match kernel */
3177428d7b3dSmrg
3178428d7b3dSmrg	state->wm4.sampler_count = 0;	/* hardware requirement */
3179428d7b3dSmrg
3180428d7b3dSmrg	state->wm4.sampler_state_pointer = sampler >> 5;
3181428d7b3dSmrg	state->wm5.max_threads = PS_MAX_THREADS - 1;
3182428d7b3dSmrg	state->wm5.transposed_urb_read = 0;
3183428d7b3dSmrg	state->wm5.thread_dispatch_enable = 1;
3184428d7b3dSmrg	/* just use 16-pixel dispatch (4 subspans), don't need to change kernel
3185428d7b3dSmrg	 * start point
3186428d7b3dSmrg	 */
3187428d7b3dSmrg	state->wm5.enable_16_pix = 1;
3188428d7b3dSmrg	state->wm5.enable_8_pix = 0;
3189428d7b3dSmrg	state->wm5.early_depth_test = 1;
3190428d7b3dSmrg
3191428d7b3dSmrg	/* Each pair of attributes (src/mask coords) is two URB entries */
3192428d7b3dSmrg	if (has_mask) {
3193428d7b3dSmrg		state->thread1.binding_table_entry_count = 3;	/* 2 tex and fb */
3194428d7b3dSmrg		state->thread3.urb_entry_read_length = 4;
3195428d7b3dSmrg	} else {
3196428d7b3dSmrg		state->thread1.binding_table_entry_count = 2;	/* 1 tex and fb */
3197428d7b3dSmrg		state->thread3.urb_entry_read_length = 2;
3198428d7b3dSmrg	}
3199428d7b3dSmrg
3200428d7b3dSmrg	/* binding table entry count is only used for prefetching,
3201428d7b3dSmrg	 * and it has to be set 0 for Ironlake
3202428d7b3dSmrg	 */
3203428d7b3dSmrg	state->thread1.binding_table_entry_count = 0;
3204428d7b3dSmrg}
3205428d7b3dSmrg
3206428d7b3dSmrgstatic uint32_t gen5_create_cc_unit_state(struct sna_static_stream *stream)
3207428d7b3dSmrg{
3208428d7b3dSmrg	uint8_t *ptr, *base;
3209428d7b3dSmrg	int i, j;
3210428d7b3dSmrg
3211428d7b3dSmrg	base = ptr =
3212428d7b3dSmrg		sna_static_stream_map(stream,
3213428d7b3dSmrg				      GEN5_BLENDFACTOR_COUNT*GEN5_BLENDFACTOR_COUNT*64,
3214428d7b3dSmrg				      64);
3215428d7b3dSmrg
3216428d7b3dSmrg	for (i = 0; i < GEN5_BLENDFACTOR_COUNT; i++) {
3217428d7b3dSmrg		for (j = 0; j < GEN5_BLENDFACTOR_COUNT; j++) {
3218428d7b3dSmrg			struct gen5_cc_unit_state *state =
3219428d7b3dSmrg				(struct gen5_cc_unit_state *)ptr;
3220428d7b3dSmrg
3221428d7b3dSmrg			state->cc3.blend_enable =
3222428d7b3dSmrg				!(j == GEN5_BLENDFACTOR_ZERO && i == GEN5_BLENDFACTOR_ONE);
3223428d7b3dSmrg
3224428d7b3dSmrg			state->cc5.logicop_func = 0xc;	/* COPY */
3225428d7b3dSmrg			state->cc5.ia_blend_function = GEN5_BLENDFUNCTION_ADD;
3226428d7b3dSmrg
3227428d7b3dSmrg			/* Fill in alpha blend factors same as color, for the future. */
3228428d7b3dSmrg			state->cc5.ia_src_blend_factor = i;
3229428d7b3dSmrg			state->cc5.ia_dest_blend_factor = j;
3230428d7b3dSmrg
3231428d7b3dSmrg			state->cc6.blend_function = GEN5_BLENDFUNCTION_ADD;
3232428d7b3dSmrg			state->cc6.clamp_post_alpha_blend = 1;
3233428d7b3dSmrg			state->cc6.clamp_pre_alpha_blend = 1;
3234428d7b3dSmrg			state->cc6.src_blend_factor = i;
3235428d7b3dSmrg			state->cc6.dest_blend_factor = j;
3236428d7b3dSmrg
3237428d7b3dSmrg			ptr += 64;
3238428d7b3dSmrg		}
3239428d7b3dSmrg	}
3240428d7b3dSmrg
3241428d7b3dSmrg	return sna_static_stream_offsetof(stream, base);
3242428d7b3dSmrg}
3243428d7b3dSmrg
3244428d7b3dSmrgstatic bool gen5_render_setup(struct sna *sna)
3245428d7b3dSmrg{
3246428d7b3dSmrg	struct gen5_render_state *state = &sna->render_state.gen5;
3247428d7b3dSmrg	struct sna_static_stream general;
3248428d7b3dSmrg	struct gen5_wm_unit_state_padded *wm_state;
3249428d7b3dSmrg	uint32_t sf[2], wm[KERNEL_COUNT];
3250428d7b3dSmrg	int i, j, k, l, m;
3251428d7b3dSmrg
3252428d7b3dSmrg	sna_static_stream_init(&general);
3253428d7b3dSmrg
3254428d7b3dSmrg	/* Zero pad the start. If you see an offset of 0x0 in the batchbuffer
3255428d7b3dSmrg	 * dumps, you know it points to zero.
3256428d7b3dSmrg	 */
3257428d7b3dSmrg	null_create(&general);
3258428d7b3dSmrg
3259428d7b3dSmrg	/* Set up the two SF states (one for blending with a mask, one without) */
3260428d7b3dSmrg	sf[0] = sna_static_stream_compile_sf(sna, &general, brw_sf_kernel__nomask);
3261428d7b3dSmrg	sf[1] = sna_static_stream_compile_sf(sna, &general, brw_sf_kernel__mask);
3262428d7b3dSmrg
3263428d7b3dSmrg	for (m = 0; m < KERNEL_COUNT; m++) {
3264428d7b3dSmrg		if (wm_kernels[m].size) {
3265428d7b3dSmrg			wm[m] = sna_static_stream_add(&general,
3266428d7b3dSmrg						      wm_kernels[m].data,
3267428d7b3dSmrg						      wm_kernels[m].size,
3268428d7b3dSmrg						      64);
3269428d7b3dSmrg		} else {
3270428d7b3dSmrg			wm[m] = sna_static_stream_compile_wm(sna, &general,
3271428d7b3dSmrg							     wm_kernels[m].data,
3272428d7b3dSmrg							     16);
3273428d7b3dSmrg		}
3274428d7b3dSmrg		assert(wm[m]);
3275428d7b3dSmrg	}
3276428d7b3dSmrg
3277428d7b3dSmrg	state->vs = gen5_create_vs_unit_state(&general);
3278428d7b3dSmrg
3279428d7b3dSmrg	state->sf[0] = gen5_create_sf_state(&general, sf[0]);
3280428d7b3dSmrg	state->sf[1] = gen5_create_sf_state(&general, sf[1]);
3281428d7b3dSmrg
3282428d7b3dSmrg
3283428d7b3dSmrg	/* Set up the WM states: each filter/extend type for source and mask, per
3284428d7b3dSmrg	 * kernel.
3285428d7b3dSmrg	 */
3286428d7b3dSmrg	wm_state = sna_static_stream_map(&general,
3287428d7b3dSmrg					  sizeof(*wm_state) * KERNEL_COUNT *
3288428d7b3dSmrg					  FILTER_COUNT * EXTEND_COUNT *
3289428d7b3dSmrg					  FILTER_COUNT * EXTEND_COUNT,
3290428d7b3dSmrg					  64);
3291428d7b3dSmrg	state->wm = sna_static_stream_offsetof(&general, wm_state);
3292428d7b3dSmrg	for (i = 0; i < FILTER_COUNT; i++) {
3293428d7b3dSmrg		for (j = 0; j < EXTEND_COUNT; j++) {
3294428d7b3dSmrg			for (k = 0; k < FILTER_COUNT; k++) {
3295428d7b3dSmrg				for (l = 0; l < EXTEND_COUNT; l++) {
3296428d7b3dSmrg					uint32_t sampler_state;
3297428d7b3dSmrg
3298428d7b3dSmrg					sampler_state =
3299428d7b3dSmrg						gen5_create_sampler_state(&general,
3300428d7b3dSmrg									  i, j,
3301428d7b3dSmrg									  k, l);
3302428d7b3dSmrg
3303428d7b3dSmrg					for (m = 0; m < KERNEL_COUNT; m++) {
3304428d7b3dSmrg						gen5_init_wm_state(&wm_state->state,
3305428d7b3dSmrg								   wm_kernels[m].has_mask,
3306428d7b3dSmrg								   wm[m], sampler_state);
3307428d7b3dSmrg						wm_state++;
3308428d7b3dSmrg					}
3309428d7b3dSmrg				}
3310428d7b3dSmrg			}
3311428d7b3dSmrg		}
3312428d7b3dSmrg	}
3313428d7b3dSmrg
3314428d7b3dSmrg	state->cc = gen5_create_cc_unit_state(&general);
3315428d7b3dSmrg
3316428d7b3dSmrg	state->general_bo = sna_static_stream_fini(sna, &general);
3317428d7b3dSmrg	return state->general_bo != NULL;
3318428d7b3dSmrg}
3319428d7b3dSmrg
3320428d7b3dSmrgconst char *gen5_render_init(struct sna *sna, const char *backend)
3321428d7b3dSmrg{
3322428d7b3dSmrg	if (!gen5_render_setup(sna))
3323428d7b3dSmrg		return backend;
3324428d7b3dSmrg
3325428d7b3dSmrg	sna->kgem.context_switch = gen5_render_context_switch;
3326428d7b3dSmrg	sna->kgem.retire = gen4_render_retire;
3327428d7b3dSmrg	sna->kgem.expire = gen4_render_expire;
3328428d7b3dSmrg
3329428d7b3dSmrg#if !NO_COMPOSITE
3330428d7b3dSmrg	sna->render.composite = gen5_render_composite;
3331428d7b3dSmrg	sna->render.prefer_gpu |= PREFER_GPU_RENDER;
3332428d7b3dSmrg#endif
3333428d7b3dSmrg#if !NO_COMPOSITE_SPANS
3334428d7b3dSmrg	sna->render.check_composite_spans = gen5_check_composite_spans;
3335428d7b3dSmrg	sna->render.composite_spans = gen5_render_composite_spans;
3336428d7b3dSmrg	if (intel_get_device_id(sna->dev) == 0x0044)
3337428d7b3dSmrg		sna->render.prefer_gpu |= PREFER_GPU_SPANS;
3338428d7b3dSmrg#endif
3339428d7b3dSmrg	sna->render.video = gen5_render_video;
3340428d7b3dSmrg
3341428d7b3dSmrg	sna->render.copy_boxes = gen5_render_copy_boxes;
3342428d7b3dSmrg	sna->render.copy = gen5_render_copy;
3343428d7b3dSmrg
3344428d7b3dSmrg	sna->render.fill_boxes = gen5_render_fill_boxes;
3345428d7b3dSmrg	sna->render.fill = gen5_render_fill;
3346428d7b3dSmrg	sna->render.fill_one = gen5_render_fill_one;
3347428d7b3dSmrg
3348428d7b3dSmrg	sna->render.flush = gen4_render_flush;
3349428d7b3dSmrg	sna->render.reset = gen5_render_reset;
3350428d7b3dSmrg	sna->render.fini = gen5_render_fini;
3351428d7b3dSmrg
3352428d7b3dSmrg	sna->render.max_3d_size = MAX_3D_SIZE;
3353428d7b3dSmrg	sna->render.max_3d_pitch = 1 << 18;
3354428d7b3dSmrg	return "Ironlake (gen5)";
3355428d7b3dSmrg}
3356