sna_tiling.c revision 428d7b3d
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
36struct sna_tile_span {
37	BoxRec box;
38	float opacity;
39};
40
41struct 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
57static void
58sna_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
87fastcall static void
88sna_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
96fastcall static void
97sna_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
114static void
115sna_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
135static void
136sna_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
269done:
270	if (tile->rects != tile->rects_embedded)
271		free(tile->rects);
272	free(tile);
273}
274
275bool
276sna_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
329fastcall static void
330sna_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
366static void
367sna_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->base.priv, box++, opacity);
373	(void)sna;
374}
375
376fastcall static void
377sna_tiling_composite_spans_done(struct sna *sna,
378				const struct sna_composite_spans_op *op)
379{
380	struct sna_tile_state *tile = op->base.priv;
381	struct sna_composite_spans_op tmp;
382	int x, y, n, step, max_size;
383	bool force_fallback = false;
384
385	/* Use a small step to accommodate enlargement through tile alignment */
386	step = sna->render.max_3d_size;
387	if (tile->dst_x & (8*512 / tile->dst->pDrawable->bitsPerPixel - 1) ||
388	    tile->dst_y & 63)
389		step /= 2;
390
391	max_size = sna_max_tile_copy_size(sna, op->base.dst.bo, op->base.dst.bo);
392	if (max_size == 0)
393		goto done;
394
395	while (step * step * 4 > max_size)
396		step /= 2;
397
398	DBG(("%s -- %dx%d, count=%d, step size=%d\n", __FUNCTION__,
399	     tile->width, tile->height, tile->rect_count, step));
400
401	if (tile->rect_count == 0)
402		goto done;
403
404	for (y = 0; y < tile->height; y += step) {
405		int height = step;
406		if (y + height > tile->height)
407			height = tile->height - y;
408		for (x = 0; x < tile->width; x += step) {
409			const struct sna_tile_span *r = (void *)tile->rects;
410			int width = step;
411			if (x + width > tile->width)
412				width = tile->width - x;
413			if (!force_fallback &&
414			    sna->render.composite_spans(sna, tile->op,
415							tile->src, tile->dst,
416							tile->src_x + x,  tile->src_y + y,
417							tile->dst_x + x,  tile->dst_y + y,
418							width, height, tile->flags,
419							memset(&tmp, 0, sizeof(tmp)))) {
420				for (n = 0; n < tile->rect_count; n++) {
421					BoxRec b;
422
423					b.x1 = r->box.x1 - tile->dst_x;
424					if (b.x1 < x)
425						b.x1 = x;
426
427					b.y1 = r->box.y1 - tile->dst_y;
428					if (b.y1 < y)
429						b.y1 = y;
430
431					b.x2 = r->box.x2 - tile->dst_x;
432					if (b.x2 > x + width)
433						b.x2 = x + width;
434
435					b.y2 = r->box.y2 - tile->dst_y;
436					if (b.y2 > y + height)
437						b.y2 = y + height;
438
439					DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d)\n",
440					     __FUNCTION__, n,
441					     r->box.x1, r->box.y1,
442					     r->box.x2-r->box.x1, r->box.y2-r->box.y1,
443					     x, y, width, height,
444					     b.x1, b.y1, b.x2, b.y2));
445
446					if (b.y2 > b.y1 && b.x2 > b.x1)
447						tmp.box(sna, &tmp, &b, r->opacity);
448					r++;
449				}
450				tmp.done(sna, &tmp);
451			} else {
452				unsigned int flags;
453
454				DBG(("%s -- falback\n", __FUNCTION__));
455
456				if (tile->op <= PictOpSrc)
457					flags = MOVE_WRITE;
458				else
459					flags = MOVE_WRITE | MOVE_READ;
460				if (!sna_drawable_move_to_cpu(tile->dst->pDrawable,
461							      flags))
462					goto done;
463				if (tile->dst->alphaMap &&
464				    !sna_drawable_move_to_cpu(tile->dst->alphaMap->pDrawable,
465							      flags))
466					goto done;
467
468				if (tile->src->pDrawable &&
469				    !sna_drawable_move_to_cpu(tile->src->pDrawable,
470							      MOVE_READ))
471					goto done;
472				if (tile->src->alphaMap &&
473				    !sna_drawable_move_to_cpu(tile->src->alphaMap->pDrawable,
474							      MOVE_READ))
475					goto done;
476
477				for (n = 0; n < tile->rect_count; n++) {
478					BoxRec b;
479
480					b.x1 = r->box.x1 - tile->dst_x;
481					if (b.x1 < x)
482						b.x1 = x;
483
484					b.y1 = r->box.y1 - tile->dst_y;
485					if (b.y1 < y)
486						b.y1 = y;
487
488					b.x2 = r->box.x2 - tile->dst_x;
489					if (b.x2 > x + width)
490						b.x2 = x + width;
491
492					b.y2 = r->box.y2 - tile->dst_y;
493					if (b.y2 > y + height)
494						b.y2 = y + height;
495
496					DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d)\n",
497					     __FUNCTION__, n,
498					     r->box.x1, r->box.y1,
499					     r->box.x2-r->box.x1, r->box.y2-r->box.y1,
500					     x, y, width, height,
501					     b.x1, b.y1, b.x2, b.y2));
502
503					if (b.y2 > b.y1 && b.x2 > b.x1) {
504						xRenderColor alpha;
505						PicturePtr mask;
506						int error;
507
508						alpha.red = alpha.green = alpha.blue = 0;
509						alpha.alpha = r->opacity * 0xffff;
510
511						mask = CreateSolidPicture(0, &alpha, &error);
512						if (!mask)
513							goto done;
514
515						if (sigtrap_get() == 0) {
516							fbComposite(tile->op,
517								    tile->src, mask, tile->dst,
518								    tile->src_x + x,  tile->src_y + y,
519								    0, 0,
520								    tile->dst_x + x,  tile->dst_y + y,
521								    width, height);
522							sigtrap_put();
523						}
524
525						FreePicture(mask, 0);
526					}
527					r++;
528				}
529
530				force_fallback = true;
531			}
532		}
533	}
534
535done:
536	if (tile->rects != tile->rects_embedded)
537		free(tile->rects);
538	free(tile);
539}
540
541bool
542sna_tiling_composite_spans(uint32_t op,
543			   PicturePtr src,
544			   PicturePtr dst,
545			   int16_t src_x,  int16_t src_y,
546			   int16_t dst_x,  int16_t dst_y,
547			   int16_t width,  int16_t height,
548			   unsigned flags,
549			   struct sna_composite_spans_op *tmp)
550{
551	struct sna_tile_state *tile;
552	struct sna_pixmap *priv;
553
554	DBG(("%s size=(%d, %d), tile=%d\n",
555	     __FUNCTION__, width, height,
556	     to_sna_from_drawable(dst->pDrawable)->render.max_3d_size));
557
558	priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable));
559	if (priv == NULL || priv->gpu_bo == NULL)
560		return false;
561
562	tile = malloc(sizeof(*tile));
563	if (!tile)
564		return false;
565
566	tile->op = op;
567	tile->flags = flags;
568
569	tile->src  = src;
570	tile->mask = NULL;
571	tile->dst  = dst;
572
573	tile->src_x = src_x;
574	tile->src_y = src_y;
575	tile->mask_x = 0;
576	tile->mask_y = 0;
577	tile->dst_x = dst_x;
578	tile->dst_y = dst_y;
579	tile->width = width;
580	tile->height = height;
581	tile->rects = tile->rects_embedded;
582	tile->rect_count = 0;
583	tile->rect_size = ARRAY_SIZE(tile->rects_embedded);
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
594bool
595sna_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;
700err:
701	kgem_bo_destroy(&sna->kgem, bo);
702	RegionUninit(&this);
703done:
704	pixman_region_fini(&region);
705	return ret;
706}
707
708fastcall static void
709tiling_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
759fastcall static void
760tiling_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
773static void
774tiling_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
786static bool
787sna_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;
891err:
892	kgem_bo_destroy(&sna->kgem, bo);
893	RegionUninit(&this);
894done:
895	pixman_region_fini(&region);
896	return ret;
897}
898
899fastcall static void
900tiling_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
950fastcall static void
951tiling_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
964static void
965tiling_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
977static 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
983bool
984sna_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
1012bool 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;
1117err:
1118	kgem_bo_destroy(&sna->kgem, bo);
1119	RegionUninit(&this);
1120done:
1121	pixman_region_fini(&region);
1122	return ret;
1123}
1124
1125bool
1126sna_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;
1248tiled_error:
1249	if (clipped != stack)
1250		free(clipped);
1251
1252	return ret;
1253}
1254