1 /*
2  * Copyright © 2010 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  *
23  * Authors:
24  *    Chris Wilson <chris@chris-wilson.co.uk>
25  *
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include "sna.h"
33 #include "sna_render.h"
34 #include "fb/fbpict.h"
35 
36 struct sna_tile_span {
37 	BoxRec box;
38 	float opacity;
39 };
40 
41 struct sna_tile_state {
42 	int op;
43 	PicturePtr src, mask, dst;
44 	PixmapPtr dst_pixmap;
45 	uint32_t dst_format;
46 	int16_t src_x, src_y;
47 	int16_t mask_x, mask_y;
48 	int16_t dst_x, dst_y;
49 	int16_t width, height;
50 	unsigned flags;
51 
52 	int rect_count;
53 	int rect_size;
54 	struct sna_composite_rectangles rects_embedded[16], *rects;
55 };
56 
57 static void
sna_tiling_composite_add_rect(struct sna_tile_state * tile,const struct sna_composite_rectangles * r)58 sna_tiling_composite_add_rect(struct sna_tile_state *tile,
59 			      const struct sna_composite_rectangles *r)
60 {
61 	if (tile->rect_count == tile->rect_size) {
62 		struct sna_composite_rectangles *a;
63 		int newsize = tile->rect_size * 2;
64 
65 		if (tile->rects == tile->rects_embedded) {
66 			a = malloc (sizeof(struct sna_composite_rectangles) * newsize);
67 			if (a == NULL)
68 				return;
69 
70 			memcpy(a,
71 			       tile->rects_embedded,
72 			       sizeof(struct sna_composite_rectangles) * tile->rect_count);
73 		} else {
74 			a = realloc(tile->rects,
75 				    sizeof(struct sna_composite_rectangles) * newsize);
76 			if (a == NULL)
77 				return;
78 		}
79 
80 		tile->rects = a;
81 		tile->rect_size = newsize;
82 	}
83 
84 	tile->rects[tile->rect_count++] = *r;
85 }
86 
87 fastcall static void
sna_tiling_composite_blt(struct sna * sna,const struct sna_composite_op * op,const struct sna_composite_rectangles * r)88 sna_tiling_composite_blt(struct sna *sna,
89 			 const struct sna_composite_op *op,
90 			 const struct sna_composite_rectangles *r)
91 {
92 	sna_tiling_composite_add_rect(op->priv, r);
93 	(void)sna;
94 }
95 
96 fastcall static void
sna_tiling_composite_box(struct sna * sna,const struct sna_composite_op * op,const BoxRec * box)97 sna_tiling_composite_box(struct sna *sna,
98 			 const struct sna_composite_op *op,
99 			 const BoxRec *box)
100 {
101 	struct sna_composite_rectangles r;
102 
103 	r.dst.x = box->x1;
104 	r.dst.y = box->y1;
105 	r.mask = r.src = r.dst;
106 
107 	r.width  = box->x2 - box->x1;
108 	r.height = box->y2 - box->y1;
109 
110 	sna_tiling_composite_add_rect(op->priv, &r);
111 	(void)sna;
112 }
113 
114 static void
sna_tiling_composite_boxes(struct sna * sna,const struct sna_composite_op * op,const BoxRec * box,int nbox)115 sna_tiling_composite_boxes(struct sna *sna,
116 			   const struct sna_composite_op *op,
117 			   const BoxRec *box, int nbox)
118 {
119 	while (nbox--) {
120 		struct sna_composite_rectangles r;
121 
122 		r.dst.x = box->x1;
123 		r.dst.y = box->y1;
124 		r.mask = r.src = r.dst;
125 
126 		r.width  = box->x2 - box->x1;
127 		r.height = box->y2 - box->y1;
128 
129 		sna_tiling_composite_add_rect(op->priv, &r);
130 		box++;
131 	}
132 	(void)sna;
133 }
134 
135 static void
sna_tiling_composite_done(struct sna * sna,const struct sna_composite_op * op)136 sna_tiling_composite_done(struct sna *sna,
137 			  const struct sna_composite_op *op)
138 {
139 	struct sna_tile_state *tile = op->priv;
140 	struct sna_composite_op tmp;
141 	int x, y, n, step, max_size;
142 
143 	/* Use a small step to accommodate enlargement through tile alignment */
144 	step = sna->render.max_3d_size;
145 	if (tile->dst_x & (8*512 / tile->dst->pDrawable->bitsPerPixel - 1) ||
146 	    tile->dst_y & 63)
147 		step /= 2;
148 
149 	max_size = sna_max_tile_copy_size(sna, op->dst.bo, op->dst.bo);
150 	if (max_size == 0)
151 		goto done;
152 
153 	while (step * step * 4 > max_size)
154 		step /= 2;
155 
156 	DBG(("%s -- %dx%d, count=%d, step size=%d\n", __FUNCTION__,
157 	     tile->width, tile->height, tile->rect_count, step));
158 
159 	if (tile->rect_count == 0)
160 		goto done;
161 
162 	for (y = 0; y < tile->height; y += step) {
163 		int height = step;
164 		if (y + height > tile->height)
165 			height = tile->height - y;
166 		for (x = 0; x < tile->width; x += step) {
167 			int width = step;
168 			if (x + width > tile->width)
169 				width = tile->width - x;
170 			if (sna->render.composite(sna, tile->op,
171 						  tile->src, tile->mask, tile->dst,
172 						  tile->src_x + x,  tile->src_y + y,
173 						  tile->mask_x + x, tile->mask_y + y,
174 						  tile->dst_x + x,  tile->dst_y + y,
175 						  width, height,
176 						  COMPOSITE_PARTIAL, memset(&tmp, 0, sizeof(tmp)))) {
177 				for (n = 0; n < tile->rect_count; n++) {
178 					const struct sna_composite_rectangles *r = &tile->rects[n];
179 					int x1, x2, dx, y1, y2, dy;
180 
181 					x1 = r->dst.x - tile->dst_x, dx = 0;
182 					if (x1 < x)
183 						dx = x - x1, x1 = x;
184 					y1 = r->dst.y - tile->dst_y, dy = 0;
185 					if (y1 < y)
186 						dy = y - y1, y1 = y;
187 
188 					x2 = r->dst.x + r->width - tile->dst_x;
189 					if (x2 > x + width)
190 						x2 = x + width;
191 					y2 = r->dst.y + r->height - tile->dst_y;
192 					if (y2 > y + height)
193 						y2 = y + height;
194 
195 					DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d), delta=(%d,%d)\n",
196 					     __FUNCTION__, n,
197 					     r->dst.x, r->dst.y,
198 					     r->width, r->height,
199 					     x, y, width, height,
200 					     x1, y1, x2, y2,
201 					     dx, dy));
202 
203 					if (y2 > y1 && x2 > x1) {
204 						struct sna_composite_rectangles rr;
205 						rr.src.x = dx + r->src.x;
206 						rr.src.y = dy + r->src.y;
207 
208 						rr.mask.x = dx + r->mask.x;
209 						rr.mask.y = dy + r->mask.y;
210 
211 						rr.dst.x = dx + r->dst.x;
212 						rr.dst.y = dy + r->dst.y;
213 
214 						rr.width  = x2 - x1;
215 						rr.height = y2 - y1;
216 
217 						tmp.blt(sna, &tmp, &rr);
218 					}
219 				}
220 				tmp.done(sna, &tmp);
221 			} else {
222 				unsigned int flags;
223 				DBG(("%s -- falback\n", __FUNCTION__));
224 
225 				if (tile->op <= PictOpSrc)
226 					flags = MOVE_WRITE;
227 				else
228 					flags = MOVE_WRITE | MOVE_READ;
229 				if (!sna_drawable_move_to_cpu(tile->dst->pDrawable,
230 							      flags))
231 					goto done;
232 				if (tile->dst->alphaMap &&
233 				    !sna_drawable_move_to_cpu(tile->dst->alphaMap->pDrawable,
234 							      flags))
235 					goto done;
236 
237 				if (tile->src->pDrawable &&
238 				    !sna_drawable_move_to_cpu(tile->src->pDrawable,
239 							      MOVE_READ))
240 					goto done;
241 				if (tile->src->alphaMap &&
242 				    !sna_drawable_move_to_cpu(tile->src->alphaMap->pDrawable,
243 							      MOVE_READ))
244 					goto done;
245 
246 				if (tile->mask && tile->mask->pDrawable &&
247 				    !sna_drawable_move_to_cpu(tile->mask->pDrawable,
248 							      MOVE_READ))
249 					goto done;
250 
251 				if (tile->mask && tile->mask->alphaMap &&
252 				    !sna_drawable_move_to_cpu(tile->mask->alphaMap->pDrawable,
253 							      MOVE_READ))
254 					goto done;
255 
256 				if (sigtrap_get() == 0) {
257 					fbComposite(tile->op,
258 						    tile->src, tile->mask, tile->dst,
259 						    tile->src_x + x,  tile->src_y + y,
260 						    tile->mask_x + x, tile->mask_y + y,
261 						    tile->dst_x + x,  tile->dst_y + y,
262 						    width, height);
263 					sigtrap_put();
264 				}
265 			}
266 		}
267 	}
268 
269 done:
270 	if (tile->rects != tile->rects_embedded)
271 		free(tile->rects);
272 	free(tile);
273 }
274 
275 bool
sna_tiling_composite(uint32_t op,PicturePtr src,PicturePtr mask,PicturePtr dst,int16_t src_x,int16_t src_y,int16_t mask_x,int16_t mask_y,int16_t dst_x,int16_t dst_y,int16_t width,int16_t height,struct sna_composite_op * tmp)276 sna_tiling_composite(uint32_t op,
277 		     PicturePtr src,
278 		     PicturePtr mask,
279 		     PicturePtr dst,
280 		     int16_t src_x,  int16_t src_y,
281 		     int16_t mask_x, int16_t mask_y,
282 		     int16_t dst_x,  int16_t dst_y,
283 		     int16_t width,  int16_t height,
284 		     struct sna_composite_op *tmp)
285 {
286 	struct sna_tile_state *tile;
287 	struct sna_pixmap *priv;
288 
289 	DBG(("%s size=(%d, %d), tile=%d\n",
290 	     __FUNCTION__, width, height,
291 	     to_sna_from_drawable(dst->pDrawable)->render.max_3d_size));
292 
293 	priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable));
294 	if (priv == NULL || priv->gpu_bo == NULL)
295 		return false;
296 
297 	tile = malloc(sizeof(*tile));
298 	if (!tile)
299 		return false;
300 
301 	tile->op = op;
302 
303 	tile->src  = src;
304 	tile->mask = mask;
305 	tile->dst  = dst;
306 
307 	tile->src_x = src_x;
308 	tile->src_y = src_y;
309 	tile->mask_x = mask_x;
310 	tile->mask_y = mask_y;
311 	tile->dst_x = dst_x;
312 	tile->dst_y = dst_y;
313 	tile->width = width;
314 	tile->height = height;
315 	tile->rects = tile->rects_embedded;
316 	tile->rect_count = 0;
317 	tile->rect_size = ARRAY_SIZE(tile->rects_embedded);
318 
319 	tmp->blt   = sna_tiling_composite_blt;
320 	tmp->box   = sna_tiling_composite_box;
321 	tmp->boxes = sna_tiling_composite_boxes;
322 	tmp->done  = sna_tiling_composite_done;
323 
324 	tmp->priv = tile;
325 	tmp->dst.bo = priv->gpu_bo;
326 	return true;
327 }
328 
329 fastcall static void
sna_tiling_composite_spans_box(struct sna * sna,const struct sna_composite_spans_op * op,const BoxRec * box,float opacity)330 sna_tiling_composite_spans_box(struct sna *sna,
331 			       const struct sna_composite_spans_op *op,
332 			       const BoxRec *box, float opacity)
333 {
334 	struct sna_tile_state *tile = op->base.priv;
335 	struct sna_tile_span *a;
336 
337 	if (tile->rect_count == tile->rect_size) {
338 		int newsize = tile->rect_size * 2;
339 
340 		if (tile->rects == tile->rects_embedded) {
341 			a = malloc (sizeof(struct sna_tile_span) * newsize);
342 			if (a == NULL)
343 				return;
344 
345 			memcpy(a,
346 			       tile->rects_embedded,
347 			       sizeof(struct sna_tile_span) * tile->rect_count);
348 		} else {
349 			a = realloc(tile->rects,
350 				    sizeof(struct sna_tile_span) * newsize);
351 			if (a == NULL)
352 				return;
353 		}
354 
355 		tile->rects = (void *)a;
356 		tile->rect_size = newsize;
357 	} else
358 		a = (void *)tile->rects;
359 
360 	a[tile->rect_count].box = *box;
361 	a[tile->rect_count].opacity = opacity;
362 	tile->rect_count++;
363 	(void)sna;
364 }
365 
366 static void
sna_tiling_composite_spans_boxes(struct sna * sna,const struct sna_composite_spans_op * op,const BoxRec * box,int nbox,float opacity)367 sna_tiling_composite_spans_boxes(struct sna *sna,
368 				 const struct sna_composite_spans_op *op,
369 				 const BoxRec *box, int nbox, float opacity)
370 {
371 	while (nbox--)
372 		sna_tiling_composite_spans_box(sna, op, box++, opacity);
373 }
374 
375 fastcall static void
sna_tiling_composite_spans_done(struct sna * sna,const struct sna_composite_spans_op * op)376 sna_tiling_composite_spans_done(struct sna *sna,
377 				const struct sna_composite_spans_op *op)
378 {
379 	struct sna_tile_state *tile = op->base.priv;
380 	struct sna_composite_spans_op tmp;
381 	int x, y, n, step, max_size;
382 	bool force_fallback = false;
383 
384 	/* Use a small step to accommodate enlargement through tile alignment */
385 	step = sna->render.max_3d_size;
386 	if (tile->dst_x & (8*512 / tile->dst->pDrawable->bitsPerPixel - 1) ||
387 	    tile->dst_y & 63)
388 		step /= 2;
389 
390 	max_size = sna_max_tile_copy_size(sna, op->base.dst.bo, op->base.dst.bo);
391 	if (max_size == 0)
392 		goto done;
393 
394 	while (step * step * 4 > max_size)
395 		step /= 2;
396 
397 	DBG(("%s -- %dx%d, count=%d, step size=%d\n", __FUNCTION__,
398 	     tile->width, tile->height, tile->rect_count, step));
399 
400 	if (tile->rect_count == 0)
401 		goto done;
402 
403 	for (y = 0; y < tile->height; y += step) {
404 		int height = step;
405 		if (y + height > tile->height)
406 			height = tile->height - y;
407 		for (x = 0; x < tile->width; x += step) {
408 			const struct sna_tile_span *r = (void *)tile->rects;
409 			int width = step;
410 			if (x + width > tile->width)
411 				width = tile->width - x;
412 			if (!force_fallback &&
413 			    sna->render.composite_spans(sna, tile->op,
414 							tile->src, tile->dst,
415 							tile->src_x + x,  tile->src_y + y,
416 							tile->dst_x + x,  tile->dst_y + y,
417 							width, height, tile->flags,
418 							memset(&tmp, 0, sizeof(tmp)))) {
419 				for (n = 0; n < tile->rect_count; n++) {
420 					BoxRec b;
421 
422 					b.x1 = r->box.x1 - tile->dst_x;
423 					if (b.x1 < x)
424 						b.x1 = x;
425 
426 					b.y1 = r->box.y1 - tile->dst_y;
427 					if (b.y1 < y)
428 						b.y1 = y;
429 
430 					b.x2 = r->box.x2 - tile->dst_x;
431 					if (b.x2 > x + width)
432 						b.x2 = x + width;
433 
434 					b.y2 = r->box.y2 - tile->dst_y;
435 					if (b.y2 > y + height)
436 						b.y2 = y + height;
437 
438 					DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d)\n",
439 					     __FUNCTION__, n,
440 					     r->box.x1, r->box.y1,
441 					     r->box.x2-r->box.x1, r->box.y2-r->box.y1,
442 					     x, y, width, height,
443 					     b.x1, b.y1, b.x2, b.y2));
444 
445 					if (b.y2 > b.y1 && b.x2 > b.x1)
446 						tmp.box(sna, &tmp, &b, r->opacity);
447 					r++;
448 				}
449 				tmp.done(sna, &tmp);
450 			} else {
451 				unsigned int flags;
452 
453 				DBG(("%s -- falback\n", __FUNCTION__));
454 
455 				if (tile->op <= PictOpSrc)
456 					flags = MOVE_WRITE;
457 				else
458 					flags = MOVE_WRITE | MOVE_READ;
459 				if (!sna_drawable_move_to_cpu(tile->dst->pDrawable,
460 							      flags))
461 					goto done;
462 				if (tile->dst->alphaMap &&
463 				    !sna_drawable_move_to_cpu(tile->dst->alphaMap->pDrawable,
464 							      flags))
465 					goto done;
466 
467 				if (tile->src->pDrawable &&
468 				    !sna_drawable_move_to_cpu(tile->src->pDrawable,
469 							      MOVE_READ))
470 					goto done;
471 				if (tile->src->alphaMap &&
472 				    !sna_drawable_move_to_cpu(tile->src->alphaMap->pDrawable,
473 							      MOVE_READ))
474 					goto done;
475 
476 				for (n = 0; n < tile->rect_count; n++) {
477 					BoxRec b;
478 
479 					b.x1 = r->box.x1 - tile->dst_x;
480 					if (b.x1 < x)
481 						b.x1 = x;
482 
483 					b.y1 = r->box.y1 - tile->dst_y;
484 					if (b.y1 < y)
485 						b.y1 = y;
486 
487 					b.x2 = r->box.x2 - tile->dst_x;
488 					if (b.x2 > x + width)
489 						b.x2 = x + width;
490 
491 					b.y2 = r->box.y2 - tile->dst_y;
492 					if (b.y2 > y + height)
493 						b.y2 = y + height;
494 
495 					DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d)\n",
496 					     __FUNCTION__, n,
497 					     r->box.x1, r->box.y1,
498 					     r->box.x2-r->box.x1, r->box.y2-r->box.y1,
499 					     x, y, width, height,
500 					     b.x1, b.y1, b.x2, b.y2));
501 
502 					if (b.y2 > b.y1 && b.x2 > b.x1) {
503 						xRenderColor alpha;
504 						PicturePtr mask;
505 						int error;
506 
507 						alpha.red = alpha.green = alpha.blue = 0;
508 						alpha.alpha = r->opacity * 0xffff;
509 
510 						mask = CreateSolidPicture(0, &alpha, &error);
511 						if (!mask)
512 							goto done;
513 
514 						if (sigtrap_get() == 0) {
515 							fbComposite(tile->op,
516 								    tile->src, mask, tile->dst,
517 								    tile->src_x + x,  tile->src_y + y,
518 								    0, 0,
519 								    tile->dst_x + x,  tile->dst_y + y,
520 								    width, height);
521 							sigtrap_put();
522 						}
523 
524 						FreePicture(mask, 0);
525 					}
526 					r++;
527 				}
528 
529 				force_fallback = true;
530 			}
531 		}
532 	}
533 
534 done:
535 	if (tile->rects != tile->rects_embedded)
536 		free(tile->rects);
537 	free(tile);
538 }
539 
540 bool
sna_tiling_composite_spans(uint32_t op,PicturePtr src,PicturePtr dst,int16_t src_x,int16_t src_y,int16_t dst_x,int16_t dst_y,int16_t width,int16_t height,unsigned flags,struct sna_composite_spans_op * tmp)541 sna_tiling_composite_spans(uint32_t op,
542 			   PicturePtr src,
543 			   PicturePtr dst,
544 			   int16_t src_x,  int16_t src_y,
545 			   int16_t dst_x,  int16_t dst_y,
546 			   int16_t width,  int16_t height,
547 			   unsigned flags,
548 			   struct sna_composite_spans_op *tmp)
549 {
550 	struct sna_tile_state *tile;
551 	struct sna_pixmap *priv;
552 
553 	DBG(("%s size=(%d, %d), tile=%d\n",
554 	     __FUNCTION__, width, height,
555 	     to_sna_from_drawable(dst->pDrawable)->render.max_3d_size));
556 
557 	priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable));
558 	if (priv == NULL || priv->gpu_bo == NULL)
559 		return false;
560 
561 	tile = malloc(sizeof(*tile));
562 	if (!tile)
563 		return false;
564 
565 	tile->op = op;
566 	tile->flags = flags;
567 
568 	tile->src  = src;
569 	tile->mask = NULL;
570 	tile->dst  = dst;
571 
572 	tile->src_x = src_x;
573 	tile->src_y = src_y;
574 	tile->mask_x = 0;
575 	tile->mask_y = 0;
576 	tile->dst_x = dst_x;
577 	tile->dst_y = dst_y;
578 	tile->width = width;
579 	tile->height = height;
580 	tile->rects = tile->rects_embedded;
581 	tile->rect_count = 0;
582 	tile->rect_size = ARRAY_SIZE(tile->rects_embedded);
583 	COMPILE_TIME_ASSERT(sizeof(tile->rects_embedded[0]) >= sizeof(struct sna_tile_span));
584 
585 	tmp->box   = sna_tiling_composite_spans_box;
586 	tmp->boxes = sna_tiling_composite_spans_boxes;
587 	tmp->done  = sna_tiling_composite_spans_done;
588 
589 	tmp->base.priv = tile;
590 	tmp->base.dst.bo = priv->gpu_bo;
591 	return true;
592 }
593 
594 bool
sna_tiling_fill_boxes(struct sna * sna,CARD8 op,PictFormat format,const xRenderColor * color,const DrawableRec * dst,struct kgem_bo * dst_bo,const BoxRec * box,int n)595 sna_tiling_fill_boxes(struct sna *sna,
596 		      CARD8 op,
597 		      PictFormat format,
598 		      const xRenderColor *color,
599 		      const DrawableRec *dst, struct kgem_bo *dst_bo,
600 		      const BoxRec *box, int n)
601 {
602 	RegionRec region, tile, this;
603 	struct kgem_bo *bo;
604 	int step, max_size;
605 	bool ret = false;
606 
607 	pixman_region_init_rects(&region, box, n);
608 
609 	/* Use a small step to accommodate enlargement through tile alignment */
610 	step = sna->render.max_3d_size;
611 	if (region.extents.x1 & (8*512 / dst->bitsPerPixel - 1) ||
612 	    region.extents.y1 & 63)
613 		step /= 2;
614 
615 	max_size = sna_max_tile_copy_size(sna, dst_bo, dst_bo);
616 	if (max_size == 0)
617 		goto done;
618 
619 	while (step * step * 4 > max_size)
620 		step /= 2;
621 
622 	DBG(("%s (op=%d, format=%x, color=(%04x,%04x,%04x, %04x), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n",
623 	     __FUNCTION__, op, (int)format,
624 	     color->red, color->green, color->blue, color->alpha,
625 	     step, n,
626 	     region.extents.x1, region.extents.y1,
627 	     region.extents.x2, region.extents.y2));
628 
629 	for (tile.extents.y1 = tile.extents.y2 = region.extents.y1;
630 	     tile.extents.y2 < region.extents.y2;
631 	     tile.extents.y1 = tile.extents.y2) {
632 		int y2 = tile.extents.y1 + step;
633 		if (y2 > region.extents.y2)
634 			y2 = region.extents.y2;
635 		tile.extents.y2 = y2;
636 
637 		for (tile.extents.x1 = tile.extents.x2 = region.extents.x1;
638 		     tile.extents.x2 < region.extents.x2;
639 		     tile.extents.x1 = tile.extents.x2) {
640 			DrawableRec tmp;
641 			int x2 = tile.extents.x1 + step;
642 			if (x2 > region.extents.x2)
643 				x2 = region.extents.x2;
644 			tile.extents.x2 = x2;
645 
646 			tile.data = NULL;
647 
648 			RegionNull(&this);
649 			RegionIntersect(&this, &region, &tile);
650 			if (RegionNil(&this))
651 				continue;
652 
653 			tmp.width  = this.extents.x2 - this.extents.x1;
654 			tmp.height = this.extents.y2 - this.extents.y1;
655 			tmp.depth  = dst->depth;
656 			tmp.bitsPerPixel = dst->bitsPerPixel;
657 
658 			bo = kgem_create_2d(&sna->kgem,
659 					    tmp.width,
660 					    tmp.height,
661 					    dst->bitsPerPixel,
662 					    kgem_choose_tiling(&sna->kgem,
663 							       I915_TILING_X,
664 							       tmp.width,
665 							       tmp.height,
666 							       dst->bitsPerPixel),
667 					    CREATE_TEMPORARY);
668 			if (bo) {
669 				int16_t dx = this.extents.x1;
670 				int16_t dy = this.extents.y1;
671 
672 				assert(kgem_bo_can_blt(&sna->kgem, bo));
673 
674 				if (op > PictOpSrc &&
675 				    !sna->render.copy_boxes(sna, GXcopy,
676 							    dst, dst_bo, 0, 0,
677 							    &tmp, bo, -dx, -dy,
678 							    region_rects(&this), region_num_rects(&this), 0))
679 					goto err;
680 
681 				RegionTranslate(&this, -dx, -dy);
682 				if (!sna->render.fill_boxes(sna, op, format, color, &tmp, bo,
683 							    region_rects(&this), region_num_rects(&this)))
684 					goto err;
685 
686 				if (!sna->render.copy_boxes(sna, GXcopy,
687 							    &tmp, bo, 0, 0,
688 							    dst, dst_bo, dx, dy,
689 							    region_rects(&this), region_num_rects(&this), 0))
690 					goto err;
691 
692 				kgem_bo_destroy(&sna->kgem, bo);
693 			}
694 			RegionUninit(&this);
695 		}
696 	}
697 
698 	ret = true;
699 	goto done;
700 err:
701 	kgem_bo_destroy(&sna->kgem, bo);
702 	RegionUninit(&this);
703 done:
704 	pixman_region_fini(&region);
705 	return ret;
706 }
707 
708 fastcall static void
tiling_blt(struct sna * sna,const struct sna_composite_op * op,const struct sna_composite_rectangles * r)709 tiling_blt(struct sna *sna,
710 	   const struct sna_composite_op *op,
711 	   const struct sna_composite_rectangles *r)
712 {
713 	int x1, x2, y1, y2;
714 	int src_x, src_y;
715 	BoxRec box;
716 
717 	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n",
718 	     __FUNCTION__,
719 	     r->src.x, r->src.y,
720 	     r->dst.x, r->dst.y,
721 	     r->width, r->height));
722 
723 	/* XXX higher layer should have clipped? */
724 
725 	x1 = r->dst.x + op->dst.x;
726 	y1 = r->dst.y + op->dst.y;
727 	x2 = x1 + r->width;
728 	y2 = y1 + r->height;
729 
730 	src_x = r->src.x - x1 + op->u.blt.sx;
731 	src_y = r->src.y - y1 + op->u.blt.sy;
732 
733 	/* clip against dst */
734 	if (x1 < 0)
735 		x1 = 0;
736 	if (y1 < 0)
737 		y1 = 0;
738 
739 	if (x2 > op->dst.width)
740 		x2 = op->dst.width;
741 
742 	if (y2 > op->dst.height)
743 		y2 = op->dst.height;
744 
745 	DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2));
746 
747 	if (x2 <= x1 || y2 <= y1)
748 		return;
749 
750 	box.x1 = x1; box.y1 = y1;
751 	box.x2 = x2; box.y2 = y2;
752 	sna_tiling_blt_copy_boxes(sna, GXcopy,
753 				  op->src.bo, src_x, src_y,
754 				  op->dst.bo, 0, 0,
755 				  op->u.blt.bpp,
756 				  &box, 1);
757 }
758 
759 fastcall static void
tiling_blt_box(struct sna * sna,const struct sna_composite_op * op,const BoxRec * box)760 tiling_blt_box(struct sna *sna,
761 	       const struct sna_composite_op *op,
762 	       const BoxRec *box)
763 {
764 	DBG(("%s: box (%d, %d), (%d, %d)\n",
765 	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
766 	sna_tiling_blt_copy_boxes(sna, GXcopy,
767 				  op->src.bo, op->u.blt.sx, op->u.blt.sy,
768 				  op->dst.bo, op->dst.x, op->dst.y,
769 				  op->u.blt.bpp,
770 				  box, 1);
771 }
772 
773 static void
tiling_blt_boxes(struct sna * sna,const struct sna_composite_op * op,const BoxRec * box,int nbox)774 tiling_blt_boxes(struct sna *sna,
775 		 const struct sna_composite_op *op,
776 		 const BoxRec *box, int nbox)
777 {
778 	DBG(("%s: nbox=%d\n", __FUNCTION__, nbox));
779 	sna_tiling_blt_copy_boxes(sna, GXcopy,
780 				  op->src.bo, op->u.blt.sx, op->u.blt.sy,
781 				  op->dst.bo, op->dst.x, op->dst.y,
782 				  op->u.blt.bpp,
783 				  box, nbox);
784 }
785 
786 static bool
sna_tiling_blt_copy_boxes__with_alpha(struct sna * sna,uint8_t alu,struct kgem_bo * src_bo,int16_t src_dx,int16_t src_dy,struct kgem_bo * dst_bo,int16_t dst_dx,int16_t dst_dy,int bpp,int alpha_fixup,const BoxRec * box,int nbox)787 sna_tiling_blt_copy_boxes__with_alpha(struct sna *sna, uint8_t alu,
788 				      struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
789 				      struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
790 				      int bpp, int alpha_fixup,
791 				      const BoxRec *box, int nbox)
792 {
793 	RegionRec region, tile, this;
794 	struct kgem_bo *bo;
795 	int max_size, step;
796 	bool ret = false;
797 
798 	if (wedged(sna) ||
799 	    !kgem_bo_can_blt(&sna->kgem, src_bo) ||
800 	    !kgem_bo_can_blt(&sna->kgem, dst_bo)) {
801 		/* XXX */
802 		DBG(("%s: tiling blt fail: src?=%d, dst?=%d\n",
803 		     __FUNCTION__,
804 		     kgem_bo_can_blt(&sna->kgem, src_bo),
805 		     kgem_bo_can_blt(&sna->kgem, dst_bo)));
806 		return false;
807 	}
808 
809 	max_size = sna_max_tile_copy_size(sna, src_bo, dst_bo);
810 	if (max_size == 0)
811 		return false;
812 
813 	pixman_region_init_rects(&region, box, nbox);
814 
815 	/* Use a small step to accommodate enlargement through tile alignment */
816 	step = sna->render.max_3d_size;
817 	if (region.extents.x1 & (8*512 / bpp - 1) || region.extents.y1 & 63)
818 		step /= 2;
819 	while (step * step * 4 > max_size)
820 		step /= 2;
821 	if (sna->kgem.gen < 033)
822 		step /= 2; /* accommodate severe fence restrictions */
823 	if (step == 0) {
824 		DBG(("%s: tiles cannot fit into aperture\n", __FUNCTION__));
825 		return false;
826 	}
827 
828 	DBG(("%s (alu=%d), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n",
829 	     __FUNCTION__, alu, step, nbox,
830 	     region.extents.x1, region.extents.y1,
831 	     region.extents.x2, region.extents.y2));
832 
833 	for (tile.extents.y1 = tile.extents.y2 = region.extents.y1;
834 	     tile.extents.y2 < region.extents.y2;
835 	     tile.extents.y1 = tile.extents.y2) {
836 		int y2 = tile.extents.y1 + step;
837 		if (y2 > region.extents.y2)
838 			y2 = region.extents.y2;
839 		tile.extents.y2 = y2;
840 
841 		for (tile.extents.x1 = tile.extents.x2 = region.extents.x1;
842 		     tile.extents.x2 < region.extents.x2;
843 		     tile.extents.x1 = tile.extents.x2) {
844 			int w, h;
845 			int x2 = tile.extents.x1 + step;
846 			if (x2 > region.extents.x2)
847 				x2 = region.extents.x2;
848 			tile.extents.x2 = x2;
849 
850 			tile.data = NULL;
851 
852 			RegionNull(&this);
853 			RegionIntersect(&this, &region, &tile);
854 			if (RegionNil(&this))
855 				continue;
856 
857 			w = this.extents.x2 - this.extents.x1;
858 			h = this.extents.y2 - this.extents.y1;
859 			bo = kgem_create_2d(&sna->kgem, w, h, bpp,
860 					    kgem_choose_tiling(&sna->kgem,
861 							       I915_TILING_X,
862 							       w, h, bpp),
863 					    CREATE_TEMPORARY);
864 			if (bo) {
865 				int16_t dx = this.extents.x1;
866 				int16_t dy = this.extents.y1;
867 
868 				assert(kgem_bo_can_blt(&sna->kgem, bo));
869 
870 				if (!sna_blt_copy_boxes(sna, GXcopy,
871 							src_bo, src_dx, src_dy,
872 							bo, -dx, -dy,
873 							bpp, region_rects(&this), region_num_rects(&this)))
874 					goto err;
875 
876 				if (!sna_blt_copy_boxes__with_alpha(sna, alu,
877 								    bo, -dx, -dy,
878 								    dst_bo, dst_dx, dst_dy,
879 								    bpp, alpha_fixup,
880 								    region_rects(&this), region_num_rects(&this)))
881 					goto err;
882 
883 				kgem_bo_destroy(&sna->kgem, bo);
884 			}
885 			RegionUninit(&this);
886 		}
887 	}
888 
889 	ret = true;
890 	goto done;
891 err:
892 	kgem_bo_destroy(&sna->kgem, bo);
893 	RegionUninit(&this);
894 done:
895 	pixman_region_fini(&region);
896 	return ret;
897 }
898 
899 fastcall static void
tiling_blt__with_alpha(struct sna * sna,const struct sna_composite_op * op,const struct sna_composite_rectangles * r)900 tiling_blt__with_alpha(struct sna *sna,
901 		       const struct sna_composite_op *op,
902 		       const struct sna_composite_rectangles *r)
903 {
904 	int x1, x2, y1, y2;
905 	int src_x, src_y;
906 	BoxRec box;
907 
908 	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n",
909 	     __FUNCTION__,
910 	     r->src.x, r->src.y,
911 	     r->dst.x, r->dst.y,
912 	     r->width, r->height));
913 
914 	/* XXX higher layer should have clipped? */
915 
916 	x1 = r->dst.x + op->dst.x;
917 	y1 = r->dst.y + op->dst.y;
918 	x2 = x1 + r->width;
919 	y2 = y1 + r->height;
920 
921 	src_x = r->src.x - x1 + op->u.blt.sx;
922 	src_y = r->src.y - y1 + op->u.blt.sy;
923 
924 	/* clip against dst */
925 	if (x1 < 0)
926 		x1 = 0;
927 	if (y1 < 0)
928 		y1 = 0;
929 
930 	if (x2 > op->dst.width)
931 		x2 = op->dst.width;
932 
933 	if (y2 > op->dst.height)
934 		y2 = op->dst.height;
935 
936 	DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2));
937 
938 	if (x2 <= x1 || y2 <= y1)
939 		return;
940 
941 	box.x1 = x1; box.y1 = y1;
942 	box.x2 = x2; box.y2 = y2;
943 	sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy,
944 					      op->src.bo, src_x, src_y,
945 					      op->dst.bo, 0, 0,
946 					      op->u.blt.bpp, op->u.blt.pixel,
947 					      &box, 1);
948 }
949 
950 fastcall static void
tiling_blt_box__with_alpha(struct sna * sna,const struct sna_composite_op * op,const BoxRec * box)951 tiling_blt_box__with_alpha(struct sna *sna,
952 			   const struct sna_composite_op *op,
953 			   const BoxRec *box)
954 {
955 	DBG(("%s: box (%d, %d), (%d, %d)\n",
956 	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
957 	sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy,
958 					      op->src.bo, op->u.blt.sx, op->u.blt.sy,
959 					      op->dst.bo, op->dst.x, op->dst.y,
960 					      op->u.blt.bpp, op->u.blt.pixel,
961 					      box, 1);
962 }
963 
964 static void
tiling_blt_boxes__with_alpha(struct sna * sna,const struct sna_composite_op * op,const BoxRec * box,int nbox)965 tiling_blt_boxes__with_alpha(struct sna *sna,
966 			     const struct sna_composite_op *op,
967 			     const BoxRec *box, int nbox)
968 {
969 	DBG(("%s: nbox=%d\n", __FUNCTION__, nbox));
970 	sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy,
971 					      op->src.bo, op->u.blt.sx, op->u.blt.sy,
972 					      op->dst.bo, op->dst.x, op->dst.y,
973 					      op->u.blt.bpp, op->u.blt.pixel,
974 					      box, nbox);
975 }
976 
nop_done(struct sna * sna,const struct sna_composite_op * op)977 static void nop_done(struct sna *sna, const struct sna_composite_op *op)
978 {
979 	assert(sna->kgem.nbatch <= KGEM_BATCH_SIZE(&sna->kgem));
980 	(void)op;
981 }
982 
983 bool
sna_tiling_blt_composite(struct sna * sna,struct sna_composite_op * op,struct kgem_bo * bo,int bpp,uint32_t alpha_fixup)984 sna_tiling_blt_composite(struct sna *sna,
985 			 struct sna_composite_op *op,
986 			 struct kgem_bo *bo,
987 			 int bpp,
988 			 uint32_t alpha_fixup)
989 {
990 	assert(op->dst.bo);
991 	assert(kgem_bo_can_blt(&sna->kgem, op->dst.bo));
992 	assert(kgem_bo_can_blt(&sna->kgem, bo));
993 
994 	op->src.bo = bo;
995 	op->u.blt.bpp = bpp;
996 	op->u.blt.pixel = alpha_fixup;
997 
998 	if (alpha_fixup) {
999 		op->blt   = tiling_blt__with_alpha;
1000 		op->box   = tiling_blt_box__with_alpha;
1001 		op->boxes = tiling_blt_boxes__with_alpha;
1002 	} else {
1003 		op->blt   = tiling_blt;
1004 		op->box   = tiling_blt_box;
1005 		op->boxes = tiling_blt_boxes;
1006 	}
1007 	op->done  = nop_done;
1008 
1009 	return true;
1010 }
1011 
sna_tiling_blt_copy_boxes(struct sna * sna,uint8_t alu,struct kgem_bo * src_bo,int16_t src_dx,int16_t src_dy,struct kgem_bo * dst_bo,int16_t dst_dx,int16_t dst_dy,int bpp,const BoxRec * box,int nbox)1012 bool sna_tiling_blt_copy_boxes(struct sna *sna, uint8_t alu,
1013 			       struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
1014 			       struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
1015 			       int bpp, const BoxRec *box, int nbox)
1016 {
1017 	RegionRec region, tile, this;
1018 	struct kgem_bo *bo;
1019 	int max_size, step;
1020 	bool ret = false;
1021 
1022 	DBG(("%s: alu=%d, src size=%d, dst size=%d\n", __FUNCTION__,
1023 	     alu, kgem_bo_size(src_bo), kgem_bo_size(dst_bo)));
1024 
1025 	if (wedged(sna) ||
1026 	    !kgem_bo_can_blt(&sna->kgem, src_bo) ||
1027 	    !kgem_bo_can_blt(&sna->kgem, dst_bo)) {
1028 		/* XXX */
1029 		DBG(("%s: tiling blt fail: src?=%d, dst?=%d\n",
1030 		     __FUNCTION__,
1031 		     kgem_bo_can_blt(&sna->kgem, src_bo),
1032 		     kgem_bo_can_blt(&sna->kgem, dst_bo)));
1033 		return false;
1034 	}
1035 
1036 	max_size = sna_max_tile_copy_size(sna, src_bo, dst_bo);
1037 	if (max_size == 0)
1038 		return false;
1039 
1040 	pixman_region_init_rects(&region, box, nbox);
1041 
1042 	/* Use a small step to accommodate enlargement through tile alignment */
1043 	step = sna->render.max_3d_size;
1044 	if (region.extents.x1 & (8*512 / bpp - 1) || region.extents.y1 & 63)
1045 		step /= 2;
1046 	while (step * step * 4 > max_size)
1047 		step /= 2;
1048 	if (sna->kgem.gen < 033)
1049 		step /= 2; /* accommodate severe fence restrictions */
1050 	if (step == 0) {
1051 		DBG(("%s: tiles cannot fit into aperture\n", __FUNCTION__));
1052 		return false;
1053 	}
1054 
1055 	DBG(("%s (alu=%d), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n",
1056 	     __FUNCTION__, alu, step, nbox,
1057 	     region.extents.x1, region.extents.y1,
1058 	     region.extents.x2, region.extents.y2));
1059 
1060 	for (tile.extents.y1 = tile.extents.y2 = region.extents.y1;
1061 	     tile.extents.y2 < region.extents.y2;
1062 	     tile.extents.y1 = tile.extents.y2) {
1063 		int y2 = tile.extents.y1 + step;
1064 		if (y2 > region.extents.y2)
1065 			y2 = region.extents.y2;
1066 		tile.extents.y2 = y2;
1067 
1068 		for (tile.extents.x1 = tile.extents.x2 = region.extents.x1;
1069 		     tile.extents.x2 < region.extents.x2;
1070 		     tile.extents.x1 = tile.extents.x2) {
1071 			int w, h;
1072 			int x2 = tile.extents.x1 + step;
1073 			if (x2 > region.extents.x2)
1074 				x2 = region.extents.x2;
1075 			tile.extents.x2 = x2;
1076 
1077 			tile.data = NULL;
1078 
1079 			RegionNull(&this);
1080 			RegionIntersect(&this, &region, &tile);
1081 			if (RegionNil(&this))
1082 				continue;
1083 
1084 			w = this.extents.x2 - this.extents.x1;
1085 			h = this.extents.y2 - this.extents.y1;
1086 			bo = kgem_create_2d(&sna->kgem, w, h, bpp,
1087 					    kgem_choose_tiling(&sna->kgem,
1088 							       I915_TILING_X,
1089 							       w, h, bpp),
1090 					    CREATE_TEMPORARY);
1091 			if (bo) {
1092 				int16_t dx = this.extents.x1;
1093 				int16_t dy = this.extents.y1;
1094 
1095 				assert(kgem_bo_can_blt(&sna->kgem, bo));
1096 
1097 				if (!sna_blt_copy_boxes(sna, GXcopy,
1098 							src_bo, src_dx, src_dy,
1099 							bo, -dx, -dy,
1100 							bpp, region_rects(&this), region_num_rects(&this)))
1101 					goto err;
1102 
1103 				if (!sna_blt_copy_boxes(sna, alu,
1104 							bo, -dx, -dy,
1105 							dst_bo, dst_dx, dst_dy,
1106 							bpp, region_rects(&this), region_num_rects(&this)))
1107 					goto err;
1108 
1109 				kgem_bo_destroy(&sna->kgem, bo);
1110 			}
1111 			RegionUninit(&this);
1112 		}
1113 	}
1114 
1115 	ret = true;
1116 	goto done;
1117 err:
1118 	kgem_bo_destroy(&sna->kgem, bo);
1119 	RegionUninit(&this);
1120 done:
1121 	pixman_region_fini(&region);
1122 	return ret;
1123 }
1124 
1125 bool
sna_tiling_copy_boxes(struct sna * sna,uint8_t alu,const DrawableRec * src,struct kgem_bo * src_bo,int16_t src_dx,int16_t src_dy,const DrawableRec * dst,struct kgem_bo * dst_bo,int16_t dst_dx,int16_t dst_dy,const BoxRec * box,int n)1126 sna_tiling_copy_boxes(struct sna *sna, uint8_t alu,
1127 		      const DrawableRec *src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
1128 		      const DrawableRec *dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
1129 		      const BoxRec *box, int n)
1130 {
1131 	BoxRec extents, tile, stack[64], *clipped, *c;
1132 	DrawableRec p;
1133 	int i, step, tiling;
1134 	bool create = true;
1135 	bool ret = false;
1136 
1137 	extents = box[0];
1138 	for (i = 1; i < n; i++) {
1139 		if (box[i].x1 < extents.x1)
1140 			extents.x1 = box[i].x1;
1141 		if (box[i].y1 < extents.y1)
1142 			extents.y1 = box[i].y1;
1143 
1144 		if (box[i].x2 > extents.x2)
1145 			extents.x2 = box[i].x2;
1146 		if (box[i].y2 > extents.y2)
1147 			extents.y2 = box[i].y2;
1148 	}
1149 
1150 	tiling = I915_TILING_X;
1151 	if (!kgem_bo_can_blt(&sna->kgem, src_bo) ||
1152 	    !kgem_bo_can_blt(&sna->kgem, dst_bo))
1153 		tiling = I915_TILING_Y;
1154 
1155 	create = (src_bo->pitch > sna->render.max_3d_pitch ||
1156 		  dst_bo->pitch > sna->render.max_3d_pitch);
1157 
1158 	step = sna->render.max_3d_size / 2;
1159 	if (create) {
1160 		while (step * step * 4 > sna->kgem.max_upload_tile_size)
1161 			step /= 2;
1162 	}
1163 
1164 	DBG(("%s: tiling copy %dx%d, %s %dx%d %c tiles\n", __FUNCTION__,
1165 	     extents.x2-extents.x1, extents.y2-extents.y1,
1166 	     create ? "creating" : "using",
1167 	     step, step, tiling == I915_TILING_X ? 'X' : 'Y'));
1168 
1169 	if (n > ARRAY_SIZE(stack)) {
1170 		clipped = malloc(sizeof(BoxRec) * n);
1171 		if (clipped == NULL)
1172 			goto tiled_error;
1173 	} else
1174 		clipped = stack;
1175 
1176 	p.depth = src->depth;
1177 	p.bitsPerPixel = src->bitsPerPixel;
1178 
1179 	for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) {
1180 		int y2 = tile.y1 + step;
1181 		if (y2 > extents.y2)
1182 			y2 = extents.y2;
1183 		tile.y2 = y2;
1184 
1185 		for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) {
1186 			struct kgem_bo *tmp_bo;
1187 			int x2 = tile.x1 + step;
1188 			if (x2 > extents.x2)
1189 				x2 = extents.x2;
1190 			tile.x2 = x2;
1191 
1192 			c = clipped;
1193 			for (i = 0; i < n; i++) {
1194 				*c = box[i];
1195 				if (!box_intersect(c, &tile))
1196 					continue;
1197 
1198 				DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n",
1199 				     __FUNCTION__,
1200 				     c->x1, c->y1,
1201 				     c->x2, c->y2,
1202 				     src_dx, src_dy,
1203 				     c->x1 - tile.x1,
1204 				     c->y1 - tile.y1));
1205 				c++;
1206 			}
1207 			if (c == clipped)
1208 				continue;
1209 
1210 			p.width  = tile.x2 - tile.x1;
1211 			p.height = tile.y2 - tile.y1;
1212 
1213 			DBG(("%s: tile (%d, %d), (%d, %d)\n",
1214 			     __FUNCTION__, tile.x1, tile.y1, tile.x2, tile.y2));
1215 
1216 			if (create) {
1217 				tmp_bo = kgem_create_2d(&sna->kgem,
1218 							p.width,
1219 							p.height,
1220 							p.bitsPerPixel,
1221 							tiling, CREATE_TEMPORARY);
1222 				if (!tmp_bo)
1223 					goto tiled_error;
1224 
1225 				i = (sna->render.copy_boxes(sna, GXcopy,
1226 							    src, src_bo, src_dx, src_dy,
1227 							    &p, tmp_bo, -tile.x1, -tile.y1,
1228 							    clipped, c - clipped, 0) &&
1229 				     sna->render.copy_boxes(sna, alu,
1230 							    &p, tmp_bo, -tile.x1, -tile.y1,
1231 							    dst, dst_bo, dst_dx, dst_dy,
1232 							    clipped, c - clipped, 0));
1233 
1234 				kgem_bo_destroy(&sna->kgem, tmp_bo);
1235 			} else {
1236 				i = sna->render.copy_boxes(sna, GXcopy,
1237 							   src, src_bo, src_dx, src_dy,
1238 							   dst, dst_bo, dst_dx, dst_dy,
1239 							   clipped, c - clipped, 0);
1240 			}
1241 
1242 			if (!i)
1243 				goto tiled_error;
1244 		}
1245 	}
1246 
1247 	ret = true;
1248 tiled_error:
1249 	if (clipped != stack)
1250 		free(clipped);
1251 
1252 	return ret;
1253 }
1254