1428d7b3dSmrg/*
2428d7b3dSmrg * Copyright © 2010 Intel Corporation
3428d7b3dSmrg *
4428d7b3dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5428d7b3dSmrg * copy of this software and associated documentation files (the "Software"),
6428d7b3dSmrg * to deal in the Software without restriction, including without limitation
7428d7b3dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8428d7b3dSmrg * and/or sell copies of the Software, and to permit persons to whom the
9428d7b3dSmrg * Software is furnished to do so, subject to the following conditions:
10428d7b3dSmrg *
11428d7b3dSmrg * The above copyright notice and this permission notice (including the next
12428d7b3dSmrg * paragraph) shall be included in all copies or substantial portions of the
13428d7b3dSmrg * Software.
14428d7b3dSmrg *
15428d7b3dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16428d7b3dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17428d7b3dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18428d7b3dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19428d7b3dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20428d7b3dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21428d7b3dSmrg * SOFTWARE.
22428d7b3dSmrg *
23428d7b3dSmrg * Authors:
24428d7b3dSmrg *    Chris Wilson <chris@chris-wilson.co.uk>
25428d7b3dSmrg *
26428d7b3dSmrg */
27428d7b3dSmrg
28428d7b3dSmrg#ifdef HAVE_CONFIG_H
29428d7b3dSmrg#include "config.h"
30428d7b3dSmrg#endif
31428d7b3dSmrg
32428d7b3dSmrg#include "sna.h"
33428d7b3dSmrg#include "sna_render.h"
34428d7b3dSmrg#include "fb/fbpict.h"
35428d7b3dSmrg
36428d7b3dSmrgstruct sna_tile_span {
37428d7b3dSmrg	BoxRec box;
38428d7b3dSmrg	float opacity;
39428d7b3dSmrg};
40428d7b3dSmrg
41428d7b3dSmrgstruct sna_tile_state {
42428d7b3dSmrg	int op;
43428d7b3dSmrg	PicturePtr src, mask, dst;
44428d7b3dSmrg	PixmapPtr dst_pixmap;
45428d7b3dSmrg	uint32_t dst_format;
46428d7b3dSmrg	int16_t src_x, src_y;
47428d7b3dSmrg	int16_t mask_x, mask_y;
48428d7b3dSmrg	int16_t dst_x, dst_y;
49428d7b3dSmrg	int16_t width, height;
50428d7b3dSmrg	unsigned flags;
51428d7b3dSmrg
52428d7b3dSmrg	int rect_count;
53428d7b3dSmrg	int rect_size;
54428d7b3dSmrg	struct sna_composite_rectangles rects_embedded[16], *rects;
55428d7b3dSmrg};
56428d7b3dSmrg
57428d7b3dSmrgstatic void
58428d7b3dSmrgsna_tiling_composite_add_rect(struct sna_tile_state *tile,
59428d7b3dSmrg			      const struct sna_composite_rectangles *r)
60428d7b3dSmrg{
61428d7b3dSmrg	if (tile->rect_count == tile->rect_size) {
62428d7b3dSmrg		struct sna_composite_rectangles *a;
63428d7b3dSmrg		int newsize = tile->rect_size * 2;
64428d7b3dSmrg
65428d7b3dSmrg		if (tile->rects == tile->rects_embedded) {
66428d7b3dSmrg			a = malloc (sizeof(struct sna_composite_rectangles) * newsize);
67428d7b3dSmrg			if (a == NULL)
68428d7b3dSmrg				return;
69428d7b3dSmrg
70428d7b3dSmrg			memcpy(a,
71428d7b3dSmrg			       tile->rects_embedded,
72428d7b3dSmrg			       sizeof(struct sna_composite_rectangles) * tile->rect_count);
73428d7b3dSmrg		} else {
74428d7b3dSmrg			a = realloc(tile->rects,
75428d7b3dSmrg				    sizeof(struct sna_composite_rectangles) * newsize);
76428d7b3dSmrg			if (a == NULL)
77428d7b3dSmrg				return;
78428d7b3dSmrg		}
79428d7b3dSmrg
80428d7b3dSmrg		tile->rects = a;
81428d7b3dSmrg		tile->rect_size = newsize;
82428d7b3dSmrg	}
83428d7b3dSmrg
84428d7b3dSmrg	tile->rects[tile->rect_count++] = *r;
85428d7b3dSmrg}
86428d7b3dSmrg
87428d7b3dSmrgfastcall static void
88428d7b3dSmrgsna_tiling_composite_blt(struct sna *sna,
89428d7b3dSmrg			 const struct sna_composite_op *op,
90428d7b3dSmrg			 const struct sna_composite_rectangles *r)
91428d7b3dSmrg{
92428d7b3dSmrg	sna_tiling_composite_add_rect(op->priv, r);
93428d7b3dSmrg	(void)sna;
94428d7b3dSmrg}
95428d7b3dSmrg
96428d7b3dSmrgfastcall static void
97428d7b3dSmrgsna_tiling_composite_box(struct sna *sna,
98428d7b3dSmrg			 const struct sna_composite_op *op,
99428d7b3dSmrg			 const BoxRec *box)
100428d7b3dSmrg{
101428d7b3dSmrg	struct sna_composite_rectangles r;
102428d7b3dSmrg
103428d7b3dSmrg	r.dst.x = box->x1;
104428d7b3dSmrg	r.dst.y = box->y1;
105428d7b3dSmrg	r.mask = r.src = r.dst;
106428d7b3dSmrg
107428d7b3dSmrg	r.width  = box->x2 - box->x1;
108428d7b3dSmrg	r.height = box->y2 - box->y1;
109428d7b3dSmrg
110428d7b3dSmrg	sna_tiling_composite_add_rect(op->priv, &r);
111428d7b3dSmrg	(void)sna;
112428d7b3dSmrg}
113428d7b3dSmrg
114428d7b3dSmrgstatic void
115428d7b3dSmrgsna_tiling_composite_boxes(struct sna *sna,
116428d7b3dSmrg			   const struct sna_composite_op *op,
117428d7b3dSmrg			   const BoxRec *box, int nbox)
118428d7b3dSmrg{
119428d7b3dSmrg	while (nbox--) {
120428d7b3dSmrg		struct sna_composite_rectangles r;
121428d7b3dSmrg
122428d7b3dSmrg		r.dst.x = box->x1;
123428d7b3dSmrg		r.dst.y = box->y1;
124428d7b3dSmrg		r.mask = r.src = r.dst;
125428d7b3dSmrg
126428d7b3dSmrg		r.width  = box->x2 - box->x1;
127428d7b3dSmrg		r.height = box->y2 - box->y1;
128428d7b3dSmrg
129428d7b3dSmrg		sna_tiling_composite_add_rect(op->priv, &r);
130428d7b3dSmrg		box++;
131428d7b3dSmrg	}
132428d7b3dSmrg	(void)sna;
133428d7b3dSmrg}
134428d7b3dSmrg
135428d7b3dSmrgstatic void
136428d7b3dSmrgsna_tiling_composite_done(struct sna *sna,
137428d7b3dSmrg			  const struct sna_composite_op *op)
138428d7b3dSmrg{
139428d7b3dSmrg	struct sna_tile_state *tile = op->priv;
140428d7b3dSmrg	struct sna_composite_op tmp;
141428d7b3dSmrg	int x, y, n, step, max_size;
142428d7b3dSmrg
143428d7b3dSmrg	/* Use a small step to accommodate enlargement through tile alignment */
144428d7b3dSmrg	step = sna->render.max_3d_size;
145428d7b3dSmrg	if (tile->dst_x & (8*512 / tile->dst->pDrawable->bitsPerPixel - 1) ||
146428d7b3dSmrg	    tile->dst_y & 63)
147428d7b3dSmrg		step /= 2;
148428d7b3dSmrg
149428d7b3dSmrg	max_size = sna_max_tile_copy_size(sna, op->dst.bo, op->dst.bo);
150428d7b3dSmrg	if (max_size == 0)
151428d7b3dSmrg		goto done;
152428d7b3dSmrg
153428d7b3dSmrg	while (step * step * 4 > max_size)
154428d7b3dSmrg		step /= 2;
155428d7b3dSmrg
156428d7b3dSmrg	DBG(("%s -- %dx%d, count=%d, step size=%d\n", __FUNCTION__,
157428d7b3dSmrg	     tile->width, tile->height, tile->rect_count, step));
158428d7b3dSmrg
159428d7b3dSmrg	if (tile->rect_count == 0)
160428d7b3dSmrg		goto done;
161428d7b3dSmrg
162428d7b3dSmrg	for (y = 0; y < tile->height; y += step) {
163428d7b3dSmrg		int height = step;
164428d7b3dSmrg		if (y + height > tile->height)
165428d7b3dSmrg			height = tile->height - y;
166428d7b3dSmrg		for (x = 0; x < tile->width; x += step) {
167428d7b3dSmrg			int width = step;
168428d7b3dSmrg			if (x + width > tile->width)
169428d7b3dSmrg				width = tile->width - x;
170428d7b3dSmrg			if (sna->render.composite(sna, tile->op,
171428d7b3dSmrg						  tile->src, tile->mask, tile->dst,
172428d7b3dSmrg						  tile->src_x + x,  tile->src_y + y,
173428d7b3dSmrg						  tile->mask_x + x, tile->mask_y + y,
174428d7b3dSmrg						  tile->dst_x + x,  tile->dst_y + y,
175428d7b3dSmrg						  width, height,
176428d7b3dSmrg						  COMPOSITE_PARTIAL, memset(&tmp, 0, sizeof(tmp)))) {
177428d7b3dSmrg				for (n = 0; n < tile->rect_count; n++) {
178428d7b3dSmrg					const struct sna_composite_rectangles *r = &tile->rects[n];
179428d7b3dSmrg					int x1, x2, dx, y1, y2, dy;
180428d7b3dSmrg
181428d7b3dSmrg					x1 = r->dst.x - tile->dst_x, dx = 0;
182428d7b3dSmrg					if (x1 < x)
183428d7b3dSmrg						dx = x - x1, x1 = x;
184428d7b3dSmrg					y1 = r->dst.y - tile->dst_y, dy = 0;
185428d7b3dSmrg					if (y1 < y)
186428d7b3dSmrg						dy = y - y1, y1 = y;
187428d7b3dSmrg
188428d7b3dSmrg					x2 = r->dst.x + r->width - tile->dst_x;
189428d7b3dSmrg					if (x2 > x + width)
190428d7b3dSmrg						x2 = x + width;
191428d7b3dSmrg					y2 = r->dst.y + r->height - tile->dst_y;
192428d7b3dSmrg					if (y2 > y + height)
193428d7b3dSmrg						y2 = y + height;
194428d7b3dSmrg
195428d7b3dSmrg					DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d), delta=(%d,%d)\n",
196428d7b3dSmrg					     __FUNCTION__, n,
197428d7b3dSmrg					     r->dst.x, r->dst.y,
198428d7b3dSmrg					     r->width, r->height,
199428d7b3dSmrg					     x, y, width, height,
200428d7b3dSmrg					     x1, y1, x2, y2,
201428d7b3dSmrg					     dx, dy));
202428d7b3dSmrg
203428d7b3dSmrg					if (y2 > y1 && x2 > x1) {
204428d7b3dSmrg						struct sna_composite_rectangles rr;
205428d7b3dSmrg						rr.src.x = dx + r->src.x;
206428d7b3dSmrg						rr.src.y = dy + r->src.y;
207428d7b3dSmrg
208428d7b3dSmrg						rr.mask.x = dx + r->mask.x;
209428d7b3dSmrg						rr.mask.y = dy + r->mask.y;
210428d7b3dSmrg
211428d7b3dSmrg						rr.dst.x = dx + r->dst.x;
212428d7b3dSmrg						rr.dst.y = dy + r->dst.y;
213428d7b3dSmrg
214428d7b3dSmrg						rr.width  = x2 - x1;
215428d7b3dSmrg						rr.height = y2 - y1;
216428d7b3dSmrg
217428d7b3dSmrg						tmp.blt(sna, &tmp, &rr);
218428d7b3dSmrg					}
219428d7b3dSmrg				}
220428d7b3dSmrg				tmp.done(sna, &tmp);
221428d7b3dSmrg			} else {
222428d7b3dSmrg				unsigned int flags;
223428d7b3dSmrg				DBG(("%s -- falback\n", __FUNCTION__));
224428d7b3dSmrg
225428d7b3dSmrg				if (tile->op <= PictOpSrc)
226428d7b3dSmrg					flags = MOVE_WRITE;
227428d7b3dSmrg				else
228428d7b3dSmrg					flags = MOVE_WRITE | MOVE_READ;
229428d7b3dSmrg				if (!sna_drawable_move_to_cpu(tile->dst->pDrawable,
230428d7b3dSmrg							      flags))
231428d7b3dSmrg					goto done;
232428d7b3dSmrg				if (tile->dst->alphaMap &&
233428d7b3dSmrg				    !sna_drawable_move_to_cpu(tile->dst->alphaMap->pDrawable,
234428d7b3dSmrg							      flags))
235428d7b3dSmrg					goto done;
236428d7b3dSmrg
237428d7b3dSmrg				if (tile->src->pDrawable &&
238428d7b3dSmrg				    !sna_drawable_move_to_cpu(tile->src->pDrawable,
239428d7b3dSmrg							      MOVE_READ))
240428d7b3dSmrg					goto done;
241428d7b3dSmrg				if (tile->src->alphaMap &&
242428d7b3dSmrg				    !sna_drawable_move_to_cpu(tile->src->alphaMap->pDrawable,
243428d7b3dSmrg							      MOVE_READ))
244428d7b3dSmrg					goto done;
245428d7b3dSmrg
246428d7b3dSmrg				if (tile->mask && tile->mask->pDrawable &&
247428d7b3dSmrg				    !sna_drawable_move_to_cpu(tile->mask->pDrawable,
248428d7b3dSmrg							      MOVE_READ))
249428d7b3dSmrg					goto done;
250428d7b3dSmrg
251428d7b3dSmrg				if (tile->mask && tile->mask->alphaMap &&
252428d7b3dSmrg				    !sna_drawable_move_to_cpu(tile->mask->alphaMap->pDrawable,
253428d7b3dSmrg							      MOVE_READ))
254428d7b3dSmrg					goto done;
255428d7b3dSmrg
256428d7b3dSmrg				if (sigtrap_get() == 0) {
257428d7b3dSmrg					fbComposite(tile->op,
258428d7b3dSmrg						    tile->src, tile->mask, tile->dst,
259428d7b3dSmrg						    tile->src_x + x,  tile->src_y + y,
260428d7b3dSmrg						    tile->mask_x + x, tile->mask_y + y,
261428d7b3dSmrg						    tile->dst_x + x,  tile->dst_y + y,
262428d7b3dSmrg						    width, height);
263428d7b3dSmrg					sigtrap_put();
264428d7b3dSmrg				}
265428d7b3dSmrg			}
266428d7b3dSmrg		}
267428d7b3dSmrg	}
268428d7b3dSmrg
269428d7b3dSmrgdone:
270428d7b3dSmrg	if (tile->rects != tile->rects_embedded)
271428d7b3dSmrg		free(tile->rects);
272428d7b3dSmrg	free(tile);
273428d7b3dSmrg}
274428d7b3dSmrg
275428d7b3dSmrgbool
276428d7b3dSmrgsna_tiling_composite(uint32_t op,
277428d7b3dSmrg		     PicturePtr src,
278428d7b3dSmrg		     PicturePtr mask,
279428d7b3dSmrg		     PicturePtr dst,
280428d7b3dSmrg		     int16_t src_x,  int16_t src_y,
281428d7b3dSmrg		     int16_t mask_x, int16_t mask_y,
282428d7b3dSmrg		     int16_t dst_x,  int16_t dst_y,
283428d7b3dSmrg		     int16_t width,  int16_t height,
284428d7b3dSmrg		     struct sna_composite_op *tmp)
285428d7b3dSmrg{
286428d7b3dSmrg	struct sna_tile_state *tile;
287428d7b3dSmrg	struct sna_pixmap *priv;
288428d7b3dSmrg
289428d7b3dSmrg	DBG(("%s size=(%d, %d), tile=%d\n",
290428d7b3dSmrg	     __FUNCTION__, width, height,
291428d7b3dSmrg	     to_sna_from_drawable(dst->pDrawable)->render.max_3d_size));
292428d7b3dSmrg
293428d7b3dSmrg	priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable));
294428d7b3dSmrg	if (priv == NULL || priv->gpu_bo == NULL)
295428d7b3dSmrg		return false;
296428d7b3dSmrg
297428d7b3dSmrg	tile = malloc(sizeof(*tile));
298428d7b3dSmrg	if (!tile)
299428d7b3dSmrg		return false;
300428d7b3dSmrg
301428d7b3dSmrg	tile->op = op;
302428d7b3dSmrg
303428d7b3dSmrg	tile->src  = src;
304428d7b3dSmrg	tile->mask = mask;
305428d7b3dSmrg	tile->dst  = dst;
306428d7b3dSmrg
307428d7b3dSmrg	tile->src_x = src_x;
308428d7b3dSmrg	tile->src_y = src_y;
309428d7b3dSmrg	tile->mask_x = mask_x;
310428d7b3dSmrg	tile->mask_y = mask_y;
311428d7b3dSmrg	tile->dst_x = dst_x;
312428d7b3dSmrg	tile->dst_y = dst_y;
313428d7b3dSmrg	tile->width = width;
314428d7b3dSmrg	tile->height = height;
315428d7b3dSmrg	tile->rects = tile->rects_embedded;
316428d7b3dSmrg	tile->rect_count = 0;
317428d7b3dSmrg	tile->rect_size = ARRAY_SIZE(tile->rects_embedded);
318428d7b3dSmrg
319428d7b3dSmrg	tmp->blt   = sna_tiling_composite_blt;
320428d7b3dSmrg	tmp->box   = sna_tiling_composite_box;
321428d7b3dSmrg	tmp->boxes = sna_tiling_composite_boxes;
322428d7b3dSmrg	tmp->done  = sna_tiling_composite_done;
323428d7b3dSmrg
324428d7b3dSmrg	tmp->priv = tile;
325428d7b3dSmrg	tmp->dst.bo = priv->gpu_bo;
326428d7b3dSmrg	return true;
327428d7b3dSmrg}
328428d7b3dSmrg
329428d7b3dSmrgfastcall static void
330428d7b3dSmrgsna_tiling_composite_spans_box(struct sna *sna,
331428d7b3dSmrg			       const struct sna_composite_spans_op *op,
332428d7b3dSmrg			       const BoxRec *box, float opacity)
333428d7b3dSmrg{
334428d7b3dSmrg	struct sna_tile_state *tile = op->base.priv;
335428d7b3dSmrg	struct sna_tile_span *a;
336428d7b3dSmrg
337428d7b3dSmrg	if (tile->rect_count == tile->rect_size) {
338428d7b3dSmrg		int newsize = tile->rect_size * 2;
339428d7b3dSmrg
340428d7b3dSmrg		if (tile->rects == tile->rects_embedded) {
341428d7b3dSmrg			a = malloc (sizeof(struct sna_tile_span) * newsize);
342428d7b3dSmrg			if (a == NULL)
343428d7b3dSmrg				return;
344428d7b3dSmrg
345428d7b3dSmrg			memcpy(a,
346428d7b3dSmrg			       tile->rects_embedded,
347428d7b3dSmrg			       sizeof(struct sna_tile_span) * tile->rect_count);
348428d7b3dSmrg		} else {
349428d7b3dSmrg			a = realloc(tile->rects,
350428d7b3dSmrg				    sizeof(struct sna_tile_span) * newsize);
351428d7b3dSmrg			if (a == NULL)
352428d7b3dSmrg				return;
353428d7b3dSmrg		}
354428d7b3dSmrg
355428d7b3dSmrg		tile->rects = (void *)a;
356428d7b3dSmrg		tile->rect_size = newsize;
357428d7b3dSmrg	} else
358428d7b3dSmrg		a = (void *)tile->rects;
359428d7b3dSmrg
360428d7b3dSmrg	a[tile->rect_count].box = *box;
361428d7b3dSmrg	a[tile->rect_count].opacity = opacity;
362428d7b3dSmrg	tile->rect_count++;
363428d7b3dSmrg	(void)sna;
364428d7b3dSmrg}
365428d7b3dSmrg
366428d7b3dSmrgstatic void
367428d7b3dSmrgsna_tiling_composite_spans_boxes(struct sna *sna,
368428d7b3dSmrg				 const struct sna_composite_spans_op *op,
369428d7b3dSmrg				 const BoxRec *box, int nbox, float opacity)
370428d7b3dSmrg{
371428d7b3dSmrg	while (nbox--)
372428d7b3dSmrg		sna_tiling_composite_spans_box(sna, op->base.priv, box++, opacity);
373428d7b3dSmrg	(void)sna;
374428d7b3dSmrg}
375428d7b3dSmrg
376428d7b3dSmrgfastcall static void
377428d7b3dSmrgsna_tiling_composite_spans_done(struct sna *sna,
378428d7b3dSmrg				const struct sna_composite_spans_op *op)
379428d7b3dSmrg{
380428d7b3dSmrg	struct sna_tile_state *tile = op->base.priv;
381428d7b3dSmrg	struct sna_composite_spans_op tmp;
382428d7b3dSmrg	int x, y, n, step, max_size;
383428d7b3dSmrg	bool force_fallback = false;
384428d7b3dSmrg
385428d7b3dSmrg	/* Use a small step to accommodate enlargement through tile alignment */
386428d7b3dSmrg	step = sna->render.max_3d_size;
387428d7b3dSmrg	if (tile->dst_x & (8*512 / tile->dst->pDrawable->bitsPerPixel - 1) ||
388428d7b3dSmrg	    tile->dst_y & 63)
389428d7b3dSmrg		step /= 2;
390428d7b3dSmrg
391428d7b3dSmrg	max_size = sna_max_tile_copy_size(sna, op->base.dst.bo, op->base.dst.bo);
392428d7b3dSmrg	if (max_size == 0)
393428d7b3dSmrg		goto done;
394428d7b3dSmrg
395428d7b3dSmrg	while (step * step * 4 > max_size)
396428d7b3dSmrg		step /= 2;
397428d7b3dSmrg
398428d7b3dSmrg	DBG(("%s -- %dx%d, count=%d, step size=%d\n", __FUNCTION__,
399428d7b3dSmrg	     tile->width, tile->height, tile->rect_count, step));
400428d7b3dSmrg
401428d7b3dSmrg	if (tile->rect_count == 0)
402428d7b3dSmrg		goto done;
403428d7b3dSmrg
404428d7b3dSmrg	for (y = 0; y < tile->height; y += step) {
405428d7b3dSmrg		int height = step;
406428d7b3dSmrg		if (y + height > tile->height)
407428d7b3dSmrg			height = tile->height - y;
408428d7b3dSmrg		for (x = 0; x < tile->width; x += step) {
409428d7b3dSmrg			const struct sna_tile_span *r = (void *)tile->rects;
410428d7b3dSmrg			int width = step;
411428d7b3dSmrg			if (x + width > tile->width)
412428d7b3dSmrg				width = tile->width - x;
413428d7b3dSmrg			if (!force_fallback &&
414428d7b3dSmrg			    sna->render.composite_spans(sna, tile->op,
415428d7b3dSmrg							tile->src, tile->dst,
416428d7b3dSmrg							tile->src_x + x,  tile->src_y + y,
417428d7b3dSmrg							tile->dst_x + x,  tile->dst_y + y,
418428d7b3dSmrg							width, height, tile->flags,
419428d7b3dSmrg							memset(&tmp, 0, sizeof(tmp)))) {
420428d7b3dSmrg				for (n = 0; n < tile->rect_count; n++) {
421428d7b3dSmrg					BoxRec b;
422428d7b3dSmrg
423428d7b3dSmrg					b.x1 = r->box.x1 - tile->dst_x;
424428d7b3dSmrg					if (b.x1 < x)
425428d7b3dSmrg						b.x1 = x;
426428d7b3dSmrg
427428d7b3dSmrg					b.y1 = r->box.y1 - tile->dst_y;
428428d7b3dSmrg					if (b.y1 < y)
429428d7b3dSmrg						b.y1 = y;
430428d7b3dSmrg
431428d7b3dSmrg					b.x2 = r->box.x2 - tile->dst_x;
432428d7b3dSmrg					if (b.x2 > x + width)
433428d7b3dSmrg						b.x2 = x + width;
434428d7b3dSmrg
435428d7b3dSmrg					b.y2 = r->box.y2 - tile->dst_y;
436428d7b3dSmrg					if (b.y2 > y + height)
437428d7b3dSmrg						b.y2 = y + height;
438428d7b3dSmrg
439428d7b3dSmrg					DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d)\n",
440428d7b3dSmrg					     __FUNCTION__, n,
441428d7b3dSmrg					     r->box.x1, r->box.y1,
442428d7b3dSmrg					     r->box.x2-r->box.x1, r->box.y2-r->box.y1,
443428d7b3dSmrg					     x, y, width, height,
444428d7b3dSmrg					     b.x1, b.y1, b.x2, b.y2));
445428d7b3dSmrg
446428d7b3dSmrg					if (b.y2 > b.y1 && b.x2 > b.x1)
447428d7b3dSmrg						tmp.box(sna, &tmp, &b, r->opacity);
448428d7b3dSmrg					r++;
449428d7b3dSmrg				}
450428d7b3dSmrg				tmp.done(sna, &tmp);
451428d7b3dSmrg			} else {
452428d7b3dSmrg				unsigned int flags;
453428d7b3dSmrg
454428d7b3dSmrg				DBG(("%s -- falback\n", __FUNCTION__));
455428d7b3dSmrg
456428d7b3dSmrg				if (tile->op <= PictOpSrc)
457428d7b3dSmrg					flags = MOVE_WRITE;
458428d7b3dSmrg				else
459428d7b3dSmrg					flags = MOVE_WRITE | MOVE_READ;
460428d7b3dSmrg				if (!sna_drawable_move_to_cpu(tile->dst->pDrawable,
461428d7b3dSmrg							      flags))
462428d7b3dSmrg					goto done;
463428d7b3dSmrg				if (tile->dst->alphaMap &&
464428d7b3dSmrg				    !sna_drawable_move_to_cpu(tile->dst->alphaMap->pDrawable,
465428d7b3dSmrg							      flags))
466428d7b3dSmrg					goto done;
467428d7b3dSmrg
468428d7b3dSmrg				if (tile->src->pDrawable &&
469428d7b3dSmrg				    !sna_drawable_move_to_cpu(tile->src->pDrawable,
470428d7b3dSmrg							      MOVE_READ))
471428d7b3dSmrg					goto done;
472428d7b3dSmrg				if (tile->src->alphaMap &&
473428d7b3dSmrg				    !sna_drawable_move_to_cpu(tile->src->alphaMap->pDrawable,
474428d7b3dSmrg							      MOVE_READ))
475428d7b3dSmrg					goto done;
476428d7b3dSmrg
477428d7b3dSmrg				for (n = 0; n < tile->rect_count; n++) {
478428d7b3dSmrg					BoxRec b;
479428d7b3dSmrg
480428d7b3dSmrg					b.x1 = r->box.x1 - tile->dst_x;
481428d7b3dSmrg					if (b.x1 < x)
482428d7b3dSmrg						b.x1 = x;
483428d7b3dSmrg
484428d7b3dSmrg					b.y1 = r->box.y1 - tile->dst_y;
485428d7b3dSmrg					if (b.y1 < y)
486428d7b3dSmrg						b.y1 = y;
487428d7b3dSmrg
488428d7b3dSmrg					b.x2 = r->box.x2 - tile->dst_x;
489428d7b3dSmrg					if (b.x2 > x + width)
490428d7b3dSmrg						b.x2 = x + width;
491428d7b3dSmrg
492428d7b3dSmrg					b.y2 = r->box.y2 - tile->dst_y;
493428d7b3dSmrg					if (b.y2 > y + height)
494428d7b3dSmrg						b.y2 = y + height;
495428d7b3dSmrg
496428d7b3dSmrg					DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d)\n",
497428d7b3dSmrg					     __FUNCTION__, n,
498428d7b3dSmrg					     r->box.x1, r->box.y1,
499428d7b3dSmrg					     r->box.x2-r->box.x1, r->box.y2-r->box.y1,
500428d7b3dSmrg					     x, y, width, height,
501428d7b3dSmrg					     b.x1, b.y1, b.x2, b.y2));
502428d7b3dSmrg
503428d7b3dSmrg					if (b.y2 > b.y1 && b.x2 > b.x1) {
504428d7b3dSmrg						xRenderColor alpha;
505428d7b3dSmrg						PicturePtr mask;
506428d7b3dSmrg						int error;
507428d7b3dSmrg
508428d7b3dSmrg						alpha.red = alpha.green = alpha.blue = 0;
509428d7b3dSmrg						alpha.alpha = r->opacity * 0xffff;
510428d7b3dSmrg
511428d7b3dSmrg						mask = CreateSolidPicture(0, &alpha, &error);
512428d7b3dSmrg						if (!mask)
513428d7b3dSmrg							goto done;
514428d7b3dSmrg
515428d7b3dSmrg						if (sigtrap_get() == 0) {
516428d7b3dSmrg							fbComposite(tile->op,
517428d7b3dSmrg								    tile->src, mask, tile->dst,
518428d7b3dSmrg								    tile->src_x + x,  tile->src_y + y,
519428d7b3dSmrg								    0, 0,
520428d7b3dSmrg								    tile->dst_x + x,  tile->dst_y + y,
521428d7b3dSmrg								    width, height);
522428d7b3dSmrg							sigtrap_put();
523428d7b3dSmrg						}
524428d7b3dSmrg
525428d7b3dSmrg						FreePicture(mask, 0);
526428d7b3dSmrg					}
527428d7b3dSmrg					r++;
528428d7b3dSmrg				}
529428d7b3dSmrg
530428d7b3dSmrg				force_fallback = true;
531428d7b3dSmrg			}
532428d7b3dSmrg		}
533428d7b3dSmrg	}
534428d7b3dSmrg
535428d7b3dSmrgdone:
536428d7b3dSmrg	if (tile->rects != tile->rects_embedded)
537428d7b3dSmrg		free(tile->rects);
538428d7b3dSmrg	free(tile);
539428d7b3dSmrg}
540428d7b3dSmrg
541428d7b3dSmrgbool
542428d7b3dSmrgsna_tiling_composite_spans(uint32_t op,
543428d7b3dSmrg			   PicturePtr src,
544428d7b3dSmrg			   PicturePtr dst,
545428d7b3dSmrg			   int16_t src_x,  int16_t src_y,
546428d7b3dSmrg			   int16_t dst_x,  int16_t dst_y,
547428d7b3dSmrg			   int16_t width,  int16_t height,
548428d7b3dSmrg			   unsigned flags,
549428d7b3dSmrg			   struct sna_composite_spans_op *tmp)
550428d7b3dSmrg{
551428d7b3dSmrg	struct sna_tile_state *tile;
552428d7b3dSmrg	struct sna_pixmap *priv;
553428d7b3dSmrg
554428d7b3dSmrg	DBG(("%s size=(%d, %d), tile=%d\n",
555428d7b3dSmrg	     __FUNCTION__, width, height,
556428d7b3dSmrg	     to_sna_from_drawable(dst->pDrawable)->render.max_3d_size));
557428d7b3dSmrg
558428d7b3dSmrg	priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable));
559428d7b3dSmrg	if (priv == NULL || priv->gpu_bo == NULL)
560428d7b3dSmrg		return false;
561428d7b3dSmrg
562428d7b3dSmrg	tile = malloc(sizeof(*tile));
563428d7b3dSmrg	if (!tile)
564428d7b3dSmrg		return false;
565428d7b3dSmrg
566428d7b3dSmrg	tile->op = op;
567428d7b3dSmrg	tile->flags = flags;
568428d7b3dSmrg
569428d7b3dSmrg	tile->src  = src;
570428d7b3dSmrg	tile->mask = NULL;
571428d7b3dSmrg	tile->dst  = dst;
572428d7b3dSmrg
573428d7b3dSmrg	tile->src_x = src_x;
574428d7b3dSmrg	tile->src_y = src_y;
575428d7b3dSmrg	tile->mask_x = 0;
576428d7b3dSmrg	tile->mask_y = 0;
577428d7b3dSmrg	tile->dst_x = dst_x;
578428d7b3dSmrg	tile->dst_y = dst_y;
579428d7b3dSmrg	tile->width = width;
580428d7b3dSmrg	tile->height = height;
581428d7b3dSmrg	tile->rects = tile->rects_embedded;
582428d7b3dSmrg	tile->rect_count = 0;
583428d7b3dSmrg	tile->rect_size = ARRAY_SIZE(tile->rects_embedded);
584428d7b3dSmrg
585428d7b3dSmrg	tmp->box   = sna_tiling_composite_spans_box;
586428d7b3dSmrg	tmp->boxes = sna_tiling_composite_spans_boxes;
587428d7b3dSmrg	tmp->done  = sna_tiling_composite_spans_done;
588428d7b3dSmrg
589428d7b3dSmrg	tmp->base.priv = tile;
590428d7b3dSmrg	tmp->base.dst.bo = priv->gpu_bo;
591428d7b3dSmrg	return true;
592428d7b3dSmrg}
593428d7b3dSmrg
594428d7b3dSmrgbool
595428d7b3dSmrgsna_tiling_fill_boxes(struct sna *sna,
596428d7b3dSmrg		      CARD8 op,
597428d7b3dSmrg		      PictFormat format,
598428d7b3dSmrg		      const xRenderColor *color,
599428d7b3dSmrg		      const DrawableRec *dst, struct kgem_bo *dst_bo,
600428d7b3dSmrg		      const BoxRec *box, int n)
601428d7b3dSmrg{
602428d7b3dSmrg	RegionRec region, tile, this;
603428d7b3dSmrg	struct kgem_bo *bo;
604428d7b3dSmrg	int step, max_size;
605428d7b3dSmrg	bool ret = false;
606428d7b3dSmrg
607428d7b3dSmrg	pixman_region_init_rects(&region, box, n);
608428d7b3dSmrg
609428d7b3dSmrg	/* Use a small step to accommodate enlargement through tile alignment */
610428d7b3dSmrg	step = sna->render.max_3d_size;
611428d7b3dSmrg	if (region.extents.x1 & (8*512 / dst->bitsPerPixel - 1) ||
612428d7b3dSmrg	    region.extents.y1 & 63)
613428d7b3dSmrg		step /= 2;
614428d7b3dSmrg
615428d7b3dSmrg	max_size = sna_max_tile_copy_size(sna, dst_bo, dst_bo);
616428d7b3dSmrg	if (max_size == 0)
617428d7b3dSmrg		goto done;
618428d7b3dSmrg
619428d7b3dSmrg	while (step * step * 4 > max_size)
620428d7b3dSmrg		step /= 2;
621428d7b3dSmrg
622428d7b3dSmrg	DBG(("%s (op=%d, format=%x, color=(%04x,%04x,%04x, %04x), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n",
623428d7b3dSmrg	     __FUNCTION__, op, (int)format,
624428d7b3dSmrg	     color->red, color->green, color->blue, color->alpha,
625428d7b3dSmrg	     step, n,
626428d7b3dSmrg	     region.extents.x1, region.extents.y1,
627428d7b3dSmrg	     region.extents.x2, region.extents.y2));
628428d7b3dSmrg
629428d7b3dSmrg	for (tile.extents.y1 = tile.extents.y2 = region.extents.y1;
630428d7b3dSmrg	     tile.extents.y2 < region.extents.y2;
631428d7b3dSmrg	     tile.extents.y1 = tile.extents.y2) {
632428d7b3dSmrg		int y2 = tile.extents.y1 + step;
633428d7b3dSmrg		if (y2 > region.extents.y2)
634428d7b3dSmrg			y2 = region.extents.y2;
635428d7b3dSmrg		tile.extents.y2 = y2;
636428d7b3dSmrg
637428d7b3dSmrg		for (tile.extents.x1 = tile.extents.x2 = region.extents.x1;
638428d7b3dSmrg		     tile.extents.x2 < region.extents.x2;
639428d7b3dSmrg		     tile.extents.x1 = tile.extents.x2) {
640428d7b3dSmrg			DrawableRec tmp;
641428d7b3dSmrg			int x2 = tile.extents.x1 + step;
642428d7b3dSmrg			if (x2 > region.extents.x2)
643428d7b3dSmrg				x2 = region.extents.x2;
644428d7b3dSmrg			tile.extents.x2 = x2;
645428d7b3dSmrg
646428d7b3dSmrg			tile.data = NULL;
647428d7b3dSmrg
648428d7b3dSmrg			RegionNull(&this);
649428d7b3dSmrg			RegionIntersect(&this, &region, &tile);
650428d7b3dSmrg			if (RegionNil(&this))
651428d7b3dSmrg				continue;
652428d7b3dSmrg
653428d7b3dSmrg			tmp.width  = this.extents.x2 - this.extents.x1;
654428d7b3dSmrg			tmp.height = this.extents.y2 - this.extents.y1;
655428d7b3dSmrg			tmp.depth  = dst->depth;
656428d7b3dSmrg			tmp.bitsPerPixel = dst->bitsPerPixel;
657428d7b3dSmrg
658428d7b3dSmrg			bo = kgem_create_2d(&sna->kgem,
659428d7b3dSmrg					    tmp.width,
660428d7b3dSmrg					    tmp.height,
661428d7b3dSmrg					    dst->bitsPerPixel,
662428d7b3dSmrg					    kgem_choose_tiling(&sna->kgem,
663428d7b3dSmrg							       I915_TILING_X,
664428d7b3dSmrg							       tmp.width,
665428d7b3dSmrg							       tmp.height,
666428d7b3dSmrg							       dst->bitsPerPixel),
667428d7b3dSmrg					    CREATE_TEMPORARY);
668428d7b3dSmrg			if (bo) {
669428d7b3dSmrg				int16_t dx = this.extents.x1;
670428d7b3dSmrg				int16_t dy = this.extents.y1;
671428d7b3dSmrg
672428d7b3dSmrg				assert(kgem_bo_can_blt(&sna->kgem, bo));
673428d7b3dSmrg
674428d7b3dSmrg				if (op > PictOpSrc &&
675428d7b3dSmrg				    !sna->render.copy_boxes(sna, GXcopy,
676428d7b3dSmrg							    dst, dst_bo, 0, 0,
677428d7b3dSmrg							    &tmp, bo, -dx, -dy,
678428d7b3dSmrg							    region_rects(&this), region_num_rects(&this), 0))
679428d7b3dSmrg					goto err;
680428d7b3dSmrg
681428d7b3dSmrg				RegionTranslate(&this, -dx, -dy);
682428d7b3dSmrg				if (!sna->render.fill_boxes(sna, op, format, color, &tmp, bo,
683428d7b3dSmrg							    region_rects(&this), region_num_rects(&this)))
684428d7b3dSmrg					goto err;
685428d7b3dSmrg
686428d7b3dSmrg				if (!sna->render.copy_boxes(sna, GXcopy,
687428d7b3dSmrg							    &tmp, bo, 0, 0,
688428d7b3dSmrg							    dst, dst_bo, dx, dy,
689428d7b3dSmrg							    region_rects(&this), region_num_rects(&this), 0))
690428d7b3dSmrg					goto err;
691428d7b3dSmrg
692428d7b3dSmrg				kgem_bo_destroy(&sna->kgem, bo);
693428d7b3dSmrg			}
694428d7b3dSmrg			RegionUninit(&this);
695428d7b3dSmrg		}
696428d7b3dSmrg	}
697428d7b3dSmrg
698428d7b3dSmrg	ret = true;
699428d7b3dSmrg	goto done;
700428d7b3dSmrgerr:
701428d7b3dSmrg	kgem_bo_destroy(&sna->kgem, bo);
702428d7b3dSmrg	RegionUninit(&this);
703428d7b3dSmrgdone:
704428d7b3dSmrg	pixman_region_fini(&region);
705428d7b3dSmrg	return ret;
706428d7b3dSmrg}
707428d7b3dSmrg
708428d7b3dSmrgfastcall static void
709428d7b3dSmrgtiling_blt(struct sna *sna,
710428d7b3dSmrg	   const struct sna_composite_op *op,
711428d7b3dSmrg	   const struct sna_composite_rectangles *r)
712428d7b3dSmrg{
713428d7b3dSmrg	int x1, x2, y1, y2;
714428d7b3dSmrg	int src_x, src_y;
715428d7b3dSmrg	BoxRec box;
716428d7b3dSmrg
717428d7b3dSmrg	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n",
718428d7b3dSmrg	     __FUNCTION__,
719428d7b3dSmrg	     r->src.x, r->src.y,
720428d7b3dSmrg	     r->dst.x, r->dst.y,
721428d7b3dSmrg	     r->width, r->height));
722428d7b3dSmrg
723428d7b3dSmrg	/* XXX higher layer should have clipped? */
724428d7b3dSmrg
725428d7b3dSmrg	x1 = r->dst.x + op->dst.x;
726428d7b3dSmrg	y1 = r->dst.y + op->dst.y;
727428d7b3dSmrg	x2 = x1 + r->width;
728428d7b3dSmrg	y2 = y1 + r->height;
729428d7b3dSmrg
730428d7b3dSmrg	src_x = r->src.x - x1 + op->u.blt.sx;
731428d7b3dSmrg	src_y = r->src.y - y1 + op->u.blt.sy;
732428d7b3dSmrg
733428d7b3dSmrg	/* clip against dst */
734428d7b3dSmrg	if (x1 < 0)
735428d7b3dSmrg		x1 = 0;
736428d7b3dSmrg	if (y1 < 0)
737428d7b3dSmrg		y1 = 0;
738428d7b3dSmrg
739428d7b3dSmrg	if (x2 > op->dst.width)
740428d7b3dSmrg		x2 = op->dst.width;
741428d7b3dSmrg
742428d7b3dSmrg	if (y2 > op->dst.height)
743428d7b3dSmrg		y2 = op->dst.height;
744428d7b3dSmrg
745428d7b3dSmrg	DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2));
746428d7b3dSmrg
747428d7b3dSmrg	if (x2 <= x1 || y2 <= y1)
748428d7b3dSmrg		return;
749428d7b3dSmrg
750428d7b3dSmrg	box.x1 = x1; box.y1 = y1;
751428d7b3dSmrg	box.x2 = x2; box.y2 = y2;
752428d7b3dSmrg	sna_tiling_blt_copy_boxes(sna, GXcopy,
753428d7b3dSmrg				  op->src.bo, src_x, src_y,
754428d7b3dSmrg				  op->dst.bo, 0, 0,
755428d7b3dSmrg				  op->u.blt.bpp,
756428d7b3dSmrg				  &box, 1);
757428d7b3dSmrg}
758428d7b3dSmrg
759428d7b3dSmrgfastcall static void
760428d7b3dSmrgtiling_blt_box(struct sna *sna,
761428d7b3dSmrg	       const struct sna_composite_op *op,
762428d7b3dSmrg	       const BoxRec *box)
763428d7b3dSmrg{
764428d7b3dSmrg	DBG(("%s: box (%d, %d), (%d, %d)\n",
765428d7b3dSmrg	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
766428d7b3dSmrg	sna_tiling_blt_copy_boxes(sna, GXcopy,
767428d7b3dSmrg				  op->src.bo, op->u.blt.sx, op->u.blt.sy,
768428d7b3dSmrg				  op->dst.bo, op->dst.x, op->dst.y,
769428d7b3dSmrg				  op->u.blt.bpp,
770428d7b3dSmrg				  box, 1);
771428d7b3dSmrg}
772428d7b3dSmrg
773428d7b3dSmrgstatic void
774428d7b3dSmrgtiling_blt_boxes(struct sna *sna,
775428d7b3dSmrg		 const struct sna_composite_op *op,
776428d7b3dSmrg		 const BoxRec *box, int nbox)
777428d7b3dSmrg{
778428d7b3dSmrg	DBG(("%s: nbox=%d\n", __FUNCTION__, nbox));
779428d7b3dSmrg	sna_tiling_blt_copy_boxes(sna, GXcopy,
780428d7b3dSmrg				  op->src.bo, op->u.blt.sx, op->u.blt.sy,
781428d7b3dSmrg				  op->dst.bo, op->dst.x, op->dst.y,
782428d7b3dSmrg				  op->u.blt.bpp,
783428d7b3dSmrg				  box, nbox);
784428d7b3dSmrg}
785428d7b3dSmrg
786428d7b3dSmrgstatic bool
787428d7b3dSmrgsna_tiling_blt_copy_boxes__with_alpha(struct sna *sna, uint8_t alu,
788428d7b3dSmrg				      struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
789428d7b3dSmrg				      struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
790428d7b3dSmrg				      int bpp, int alpha_fixup,
791428d7b3dSmrg				      const BoxRec *box, int nbox)
792428d7b3dSmrg{
793428d7b3dSmrg	RegionRec region, tile, this;
794428d7b3dSmrg	struct kgem_bo *bo;
795428d7b3dSmrg	int max_size, step;
796428d7b3dSmrg	bool ret = false;
797428d7b3dSmrg
798428d7b3dSmrg	if (wedged(sna) ||
799428d7b3dSmrg	    !kgem_bo_can_blt(&sna->kgem, src_bo) ||
800428d7b3dSmrg	    !kgem_bo_can_blt(&sna->kgem, dst_bo)) {
801428d7b3dSmrg		/* XXX */
802428d7b3dSmrg		DBG(("%s: tiling blt fail: src?=%d, dst?=%d\n",
803428d7b3dSmrg		     __FUNCTION__,
804428d7b3dSmrg		     kgem_bo_can_blt(&sna->kgem, src_bo),
805428d7b3dSmrg		     kgem_bo_can_blt(&sna->kgem, dst_bo)));
806428d7b3dSmrg		return false;
807428d7b3dSmrg	}
808428d7b3dSmrg
809428d7b3dSmrg	max_size = sna_max_tile_copy_size(sna, src_bo, dst_bo);
810428d7b3dSmrg	if (max_size == 0)
811428d7b3dSmrg		return false;
812428d7b3dSmrg
813428d7b3dSmrg	pixman_region_init_rects(&region, box, nbox);
814428d7b3dSmrg
815428d7b3dSmrg	/* Use a small step to accommodate enlargement through tile alignment */
816428d7b3dSmrg	step = sna->render.max_3d_size;
817428d7b3dSmrg	if (region.extents.x1 & (8*512 / bpp - 1) || region.extents.y1 & 63)
818428d7b3dSmrg		step /= 2;
819428d7b3dSmrg	while (step * step * 4 > max_size)
820428d7b3dSmrg		step /= 2;
821428d7b3dSmrg	if (sna->kgem.gen < 033)
822428d7b3dSmrg		step /= 2; /* accommodate severe fence restrictions */
823428d7b3dSmrg	if (step == 0) {
824428d7b3dSmrg		DBG(("%s: tiles cannot fit into aperture\n", __FUNCTION__));
825428d7b3dSmrg		return false;
826428d7b3dSmrg	}
827428d7b3dSmrg
828428d7b3dSmrg	DBG(("%s (alu=%d), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n",
829428d7b3dSmrg	     __FUNCTION__, alu, step, nbox,
830428d7b3dSmrg	     region.extents.x1, region.extents.y1,
831428d7b3dSmrg	     region.extents.x2, region.extents.y2));
832428d7b3dSmrg
833428d7b3dSmrg	for (tile.extents.y1 = tile.extents.y2 = region.extents.y1;
834428d7b3dSmrg	     tile.extents.y2 < region.extents.y2;
835428d7b3dSmrg	     tile.extents.y1 = tile.extents.y2) {
836428d7b3dSmrg		int y2 = tile.extents.y1 + step;
837428d7b3dSmrg		if (y2 > region.extents.y2)
838428d7b3dSmrg			y2 = region.extents.y2;
839428d7b3dSmrg		tile.extents.y2 = y2;
840428d7b3dSmrg
841428d7b3dSmrg		for (tile.extents.x1 = tile.extents.x2 = region.extents.x1;
842428d7b3dSmrg		     tile.extents.x2 < region.extents.x2;
843428d7b3dSmrg		     tile.extents.x1 = tile.extents.x2) {
844428d7b3dSmrg			int w, h;
845428d7b3dSmrg			int x2 = tile.extents.x1 + step;
846428d7b3dSmrg			if (x2 > region.extents.x2)
847428d7b3dSmrg				x2 = region.extents.x2;
848428d7b3dSmrg			tile.extents.x2 = x2;
849428d7b3dSmrg
850428d7b3dSmrg			tile.data = NULL;
851428d7b3dSmrg
852428d7b3dSmrg			RegionNull(&this);
853428d7b3dSmrg			RegionIntersect(&this, &region, &tile);
854428d7b3dSmrg			if (RegionNil(&this))
855428d7b3dSmrg				continue;
856428d7b3dSmrg
857428d7b3dSmrg			w = this.extents.x2 - this.extents.x1;
858428d7b3dSmrg			h = this.extents.y2 - this.extents.y1;
859428d7b3dSmrg			bo = kgem_create_2d(&sna->kgem, w, h, bpp,
860428d7b3dSmrg					    kgem_choose_tiling(&sna->kgem,
861428d7b3dSmrg							       I915_TILING_X,
862428d7b3dSmrg							       w, h, bpp),
863428d7b3dSmrg					    CREATE_TEMPORARY);
864428d7b3dSmrg			if (bo) {
865428d7b3dSmrg				int16_t dx = this.extents.x1;
866428d7b3dSmrg				int16_t dy = this.extents.y1;
867428d7b3dSmrg
868428d7b3dSmrg				assert(kgem_bo_can_blt(&sna->kgem, bo));
869428d7b3dSmrg
870428d7b3dSmrg				if (!sna_blt_copy_boxes(sna, GXcopy,
871428d7b3dSmrg							src_bo, src_dx, src_dy,
872428d7b3dSmrg							bo, -dx, -dy,
873428d7b3dSmrg							bpp, region_rects(&this), region_num_rects(&this)))
874428d7b3dSmrg					goto err;
875428d7b3dSmrg
876428d7b3dSmrg				if (!sna_blt_copy_boxes__with_alpha(sna, alu,
877428d7b3dSmrg								    bo, -dx, -dy,
878428d7b3dSmrg								    dst_bo, dst_dx, dst_dy,
879428d7b3dSmrg								    bpp, alpha_fixup,
880428d7b3dSmrg								    region_rects(&this), region_num_rects(&this)))
881428d7b3dSmrg					goto err;
882428d7b3dSmrg
883428d7b3dSmrg				kgem_bo_destroy(&sna->kgem, bo);
884428d7b3dSmrg			}
885428d7b3dSmrg			RegionUninit(&this);
886428d7b3dSmrg		}
887428d7b3dSmrg	}
888428d7b3dSmrg
889428d7b3dSmrg	ret = true;
890428d7b3dSmrg	goto done;
891428d7b3dSmrgerr:
892428d7b3dSmrg	kgem_bo_destroy(&sna->kgem, bo);
893428d7b3dSmrg	RegionUninit(&this);
894428d7b3dSmrgdone:
895428d7b3dSmrg	pixman_region_fini(&region);
896428d7b3dSmrg	return ret;
897428d7b3dSmrg}
898428d7b3dSmrg
899428d7b3dSmrgfastcall static void
900428d7b3dSmrgtiling_blt__with_alpha(struct sna *sna,
901428d7b3dSmrg		       const struct sna_composite_op *op,
902428d7b3dSmrg		       const struct sna_composite_rectangles *r)
903428d7b3dSmrg{
904428d7b3dSmrg	int x1, x2, y1, y2;
905428d7b3dSmrg	int src_x, src_y;
906428d7b3dSmrg	BoxRec box;
907428d7b3dSmrg
908428d7b3dSmrg	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n",
909428d7b3dSmrg	     __FUNCTION__,
910428d7b3dSmrg	     r->src.x, r->src.y,
911428d7b3dSmrg	     r->dst.x, r->dst.y,
912428d7b3dSmrg	     r->width, r->height));
913428d7b3dSmrg
914428d7b3dSmrg	/* XXX higher layer should have clipped? */
915428d7b3dSmrg
916428d7b3dSmrg	x1 = r->dst.x + op->dst.x;
917428d7b3dSmrg	y1 = r->dst.y + op->dst.y;
918428d7b3dSmrg	x2 = x1 + r->width;
919428d7b3dSmrg	y2 = y1 + r->height;
920428d7b3dSmrg
921428d7b3dSmrg	src_x = r->src.x - x1 + op->u.blt.sx;
922428d7b3dSmrg	src_y = r->src.y - y1 + op->u.blt.sy;
923428d7b3dSmrg
924428d7b3dSmrg	/* clip against dst */
925428d7b3dSmrg	if (x1 < 0)
926428d7b3dSmrg		x1 = 0;
927428d7b3dSmrg	if (y1 < 0)
928428d7b3dSmrg		y1 = 0;
929428d7b3dSmrg
930428d7b3dSmrg	if (x2 > op->dst.width)
931428d7b3dSmrg		x2 = op->dst.width;
932428d7b3dSmrg
933428d7b3dSmrg	if (y2 > op->dst.height)
934428d7b3dSmrg		y2 = op->dst.height;
935428d7b3dSmrg
936428d7b3dSmrg	DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2));
937428d7b3dSmrg
938428d7b3dSmrg	if (x2 <= x1 || y2 <= y1)
939428d7b3dSmrg		return;
940428d7b3dSmrg
941428d7b3dSmrg	box.x1 = x1; box.y1 = y1;
942428d7b3dSmrg	box.x2 = x2; box.y2 = y2;
943428d7b3dSmrg	sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy,
944428d7b3dSmrg					      op->src.bo, src_x, src_y,
945428d7b3dSmrg					      op->dst.bo, 0, 0,
946428d7b3dSmrg					      op->u.blt.bpp, op->u.blt.pixel,
947428d7b3dSmrg					      &box, 1);
948428d7b3dSmrg}
949428d7b3dSmrg
950428d7b3dSmrgfastcall static void
951428d7b3dSmrgtiling_blt_box__with_alpha(struct sna *sna,
952428d7b3dSmrg			   const struct sna_composite_op *op,
953428d7b3dSmrg			   const BoxRec *box)
954428d7b3dSmrg{
955428d7b3dSmrg	DBG(("%s: box (%d, %d), (%d, %d)\n",
956428d7b3dSmrg	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
957428d7b3dSmrg	sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy,
958428d7b3dSmrg					      op->src.bo, op->u.blt.sx, op->u.blt.sy,
959428d7b3dSmrg					      op->dst.bo, op->dst.x, op->dst.y,
960428d7b3dSmrg					      op->u.blt.bpp, op->u.blt.pixel,
961428d7b3dSmrg					      box, 1);
962428d7b3dSmrg}
963428d7b3dSmrg
964428d7b3dSmrgstatic void
965428d7b3dSmrgtiling_blt_boxes__with_alpha(struct sna *sna,
966428d7b3dSmrg			     const struct sna_composite_op *op,
967428d7b3dSmrg			     const BoxRec *box, int nbox)
968428d7b3dSmrg{
969428d7b3dSmrg	DBG(("%s: nbox=%d\n", __FUNCTION__, nbox));
970428d7b3dSmrg	sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy,
971428d7b3dSmrg					      op->src.bo, op->u.blt.sx, op->u.blt.sy,
972428d7b3dSmrg					      op->dst.bo, op->dst.x, op->dst.y,
973428d7b3dSmrg					      op->u.blt.bpp, op->u.blt.pixel,
974428d7b3dSmrg					      box, nbox);
975428d7b3dSmrg}
976428d7b3dSmrg
977428d7b3dSmrgstatic void nop_done(struct sna *sna, const struct sna_composite_op *op)
978428d7b3dSmrg{
979428d7b3dSmrg	assert(sna->kgem.nbatch <= KGEM_BATCH_SIZE(&sna->kgem));
980428d7b3dSmrg	(void)op;
981428d7b3dSmrg}
982428d7b3dSmrg
983428d7b3dSmrgbool
984428d7b3dSmrgsna_tiling_blt_composite(struct sna *sna,
985428d7b3dSmrg			 struct sna_composite_op *op,
986428d7b3dSmrg			 struct kgem_bo *bo,
987428d7b3dSmrg			 int bpp,
988428d7b3dSmrg			 uint32_t alpha_fixup)
989428d7b3dSmrg{
990428d7b3dSmrg	assert(op->dst.bo);
991428d7b3dSmrg	assert(kgem_bo_can_blt(&sna->kgem, op->dst.bo));
992428d7b3dSmrg	assert(kgem_bo_can_blt(&sna->kgem, bo));
993428d7b3dSmrg
994428d7b3dSmrg	op->src.bo = bo;
995428d7b3dSmrg	op->u.blt.bpp = bpp;
996428d7b3dSmrg	op->u.blt.pixel = alpha_fixup;
997428d7b3dSmrg
998428d7b3dSmrg	if (alpha_fixup) {
999428d7b3dSmrg		op->blt   = tiling_blt__with_alpha;
1000428d7b3dSmrg		op->box   = tiling_blt_box__with_alpha;
1001428d7b3dSmrg		op->boxes = tiling_blt_boxes__with_alpha;
1002428d7b3dSmrg	} else {
1003428d7b3dSmrg		op->blt   = tiling_blt;
1004428d7b3dSmrg		op->box   = tiling_blt_box;
1005428d7b3dSmrg		op->boxes = tiling_blt_boxes;
1006428d7b3dSmrg	}
1007428d7b3dSmrg	op->done  = nop_done;
1008428d7b3dSmrg
1009428d7b3dSmrg	return true;
1010428d7b3dSmrg}
1011428d7b3dSmrg
1012428d7b3dSmrgbool sna_tiling_blt_copy_boxes(struct sna *sna, uint8_t alu,
1013428d7b3dSmrg			       struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
1014428d7b3dSmrg			       struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
1015428d7b3dSmrg			       int bpp, const BoxRec *box, int nbox)
1016428d7b3dSmrg{
1017428d7b3dSmrg	RegionRec region, tile, this;
1018428d7b3dSmrg	struct kgem_bo *bo;
1019428d7b3dSmrg	int max_size, step;
1020428d7b3dSmrg	bool ret = false;
1021428d7b3dSmrg
1022428d7b3dSmrg	DBG(("%s: alu=%d, src size=%d, dst size=%d\n", __FUNCTION__,
1023428d7b3dSmrg	     alu, kgem_bo_size(src_bo), kgem_bo_size(dst_bo)));
1024428d7b3dSmrg
1025428d7b3dSmrg	if (wedged(sna) ||
1026428d7b3dSmrg	    !kgem_bo_can_blt(&sna->kgem, src_bo) ||
1027428d7b3dSmrg	    !kgem_bo_can_blt(&sna->kgem, dst_bo)) {
1028428d7b3dSmrg		/* XXX */
1029428d7b3dSmrg		DBG(("%s: tiling blt fail: src?=%d, dst?=%d\n",
1030428d7b3dSmrg		     __FUNCTION__,
1031428d7b3dSmrg		     kgem_bo_can_blt(&sna->kgem, src_bo),
1032428d7b3dSmrg		     kgem_bo_can_blt(&sna->kgem, dst_bo)));
1033428d7b3dSmrg		return false;
1034428d7b3dSmrg	}
1035428d7b3dSmrg
1036428d7b3dSmrg	max_size = sna_max_tile_copy_size(sna, src_bo, dst_bo);
1037428d7b3dSmrg	if (max_size == 0)
1038428d7b3dSmrg		return false;
1039428d7b3dSmrg
1040428d7b3dSmrg	pixman_region_init_rects(&region, box, nbox);
1041428d7b3dSmrg
1042428d7b3dSmrg	/* Use a small step to accommodate enlargement through tile alignment */
1043428d7b3dSmrg	step = sna->render.max_3d_size;
1044428d7b3dSmrg	if (region.extents.x1 & (8*512 / bpp - 1) || region.extents.y1 & 63)
1045428d7b3dSmrg		step /= 2;
1046428d7b3dSmrg	while (step * step * 4 > max_size)
1047428d7b3dSmrg		step /= 2;
1048428d7b3dSmrg	if (sna->kgem.gen < 033)
1049428d7b3dSmrg		step /= 2; /* accommodate severe fence restrictions */
1050428d7b3dSmrg	if (step == 0) {
1051428d7b3dSmrg		DBG(("%s: tiles cannot fit into aperture\n", __FUNCTION__));
1052428d7b3dSmrg		return false;
1053428d7b3dSmrg	}
1054428d7b3dSmrg
1055428d7b3dSmrg	DBG(("%s (alu=%d), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n",
1056428d7b3dSmrg	     __FUNCTION__, alu, step, nbox,
1057428d7b3dSmrg	     region.extents.x1, region.extents.y1,
1058428d7b3dSmrg	     region.extents.x2, region.extents.y2));
1059428d7b3dSmrg
1060428d7b3dSmrg	for (tile.extents.y1 = tile.extents.y2 = region.extents.y1;
1061428d7b3dSmrg	     tile.extents.y2 < region.extents.y2;
1062428d7b3dSmrg	     tile.extents.y1 = tile.extents.y2) {
1063428d7b3dSmrg		int y2 = tile.extents.y1 + step;
1064428d7b3dSmrg		if (y2 > region.extents.y2)
1065428d7b3dSmrg			y2 = region.extents.y2;
1066428d7b3dSmrg		tile.extents.y2 = y2;
1067428d7b3dSmrg
1068428d7b3dSmrg		for (tile.extents.x1 = tile.extents.x2 = region.extents.x1;
1069428d7b3dSmrg		     tile.extents.x2 < region.extents.x2;
1070428d7b3dSmrg		     tile.extents.x1 = tile.extents.x2) {
1071428d7b3dSmrg			int w, h;
1072428d7b3dSmrg			int x2 = tile.extents.x1 + step;
1073428d7b3dSmrg			if (x2 > region.extents.x2)
1074428d7b3dSmrg				x2 = region.extents.x2;
1075428d7b3dSmrg			tile.extents.x2 = x2;
1076428d7b3dSmrg
1077428d7b3dSmrg			tile.data = NULL;
1078428d7b3dSmrg
1079428d7b3dSmrg			RegionNull(&this);
1080428d7b3dSmrg			RegionIntersect(&this, &region, &tile);
1081428d7b3dSmrg			if (RegionNil(&this))
1082428d7b3dSmrg				continue;
1083428d7b3dSmrg
1084428d7b3dSmrg			w = this.extents.x2 - this.extents.x1;
1085428d7b3dSmrg			h = this.extents.y2 - this.extents.y1;
1086428d7b3dSmrg			bo = kgem_create_2d(&sna->kgem, w, h, bpp,
1087428d7b3dSmrg					    kgem_choose_tiling(&sna->kgem,
1088428d7b3dSmrg							       I915_TILING_X,
1089428d7b3dSmrg							       w, h, bpp),
1090428d7b3dSmrg					    CREATE_TEMPORARY);
1091428d7b3dSmrg			if (bo) {
1092428d7b3dSmrg				int16_t dx = this.extents.x1;
1093428d7b3dSmrg				int16_t dy = this.extents.y1;
1094428d7b3dSmrg
1095428d7b3dSmrg				assert(kgem_bo_can_blt(&sna->kgem, bo));
1096428d7b3dSmrg
1097428d7b3dSmrg				if (!sna_blt_copy_boxes(sna, GXcopy,
1098428d7b3dSmrg							src_bo, src_dx, src_dy,
1099428d7b3dSmrg							bo, -dx, -dy,
1100428d7b3dSmrg							bpp, region_rects(&this), region_num_rects(&this)))
1101428d7b3dSmrg					goto err;
1102428d7b3dSmrg
1103428d7b3dSmrg				if (!sna_blt_copy_boxes(sna, alu,
1104428d7b3dSmrg							bo, -dx, -dy,
1105428d7b3dSmrg							dst_bo, dst_dx, dst_dy,
1106428d7b3dSmrg							bpp, region_rects(&this), region_num_rects(&this)))
1107428d7b3dSmrg					goto err;
1108428d7b3dSmrg
1109428d7b3dSmrg				kgem_bo_destroy(&sna->kgem, bo);
1110428d7b3dSmrg			}
1111428d7b3dSmrg			RegionUninit(&this);
1112428d7b3dSmrg		}
1113428d7b3dSmrg	}
1114428d7b3dSmrg
1115428d7b3dSmrg	ret = true;
1116428d7b3dSmrg	goto done;
1117428d7b3dSmrgerr:
1118428d7b3dSmrg	kgem_bo_destroy(&sna->kgem, bo);
1119428d7b3dSmrg	RegionUninit(&this);
1120428d7b3dSmrgdone:
1121428d7b3dSmrg	pixman_region_fini(&region);
1122428d7b3dSmrg	return ret;
1123428d7b3dSmrg}
1124428d7b3dSmrg
1125428d7b3dSmrgbool
1126428d7b3dSmrgsna_tiling_copy_boxes(struct sna *sna, uint8_t alu,
1127428d7b3dSmrg		      const DrawableRec *src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
1128428d7b3dSmrg		      const DrawableRec *dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
1129428d7b3dSmrg		      const BoxRec *box, int n)
1130428d7b3dSmrg{
1131428d7b3dSmrg	BoxRec extents, tile, stack[64], *clipped, *c;
1132428d7b3dSmrg	DrawableRec p;
1133428d7b3dSmrg	int i, step, tiling;
1134428d7b3dSmrg	bool create = true;
1135428d7b3dSmrg	bool ret = false;
1136428d7b3dSmrg
1137428d7b3dSmrg	extents = box[0];
1138428d7b3dSmrg	for (i = 1; i < n; i++) {
1139428d7b3dSmrg		if (box[i].x1 < extents.x1)
1140428d7b3dSmrg			extents.x1 = box[i].x1;
1141428d7b3dSmrg		if (box[i].y1 < extents.y1)
1142428d7b3dSmrg			extents.y1 = box[i].y1;
1143428d7b3dSmrg
1144428d7b3dSmrg		if (box[i].x2 > extents.x2)
1145428d7b3dSmrg			extents.x2 = box[i].x2;
1146428d7b3dSmrg		if (box[i].y2 > extents.y2)
1147428d7b3dSmrg			extents.y2 = box[i].y2;
1148428d7b3dSmrg	}
1149428d7b3dSmrg
1150428d7b3dSmrg	tiling = I915_TILING_X;
1151428d7b3dSmrg	if (!kgem_bo_can_blt(&sna->kgem, src_bo) ||
1152428d7b3dSmrg	    !kgem_bo_can_blt(&sna->kgem, dst_bo))
1153428d7b3dSmrg		tiling = I915_TILING_Y;
1154428d7b3dSmrg
1155428d7b3dSmrg	create = (src_bo->pitch > sna->render.max_3d_pitch ||
1156428d7b3dSmrg		  dst_bo->pitch > sna->render.max_3d_pitch);
1157428d7b3dSmrg
1158428d7b3dSmrg	step = sna->render.max_3d_size / 2;
1159428d7b3dSmrg	if (create) {
1160428d7b3dSmrg		while (step * step * 4 > sna->kgem.max_upload_tile_size)
1161428d7b3dSmrg			step /= 2;
1162428d7b3dSmrg	}
1163428d7b3dSmrg
1164428d7b3dSmrg	DBG(("%s: tiling copy %dx%d, %s %dx%d %c tiles\n", __FUNCTION__,
1165428d7b3dSmrg	     extents.x2-extents.x1, extents.y2-extents.y1,
1166428d7b3dSmrg	     create ? "creating" : "using",
1167428d7b3dSmrg	     step, step, tiling == I915_TILING_X ? 'X' : 'Y'));
1168428d7b3dSmrg
1169428d7b3dSmrg	if (n > ARRAY_SIZE(stack)) {
1170428d7b3dSmrg		clipped = malloc(sizeof(BoxRec) * n);
1171428d7b3dSmrg		if (clipped == NULL)
1172428d7b3dSmrg			goto tiled_error;
1173428d7b3dSmrg	} else
1174428d7b3dSmrg		clipped = stack;
1175428d7b3dSmrg
1176428d7b3dSmrg	p.depth = src->depth;
1177428d7b3dSmrg	p.bitsPerPixel = src->bitsPerPixel;
1178428d7b3dSmrg
1179428d7b3dSmrg	for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) {
1180428d7b3dSmrg		int y2 = tile.y1 + step;
1181428d7b3dSmrg		if (y2 > extents.y2)
1182428d7b3dSmrg			y2 = extents.y2;
1183428d7b3dSmrg		tile.y2 = y2;
1184428d7b3dSmrg
1185428d7b3dSmrg		for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) {
1186428d7b3dSmrg			struct kgem_bo *tmp_bo;
1187428d7b3dSmrg			int x2 = tile.x1 + step;
1188428d7b3dSmrg			if (x2 > extents.x2)
1189428d7b3dSmrg				x2 = extents.x2;
1190428d7b3dSmrg			tile.x2 = x2;
1191428d7b3dSmrg
1192428d7b3dSmrg			c = clipped;
1193428d7b3dSmrg			for (i = 0; i < n; i++) {
1194428d7b3dSmrg				*c = box[i];
1195428d7b3dSmrg				if (!box_intersect(c, &tile))
1196428d7b3dSmrg					continue;
1197428d7b3dSmrg
1198428d7b3dSmrg				DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n",
1199428d7b3dSmrg				     __FUNCTION__,
1200428d7b3dSmrg				     c->x1, c->y1,
1201428d7b3dSmrg				     c->x2, c->y2,
1202428d7b3dSmrg				     src_dx, src_dy,
1203428d7b3dSmrg				     c->x1 - tile.x1,
1204428d7b3dSmrg				     c->y1 - tile.y1));
1205428d7b3dSmrg				c++;
1206428d7b3dSmrg			}
1207428d7b3dSmrg			if (c == clipped)
1208428d7b3dSmrg				continue;
1209428d7b3dSmrg
1210428d7b3dSmrg			p.width  = tile.x2 - tile.x1;
1211428d7b3dSmrg			p.height = tile.y2 - tile.y1;
1212428d7b3dSmrg
1213428d7b3dSmrg			DBG(("%s: tile (%d, %d), (%d, %d)\n",
1214428d7b3dSmrg			     __FUNCTION__, tile.x1, tile.y1, tile.x2, tile.y2));
1215428d7b3dSmrg
1216428d7b3dSmrg			if (create) {
1217428d7b3dSmrg				tmp_bo = kgem_create_2d(&sna->kgem,
1218428d7b3dSmrg							p.width,
1219428d7b3dSmrg							p.height,
1220428d7b3dSmrg							p.bitsPerPixel,
1221428d7b3dSmrg							tiling, CREATE_TEMPORARY);
1222428d7b3dSmrg				if (!tmp_bo)
1223428d7b3dSmrg					goto tiled_error;
1224428d7b3dSmrg
1225428d7b3dSmrg				i = (sna->render.copy_boxes(sna, GXcopy,
1226428d7b3dSmrg							    src, src_bo, src_dx, src_dy,
1227428d7b3dSmrg							    &p, tmp_bo, -tile.x1, -tile.y1,
1228428d7b3dSmrg							    clipped, c - clipped, 0) &&
1229428d7b3dSmrg				     sna->render.copy_boxes(sna, alu,
1230428d7b3dSmrg							    &p, tmp_bo, -tile.x1, -tile.y1,
1231428d7b3dSmrg							    dst, dst_bo, dst_dx, dst_dy,
1232428d7b3dSmrg							    clipped, c - clipped, 0));
1233428d7b3dSmrg
1234428d7b3dSmrg				kgem_bo_destroy(&sna->kgem, tmp_bo);
1235428d7b3dSmrg			} else {
1236428d7b3dSmrg				i = sna->render.copy_boxes(sna, GXcopy,
1237428d7b3dSmrg							   src, src_bo, src_dx, src_dy,
1238428d7b3dSmrg							   dst, dst_bo, dst_dx, dst_dy,
1239428d7b3dSmrg							   clipped, c - clipped, 0);
1240428d7b3dSmrg			}
1241428d7b3dSmrg
1242428d7b3dSmrg			if (!i)
1243428d7b3dSmrg				goto tiled_error;
1244428d7b3dSmrg		}
1245428d7b3dSmrg	}
1246428d7b3dSmrg
1247428d7b3dSmrg	ret = true;
1248428d7b3dSmrgtiled_error:
1249428d7b3dSmrg	if (clipped != stack)
1250428d7b3dSmrg		free(clipped);
1251428d7b3dSmrg
1252428d7b3dSmrg	return ret;
1253428d7b3dSmrg}
1254