103b705cfSriastradh/*
203b705cfSriastradh * Copyright © 2010 Intel Corporation
303b705cfSriastradh *
403b705cfSriastradh * Permission is hereby granted, free of charge, to any person obtaining a
503b705cfSriastradh * copy of this software and associated documentation files (the "Software"),
603b705cfSriastradh * to deal in the Software without restriction, including without limitation
703b705cfSriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense,
803b705cfSriastradh * and/or sell copies of the Software, and to permit persons to whom the
903b705cfSriastradh * Software is furnished to do so, subject to the following conditions:
1003b705cfSriastradh *
1103b705cfSriastradh * The above copyright notice and this permission notice (including the next
1203b705cfSriastradh * paragraph) shall be included in all copies or substantial portions of the
1303b705cfSriastradh * Software.
1403b705cfSriastradh *
1503b705cfSriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1603b705cfSriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1703b705cfSriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1803b705cfSriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1903b705cfSriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2003b705cfSriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2103b705cfSriastradh * SOFTWARE.
2203b705cfSriastradh *
2303b705cfSriastradh * Authors:
2403b705cfSriastradh *    Chris Wilson <chris@chris-wilson.co.uk>
2503b705cfSriastradh *
2603b705cfSriastradh */
2703b705cfSriastradh
2803b705cfSriastradh#ifdef HAVE_CONFIG_H
2903b705cfSriastradh#include "config.h"
3003b705cfSriastradh#endif
3103b705cfSriastradh
3203b705cfSriastradh#include "sna.h"
3303b705cfSriastradh#include "sna_render.h"
3403b705cfSriastradh#include "fb/fbpict.h"
3503b705cfSriastradh
3603b705cfSriastradhstruct sna_tile_span {
3703b705cfSriastradh	BoxRec box;
3803b705cfSriastradh	float opacity;
3903b705cfSriastradh};
4003b705cfSriastradh
4103b705cfSriastradhstruct sna_tile_state {
4203b705cfSriastradh	int op;
4303b705cfSriastradh	PicturePtr src, mask, dst;
4403b705cfSriastradh	PixmapPtr dst_pixmap;
4503b705cfSriastradh	uint32_t dst_format;
4603b705cfSriastradh	int16_t src_x, src_y;
4703b705cfSriastradh	int16_t mask_x, mask_y;
4803b705cfSriastradh	int16_t dst_x, dst_y;
4903b705cfSriastradh	int16_t width, height;
5003b705cfSriastradh	unsigned flags;
5103b705cfSriastradh
5203b705cfSriastradh	int rect_count;
5303b705cfSriastradh	int rect_size;
5403b705cfSriastradh	struct sna_composite_rectangles rects_embedded[16], *rects;
5503b705cfSriastradh};
5603b705cfSriastradh
5703b705cfSriastradhstatic void
5803b705cfSriastradhsna_tiling_composite_add_rect(struct sna_tile_state *tile,
5903b705cfSriastradh			      const struct sna_composite_rectangles *r)
6003b705cfSriastradh{
6103b705cfSriastradh	if (tile->rect_count == tile->rect_size) {
6203b705cfSriastradh		struct sna_composite_rectangles *a;
6303b705cfSriastradh		int newsize = tile->rect_size * 2;
6403b705cfSriastradh
6503b705cfSriastradh		if (tile->rects == tile->rects_embedded) {
6603b705cfSriastradh			a = malloc (sizeof(struct sna_composite_rectangles) * newsize);
6703b705cfSriastradh			if (a == NULL)
6803b705cfSriastradh				return;
6903b705cfSriastradh
7003b705cfSriastradh			memcpy(a,
7103b705cfSriastradh			       tile->rects_embedded,
7203b705cfSriastradh			       sizeof(struct sna_composite_rectangles) * tile->rect_count);
7303b705cfSriastradh		} else {
7403b705cfSriastradh			a = realloc(tile->rects,
7503b705cfSriastradh				    sizeof(struct sna_composite_rectangles) * newsize);
7603b705cfSriastradh			if (a == NULL)
7703b705cfSriastradh				return;
7803b705cfSriastradh		}
7903b705cfSriastradh
8003b705cfSriastradh		tile->rects = a;
8103b705cfSriastradh		tile->rect_size = newsize;
8203b705cfSriastradh	}
8303b705cfSriastradh
8403b705cfSriastradh	tile->rects[tile->rect_count++] = *r;
8503b705cfSriastradh}
8603b705cfSriastradh
8703b705cfSriastradhfastcall static void
8803b705cfSriastradhsna_tiling_composite_blt(struct sna *sna,
8903b705cfSriastradh			 const struct sna_composite_op *op,
9003b705cfSriastradh			 const struct sna_composite_rectangles *r)
9103b705cfSriastradh{
9203b705cfSriastradh	sna_tiling_composite_add_rect(op->priv, r);
9303b705cfSriastradh	(void)sna;
9403b705cfSriastradh}
9503b705cfSriastradh
9603b705cfSriastradhfastcall static void
9703b705cfSriastradhsna_tiling_composite_box(struct sna *sna,
9803b705cfSriastradh			 const struct sna_composite_op *op,
9903b705cfSriastradh			 const BoxRec *box)
10003b705cfSriastradh{
10103b705cfSriastradh	struct sna_composite_rectangles r;
10203b705cfSriastradh
10303b705cfSriastradh	r.dst.x = box->x1;
10403b705cfSriastradh	r.dst.y = box->y1;
10503b705cfSriastradh	r.mask = r.src = r.dst;
10603b705cfSriastradh
10703b705cfSriastradh	r.width  = box->x2 - box->x1;
10803b705cfSriastradh	r.height = box->y2 - box->y1;
10903b705cfSriastradh
11003b705cfSriastradh	sna_tiling_composite_add_rect(op->priv, &r);
11103b705cfSriastradh	(void)sna;
11203b705cfSriastradh}
11303b705cfSriastradh
11403b705cfSriastradhstatic void
11503b705cfSriastradhsna_tiling_composite_boxes(struct sna *sna,
11603b705cfSriastradh			   const struct sna_composite_op *op,
11703b705cfSriastradh			   const BoxRec *box, int nbox)
11803b705cfSriastradh{
11903b705cfSriastradh	while (nbox--) {
12003b705cfSriastradh		struct sna_composite_rectangles r;
12103b705cfSriastradh
12203b705cfSriastradh		r.dst.x = box->x1;
12303b705cfSriastradh		r.dst.y = box->y1;
12403b705cfSriastradh		r.mask = r.src = r.dst;
12503b705cfSriastradh
12603b705cfSriastradh		r.width  = box->x2 - box->x1;
12703b705cfSriastradh		r.height = box->y2 - box->y1;
12803b705cfSriastradh
12903b705cfSriastradh		sna_tiling_composite_add_rect(op->priv, &r);
13003b705cfSriastradh		box++;
13103b705cfSriastradh	}
13203b705cfSriastradh	(void)sna;
13303b705cfSriastradh}
13403b705cfSriastradh
13503b705cfSriastradhstatic void
13603b705cfSriastradhsna_tiling_composite_done(struct sna *sna,
13703b705cfSriastradh			  const struct sna_composite_op *op)
13803b705cfSriastradh{
13903b705cfSriastradh	struct sna_tile_state *tile = op->priv;
14003b705cfSriastradh	struct sna_composite_op tmp;
14142542f5fSchristos	int x, y, n, step, max_size;
14203b705cfSriastradh
14303b705cfSriastradh	/* Use a small step to accommodate enlargement through tile alignment */
14403b705cfSriastradh	step = sna->render.max_3d_size;
14503b705cfSriastradh	if (tile->dst_x & (8*512 / tile->dst->pDrawable->bitsPerPixel - 1) ||
14603b705cfSriastradh	    tile->dst_y & 63)
14703b705cfSriastradh		step /= 2;
14842542f5fSchristos
14942542f5fSchristos	max_size = sna_max_tile_copy_size(sna, op->dst.bo, op->dst.bo);
15042542f5fSchristos	if (max_size == 0)
15142542f5fSchristos		goto done;
15242542f5fSchristos
15342542f5fSchristos	while (step * step * 4 > max_size)
15403b705cfSriastradh		step /= 2;
15503b705cfSriastradh
15603b705cfSriastradh	DBG(("%s -- %dx%d, count=%d, step size=%d\n", __FUNCTION__,
15703b705cfSriastradh	     tile->width, tile->height, tile->rect_count, step));
15803b705cfSriastradh
15903b705cfSriastradh	if (tile->rect_count == 0)
16003b705cfSriastradh		goto done;
16103b705cfSriastradh
16203b705cfSriastradh	for (y = 0; y < tile->height; y += step) {
16303b705cfSriastradh		int height = step;
16403b705cfSriastradh		if (y + height > tile->height)
16503b705cfSriastradh			height = tile->height - y;
16603b705cfSriastradh		for (x = 0; x < tile->width; x += step) {
16703b705cfSriastradh			int width = step;
16803b705cfSriastradh			if (x + width > tile->width)
16903b705cfSriastradh				width = tile->width - x;
17003b705cfSriastradh			if (sna->render.composite(sna, tile->op,
17103b705cfSriastradh						  tile->src, tile->mask, tile->dst,
17203b705cfSriastradh						  tile->src_x + x,  tile->src_y + y,
17303b705cfSriastradh						  tile->mask_x + x, tile->mask_y + y,
17403b705cfSriastradh						  tile->dst_x + x,  tile->dst_y + y,
17503b705cfSriastradh						  width, height,
17642542f5fSchristos						  COMPOSITE_PARTIAL, memset(&tmp, 0, sizeof(tmp)))) {
17703b705cfSriastradh				for (n = 0; n < tile->rect_count; n++) {
17803b705cfSriastradh					const struct sna_composite_rectangles *r = &tile->rects[n];
17903b705cfSriastradh					int x1, x2, dx, y1, y2, dy;
18003b705cfSriastradh
18103b705cfSriastradh					x1 = r->dst.x - tile->dst_x, dx = 0;
18203b705cfSriastradh					if (x1 < x)
18303b705cfSriastradh						dx = x - x1, x1 = x;
18403b705cfSriastradh					y1 = r->dst.y - tile->dst_y, dy = 0;
18503b705cfSriastradh					if (y1 < y)
18603b705cfSriastradh						dy = y - y1, y1 = y;
18703b705cfSriastradh
18803b705cfSriastradh					x2 = r->dst.x + r->width - tile->dst_x;
18903b705cfSriastradh					if (x2 > x + width)
19003b705cfSriastradh						x2 = x + width;
19103b705cfSriastradh					y2 = r->dst.y + r->height - tile->dst_y;
19203b705cfSriastradh					if (y2 > y + height)
19303b705cfSriastradh						y2 = y + height;
19403b705cfSriastradh
19503b705cfSriastradh					DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d), delta=(%d,%d)\n",
19603b705cfSriastradh					     __FUNCTION__, n,
19703b705cfSriastradh					     r->dst.x, r->dst.y,
19803b705cfSriastradh					     r->width, r->height,
19903b705cfSriastradh					     x, y, width, height,
20003b705cfSriastradh					     x1, y1, x2, y2,
20103b705cfSriastradh					     dx, dy));
20203b705cfSriastradh
20303b705cfSriastradh					if (y2 > y1 && x2 > x1) {
20403b705cfSriastradh						struct sna_composite_rectangles rr;
20503b705cfSriastradh						rr.src.x = dx + r->src.x;
20603b705cfSriastradh						rr.src.y = dy + r->src.y;
20703b705cfSriastradh
20803b705cfSriastradh						rr.mask.x = dx + r->mask.x;
20903b705cfSriastradh						rr.mask.y = dy + r->mask.y;
21003b705cfSriastradh
21103b705cfSriastradh						rr.dst.x = dx + r->dst.x;
21203b705cfSriastradh						rr.dst.y = dy + r->dst.y;
21303b705cfSriastradh
21403b705cfSriastradh						rr.width  = x2 - x1;
21503b705cfSriastradh						rr.height = y2 - y1;
21603b705cfSriastradh
21703b705cfSriastradh						tmp.blt(sna, &tmp, &rr);
21803b705cfSriastradh					}
21903b705cfSriastradh				}
22003b705cfSriastradh				tmp.done(sna, &tmp);
22103b705cfSriastradh			} else {
22203b705cfSriastradh				unsigned int flags;
22303b705cfSriastradh				DBG(("%s -- falback\n", __FUNCTION__));
22403b705cfSriastradh
22503b705cfSriastradh				if (tile->op <= PictOpSrc)
22603b705cfSriastradh					flags = MOVE_WRITE;
22703b705cfSriastradh				else
22803b705cfSriastradh					flags = MOVE_WRITE | MOVE_READ;
22903b705cfSriastradh				if (!sna_drawable_move_to_cpu(tile->dst->pDrawable,
23003b705cfSriastradh							      flags))
23103b705cfSriastradh					goto done;
23203b705cfSriastradh				if (tile->dst->alphaMap &&
23303b705cfSriastradh				    !sna_drawable_move_to_cpu(tile->dst->alphaMap->pDrawable,
23403b705cfSriastradh							      flags))
23503b705cfSriastradh					goto done;
23603b705cfSriastradh
23703b705cfSriastradh				if (tile->src->pDrawable &&
23803b705cfSriastradh				    !sna_drawable_move_to_cpu(tile->src->pDrawable,
23903b705cfSriastradh							      MOVE_READ))
24003b705cfSriastradh					goto done;
24103b705cfSriastradh				if (tile->src->alphaMap &&
24203b705cfSriastradh				    !sna_drawable_move_to_cpu(tile->src->alphaMap->pDrawable,
24303b705cfSriastradh							      MOVE_READ))
24403b705cfSriastradh					goto done;
24503b705cfSriastradh
24603b705cfSriastradh				if (tile->mask && tile->mask->pDrawable &&
24703b705cfSriastradh				    !sna_drawable_move_to_cpu(tile->mask->pDrawable,
24803b705cfSriastradh							      MOVE_READ))
24903b705cfSriastradh					goto done;
25003b705cfSriastradh
25103b705cfSriastradh				if (tile->mask && tile->mask->alphaMap &&
25203b705cfSriastradh				    !sna_drawable_move_to_cpu(tile->mask->alphaMap->pDrawable,
25303b705cfSriastradh							      MOVE_READ))
25403b705cfSriastradh					goto done;
25503b705cfSriastradh
25642542f5fSchristos				if (sigtrap_get() == 0) {
25742542f5fSchristos					fbComposite(tile->op,
25842542f5fSchristos						    tile->src, tile->mask, tile->dst,
25942542f5fSchristos						    tile->src_x + x,  tile->src_y + y,
26042542f5fSchristos						    tile->mask_x + x, tile->mask_y + y,
26142542f5fSchristos						    tile->dst_x + x,  tile->dst_y + y,
26242542f5fSchristos						    width, height);
26342542f5fSchristos					sigtrap_put();
26442542f5fSchristos				}
26503b705cfSriastradh			}
26603b705cfSriastradh		}
26703b705cfSriastradh	}
26803b705cfSriastradh
26903b705cfSriastradhdone:
27003b705cfSriastradh	if (tile->rects != tile->rects_embedded)
27103b705cfSriastradh		free(tile->rects);
27203b705cfSriastradh	free(tile);
27303b705cfSriastradh}
27403b705cfSriastradh
27503b705cfSriastradhbool
27603b705cfSriastradhsna_tiling_composite(uint32_t op,
27703b705cfSriastradh		     PicturePtr src,
27803b705cfSriastradh		     PicturePtr mask,
27903b705cfSriastradh		     PicturePtr dst,
28003b705cfSriastradh		     int16_t src_x,  int16_t src_y,
28103b705cfSriastradh		     int16_t mask_x, int16_t mask_y,
28203b705cfSriastradh		     int16_t dst_x,  int16_t dst_y,
28303b705cfSriastradh		     int16_t width,  int16_t height,
28403b705cfSriastradh		     struct sna_composite_op *tmp)
28503b705cfSriastradh{
28603b705cfSriastradh	struct sna_tile_state *tile;
28703b705cfSriastradh	struct sna_pixmap *priv;
28803b705cfSriastradh
28903b705cfSriastradh	DBG(("%s size=(%d, %d), tile=%d\n",
29003b705cfSriastradh	     __FUNCTION__, width, height,
29103b705cfSriastradh	     to_sna_from_drawable(dst->pDrawable)->render.max_3d_size));
29203b705cfSriastradh
29303b705cfSriastradh	priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable));
29403b705cfSriastradh	if (priv == NULL || priv->gpu_bo == NULL)
29503b705cfSriastradh		return false;
29603b705cfSriastradh
29703b705cfSriastradh	tile = malloc(sizeof(*tile));
29803b705cfSriastradh	if (!tile)
29903b705cfSriastradh		return false;
30003b705cfSriastradh
30103b705cfSriastradh	tile->op = op;
30203b705cfSriastradh
30303b705cfSriastradh	tile->src  = src;
30403b705cfSriastradh	tile->mask = mask;
30503b705cfSriastradh	tile->dst  = dst;
30603b705cfSriastradh
30703b705cfSriastradh	tile->src_x = src_x;
30803b705cfSriastradh	tile->src_y = src_y;
30903b705cfSriastradh	tile->mask_x = mask_x;
31003b705cfSriastradh	tile->mask_y = mask_y;
31103b705cfSriastradh	tile->dst_x = dst_x;
31203b705cfSriastradh	tile->dst_y = dst_y;
31303b705cfSriastradh	tile->width = width;
31403b705cfSriastradh	tile->height = height;
31503b705cfSriastradh	tile->rects = tile->rects_embedded;
31603b705cfSriastradh	tile->rect_count = 0;
31703b705cfSriastradh	tile->rect_size = ARRAY_SIZE(tile->rects_embedded);
31803b705cfSriastradh
31903b705cfSriastradh	tmp->blt   = sna_tiling_composite_blt;
32003b705cfSriastradh	tmp->box   = sna_tiling_composite_box;
32103b705cfSriastradh	tmp->boxes = sna_tiling_composite_boxes;
32203b705cfSriastradh	tmp->done  = sna_tiling_composite_done;
32303b705cfSriastradh
32403b705cfSriastradh	tmp->priv = tile;
32542542f5fSchristos	tmp->dst.bo = priv->gpu_bo;
32603b705cfSriastradh	return true;
32703b705cfSriastradh}
32803b705cfSriastradh
32903b705cfSriastradhfastcall static void
33003b705cfSriastradhsna_tiling_composite_spans_box(struct sna *sna,
33103b705cfSriastradh			       const struct sna_composite_spans_op *op,
33203b705cfSriastradh			       const BoxRec *box, float opacity)
33303b705cfSriastradh{
33403b705cfSriastradh	struct sna_tile_state *tile = op->base.priv;
33503b705cfSriastradh	struct sna_tile_span *a;
33603b705cfSriastradh
33703b705cfSriastradh	if (tile->rect_count == tile->rect_size) {
33803b705cfSriastradh		int newsize = tile->rect_size * 2;
33903b705cfSriastradh
34003b705cfSriastradh		if (tile->rects == tile->rects_embedded) {
34103b705cfSriastradh			a = malloc (sizeof(struct sna_tile_span) * newsize);
34203b705cfSriastradh			if (a == NULL)
34303b705cfSriastradh				return;
34403b705cfSriastradh
34503b705cfSriastradh			memcpy(a,
34603b705cfSriastradh			       tile->rects_embedded,
34703b705cfSriastradh			       sizeof(struct sna_tile_span) * tile->rect_count);
34803b705cfSriastradh		} else {
34903b705cfSriastradh			a = realloc(tile->rects,
35003b705cfSriastradh				    sizeof(struct sna_tile_span) * newsize);
35103b705cfSriastradh			if (a == NULL)
35203b705cfSriastradh				return;
35303b705cfSriastradh		}
35403b705cfSriastradh
35503b705cfSriastradh		tile->rects = (void *)a;
35603b705cfSriastradh		tile->rect_size = newsize;
35703b705cfSriastradh	} else
35803b705cfSriastradh		a = (void *)tile->rects;
35903b705cfSriastradh
36003b705cfSriastradh	a[tile->rect_count].box = *box;
36103b705cfSriastradh	a[tile->rect_count].opacity = opacity;
36203b705cfSriastradh	tile->rect_count++;
36303b705cfSriastradh	(void)sna;
36403b705cfSriastradh}
36503b705cfSriastradh
36603b705cfSriastradhstatic void
36703b705cfSriastradhsna_tiling_composite_spans_boxes(struct sna *sna,
36803b705cfSriastradh				 const struct sna_composite_spans_op *op,
36903b705cfSriastradh				 const BoxRec *box, int nbox, float opacity)
37003b705cfSriastradh{
37103b705cfSriastradh	while (nbox--)
372fe8aea9eSmrg		sna_tiling_composite_spans_box(sna, op, box++, opacity);
37303b705cfSriastradh}
37403b705cfSriastradh
37503b705cfSriastradhfastcall static void
37603b705cfSriastradhsna_tiling_composite_spans_done(struct sna *sna,
37703b705cfSriastradh				const struct sna_composite_spans_op *op)
37803b705cfSriastradh{
37903b705cfSriastradh	struct sna_tile_state *tile = op->base.priv;
38003b705cfSriastradh	struct sna_composite_spans_op tmp;
38142542f5fSchristos	int x, y, n, step, max_size;
38203b705cfSriastradh	bool force_fallback = false;
38303b705cfSriastradh
38403b705cfSriastradh	/* Use a small step to accommodate enlargement through tile alignment */
38503b705cfSriastradh	step = sna->render.max_3d_size;
38603b705cfSriastradh	if (tile->dst_x & (8*512 / tile->dst->pDrawable->bitsPerPixel - 1) ||
38703b705cfSriastradh	    tile->dst_y & 63)
38803b705cfSriastradh		step /= 2;
38942542f5fSchristos
39042542f5fSchristos	max_size = sna_max_tile_copy_size(sna, op->base.dst.bo, op->base.dst.bo);
39142542f5fSchristos	if (max_size == 0)
39242542f5fSchristos		goto done;
39342542f5fSchristos
39442542f5fSchristos	while (step * step * 4 > max_size)
39503b705cfSriastradh		step /= 2;
39603b705cfSriastradh
39703b705cfSriastradh	DBG(("%s -- %dx%d, count=%d, step size=%d\n", __FUNCTION__,
39803b705cfSriastradh	     tile->width, tile->height, tile->rect_count, step));
39903b705cfSriastradh
40003b705cfSriastradh	if (tile->rect_count == 0)
40103b705cfSriastradh		goto done;
40203b705cfSriastradh
40303b705cfSriastradh	for (y = 0; y < tile->height; y += step) {
40403b705cfSriastradh		int height = step;
40503b705cfSriastradh		if (y + height > tile->height)
40603b705cfSriastradh			height = tile->height - y;
40703b705cfSriastradh		for (x = 0; x < tile->width; x += step) {
40803b705cfSriastradh			const struct sna_tile_span *r = (void *)tile->rects;
40903b705cfSriastradh			int width = step;
41003b705cfSriastradh			if (x + width > tile->width)
41103b705cfSriastradh				width = tile->width - x;
41203b705cfSriastradh			if (!force_fallback &&
41303b705cfSriastradh			    sna->render.composite_spans(sna, tile->op,
41403b705cfSriastradh							tile->src, tile->dst,
41503b705cfSriastradh							tile->src_x + x,  tile->src_y + y,
41603b705cfSriastradh							tile->dst_x + x,  tile->dst_y + y,
41703b705cfSriastradh							width, height, tile->flags,
41803b705cfSriastradh							memset(&tmp, 0, sizeof(tmp)))) {
41903b705cfSriastradh				for (n = 0; n < tile->rect_count; n++) {
42003b705cfSriastradh					BoxRec b;
42103b705cfSriastradh
42203b705cfSriastradh					b.x1 = r->box.x1 - tile->dst_x;
42303b705cfSriastradh					if (b.x1 < x)
42403b705cfSriastradh						b.x1 = x;
42503b705cfSriastradh
42603b705cfSriastradh					b.y1 = r->box.y1 - tile->dst_y;
42703b705cfSriastradh					if (b.y1 < y)
42803b705cfSriastradh						b.y1 = y;
42903b705cfSriastradh
43003b705cfSriastradh					b.x2 = r->box.x2 - tile->dst_x;
43103b705cfSriastradh					if (b.x2 > x + width)
43203b705cfSriastradh						b.x2 = x + width;
43303b705cfSriastradh
43403b705cfSriastradh					b.y2 = r->box.y2 - tile->dst_y;
43503b705cfSriastradh					if (b.y2 > y + height)
43603b705cfSriastradh						b.y2 = y + height;
43703b705cfSriastradh
43803b705cfSriastradh					DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d)\n",
43903b705cfSriastradh					     __FUNCTION__, n,
44003b705cfSriastradh					     r->box.x1, r->box.y1,
44103b705cfSriastradh					     r->box.x2-r->box.x1, r->box.y2-r->box.y1,
44203b705cfSriastradh					     x, y, width, height,
44303b705cfSriastradh					     b.x1, b.y1, b.x2, b.y2));
44403b705cfSriastradh
44503b705cfSriastradh					if (b.y2 > b.y1 && b.x2 > b.x1)
44603b705cfSriastradh						tmp.box(sna, &tmp, &b, r->opacity);
44703b705cfSriastradh					r++;
44803b705cfSriastradh				}
44903b705cfSriastradh				tmp.done(sna, &tmp);
45003b705cfSriastradh			} else {
45103b705cfSriastradh				unsigned int flags;
45203b705cfSriastradh
45303b705cfSriastradh				DBG(("%s -- falback\n", __FUNCTION__));
45403b705cfSriastradh
45503b705cfSriastradh				if (tile->op <= PictOpSrc)
45603b705cfSriastradh					flags = MOVE_WRITE;
45703b705cfSriastradh				else
45803b705cfSriastradh					flags = MOVE_WRITE | MOVE_READ;
45903b705cfSriastradh				if (!sna_drawable_move_to_cpu(tile->dst->pDrawable,
46003b705cfSriastradh							      flags))
46103b705cfSriastradh					goto done;
46203b705cfSriastradh				if (tile->dst->alphaMap &&
46303b705cfSriastradh				    !sna_drawable_move_to_cpu(tile->dst->alphaMap->pDrawable,
46403b705cfSriastradh							      flags))
46503b705cfSriastradh					goto done;
46603b705cfSriastradh
46703b705cfSriastradh				if (tile->src->pDrawable &&
46803b705cfSriastradh				    !sna_drawable_move_to_cpu(tile->src->pDrawable,
46903b705cfSriastradh							      MOVE_READ))
47003b705cfSriastradh					goto done;
47103b705cfSriastradh				if (tile->src->alphaMap &&
47203b705cfSriastradh				    !sna_drawable_move_to_cpu(tile->src->alphaMap->pDrawable,
47303b705cfSriastradh							      MOVE_READ))
47403b705cfSriastradh					goto done;
47503b705cfSriastradh
47603b705cfSriastradh				for (n = 0; n < tile->rect_count; n++) {
47703b705cfSriastradh					BoxRec b;
47803b705cfSriastradh
47903b705cfSriastradh					b.x1 = r->box.x1 - tile->dst_x;
48003b705cfSriastradh					if (b.x1 < x)
48103b705cfSriastradh						b.x1 = x;
48203b705cfSriastradh
48303b705cfSriastradh					b.y1 = r->box.y1 - tile->dst_y;
48403b705cfSriastradh					if (b.y1 < y)
48503b705cfSriastradh						b.y1 = y;
48603b705cfSriastradh
48703b705cfSriastradh					b.x2 = r->box.x2 - tile->dst_x;
48803b705cfSriastradh					if (b.x2 > x + width)
48903b705cfSriastradh						b.x2 = x + width;
49003b705cfSriastradh
49103b705cfSriastradh					b.y2 = r->box.y2 - tile->dst_y;
49203b705cfSriastradh					if (b.y2 > y + height)
49303b705cfSriastradh						b.y2 = y + height;
49403b705cfSriastradh
49503b705cfSriastradh					DBG(("%s: rect[%d] = (%d, %d)x(%d,%d), tile=(%d,%d)x(%d, %d), blt=(%d,%d),(%d,%d)\n",
49603b705cfSriastradh					     __FUNCTION__, n,
49703b705cfSriastradh					     r->box.x1, r->box.y1,
49803b705cfSriastradh					     r->box.x2-r->box.x1, r->box.y2-r->box.y1,
49903b705cfSriastradh					     x, y, width, height,
50003b705cfSriastradh					     b.x1, b.y1, b.x2, b.y2));
50103b705cfSriastradh
50203b705cfSriastradh					if (b.y2 > b.y1 && b.x2 > b.x1) {
50303b705cfSriastradh						xRenderColor alpha;
50403b705cfSriastradh						PicturePtr mask;
50503b705cfSriastradh						int error;
50603b705cfSriastradh
50703b705cfSriastradh						alpha.red = alpha.green = alpha.blue = 0;
50803b705cfSriastradh						alpha.alpha = r->opacity * 0xffff;
50903b705cfSriastradh
51003b705cfSriastradh						mask = CreateSolidPicture(0, &alpha, &error);
51103b705cfSriastradh						if (!mask)
51203b705cfSriastradh							goto done;
51303b705cfSriastradh
51442542f5fSchristos						if (sigtrap_get() == 0) {
51542542f5fSchristos							fbComposite(tile->op,
51642542f5fSchristos								    tile->src, mask, tile->dst,
51742542f5fSchristos								    tile->src_x + x,  tile->src_y + y,
51842542f5fSchristos								    0, 0,
51942542f5fSchristos								    tile->dst_x + x,  tile->dst_y + y,
52042542f5fSchristos								    width, height);
52142542f5fSchristos							sigtrap_put();
52242542f5fSchristos						}
52303b705cfSriastradh
52403b705cfSriastradh						FreePicture(mask, 0);
52503b705cfSriastradh					}
52603b705cfSriastradh					r++;
52703b705cfSriastradh				}
52803b705cfSriastradh
52903b705cfSriastradh				force_fallback = true;
53003b705cfSriastradh			}
53103b705cfSriastradh		}
53203b705cfSriastradh	}
53303b705cfSriastradh
53403b705cfSriastradhdone:
53503b705cfSriastradh	if (tile->rects != tile->rects_embedded)
53603b705cfSriastradh		free(tile->rects);
53703b705cfSriastradh	free(tile);
53803b705cfSriastradh}
53903b705cfSriastradh
54003b705cfSriastradhbool
54103b705cfSriastradhsna_tiling_composite_spans(uint32_t op,
54203b705cfSriastradh			   PicturePtr src,
54303b705cfSriastradh			   PicturePtr dst,
54403b705cfSriastradh			   int16_t src_x,  int16_t src_y,
54503b705cfSriastradh			   int16_t dst_x,  int16_t dst_y,
54603b705cfSriastradh			   int16_t width,  int16_t height,
54703b705cfSriastradh			   unsigned flags,
54803b705cfSriastradh			   struct sna_composite_spans_op *tmp)
54903b705cfSriastradh{
55003b705cfSriastradh	struct sna_tile_state *tile;
55103b705cfSriastradh	struct sna_pixmap *priv;
55203b705cfSriastradh
55303b705cfSriastradh	DBG(("%s size=(%d, %d), tile=%d\n",
55403b705cfSriastradh	     __FUNCTION__, width, height,
55503b705cfSriastradh	     to_sna_from_drawable(dst->pDrawable)->render.max_3d_size));
55603b705cfSriastradh
55703b705cfSriastradh	priv = sna_pixmap(get_drawable_pixmap(dst->pDrawable));
55803b705cfSriastradh	if (priv == NULL || priv->gpu_bo == NULL)
55903b705cfSriastradh		return false;
56003b705cfSriastradh
56103b705cfSriastradh	tile = malloc(sizeof(*tile));
56203b705cfSriastradh	if (!tile)
56303b705cfSriastradh		return false;
56403b705cfSriastradh
56503b705cfSriastradh	tile->op = op;
56603b705cfSriastradh	tile->flags = flags;
56703b705cfSriastradh
56803b705cfSriastradh	tile->src  = src;
56903b705cfSriastradh	tile->mask = NULL;
57003b705cfSriastradh	tile->dst  = dst;
57103b705cfSriastradh
57203b705cfSriastradh	tile->src_x = src_x;
57303b705cfSriastradh	tile->src_y = src_y;
57403b705cfSriastradh	tile->mask_x = 0;
57503b705cfSriastradh	tile->mask_y = 0;
57603b705cfSriastradh	tile->dst_x = dst_x;
57703b705cfSriastradh	tile->dst_y = dst_y;
57803b705cfSriastradh	tile->width = width;
57903b705cfSriastradh	tile->height = height;
58003b705cfSriastradh	tile->rects = tile->rects_embedded;
58103b705cfSriastradh	tile->rect_count = 0;
58203b705cfSriastradh	tile->rect_size = ARRAY_SIZE(tile->rects_embedded);
583fe8aea9eSmrg	COMPILE_TIME_ASSERT(sizeof(tile->rects_embedded[0]) >= sizeof(struct sna_tile_span));
58403b705cfSriastradh
58503b705cfSriastradh	tmp->box   = sna_tiling_composite_spans_box;
58603b705cfSriastradh	tmp->boxes = sna_tiling_composite_spans_boxes;
58703b705cfSriastradh	tmp->done  = sna_tiling_composite_spans_done;
58803b705cfSriastradh
58903b705cfSriastradh	tmp->base.priv = tile;
59042542f5fSchristos	tmp->base.dst.bo = priv->gpu_bo;
59103b705cfSriastradh	return true;
59203b705cfSriastradh}
59303b705cfSriastradh
59403b705cfSriastradhbool
59503b705cfSriastradhsna_tiling_fill_boxes(struct sna *sna,
59603b705cfSriastradh		      CARD8 op,
59703b705cfSriastradh		      PictFormat format,
59803b705cfSriastradh		      const xRenderColor *color,
59942542f5fSchristos		      const DrawableRec *dst, struct kgem_bo *dst_bo,
60003b705cfSriastradh		      const BoxRec *box, int n)
60103b705cfSriastradh{
60203b705cfSriastradh	RegionRec region, tile, this;
60303b705cfSriastradh	struct kgem_bo *bo;
60442542f5fSchristos	int step, max_size;
60503b705cfSriastradh	bool ret = false;
60603b705cfSriastradh
60703b705cfSriastradh	pixman_region_init_rects(&region, box, n);
60803b705cfSriastradh
60903b705cfSriastradh	/* Use a small step to accommodate enlargement through tile alignment */
61003b705cfSriastradh	step = sna->render.max_3d_size;
61142542f5fSchristos	if (region.extents.x1 & (8*512 / dst->bitsPerPixel - 1) ||
61203b705cfSriastradh	    region.extents.y1 & 63)
61303b705cfSriastradh		step /= 2;
61442542f5fSchristos
61542542f5fSchristos	max_size = sna_max_tile_copy_size(sna, dst_bo, dst_bo);
61642542f5fSchristos	if (max_size == 0)
61742542f5fSchristos		goto done;
61842542f5fSchristos
61942542f5fSchristos	while (step * step * 4 > max_size)
62003b705cfSriastradh		step /= 2;
62103b705cfSriastradh
62203b705cfSriastradh	DBG(("%s (op=%d, format=%x, color=(%04x,%04x,%04x, %04x), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n",
62303b705cfSriastradh	     __FUNCTION__, op, (int)format,
62403b705cfSriastradh	     color->red, color->green, color->blue, color->alpha,
62503b705cfSriastradh	     step, n,
62603b705cfSriastradh	     region.extents.x1, region.extents.y1,
62703b705cfSriastradh	     region.extents.x2, region.extents.y2));
62803b705cfSriastradh
62903b705cfSriastradh	for (tile.extents.y1 = tile.extents.y2 = region.extents.y1;
63003b705cfSriastradh	     tile.extents.y2 < region.extents.y2;
63103b705cfSriastradh	     tile.extents.y1 = tile.extents.y2) {
63203b705cfSriastradh		int y2 = tile.extents.y1 + step;
63303b705cfSriastradh		if (y2 > region.extents.y2)
63403b705cfSriastradh			y2 = region.extents.y2;
63503b705cfSriastradh		tile.extents.y2 = y2;
63603b705cfSriastradh
63703b705cfSriastradh		for (tile.extents.x1 = tile.extents.x2 = region.extents.x1;
63803b705cfSriastradh		     tile.extents.x2 < region.extents.x2;
63903b705cfSriastradh		     tile.extents.x1 = tile.extents.x2) {
64042542f5fSchristos			DrawableRec tmp;
64103b705cfSriastradh			int x2 = tile.extents.x1 + step;
64203b705cfSriastradh			if (x2 > region.extents.x2)
64303b705cfSriastradh				x2 = region.extents.x2;
64403b705cfSriastradh			tile.extents.x2 = x2;
64503b705cfSriastradh
64603b705cfSriastradh			tile.data = NULL;
64703b705cfSriastradh
64803b705cfSriastradh			RegionNull(&this);
64903b705cfSriastradh			RegionIntersect(&this, &region, &tile);
65003b705cfSriastradh			if (RegionNil(&this))
65103b705cfSriastradh				continue;
65203b705cfSriastradh
65342542f5fSchristos			tmp.width  = this.extents.x2 - this.extents.x1;
65442542f5fSchristos			tmp.height = this.extents.y2 - this.extents.y1;
65542542f5fSchristos			tmp.depth  = dst->depth;
65642542f5fSchristos			tmp.bitsPerPixel = dst->bitsPerPixel;
65703b705cfSriastradh
65803b705cfSriastradh			bo = kgem_create_2d(&sna->kgem,
65942542f5fSchristos					    tmp.width,
66042542f5fSchristos					    tmp.height,
66142542f5fSchristos					    dst->bitsPerPixel,
66203b705cfSriastradh					    kgem_choose_tiling(&sna->kgem,
66303b705cfSriastradh							       I915_TILING_X,
66442542f5fSchristos							       tmp.width,
66542542f5fSchristos							       tmp.height,
66642542f5fSchristos							       dst->bitsPerPixel),
66703b705cfSriastradh					    CREATE_TEMPORARY);
66803b705cfSriastradh			if (bo) {
66903b705cfSriastradh				int16_t dx = this.extents.x1;
67003b705cfSriastradh				int16_t dy = this.extents.y1;
67103b705cfSriastradh
67203b705cfSriastradh				assert(kgem_bo_can_blt(&sna->kgem, bo));
67303b705cfSriastradh
67442542f5fSchristos				if (op > PictOpSrc &&
67542542f5fSchristos				    !sna->render.copy_boxes(sna, GXcopy,
67642542f5fSchristos							    dst, dst_bo, 0, 0,
67742542f5fSchristos							    &tmp, bo, -dx, -dy,
67842542f5fSchristos							    region_rects(&this), region_num_rects(&this), 0))
67903b705cfSriastradh					goto err;
68003b705cfSriastradh
68103b705cfSriastradh				RegionTranslate(&this, -dx, -dy);
68242542f5fSchristos				if (!sna->render.fill_boxes(sna, op, format, color, &tmp, bo,
68342542f5fSchristos							    region_rects(&this), region_num_rects(&this)))
68403b705cfSriastradh					goto err;
68503b705cfSriastradh
68603b705cfSriastradh				if (!sna->render.copy_boxes(sna, GXcopy,
68742542f5fSchristos							    &tmp, bo, 0, 0,
68842542f5fSchristos							    dst, dst_bo, dx, dy,
68942542f5fSchristos							    region_rects(&this), region_num_rects(&this), 0))
69003b705cfSriastradh					goto err;
69103b705cfSriastradh
69203b705cfSriastradh				kgem_bo_destroy(&sna->kgem, bo);
69303b705cfSriastradh			}
69403b705cfSriastradh			RegionUninit(&this);
69503b705cfSriastradh		}
69603b705cfSriastradh	}
69703b705cfSriastradh
69803b705cfSriastradh	ret = true;
69903b705cfSriastradh	goto done;
70003b705cfSriastradherr:
70103b705cfSriastradh	kgem_bo_destroy(&sna->kgem, bo);
70203b705cfSriastradh	RegionUninit(&this);
70303b705cfSriastradhdone:
70403b705cfSriastradh	pixman_region_fini(&region);
70503b705cfSriastradh	return ret;
70603b705cfSriastradh}
70703b705cfSriastradh
70842542f5fSchristosfastcall static void
70942542f5fSchristostiling_blt(struct sna *sna,
71042542f5fSchristos	   const struct sna_composite_op *op,
71142542f5fSchristos	   const struct sna_composite_rectangles *r)
71242542f5fSchristos{
71342542f5fSchristos	int x1, x2, y1, y2;
71442542f5fSchristos	int src_x, src_y;
71542542f5fSchristos	BoxRec box;
71642542f5fSchristos
71742542f5fSchristos	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n",
71842542f5fSchristos	     __FUNCTION__,
71942542f5fSchristos	     r->src.x, r->src.y,
72042542f5fSchristos	     r->dst.x, r->dst.y,
72142542f5fSchristos	     r->width, r->height));
72242542f5fSchristos
72342542f5fSchristos	/* XXX higher layer should have clipped? */
72442542f5fSchristos
72542542f5fSchristos	x1 = r->dst.x + op->dst.x;
72642542f5fSchristos	y1 = r->dst.y + op->dst.y;
72742542f5fSchristos	x2 = x1 + r->width;
72842542f5fSchristos	y2 = y1 + r->height;
72942542f5fSchristos
73042542f5fSchristos	src_x = r->src.x - x1 + op->u.blt.sx;
73142542f5fSchristos	src_y = r->src.y - y1 + op->u.blt.sy;
73242542f5fSchristos
73342542f5fSchristos	/* clip against dst */
73442542f5fSchristos	if (x1 < 0)
73542542f5fSchristos		x1 = 0;
73642542f5fSchristos	if (y1 < 0)
73742542f5fSchristos		y1 = 0;
73842542f5fSchristos
73942542f5fSchristos	if (x2 > op->dst.width)
74042542f5fSchristos		x2 = op->dst.width;
74142542f5fSchristos
74242542f5fSchristos	if (y2 > op->dst.height)
74342542f5fSchristos		y2 = op->dst.height;
74442542f5fSchristos
74542542f5fSchristos	DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2));
74642542f5fSchristos
74742542f5fSchristos	if (x2 <= x1 || y2 <= y1)
74842542f5fSchristos		return;
74942542f5fSchristos
75042542f5fSchristos	box.x1 = x1; box.y1 = y1;
75142542f5fSchristos	box.x2 = x2; box.y2 = y2;
75242542f5fSchristos	sna_tiling_blt_copy_boxes(sna, GXcopy,
75342542f5fSchristos				  op->src.bo, src_x, src_y,
75442542f5fSchristos				  op->dst.bo, 0, 0,
75542542f5fSchristos				  op->u.blt.bpp,
75642542f5fSchristos				  &box, 1);
75742542f5fSchristos}
75842542f5fSchristos
75942542f5fSchristosfastcall static void
76042542f5fSchristostiling_blt_box(struct sna *sna,
76142542f5fSchristos	       const struct sna_composite_op *op,
76242542f5fSchristos	       const BoxRec *box)
76342542f5fSchristos{
76442542f5fSchristos	DBG(("%s: box (%d, %d), (%d, %d)\n",
76542542f5fSchristos	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
76642542f5fSchristos	sna_tiling_blt_copy_boxes(sna, GXcopy,
76742542f5fSchristos				  op->src.bo, op->u.blt.sx, op->u.blt.sy,
76842542f5fSchristos				  op->dst.bo, op->dst.x, op->dst.y,
76942542f5fSchristos				  op->u.blt.bpp,
77042542f5fSchristos				  box, 1);
77142542f5fSchristos}
77242542f5fSchristos
77342542f5fSchristosstatic void
77442542f5fSchristostiling_blt_boxes(struct sna *sna,
77542542f5fSchristos		 const struct sna_composite_op *op,
77642542f5fSchristos		 const BoxRec *box, int nbox)
77742542f5fSchristos{
77842542f5fSchristos	DBG(("%s: nbox=%d\n", __FUNCTION__, nbox));
77942542f5fSchristos	sna_tiling_blt_copy_boxes(sna, GXcopy,
78042542f5fSchristos				  op->src.bo, op->u.blt.sx, op->u.blt.sy,
78142542f5fSchristos				  op->dst.bo, op->dst.x, op->dst.y,
78242542f5fSchristos				  op->u.blt.bpp,
78342542f5fSchristos				  box, nbox);
78442542f5fSchristos}
78542542f5fSchristos
78642542f5fSchristosstatic bool
78742542f5fSchristossna_tiling_blt_copy_boxes__with_alpha(struct sna *sna, uint8_t alu,
78842542f5fSchristos				      struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
78942542f5fSchristos				      struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
79042542f5fSchristos				      int bpp, int alpha_fixup,
79142542f5fSchristos				      const BoxRec *box, int nbox)
79242542f5fSchristos{
79342542f5fSchristos	RegionRec region, tile, this;
79442542f5fSchristos	struct kgem_bo *bo;
79542542f5fSchristos	int max_size, step;
79642542f5fSchristos	bool ret = false;
79742542f5fSchristos
79842542f5fSchristos	if (wedged(sna) ||
79942542f5fSchristos	    !kgem_bo_can_blt(&sna->kgem, src_bo) ||
80042542f5fSchristos	    !kgem_bo_can_blt(&sna->kgem, dst_bo)) {
80142542f5fSchristos		/* XXX */
80242542f5fSchristos		DBG(("%s: tiling blt fail: src?=%d, dst?=%d\n",
80342542f5fSchristos		     __FUNCTION__,
80442542f5fSchristos		     kgem_bo_can_blt(&sna->kgem, src_bo),
80542542f5fSchristos		     kgem_bo_can_blt(&sna->kgem, dst_bo)));
80642542f5fSchristos		return false;
80742542f5fSchristos	}
80842542f5fSchristos
80942542f5fSchristos	max_size = sna_max_tile_copy_size(sna, src_bo, dst_bo);
81042542f5fSchristos	if (max_size == 0)
81142542f5fSchristos		return false;
81242542f5fSchristos
81342542f5fSchristos	pixman_region_init_rects(&region, box, nbox);
81442542f5fSchristos
81542542f5fSchristos	/* Use a small step to accommodate enlargement through tile alignment */
81642542f5fSchristos	step = sna->render.max_3d_size;
81742542f5fSchristos	if (region.extents.x1 & (8*512 / bpp - 1) || region.extents.y1 & 63)
81842542f5fSchristos		step /= 2;
81942542f5fSchristos	while (step * step * 4 > max_size)
82042542f5fSchristos		step /= 2;
82142542f5fSchristos	if (sna->kgem.gen < 033)
82242542f5fSchristos		step /= 2; /* accommodate severe fence restrictions */
82342542f5fSchristos	if (step == 0) {
82442542f5fSchristos		DBG(("%s: tiles cannot fit into aperture\n", __FUNCTION__));
82542542f5fSchristos		return false;
82642542f5fSchristos	}
82742542f5fSchristos
82842542f5fSchristos	DBG(("%s (alu=%d), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n",
82942542f5fSchristos	     __FUNCTION__, alu, step, nbox,
83042542f5fSchristos	     region.extents.x1, region.extents.y1,
83142542f5fSchristos	     region.extents.x2, region.extents.y2));
83242542f5fSchristos
83342542f5fSchristos	for (tile.extents.y1 = tile.extents.y2 = region.extents.y1;
83442542f5fSchristos	     tile.extents.y2 < region.extents.y2;
83542542f5fSchristos	     tile.extents.y1 = tile.extents.y2) {
83642542f5fSchristos		int y2 = tile.extents.y1 + step;
83742542f5fSchristos		if (y2 > region.extents.y2)
83842542f5fSchristos			y2 = region.extents.y2;
83942542f5fSchristos		tile.extents.y2 = y2;
84042542f5fSchristos
84142542f5fSchristos		for (tile.extents.x1 = tile.extents.x2 = region.extents.x1;
84242542f5fSchristos		     tile.extents.x2 < region.extents.x2;
84342542f5fSchristos		     tile.extents.x1 = tile.extents.x2) {
84442542f5fSchristos			int w, h;
84542542f5fSchristos			int x2 = tile.extents.x1 + step;
84642542f5fSchristos			if (x2 > region.extents.x2)
84742542f5fSchristos				x2 = region.extents.x2;
84842542f5fSchristos			tile.extents.x2 = x2;
84942542f5fSchristos
85042542f5fSchristos			tile.data = NULL;
85142542f5fSchristos
85242542f5fSchristos			RegionNull(&this);
85342542f5fSchristos			RegionIntersect(&this, &region, &tile);
85442542f5fSchristos			if (RegionNil(&this))
85542542f5fSchristos				continue;
85642542f5fSchristos
85742542f5fSchristos			w = this.extents.x2 - this.extents.x1;
85842542f5fSchristos			h = this.extents.y2 - this.extents.y1;
85942542f5fSchristos			bo = kgem_create_2d(&sna->kgem, w, h, bpp,
86042542f5fSchristos					    kgem_choose_tiling(&sna->kgem,
86142542f5fSchristos							       I915_TILING_X,
86242542f5fSchristos							       w, h, bpp),
86342542f5fSchristos					    CREATE_TEMPORARY);
86442542f5fSchristos			if (bo) {
86542542f5fSchristos				int16_t dx = this.extents.x1;
86642542f5fSchristos				int16_t dy = this.extents.y1;
86742542f5fSchristos
86842542f5fSchristos				assert(kgem_bo_can_blt(&sna->kgem, bo));
86942542f5fSchristos
87042542f5fSchristos				if (!sna_blt_copy_boxes(sna, GXcopy,
87142542f5fSchristos							src_bo, src_dx, src_dy,
87242542f5fSchristos							bo, -dx, -dy,
87342542f5fSchristos							bpp, region_rects(&this), region_num_rects(&this)))
87442542f5fSchristos					goto err;
87542542f5fSchristos
87642542f5fSchristos				if (!sna_blt_copy_boxes__with_alpha(sna, alu,
87742542f5fSchristos								    bo, -dx, -dy,
87842542f5fSchristos								    dst_bo, dst_dx, dst_dy,
87942542f5fSchristos								    bpp, alpha_fixup,
88042542f5fSchristos								    region_rects(&this), region_num_rects(&this)))
88142542f5fSchristos					goto err;
88242542f5fSchristos
88342542f5fSchristos				kgem_bo_destroy(&sna->kgem, bo);
88442542f5fSchristos			}
88542542f5fSchristos			RegionUninit(&this);
88642542f5fSchristos		}
88742542f5fSchristos	}
88842542f5fSchristos
88942542f5fSchristos	ret = true;
89042542f5fSchristos	goto done;
89142542f5fSchristoserr:
89242542f5fSchristos	kgem_bo_destroy(&sna->kgem, bo);
89342542f5fSchristos	RegionUninit(&this);
89442542f5fSchristosdone:
89542542f5fSchristos	pixman_region_fini(&region);
89642542f5fSchristos	return ret;
89742542f5fSchristos}
89842542f5fSchristos
89942542f5fSchristosfastcall static void
90042542f5fSchristostiling_blt__with_alpha(struct sna *sna,
90142542f5fSchristos		       const struct sna_composite_op *op,
90242542f5fSchristos		       const struct sna_composite_rectangles *r)
90342542f5fSchristos{
90442542f5fSchristos	int x1, x2, y1, y2;
90542542f5fSchristos	int src_x, src_y;
90642542f5fSchristos	BoxRec box;
90742542f5fSchristos
90842542f5fSchristos	DBG(("%s: src=(%d, %d), dst=(%d, %d), size=(%d, %d)\n",
90942542f5fSchristos	     __FUNCTION__,
91042542f5fSchristos	     r->src.x, r->src.y,
91142542f5fSchristos	     r->dst.x, r->dst.y,
91242542f5fSchristos	     r->width, r->height));
91342542f5fSchristos
91442542f5fSchristos	/* XXX higher layer should have clipped? */
91542542f5fSchristos
91642542f5fSchristos	x1 = r->dst.x + op->dst.x;
91742542f5fSchristos	y1 = r->dst.y + op->dst.y;
91842542f5fSchristos	x2 = x1 + r->width;
91942542f5fSchristos	y2 = y1 + r->height;
92042542f5fSchristos
92142542f5fSchristos	src_x = r->src.x - x1 + op->u.blt.sx;
92242542f5fSchristos	src_y = r->src.y - y1 + op->u.blt.sy;
92342542f5fSchristos
92442542f5fSchristos	/* clip against dst */
92542542f5fSchristos	if (x1 < 0)
92642542f5fSchristos		x1 = 0;
92742542f5fSchristos	if (y1 < 0)
92842542f5fSchristos		y1 = 0;
92942542f5fSchristos
93042542f5fSchristos	if (x2 > op->dst.width)
93142542f5fSchristos		x2 = op->dst.width;
93242542f5fSchristos
93342542f5fSchristos	if (y2 > op->dst.height)
93442542f5fSchristos		y2 = op->dst.height;
93542542f5fSchristos
93642542f5fSchristos	DBG(("%s: box=(%d, %d), (%d, %d)\n", __FUNCTION__, x1, y1, x2, y2));
93742542f5fSchristos
93842542f5fSchristos	if (x2 <= x1 || y2 <= y1)
93942542f5fSchristos		return;
94042542f5fSchristos
94142542f5fSchristos	box.x1 = x1; box.y1 = y1;
94242542f5fSchristos	box.x2 = x2; box.y2 = y2;
94342542f5fSchristos	sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy,
94442542f5fSchristos					      op->src.bo, src_x, src_y,
94542542f5fSchristos					      op->dst.bo, 0, 0,
94642542f5fSchristos					      op->u.blt.bpp, op->u.blt.pixel,
94742542f5fSchristos					      &box, 1);
94842542f5fSchristos}
94942542f5fSchristos
95042542f5fSchristosfastcall static void
95142542f5fSchristostiling_blt_box__with_alpha(struct sna *sna,
95242542f5fSchristos			   const struct sna_composite_op *op,
95342542f5fSchristos			   const BoxRec *box)
95442542f5fSchristos{
95542542f5fSchristos	DBG(("%s: box (%d, %d), (%d, %d)\n",
95642542f5fSchristos	     __FUNCTION__, box->x1, box->y1, box->x2, box->y2));
95742542f5fSchristos	sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy,
95842542f5fSchristos					      op->src.bo, op->u.blt.sx, op->u.blt.sy,
95942542f5fSchristos					      op->dst.bo, op->dst.x, op->dst.y,
96042542f5fSchristos					      op->u.blt.bpp, op->u.blt.pixel,
96142542f5fSchristos					      box, 1);
96242542f5fSchristos}
96342542f5fSchristos
96442542f5fSchristosstatic void
96542542f5fSchristostiling_blt_boxes__with_alpha(struct sna *sna,
96642542f5fSchristos			     const struct sna_composite_op *op,
96742542f5fSchristos			     const BoxRec *box, int nbox)
96842542f5fSchristos{
96942542f5fSchristos	DBG(("%s: nbox=%d\n", __FUNCTION__, nbox));
97042542f5fSchristos	sna_tiling_blt_copy_boxes__with_alpha(sna, GXcopy,
97142542f5fSchristos					      op->src.bo, op->u.blt.sx, op->u.blt.sy,
97242542f5fSchristos					      op->dst.bo, op->dst.x, op->dst.y,
97342542f5fSchristos					      op->u.blt.bpp, op->u.blt.pixel,
97442542f5fSchristos					      box, nbox);
97542542f5fSchristos}
97642542f5fSchristos
97742542f5fSchristosstatic void nop_done(struct sna *sna, const struct sna_composite_op *op)
97842542f5fSchristos{
97942542f5fSchristos	assert(sna->kgem.nbatch <= KGEM_BATCH_SIZE(&sna->kgem));
98042542f5fSchristos	(void)op;
98142542f5fSchristos}
98242542f5fSchristos
98342542f5fSchristosbool
98442542f5fSchristossna_tiling_blt_composite(struct sna *sna,
98542542f5fSchristos			 struct sna_composite_op *op,
98642542f5fSchristos			 struct kgem_bo *bo,
98742542f5fSchristos			 int bpp,
98842542f5fSchristos			 uint32_t alpha_fixup)
98942542f5fSchristos{
99042542f5fSchristos	assert(op->dst.bo);
99142542f5fSchristos	assert(kgem_bo_can_blt(&sna->kgem, op->dst.bo));
99242542f5fSchristos	assert(kgem_bo_can_blt(&sna->kgem, bo));
99342542f5fSchristos
99442542f5fSchristos	op->src.bo = bo;
99542542f5fSchristos	op->u.blt.bpp = bpp;
99642542f5fSchristos	op->u.blt.pixel = alpha_fixup;
99742542f5fSchristos
99842542f5fSchristos	if (alpha_fixup) {
99942542f5fSchristos		op->blt   = tiling_blt__with_alpha;
100042542f5fSchristos		op->box   = tiling_blt_box__with_alpha;
100142542f5fSchristos		op->boxes = tiling_blt_boxes__with_alpha;
100242542f5fSchristos	} else {
100342542f5fSchristos		op->blt   = tiling_blt;
100442542f5fSchristos		op->box   = tiling_blt_box;
100542542f5fSchristos		op->boxes = tiling_blt_boxes;
100642542f5fSchristos	}
100742542f5fSchristos	op->done  = nop_done;
100842542f5fSchristos
100942542f5fSchristos	return true;
101042542f5fSchristos}
101142542f5fSchristos
101203b705cfSriastradhbool sna_tiling_blt_copy_boxes(struct sna *sna, uint8_t alu,
101303b705cfSriastradh			       struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
101403b705cfSriastradh			       struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
101503b705cfSriastradh			       int bpp, const BoxRec *box, int nbox)
101603b705cfSriastradh{
101703b705cfSriastradh	RegionRec region, tile, this;
101803b705cfSriastradh	struct kgem_bo *bo;
101903b705cfSriastradh	int max_size, step;
102003b705cfSriastradh	bool ret = false;
102103b705cfSriastradh
102242542f5fSchristos	DBG(("%s: alu=%d, src size=%d, dst size=%d\n", __FUNCTION__,
102342542f5fSchristos	     alu, kgem_bo_size(src_bo), kgem_bo_size(dst_bo)));
102442542f5fSchristos
102542542f5fSchristos	if (wedged(sna) ||
102642542f5fSchristos	    !kgem_bo_can_blt(&sna->kgem, src_bo) ||
102703b705cfSriastradh	    !kgem_bo_can_blt(&sna->kgem, dst_bo)) {
102803b705cfSriastradh		/* XXX */
102903b705cfSriastradh		DBG(("%s: tiling blt fail: src?=%d, dst?=%d\n",
103003b705cfSriastradh		     __FUNCTION__,
103103b705cfSriastradh		     kgem_bo_can_blt(&sna->kgem, src_bo),
103203b705cfSriastradh		     kgem_bo_can_blt(&sna->kgem, dst_bo)));
103303b705cfSriastradh		return false;
103403b705cfSriastradh	}
103503b705cfSriastradh
103642542f5fSchristos	max_size = sna_max_tile_copy_size(sna, src_bo, dst_bo);
103742542f5fSchristos	if (max_size == 0)
103803b705cfSriastradh		return false;
103903b705cfSriastradh
104003b705cfSriastradh	pixman_region_init_rects(&region, box, nbox);
104103b705cfSriastradh
104203b705cfSriastradh	/* Use a small step to accommodate enlargement through tile alignment */
104303b705cfSriastradh	step = sna->render.max_3d_size;
104403b705cfSriastradh	if (region.extents.x1 & (8*512 / bpp - 1) || region.extents.y1 & 63)
104503b705cfSriastradh		step /= 2;
104603b705cfSriastradh	while (step * step * 4 > max_size)
104703b705cfSriastradh		step /= 2;
104842542f5fSchristos	if (sna->kgem.gen < 033)
104942542f5fSchristos		step /= 2; /* accommodate severe fence restrictions */
105003b705cfSriastradh	if (step == 0) {
105103b705cfSriastradh		DBG(("%s: tiles cannot fit into aperture\n", __FUNCTION__));
105203b705cfSriastradh		return false;
105303b705cfSriastradh	}
105403b705cfSriastradh
105503b705cfSriastradh	DBG(("%s (alu=%d), tile.size=%d, box=%dx[(%d, %d), (%d, %d)])\n",
105603b705cfSriastradh	     __FUNCTION__, alu, step, nbox,
105703b705cfSriastradh	     region.extents.x1, region.extents.y1,
105803b705cfSriastradh	     region.extents.x2, region.extents.y2));
105903b705cfSriastradh
106003b705cfSriastradh	for (tile.extents.y1 = tile.extents.y2 = region.extents.y1;
106103b705cfSriastradh	     tile.extents.y2 < region.extents.y2;
106203b705cfSriastradh	     tile.extents.y1 = tile.extents.y2) {
106303b705cfSriastradh		int y2 = tile.extents.y1 + step;
106403b705cfSriastradh		if (y2 > region.extents.y2)
106503b705cfSriastradh			y2 = region.extents.y2;
106603b705cfSriastradh		tile.extents.y2 = y2;
106703b705cfSriastradh
106803b705cfSriastradh		for (tile.extents.x1 = tile.extents.x2 = region.extents.x1;
106903b705cfSriastradh		     tile.extents.x2 < region.extents.x2;
107003b705cfSriastradh		     tile.extents.x1 = tile.extents.x2) {
107103b705cfSriastradh			int w, h;
107203b705cfSriastradh			int x2 = tile.extents.x1 + step;
107303b705cfSriastradh			if (x2 > region.extents.x2)
107403b705cfSriastradh				x2 = region.extents.x2;
107503b705cfSriastradh			tile.extents.x2 = x2;
107603b705cfSriastradh
107703b705cfSriastradh			tile.data = NULL;
107803b705cfSriastradh
107903b705cfSriastradh			RegionNull(&this);
108003b705cfSriastradh			RegionIntersect(&this, &region, &tile);
108103b705cfSriastradh			if (RegionNil(&this))
108203b705cfSriastradh				continue;
108303b705cfSriastradh
108403b705cfSriastradh			w = this.extents.x2 - this.extents.x1;
108503b705cfSriastradh			h = this.extents.y2 - this.extents.y1;
108603b705cfSriastradh			bo = kgem_create_2d(&sna->kgem, w, h, bpp,
108703b705cfSriastradh					    kgem_choose_tiling(&sna->kgem,
108803b705cfSriastradh							       I915_TILING_X,
108903b705cfSriastradh							       w, h, bpp),
109003b705cfSriastradh					    CREATE_TEMPORARY);
109103b705cfSriastradh			if (bo) {
109203b705cfSriastradh				int16_t dx = this.extents.x1;
109303b705cfSriastradh				int16_t dy = this.extents.y1;
109403b705cfSriastradh
109542542f5fSchristos				assert(kgem_bo_can_blt(&sna->kgem, bo));
109603b705cfSriastradh
109742542f5fSchristos				if (!sna_blt_copy_boxes(sna, GXcopy,
109803b705cfSriastradh							src_bo, src_dx, src_dy,
109903b705cfSriastradh							bo, -dx, -dy,
110042542f5fSchristos							bpp, region_rects(&this), region_num_rects(&this)))
110103b705cfSriastradh					goto err;
110203b705cfSriastradh
110303b705cfSriastradh				if (!sna_blt_copy_boxes(sna, alu,
110403b705cfSriastradh							bo, -dx, -dy,
110503b705cfSriastradh							dst_bo, dst_dx, dst_dy,
110642542f5fSchristos							bpp, region_rects(&this), region_num_rects(&this)))
110703b705cfSriastradh					goto err;
110803b705cfSriastradh
110903b705cfSriastradh				kgem_bo_destroy(&sna->kgem, bo);
111003b705cfSriastradh			}
111103b705cfSriastradh			RegionUninit(&this);
111203b705cfSriastradh		}
111303b705cfSriastradh	}
111403b705cfSriastradh
111503b705cfSriastradh	ret = true;
111603b705cfSriastradh	goto done;
111703b705cfSriastradherr:
111803b705cfSriastradh	kgem_bo_destroy(&sna->kgem, bo);
111903b705cfSriastradh	RegionUninit(&this);
112003b705cfSriastradhdone:
112103b705cfSriastradh	pixman_region_fini(&region);
112203b705cfSriastradh	return ret;
112303b705cfSriastradh}
112403b705cfSriastradh
112503b705cfSriastradhbool
112603b705cfSriastradhsna_tiling_copy_boxes(struct sna *sna, uint8_t alu,
112742542f5fSchristos		      const DrawableRec *src, struct kgem_bo *src_bo, int16_t src_dx, int16_t src_dy,
112842542f5fSchristos		      const DrawableRec *dst, struct kgem_bo *dst_bo, int16_t dst_dx, int16_t dst_dy,
112903b705cfSriastradh		      const BoxRec *box, int n)
113003b705cfSriastradh{
113103b705cfSriastradh	BoxRec extents, tile, stack[64], *clipped, *c;
113242542f5fSchristos	DrawableRec p;
113303b705cfSriastradh	int i, step, tiling;
113403b705cfSriastradh	bool create = true;
113503b705cfSriastradh	bool ret = false;
113603b705cfSriastradh
113703b705cfSriastradh	extents = box[0];
113803b705cfSriastradh	for (i = 1; i < n; i++) {
113903b705cfSriastradh		if (box[i].x1 < extents.x1)
114003b705cfSriastradh			extents.x1 = box[i].x1;
114103b705cfSriastradh		if (box[i].y1 < extents.y1)
114203b705cfSriastradh			extents.y1 = box[i].y1;
114303b705cfSriastradh
114403b705cfSriastradh		if (box[i].x2 > extents.x2)
114503b705cfSriastradh			extents.x2 = box[i].x2;
114603b705cfSriastradh		if (box[i].y2 > extents.y2)
114703b705cfSriastradh			extents.y2 = box[i].y2;
114803b705cfSriastradh	}
114903b705cfSriastradh
115003b705cfSriastradh	tiling = I915_TILING_X;
115103b705cfSriastradh	if (!kgem_bo_can_blt(&sna->kgem, src_bo) ||
115203b705cfSriastradh	    !kgem_bo_can_blt(&sna->kgem, dst_bo))
115303b705cfSriastradh		tiling = I915_TILING_Y;
115403b705cfSriastradh
115503b705cfSriastradh	create = (src_bo->pitch > sna->render.max_3d_pitch ||
115603b705cfSriastradh		  dst_bo->pitch > sna->render.max_3d_pitch);
115703b705cfSriastradh
115803b705cfSriastradh	step = sna->render.max_3d_size / 2;
115903b705cfSriastradh	if (create) {
116003b705cfSriastradh		while (step * step * 4 > sna->kgem.max_upload_tile_size)
116103b705cfSriastradh			step /= 2;
116203b705cfSriastradh	}
116303b705cfSriastradh
116403b705cfSriastradh	DBG(("%s: tiling copy %dx%d, %s %dx%d %c tiles\n", __FUNCTION__,
116503b705cfSriastradh	     extents.x2-extents.x1, extents.y2-extents.y1,
116603b705cfSriastradh	     create ? "creating" : "using",
116703b705cfSriastradh	     step, step, tiling == I915_TILING_X ? 'X' : 'Y'));
116803b705cfSriastradh
116903b705cfSriastradh	if (n > ARRAY_SIZE(stack)) {
117003b705cfSriastradh		clipped = malloc(sizeof(BoxRec) * n);
117103b705cfSriastradh		if (clipped == NULL)
117203b705cfSriastradh			goto tiled_error;
117303b705cfSriastradh	} else
117403b705cfSriastradh		clipped = stack;
117503b705cfSriastradh
117642542f5fSchristos	p.depth = src->depth;
117742542f5fSchristos	p.bitsPerPixel = src->bitsPerPixel;
117803b705cfSriastradh
117903b705cfSriastradh	for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) {
118003b705cfSriastradh		int y2 = tile.y1 + step;
118103b705cfSriastradh		if (y2 > extents.y2)
118203b705cfSriastradh			y2 = extents.y2;
118303b705cfSriastradh		tile.y2 = y2;
118403b705cfSriastradh
118503b705cfSriastradh		for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) {
118603b705cfSriastradh			struct kgem_bo *tmp_bo;
118703b705cfSriastradh			int x2 = tile.x1 + step;
118803b705cfSriastradh			if (x2 > extents.x2)
118903b705cfSriastradh				x2 = extents.x2;
119003b705cfSriastradh			tile.x2 = x2;
119103b705cfSriastradh
119203b705cfSriastradh			c = clipped;
119303b705cfSriastradh			for (i = 0; i < n; i++) {
119403b705cfSriastradh				*c = box[i];
119503b705cfSriastradh				if (!box_intersect(c, &tile))
119603b705cfSriastradh					continue;
119703b705cfSriastradh
119803b705cfSriastradh				DBG(("%s: box(%d, %d), (%d, %d), src=(%d, %d), dst=(%d, %d)\n",
119903b705cfSriastradh				     __FUNCTION__,
120003b705cfSriastradh				     c->x1, c->y1,
120103b705cfSriastradh				     c->x2, c->y2,
120203b705cfSriastradh				     src_dx, src_dy,
120303b705cfSriastradh				     c->x1 - tile.x1,
120403b705cfSriastradh				     c->y1 - tile.y1));
120503b705cfSriastradh				c++;
120603b705cfSriastradh			}
120703b705cfSriastradh			if (c == clipped)
120803b705cfSriastradh				continue;
120903b705cfSriastradh
121042542f5fSchristos			p.width  = tile.x2 - tile.x1;
121142542f5fSchristos			p.height = tile.y2 - tile.y1;
121203b705cfSriastradh
121303b705cfSriastradh			DBG(("%s: tile (%d, %d), (%d, %d)\n",
121403b705cfSriastradh			     __FUNCTION__, tile.x1, tile.y1, tile.x2, tile.y2));
121503b705cfSriastradh
121603b705cfSriastradh			if (create) {
121703b705cfSriastradh				tmp_bo = kgem_create_2d(&sna->kgem,
121842542f5fSchristos							p.width,
121942542f5fSchristos							p.height,
122042542f5fSchristos							p.bitsPerPixel,
122103b705cfSriastradh							tiling, CREATE_TEMPORARY);
122203b705cfSriastradh				if (!tmp_bo)
122303b705cfSriastradh					goto tiled_error;
122403b705cfSriastradh
122503b705cfSriastradh				i = (sna->render.copy_boxes(sna, GXcopy,
122603b705cfSriastradh							    src, src_bo, src_dx, src_dy,
122703b705cfSriastradh							    &p, tmp_bo, -tile.x1, -tile.y1,
122803b705cfSriastradh							    clipped, c - clipped, 0) &&
122903b705cfSriastradh				     sna->render.copy_boxes(sna, alu,
123003b705cfSriastradh							    &p, tmp_bo, -tile.x1, -tile.y1,
123103b705cfSriastradh							    dst, dst_bo, dst_dx, dst_dy,
123203b705cfSriastradh							    clipped, c - clipped, 0));
123303b705cfSriastradh
123403b705cfSriastradh				kgem_bo_destroy(&sna->kgem, tmp_bo);
123503b705cfSriastradh			} else {
123603b705cfSriastradh				i = sna->render.copy_boxes(sna, GXcopy,
123703b705cfSriastradh							   src, src_bo, src_dx, src_dy,
123803b705cfSriastradh							   dst, dst_bo, dst_dx, dst_dy,
123903b705cfSriastradh							   clipped, c - clipped, 0);
124003b705cfSriastradh			}
124103b705cfSriastradh
124203b705cfSriastradh			if (!i)
124303b705cfSriastradh				goto tiled_error;
124403b705cfSriastradh		}
124503b705cfSriastradh	}
124603b705cfSriastradh
124703b705cfSriastradh	ret = true;
124803b705cfSriastradhtiled_error:
124903b705cfSriastradh	if (clipped != stack)
125003b705cfSriastradh		free(clipped);
125103b705cfSriastradh
125203b705cfSriastradh	return ret;
125303b705cfSriastradh}
1254