103b705cfSriastradh/**************************************************************************
203b705cfSriastradh
303b705cfSriastradhCopyright (c) 2011 Intel Corporation
403b705cfSriastradh
503b705cfSriastradhPermission is hereby granted, free of charge, to any person obtaining a
603b705cfSriastradhcopy of this software and associated documentation files (the
703b705cfSriastradh"Software"), to deal in the Software without restriction, including
803b705cfSriastradhwithout limitation the rights to use, copy, modify, merge, publish,
903b705cfSriastradhdistribute, sub license, and/or sell copies of the Software, and to
1003b705cfSriastradhpermit persons to whom the Software is furnished to do so, subject to
1103b705cfSriastradhthe following conditions:
1203b705cfSriastradh
1303b705cfSriastradhThe above copyright notice and this permission notice (including the
1403b705cfSriastradhnext paragraph) shall be included in all copies or substantial portions
1503b705cfSriastradhof the Software.
1603b705cfSriastradh
1703b705cfSriastradhTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1803b705cfSriastradhOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1903b705cfSriastradhMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
2003b705cfSriastradhIN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
2103b705cfSriastradhANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
2203b705cfSriastradhTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2303b705cfSriastradhSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2403b705cfSriastradh
2503b705cfSriastradh **************************************************************************/
2603b705cfSriastradh
2703b705cfSriastradh#ifdef HAVE_CONFIG_H
2803b705cfSriastradh#include "config.h"
2903b705cfSriastradh#endif
3003b705cfSriastradh
3103b705cfSriastradh#include "sna.h"
3203b705cfSriastradh#include "sna_damage.h"
3303b705cfSriastradh
3403b705cfSriastradh/*
3503b705cfSriastradh * sna_damage is a batching layer on top of the regular pixman_region_t.
3603b705cfSriastradh * It is required as the ever-growing accumulation of invidual small
3703b705cfSriastradh * damage regions is an O(n^2) operation. Instead the accumulation of a
3803b705cfSriastradh * batch can be done in closer to O(n.lgn), and so prevents abysmal
3903b705cfSriastradh * performance in x11perf -copywinwin10.
4003b705cfSriastradh *
4103b705cfSriastradh * As with the core of SNA, damage is handled modally. That is, it
4203b705cfSriastradh * accumulates whilst rendering and then subtracts during migration of the
4303b705cfSriastradh * pixmap from GPU to CPU or vice versa. As such we can track the current
4403b705cfSriastradh * mode globally and when that mode switches perform the update of the region
4503b705cfSriastradh * in a single operation.
4603b705cfSriastradh *
4703b705cfSriastradh * Furthermore, we can track whether the whole pixmap is damaged and so
4803b705cfSriastradh * cheapy discard no-ops.
4903b705cfSriastradh */
5003b705cfSriastradh
5103b705cfSriastradhstruct sna_damage_box {
5203b705cfSriastradh	struct list list;
5303b705cfSriastradh	int size;
5403b705cfSriastradh} __attribute__((packed));
5503b705cfSriastradh
5603b705cfSriastradhstatic struct sna_damage *__freed_damage;
5703b705cfSriastradh
5842542f5fSchristosstatic inline bool region_is_singular(const RegionRec *r)
5903b705cfSriastradh{
6003b705cfSriastradh	return r->data == NULL;
6103b705cfSriastradh}
6203b705cfSriastradh
6342542f5fSchristosstatic inline bool region_is_singular_or_empty(const RegionRec *r)
6442542f5fSchristos{
6542542f5fSchristos	return r->data == NULL || r->data->numRects == 0;
6642542f5fSchristos}
6742542f5fSchristos
6803b705cfSriastradh#if HAS_DEBUG_FULL
6903b705cfSriastradhstatic const char *_debug_describe_region(char *buf, int max,
7042542f5fSchristos					  const RegionRec *region)
7103b705cfSriastradh{
7242542f5fSchristos	const BoxRec *box;
7342542f5fSchristos	int n, len;
7403b705cfSriastradh
7503b705cfSriastradh	if (region == NULL)
7603b705cfSriastradh		return "nil";
7703b705cfSriastradh
7842542f5fSchristos	n = region_num_rects(region);
7903b705cfSriastradh	if (n == 0)
8003b705cfSriastradh		return "[0]";
8103b705cfSriastradh
8203b705cfSriastradh	if (n == 1) {
8303b705cfSriastradh		sprintf(buf,
8403b705cfSriastradh			"[(%d, %d), (%d, %d)]",
8542542f5fSchristos			region->extents.x1, region->extents.y1,
8642542f5fSchristos			region->extents.x2, region->extents.y2);
8703b705cfSriastradh		return buf;
8803b705cfSriastradh	}
8903b705cfSriastradh
9003b705cfSriastradh	len = sprintf(buf,
9103b705cfSriastradh		      "[(%d, %d), (%d, %d) x %d: ",
9242542f5fSchristos		      region->extents.x1, region->extents.y1,
9342542f5fSchristos		      region->extents.x2, region->extents.y2,
9403b705cfSriastradh		      n) + 3;
9503b705cfSriastradh	max -= 2;
9642542f5fSchristos	box = region_rects(region);
9703b705cfSriastradh	while (n--) {
9803b705cfSriastradh		char tmp[80];
9903b705cfSriastradh		int this;
10003b705cfSriastradh
10103b705cfSriastradh		this = snprintf(tmp, sizeof(tmp),
10203b705cfSriastradh				"((%d, %d), (%d, %d))%s",
10303b705cfSriastradh				box->x1, box->y1,
10403b705cfSriastradh				box->x2, box->y2,
10503b705cfSriastradh				n ? ", ..." : "");
10603b705cfSriastradh		box++;
10703b705cfSriastradh
10803b705cfSriastradh		if (this > max - len)
10903b705cfSriastradh			break;
11003b705cfSriastradh
11103b705cfSriastradh		len -= 3;
11203b705cfSriastradh		memcpy(buf + len, tmp, this);
11303b705cfSriastradh		len += this;
11403b705cfSriastradh	}
11503b705cfSriastradh	buf[len++] = ']';
11603b705cfSriastradh	buf[len] = '\0';
11703b705cfSriastradh	return buf;
11803b705cfSriastradh}
11903b705cfSriastradh
12003b705cfSriastradhstatic const char *_debug_describe_damage(char *buf, int max,
12103b705cfSriastradh					  const struct sna_damage *damage)
12203b705cfSriastradh{
12303b705cfSriastradh	char damage_str[500], region_str[500];
12403b705cfSriastradh	int str_max;
12503b705cfSriastradh
12603b705cfSriastradh	if (damage == NULL)
12703b705cfSriastradh		return "None";
12803b705cfSriastradh
12903b705cfSriastradh	str_max = max/2 - 6;
13003b705cfSriastradh	if (str_max > sizeof(damage_str))
13103b705cfSriastradh		str_max = sizeof(damage_str);
13203b705cfSriastradh
13303b705cfSriastradh	if (damage->mode == DAMAGE_ALL) {
13403b705cfSriastradh		snprintf(buf, max, "[[(%d, %d), (%d, %d)]: all]",
13503b705cfSriastradh			 damage->extents.x1, damage->extents.y1,
13603b705cfSriastradh			 damage->extents.x2, damage->extents.y2);
13703b705cfSriastradh	} else {
13803b705cfSriastradh		if (damage->dirty) {
13903b705cfSriastradh			sprintf(damage_str, "%c[ ...]",
14003b705cfSriastradh				damage->mode == DAMAGE_SUBTRACT ? '-' : '+');
14103b705cfSriastradh		} else
14203b705cfSriastradh			damage_str[0] = '\0';
14303b705cfSriastradh		snprintf(buf, max, "[[(%d, %d), (%d, %d)]: %s %s]%c",
14403b705cfSriastradh			 damage->extents.x1, damage->extents.y1,
14503b705cfSriastradh			 damage->extents.x2, damage->extents.y2,
14603b705cfSriastradh			 _debug_describe_region(region_str, str_max,
14703b705cfSriastradh						&damage->region),
14803b705cfSriastradh			 damage_str, damage->dirty ? '*' : ' ');
14903b705cfSriastradh	}
15003b705cfSriastradh
15103b705cfSriastradh	return buf;
15203b705cfSriastradh}
15303b705cfSriastradh#endif
15403b705cfSriastradh
15542542f5fSchristosstatic struct sna_damage_box *
15642542f5fSchristoslast_box(struct sna_damage *damage)
15742542f5fSchristos{
15842542f5fSchristos	return list_entry(damage->embedded_box.list.prev,
15942542f5fSchristos			  struct sna_damage_box,
16042542f5fSchristos			  list);
16142542f5fSchristos}
16242542f5fSchristos
16303b705cfSriastradhstatic void
16403b705cfSriastradhreset_embedded_box(struct sna_damage *damage)
16503b705cfSriastradh{
16603b705cfSriastradh	damage->dirty = false;
16703b705cfSriastradh	damage->box = damage->embedded_box.box;
16803b705cfSriastradh	damage->embedded_box.size =
16903b705cfSriastradh		damage->remain = ARRAY_SIZE(damage->embedded_box.box);
17003b705cfSriastradh	list_init(&damage->embedded_box.list);
17103b705cfSriastradh}
17203b705cfSriastradh
17303b705cfSriastradhstatic void reset_extents(struct sna_damage *damage)
17403b705cfSriastradh{
17503b705cfSriastradh	damage->extents.x1 = damage->extents.y1 = MAXSHORT;
17603b705cfSriastradh	damage->extents.x2 = damage->extents.y2 = MINSHORT;
17703b705cfSriastradh}
17803b705cfSriastradh
17903b705cfSriastradhstatic struct sna_damage *_sna_damage_create(void)
18003b705cfSriastradh{
18103b705cfSriastradh	struct sna_damage *damage;
18203b705cfSriastradh
18303b705cfSriastradh	if (__freed_damage) {
18403b705cfSriastradh		damage = __freed_damage;
18503b705cfSriastradh		__freed_damage = *(void **)__freed_damage;
18603b705cfSriastradh	} else {
18703b705cfSriastradh		damage = malloc(sizeof(*damage));
18803b705cfSriastradh		if (damage == NULL)
18903b705cfSriastradh			return NULL;
19003b705cfSriastradh	}
19103b705cfSriastradh	reset_embedded_box(damage);
19203b705cfSriastradh	damage->mode = DAMAGE_ADD;
19303b705cfSriastradh	pixman_region_init(&damage->region);
19403b705cfSriastradh	reset_extents(damage);
19503b705cfSriastradh
19603b705cfSriastradh	return damage;
19703b705cfSriastradh}
19803b705cfSriastradh
19903b705cfSriastradhstruct sna_damage *sna_damage_create(void)
20003b705cfSriastradh{
20103b705cfSriastradh	return _sna_damage_create();
20203b705cfSriastradh}
20303b705cfSriastradh
20442542f5fSchristosstatic void free_list(struct list *head)
20542542f5fSchristos{
20642542f5fSchristos	while (!list_is_empty(head)) {
20742542f5fSchristos		struct list *l = head->next;
20842542f5fSchristos		list_del(l);
20942542f5fSchristos		free(l);
21042542f5fSchristos	}
21142542f5fSchristos}
21242542f5fSchristos
21342542f5fSchristosstatic void __sna_damage_reduce(struct sna_damage *damage)
21442542f5fSchristos{
21542542f5fSchristos	int n, nboxes;
21642542f5fSchristos	BoxPtr boxes, free_boxes = NULL;
21742542f5fSchristos	pixman_region16_t *region = &damage->region;
21842542f5fSchristos	struct sna_damage_box *iter;
21942542f5fSchristos
22042542f5fSchristos	assert(damage->mode != DAMAGE_ALL);
22142542f5fSchristos	assert(damage->dirty);
22242542f5fSchristos
22342542f5fSchristos	DBG(("    reduce: before region.n=%d\n", region_num_rects(region)));
22442542f5fSchristos
22542542f5fSchristos	nboxes = damage->embedded_box.size;
22642542f5fSchristos	list_for_each_entry(iter, &damage->embedded_box.list, list)
22742542f5fSchristos		nboxes += iter->size;
22842542f5fSchristos	DBG(("   nboxes=%d, residual=%d\n", nboxes, damage->remain));
22942542f5fSchristos	nboxes -= damage->remain;
23042542f5fSchristos	if (nboxes == 0)
23142542f5fSchristos		goto done;
23242542f5fSchristos	if (nboxes == 1) {
23342542f5fSchristos		pixman_region16_t tmp;
23442542f5fSchristos
23542542f5fSchristos		tmp.extents = damage->embedded_box.box[0];
23642542f5fSchristos		tmp.data = NULL;
23742542f5fSchristos
23842542f5fSchristos		if (damage->mode == DAMAGE_ADD)
23942542f5fSchristos			pixman_region_union(region, region, &tmp);
24042542f5fSchristos		else
24142542f5fSchristos			pixman_region_subtract(region, region, &tmp);
24242542f5fSchristos		damage->extents = region->extents;
24342542f5fSchristos
24442542f5fSchristos		goto done;
24542542f5fSchristos	}
24642542f5fSchristos
24742542f5fSchristos	if (damage->mode == DAMAGE_ADD)
24842542f5fSchristos		nboxes += region_num_rects(region);
24942542f5fSchristos
25042542f5fSchristos	iter = last_box(damage);
25142542f5fSchristos	n = iter->size - damage->remain;
25242542f5fSchristos	boxes = (BoxRec *)(iter+1);
25342542f5fSchristos	DBG(("   last box count=%d/%d, need=%d\n", n, iter->size, nboxes));
25442542f5fSchristos	if (nboxes > iter->size) {
25542542f5fSchristos		boxes = malloc(sizeof(BoxRec)*nboxes);
25642542f5fSchristos		if (boxes == NULL)
25742542f5fSchristos			goto done;
25842542f5fSchristos
25942542f5fSchristos		free_boxes = boxes;
26042542f5fSchristos	}
26142542f5fSchristos
26242542f5fSchristos	if (boxes != damage->embedded_box.box) {
26342542f5fSchristos		if (list_is_empty(&damage->embedded_box.list)) {
26442542f5fSchristos			DBG(("   copying embedded boxes\n"));
26542542f5fSchristos			memcpy(boxes,
26642542f5fSchristos			       damage->embedded_box.box,
26742542f5fSchristos			       n*sizeof(BoxRec));
26842542f5fSchristos		} else {
26942542f5fSchristos			if (boxes != (BoxPtr)(iter+1)) {
27042542f5fSchristos				DBG(("   copying %d boxes from last\n", n));
27142542f5fSchristos				memcpy(boxes, iter+1, n*sizeof(BoxRec));
27242542f5fSchristos			}
27342542f5fSchristos
27442542f5fSchristos			iter = list_entry(iter->list.prev,
27542542f5fSchristos					  struct sna_damage_box,
27642542f5fSchristos					  list);
27742542f5fSchristos			while (&iter->list != &damage->embedded_box.list) {
27842542f5fSchristos				DBG(("   copy %d boxes from %d\n",
27942542f5fSchristos				     iter->size, n));
28042542f5fSchristos				memcpy(boxes + n, iter+1,
28142542f5fSchristos				       iter->size * sizeof(BoxRec));
28242542f5fSchristos				n += iter->size;
28342542f5fSchristos
28442542f5fSchristos				iter = list_entry(iter->list.prev,
28542542f5fSchristos						  struct sna_damage_box,
28642542f5fSchristos						  list);
28742542f5fSchristos			}
28842542f5fSchristos
28942542f5fSchristos			DBG(("   copying embedded boxes to %d\n", n));
29042542f5fSchristos			memcpy(boxes + n,
29142542f5fSchristos			       damage->embedded_box.box,
29242542f5fSchristos			       sizeof(damage->embedded_box.box));
29342542f5fSchristos			n += damage->embedded_box.size;
29442542f5fSchristos		}
29542542f5fSchristos	}
29642542f5fSchristos
29742542f5fSchristos	if (damage->mode == DAMAGE_ADD) {
29842542f5fSchristos		memcpy(boxes + n,
29942542f5fSchristos		       region_rects(region),
30042542f5fSchristos		       region_num_rects(region)*sizeof(BoxRec));
30142542f5fSchristos		assert(n + region_num_rects(region) == nboxes);
30242542f5fSchristos		pixman_region_fini(region);
30342542f5fSchristos		pixman_region_init_rects(region, boxes, nboxes);
30442542f5fSchristos
30542542f5fSchristos		assert(pixman_region_not_empty(region));
30642542f5fSchristos		assert(damage->extents.x1 == region->extents.x1 &&
30742542f5fSchristos		       damage->extents.y1 == region->extents.y1 &&
30842542f5fSchristos		       damage->extents.x2 == region->extents.x2 &&
30942542f5fSchristos		       damage->extents.y2 == region->extents.y2);
31042542f5fSchristos	} else {
31142542f5fSchristos		pixman_region16_t tmp;
31242542f5fSchristos
31342542f5fSchristos		assert(n == nboxes);
31442542f5fSchristos		pixman_region_init_rects(&tmp, boxes, nboxes);
31542542f5fSchristos		pixman_region_subtract(region, region, &tmp);
31642542f5fSchristos		pixman_region_fini(&tmp);
31742542f5fSchristos
31842542f5fSchristos		assert(damage->extents.x1 <= region->extents.x1 &&
31942542f5fSchristos		       damage->extents.y1 <= region->extents.y1 &&
32042542f5fSchristos		       damage->extents.x2 >= region->extents.x2 &&
32142542f5fSchristos		       damage->extents.y2 >= region->extents.y2);
32242542f5fSchristos		if (pixman_region_not_empty(region))
32342542f5fSchristos			damage->extents = region->extents;
32442542f5fSchristos		else
32542542f5fSchristos			reset_extents(damage);
32642542f5fSchristos	}
32742542f5fSchristos
32842542f5fSchristos	free(free_boxes);
32942542f5fSchristos
33042542f5fSchristosdone:
33142542f5fSchristos	damage->mode = DAMAGE_ADD;
33242542f5fSchristos	free_list(&damage->embedded_box.list);
33342542f5fSchristos	reset_embedded_box(damage);
33442542f5fSchristos
33542542f5fSchristos	DBG(("    reduce: after region.n=%d\n", region_num_rects(region)));
33642542f5fSchristos}
33742542f5fSchristos
33803b705cfSriastradhstatic bool _sna_damage_create_boxes(struct sna_damage *damage,
33903b705cfSriastradh				     int count)
34003b705cfSriastradh{
34103b705cfSriastradh	struct sna_damage_box *box;
34203b705cfSriastradh	int n;
34303b705cfSriastradh
34442542f5fSchristos	box = last_box(damage);
34503b705cfSriastradh	n = 4*box->size;
34603b705cfSriastradh	if (n < count)
34703b705cfSriastradh		n = ALIGN(count, 64);
34803b705cfSriastradh
34903b705cfSriastradh	DBG(("    %s(%d->%d): new\n", __FUNCTION__, count, n));
35003b705cfSriastradh
35142542f5fSchristos	if (n >= (INT_MAX - sizeof(*box)) / sizeof(BoxRec))
35242542f5fSchristos		return false;
35342542f5fSchristos
35403b705cfSriastradh	box = malloc(sizeof(*box) + sizeof(BoxRec)*n);
35503b705cfSriastradh	if (box == NULL)
35603b705cfSriastradh		return false;
35703b705cfSriastradh
35803b705cfSriastradh	list_add_tail(&box->list, &damage->embedded_box.list);
35903b705cfSriastradh
36003b705cfSriastradh	box->size = damage->remain = n;
36103b705cfSriastradh	damage->box = (BoxRec *)(box + 1);
36203b705cfSriastradh	return true;
36303b705cfSriastradh}
36403b705cfSriastradh
36503b705cfSriastradhstatic struct sna_damage *
36603b705cfSriastradh_sna_damage_create_elt(struct sna_damage *damage,
36703b705cfSriastradh		       const BoxRec *boxes, int count)
36803b705cfSriastradh{
36903b705cfSriastradh	int n;
37003b705cfSriastradh
37103b705cfSriastradh	DBG(("    %s: prev=(remain %d), count=%d\n",
37203b705cfSriastradh	     __FUNCTION__, damage->remain, count));
37342542f5fSchristos	assert(count);
37403b705cfSriastradh
37542542f5fSchristosrestart:
37603b705cfSriastradh	n = count;
37703b705cfSriastradh	if (n > damage->remain)
37803b705cfSriastradh		n = damage->remain;
37903b705cfSriastradh	if (n) {
38003b705cfSriastradh		memcpy(damage->box, boxes, n * sizeof(BoxRec));
38103b705cfSriastradh		damage->box += n;
38203b705cfSriastradh		damage->remain -= n;
38342542f5fSchristos		damage->dirty = true;
38403b705cfSriastradh
38503b705cfSriastradh		count -= n;
38603b705cfSriastradh		boxes += n;
38703b705cfSriastradh		if (count == 0)
38803b705cfSriastradh			return damage;
38903b705cfSriastradh	}
39003b705cfSriastradh
39103b705cfSriastradh	DBG(("    %s(): new elt\n", __FUNCTION__));
39242542f5fSchristos	assert(damage->remain == 0);
39342542f5fSchristos	assert(damage->box - (BoxRec *)(last_box(damage)+1) == last_box(damage)->size);
39442542f5fSchristos
39542542f5fSchristos	if (!_sna_damage_create_boxes(damage, count)) {
39642542f5fSchristos		unsigned mode;
39742542f5fSchristos
39842542f5fSchristos		if (!damage->dirty)
39942542f5fSchristos			return damage;
40042542f5fSchristos
40142542f5fSchristos		mode = damage->mode;
40242542f5fSchristos		__sna_damage_reduce(damage);
40342542f5fSchristos		damage->mode = mode;
40403b705cfSriastradh
40542542f5fSchristos		goto restart;
40603b705cfSriastradh	}
40742542f5fSchristos
40842542f5fSchristos	memcpy(damage->box, boxes, count * sizeof(BoxRec));
40942542f5fSchristos	damage->box += count;
41042542f5fSchristos	damage->remain -= count;
41142542f5fSchristos	damage->dirty = true;
41203b705cfSriastradh	assert(damage->remain >= 0);
41303b705cfSriastradh
41403b705cfSriastradh	return damage;
41503b705cfSriastradh}
41603b705cfSriastradh
41703b705cfSriastradhstatic struct sna_damage *
41803b705cfSriastradh_sna_damage_create_elt_from_boxes(struct sna_damage *damage,
41903b705cfSriastradh				  const BoxRec *boxes, int count,
42003b705cfSriastradh				  int16_t dx, int16_t dy)
42103b705cfSriastradh{
42203b705cfSriastradh	int i, n;
42303b705cfSriastradh
42403b705cfSriastradh	DBG(("    %s: prev=(remain %d)\n", __FUNCTION__, damage->remain));
42542542f5fSchristos	assert(count);
42603b705cfSriastradh
42742542f5fSchristosrestart:
42803b705cfSriastradh	n = count;
42903b705cfSriastradh	if (n > damage->remain)
43003b705cfSriastradh		n = damage->remain;
43103b705cfSriastradh	if (n) {
43203b705cfSriastradh		for (i = 0; i < n; i++) {
43303b705cfSriastradh			damage->box[i].x1 = boxes[i].x1 + dx;
43403b705cfSriastradh			damage->box[i].x2 = boxes[i].x2 + dx;
43503b705cfSriastradh			damage->box[i].y1 = boxes[i].y1 + dy;
43603b705cfSriastradh			damage->box[i].y2 = boxes[i].y2 + dy;
43703b705cfSriastradh		}
43803b705cfSriastradh		damage->box += n;
43903b705cfSriastradh		damage->remain -= n;
44042542f5fSchristos		damage->dirty = true;
44103b705cfSriastradh
44203b705cfSriastradh		count -= n;
44303b705cfSriastradh		boxes += n;
44403b705cfSriastradh		if (count == 0)
44503b705cfSriastradh			return damage;
44603b705cfSriastradh	}
44703b705cfSriastradh
44803b705cfSriastradh	DBG(("    %s(): new elt\n", __FUNCTION__));
44942542f5fSchristos	assert(damage->remain == 0);
45042542f5fSchristos	assert(damage->box - (BoxRec *)(last_box(damage)+1) == last_box(damage)->size);
45103b705cfSriastradh
45242542f5fSchristos	if (!_sna_damage_create_boxes(damage, count)) {
45342542f5fSchristos		unsigned mode;
45442542f5fSchristos
45542542f5fSchristos		if (!damage->dirty)
45642542f5fSchristos			return damage;
45742542f5fSchristos
45842542f5fSchristos		mode = damage->mode;
45942542f5fSchristos		__sna_damage_reduce(damage);
46042542f5fSchristos		damage->mode = mode;
46142542f5fSchristos
46242542f5fSchristos		goto restart;
46342542f5fSchristos	}
46403b705cfSriastradh
46503b705cfSriastradh	for (i = 0; i < count; i++) {
46603b705cfSriastradh		damage->box[i].x1 = boxes[i].x1 + dx;
46703b705cfSriastradh		damage->box[i].x2 = boxes[i].x2 + dx;
46803b705cfSriastradh		damage->box[i].y1 = boxes[i].y1 + dy;
46903b705cfSriastradh		damage->box[i].y2 = boxes[i].y2 + dy;
47003b705cfSriastradh	}
47103b705cfSriastradh	damage->box += count;
47203b705cfSriastradh	damage->remain -= count;
47342542f5fSchristos	damage->dirty = true;
47403b705cfSriastradh	assert(damage->remain >= 0);
47503b705cfSriastradh
47603b705cfSriastradh	return damage;
47703b705cfSriastradh}
47803b705cfSriastradh
47903b705cfSriastradhstatic struct sna_damage *
48003b705cfSriastradh_sna_damage_create_elt_from_rectangles(struct sna_damage *damage,
48103b705cfSriastradh				       const xRectangle *r, int count,
48203b705cfSriastradh				       int16_t dx, int16_t dy)
48303b705cfSriastradh{
48403b705cfSriastradh	int i, n;
48503b705cfSriastradh
48603b705cfSriastradh	DBG(("    %s: prev=(remain %d), count=%d\n",
48703b705cfSriastradh	     __FUNCTION__, damage->remain, count));
48842542f5fSchristos	assert(count);
48903b705cfSriastradh
49042542f5fSchristosrestart:
49103b705cfSriastradh	n = count;
49203b705cfSriastradh	if (n > damage->remain)
49303b705cfSriastradh		n = damage->remain;
49403b705cfSriastradh	if (n) {
49503b705cfSriastradh		for (i = 0; i < n; i++) {
49603b705cfSriastradh			damage->box[i].x1 = r[i].x + dx;
49703b705cfSriastradh			damage->box[i].x2 = damage->box[i].x1 + r[i].width;
49803b705cfSriastradh			damage->box[i].y1 = r[i].y + dy;
49903b705cfSriastradh			damage->box[i].y2 = damage->box[i].y1 + r[i].height;
50003b705cfSriastradh		}
50103b705cfSriastradh		damage->box += n;
50203b705cfSriastradh		damage->remain -= n;
50342542f5fSchristos		damage->dirty = true;
50403b705cfSriastradh
50503b705cfSriastradh		count -= n;
50603b705cfSriastradh		r += n;
50703b705cfSriastradh		if (count == 0)
50803b705cfSriastradh			return damage;
50903b705cfSriastradh	}
51003b705cfSriastradh
51103b705cfSriastradh	DBG(("    %s(): new elt\n", __FUNCTION__));
51242542f5fSchristos	assert(damage->remain == 0);
51342542f5fSchristos	assert(damage->box - (BoxRec *)(last_box(damage)+1) == last_box(damage)->size);
51403b705cfSriastradh
51542542f5fSchristos	if (!_sna_damage_create_boxes(damage, count)) {
51642542f5fSchristos		unsigned mode;
51742542f5fSchristos
51842542f5fSchristos		if (!damage->dirty)
51942542f5fSchristos			return damage;
52042542f5fSchristos
52142542f5fSchristos		mode = damage->mode;
52242542f5fSchristos		__sna_damage_reduce(damage);
52342542f5fSchristos		damage->mode = mode;
52442542f5fSchristos
52542542f5fSchristos		goto restart;
52642542f5fSchristos	}
52703b705cfSriastradh
52803b705cfSriastradh	for (i = 0; i < count; i++) {
52903b705cfSriastradh		damage->box[i].x1 = r[i].x + dx;
53003b705cfSriastradh		damage->box[i].x2 = damage->box[i].x1 + r[i].width;
53103b705cfSriastradh		damage->box[i].y1 = r[i].y + dy;
53203b705cfSriastradh		damage->box[i].y2 = damage->box[i].y1 + r[i].height;
53303b705cfSriastradh	}
53403b705cfSriastradh	damage->box += count;
53503b705cfSriastradh	damage->remain -= count;
53642542f5fSchristos	damage->dirty = true;
53703b705cfSriastradh	assert(damage->remain >= 0);
53803b705cfSriastradh
53903b705cfSriastradh	return damage;
54003b705cfSriastradh}
54103b705cfSriastradh
54203b705cfSriastradhstatic struct sna_damage *
54303b705cfSriastradh_sna_damage_create_elt_from_points(struct sna_damage *damage,
54403b705cfSriastradh				   const DDXPointRec *p, int count,
54503b705cfSriastradh				   int16_t dx, int16_t dy)
54603b705cfSriastradh{
54703b705cfSriastradh	int i, n;
54803b705cfSriastradh
54903b705cfSriastradh	DBG(("    %s: prev=(remain %d), count=%d\n",
55003b705cfSriastradh	     __FUNCTION__, damage->remain, count));
55142542f5fSchristos	assert(count);
55203b705cfSriastradh
55342542f5fSchristosrestart:
55403b705cfSriastradh	n = count;
55503b705cfSriastradh	if (n > damage->remain)
55603b705cfSriastradh		n = damage->remain;
55703b705cfSriastradh	if (n) {
55803b705cfSriastradh		for (i = 0; i < n; i++) {
55903b705cfSriastradh			damage->box[i].x1 = p[i].x + dx;
56003b705cfSriastradh			damage->box[i].x2 = damage->box[i].x1 + 1;
56103b705cfSriastradh			damage->box[i].y1 = p[i].y + dy;
56203b705cfSriastradh			damage->box[i].y2 = damage->box[i].y1 + 1;
56303b705cfSriastradh		}
56403b705cfSriastradh		damage->box += n;
56503b705cfSriastradh		damage->remain -= n;
56642542f5fSchristos		damage->dirty = true;
56703b705cfSriastradh
56803b705cfSriastradh		count -= n;
56903b705cfSriastradh		p += n;
57003b705cfSriastradh		if (count == 0)
57103b705cfSriastradh			return damage;
57203b705cfSriastradh	}
57303b705cfSriastradh
57403b705cfSriastradh	DBG(("    %s(): new elt\n", __FUNCTION__));
57542542f5fSchristos	assert(damage->remain == 0);
57642542f5fSchristos	assert(damage->box - (BoxRec *)(last_box(damage)+1) == last_box(damage)->size);
57703b705cfSriastradh
57842542f5fSchristos	if (!_sna_damage_create_boxes(damage, count)) {
57942542f5fSchristos		unsigned mode;
58042542f5fSchristos
58142542f5fSchristos		if (!damage->dirty)
58242542f5fSchristos			return damage;
58342542f5fSchristos
58442542f5fSchristos		mode = damage->mode;
58542542f5fSchristos		__sna_damage_reduce(damage);
58642542f5fSchristos		damage->mode = mode;
58742542f5fSchristos
58842542f5fSchristos		goto restart;
58942542f5fSchristos	}
59003b705cfSriastradh
59103b705cfSriastradh	for (i = 0; i < count; i++) {
59203b705cfSriastradh		damage->box[i].x1 = p[i].x + dx;
59303b705cfSriastradh		damage->box[i].x2 = damage->box[i].x1 + 1;
59403b705cfSriastradh		damage->box[i].y1 = p[i].y + dy;
59503b705cfSriastradh		damage->box[i].y2 = damage->box[i].y1 + 1;
59603b705cfSriastradh	}
59703b705cfSriastradh	damage->box += count;
59803b705cfSriastradh	damage->remain -= count;
59942542f5fSchristos	damage->dirty = true;
60003b705cfSriastradh	assert(damage->remain >= 0);
60103b705cfSriastradh
60203b705cfSriastradh	return damage;
60303b705cfSriastradh}
60403b705cfSriastradh
60503b705cfSriastradhstatic void damage_union(struct sna_damage *damage, const BoxRec *box)
60603b705cfSriastradh{
60703b705cfSriastradh	DBG(("%s: extending damage (%d, %d), (%d, %d) by (%d, %d), (%d, %d)\n",
60803b705cfSriastradh	     __FUNCTION__,
60903b705cfSriastradh	     damage->extents.x1, damage->extents.y1,
61003b705cfSriastradh	     damage->extents.x2, damage->extents.y2,
61103b705cfSriastradh	     box->x1, box->y1, box->x2, box->y2));
61203b705cfSriastradh	assert(box->x2 > box->x1 && box->y2 > box->y1);
61303b705cfSriastradh	if (damage->extents.x2 < damage->extents.x1) {
61403b705cfSriastradh		damage->extents = *box;
61503b705cfSriastradh	} else {
61603b705cfSriastradh		if (damage->extents.x1 > box->x1)
61703b705cfSriastradh			damage->extents.x1 = box->x1;
61803b705cfSriastradh		if (damage->extents.x2 < box->x2)
61903b705cfSriastradh			damage->extents.x2 = box->x2;
62003b705cfSriastradh
62103b705cfSriastradh		if (damage->extents.y1 > box->y1)
62203b705cfSriastradh			damage->extents.y1 = box->y1;
62303b705cfSriastradh		if (damage->extents.y2 < box->y2)
62403b705cfSriastradh			damage->extents.y2 = box->y2;
62503b705cfSriastradh	}
62603b705cfSriastradh	assert(damage->extents.x2 > damage->extents.x1);
62703b705cfSriastradh	assert(damage->extents.y2 > damage->extents.y1);
62803b705cfSriastradh}
62903b705cfSriastradh
63003b705cfSriastradhstatic void _pixman_region_union_box(RegionRec *region, const BoxRec *box)
63103b705cfSriastradh{
63203b705cfSriastradh	RegionRec u = { *box, NULL };
63303b705cfSriastradh	pixman_region_union(region, region, &u);
63403b705cfSriastradh}
63503b705cfSriastradh
63603b705cfSriastradhstatic bool box_contains_region(const BoxRec *b, const RegionRec *r)
63703b705cfSriastradh{
63803b705cfSriastradh	return (b->x1 <= r->extents.x1 && b->x2 >= r->extents.x2 &&
63903b705cfSriastradh		b->y1 <= r->extents.y1 && b->y2 >= r->extents.y2);
64003b705cfSriastradh}
64103b705cfSriastradh
64203b705cfSriastradhstatic struct sna_damage *__sna_damage_add_box(struct sna_damage *damage,
64303b705cfSriastradh					       const BoxRec *box)
64403b705cfSriastradh{
64503b705cfSriastradh	if (box->y2 <= box->y1 || box->x2 <= box->x1)
64603b705cfSriastradh		return damage;
64703b705cfSriastradh
64803b705cfSriastradh	if (!damage) {
64903b705cfSriastradh		damage = _sna_damage_create();
65003b705cfSriastradh		if (damage == NULL)
65103b705cfSriastradh			return NULL;
65203b705cfSriastradh	} else switch (damage->mode) {
65303b705cfSriastradh	case DAMAGE_ALL:
65403b705cfSriastradh		return damage;
65503b705cfSriastradh	case DAMAGE_SUBTRACT:
65603b705cfSriastradh		__sna_damage_reduce(damage);
65703b705cfSriastradh	case DAMAGE_ADD:
65803b705cfSriastradh		break;
65903b705cfSriastradh	}
66003b705cfSriastradh
66142542f5fSchristos	if (region_is_singular_or_empty(&damage->region) ||
66203b705cfSriastradh	    box_contains_region(box, &damage->region)) {
66303b705cfSriastradh		_pixman_region_union_box(&damage->region, box);
66403b705cfSriastradh		assert(damage->region.extents.x2 > damage->region.extents.x1);
66503b705cfSriastradh		assert(damage->region.extents.y2 > damage->region.extents.y1);
66603b705cfSriastradh		damage_union(damage, box);
66703b705cfSriastradh		return damage;
66803b705cfSriastradh	}
66903b705cfSriastradh
67003b705cfSriastradh	if (pixman_region_contains_rectangle(&damage->region,
67103b705cfSriastradh					     (BoxPtr)box) == PIXMAN_REGION_IN)
67203b705cfSriastradh		return damage;
67303b705cfSriastradh
67403b705cfSriastradh	damage_union(damage, box);
67503b705cfSriastradh	return _sna_damage_create_elt(damage, box, 1);
67603b705cfSriastradh}
67703b705cfSriastradh
67803b705cfSriastradhinline static struct sna_damage *__sna_damage_add(struct sna_damage *damage,
67903b705cfSriastradh						  RegionPtr region)
68003b705cfSriastradh{
68103b705cfSriastradh	assert(RegionNotEmpty(region));
68203b705cfSriastradh
68303b705cfSriastradh	if (!damage) {
68403b705cfSriastradh		damage = _sna_damage_create();
68503b705cfSriastradh		if (damage == NULL)
68603b705cfSriastradh			return NULL;
68703b705cfSriastradh	} else switch (damage->mode) {
68803b705cfSriastradh	case DAMAGE_ALL:
68903b705cfSriastradh		return damage;
69003b705cfSriastradh	case DAMAGE_SUBTRACT:
69103b705cfSriastradh		__sna_damage_reduce(damage);
69203b705cfSriastradh	case DAMAGE_ADD:
69303b705cfSriastradh		break;
69403b705cfSriastradh	}
69503b705cfSriastradh
69642542f5fSchristos	if (region_is_singular(region))
69703b705cfSriastradh		return __sna_damage_add_box(damage, &region->extents);
69803b705cfSriastradh
69942542f5fSchristos	if (region_is_singular_or_empty(&damage->region)) {
70003b705cfSriastradh		pixman_region_union(&damage->region, &damage->region, region);
70103b705cfSriastradh		assert(damage->region.extents.x2 > damage->region.extents.x1);
70203b705cfSriastradh		assert(damage->region.extents.y2 > damage->region.extents.y1);
70303b705cfSriastradh		damage_union(damage, &region->extents);
70403b705cfSriastradh		return damage;
70503b705cfSriastradh	}
70603b705cfSriastradh
70703b705cfSriastradh	if (pixman_region_contains_rectangle(&damage->region,
70803b705cfSriastradh					     &region->extents) == PIXMAN_REGION_IN)
70903b705cfSriastradh		return damage;
71003b705cfSriastradh
71103b705cfSriastradh	damage_union(damage, &region->extents);
71203b705cfSriastradh	return _sna_damage_create_elt(damage,
71342542f5fSchristos				      region_rects(region),
71442542f5fSchristos				      region_num_rects(region));
71503b705cfSriastradh}
71603b705cfSriastradh
71703b705cfSriastradh#if HAS_DEBUG_FULL
71803b705cfSriastradhfastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage,
71903b705cfSriastradh					    RegionPtr region)
72003b705cfSriastradh{
72103b705cfSriastradh	char region_buf[120];
72203b705cfSriastradh	char damage_buf[1000];
72303b705cfSriastradh
72403b705cfSriastradh	DBG(("%s(%s + %s)\n", __FUNCTION__,
72503b705cfSriastradh	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
72603b705cfSriastradh	     _debug_describe_region(region_buf, sizeof(region_buf), region)));
72703b705cfSriastradh
72803b705cfSriastradh	damage = __sna_damage_add(damage, region);
72903b705cfSriastradh
73042542f5fSchristos	DBG(("  = %s\n",
73142542f5fSchristos	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
73242542f5fSchristos	assert(region_num_rects(&damage->region));
73303b705cfSriastradh	assert(damage->region.extents.x2 > damage->region.extents.x1);
73403b705cfSriastradh	assert(damage->region.extents.y2 > damage->region.extents.y1);
73503b705cfSriastradh
73603b705cfSriastradh	return damage;
73703b705cfSriastradh}
73803b705cfSriastradh#else
73903b705cfSriastradhfastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage,
74003b705cfSriastradh					    RegionPtr region)
74103b705cfSriastradh{
74203b705cfSriastradh	return __sna_damage_add(damage, region);
74303b705cfSriastradh}
74403b705cfSriastradh#endif
74503b705cfSriastradh
74603b705cfSriastradhinline static struct sna_damage *
74703b705cfSriastradh__sna_damage_add_boxes(struct sna_damage *damage,
74803b705cfSriastradh		       const BoxRec *box, int n,
74903b705cfSriastradh		       int16_t dx, int16_t dy)
75003b705cfSriastradh{
75103b705cfSriastradh	BoxRec extents;
75203b705cfSriastradh	int i;
75303b705cfSriastradh
75403b705cfSriastradh	assert(n);
75503b705cfSriastradh
75603b705cfSriastradh	if (!damage) {
75703b705cfSriastradh		damage = _sna_damage_create();
75803b705cfSriastradh		if (damage == NULL)
75903b705cfSriastradh			return NULL;
76003b705cfSriastradh	} else switch (damage->mode) {
76103b705cfSriastradh	case DAMAGE_ALL:
76203b705cfSriastradh		return damage;
76303b705cfSriastradh	case DAMAGE_SUBTRACT:
76403b705cfSriastradh		__sna_damage_reduce(damage);
76503b705cfSriastradh	case DAMAGE_ADD:
76603b705cfSriastradh		break;
76703b705cfSriastradh	}
76803b705cfSriastradh
76903b705cfSriastradh	assert(box[0].x2 > box[0].x1 && box[0].y2 > box[0].y1);
77003b705cfSriastradh	extents = box[0];
77103b705cfSriastradh	for (i = 1; i < n; i++) {
77203b705cfSriastradh		assert(box[i].x2 > box[i].x1 && box[i].y2 > box[i].y1);
77303b705cfSriastradh		if (extents.x1 > box[i].x1)
77403b705cfSriastradh			extents.x1 = box[i].x1;
77503b705cfSriastradh		if (extents.x2 < box[i].x2)
77603b705cfSriastradh			extents.x2 = box[i].x2;
77703b705cfSriastradh		if (extents.y1 > box[i].y1)
77803b705cfSriastradh			extents.y1 = box[i].y1;
77903b705cfSriastradh		if (extents.y2 < box[i].y2)
78003b705cfSriastradh			extents.y2 = box[i].y2;
78103b705cfSriastradh	}
78203b705cfSriastradh
78303b705cfSriastradh	assert(extents.y2 > extents.y1 && extents.x2 > extents.x1);
78403b705cfSriastradh
78503b705cfSriastradh	extents.x1 += dx;
78603b705cfSriastradh	extents.x2 += dx;
78703b705cfSriastradh	extents.y1 += dy;
78803b705cfSriastradh	extents.y2 += dy;
78903b705cfSriastradh
79003b705cfSriastradh	if (n == 1)
79103b705cfSriastradh		return __sna_damage_add_box(damage, &extents);
79203b705cfSriastradh
79303b705cfSriastradh	if (pixman_region_contains_rectangle(&damage->region,
79403b705cfSriastradh					     &extents) == PIXMAN_REGION_IN)
79503b705cfSriastradh		return damage;
79603b705cfSriastradh
79703b705cfSriastradh	damage_union(damage, &extents);
79803b705cfSriastradh	return _sna_damage_create_elt_from_boxes(damage, box, n, dx, dy);
79903b705cfSriastradh}
80003b705cfSriastradh
80103b705cfSriastradh#if HAS_DEBUG_FULL
80203b705cfSriastradhstruct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
80303b705cfSriastradh					 const BoxRec *b, int n,
80403b705cfSriastradh					 int16_t dx, int16_t dy)
80503b705cfSriastradh{
80603b705cfSriastradh	char damage_buf[1000];
80703b705cfSriastradh
80803b705cfSriastradh	DBG(("%s(%s + [(%d, %d), (%d, %d) ... x %d])\n", __FUNCTION__,
80903b705cfSriastradh	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
81003b705cfSriastradh	     b->x1, b->y1, b->x2, b->y2, n));
81103b705cfSriastradh
81203b705cfSriastradh	damage = __sna_damage_add_boxes(damage, b, n, dx, dy);
81303b705cfSriastradh
81442542f5fSchristos	DBG(("  = %s\n",
81542542f5fSchristos	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
81642542f5fSchristos	if (region_num_rects(&damage->region)) {
81703b705cfSriastradh		assert(damage->region.extents.x2 > damage->region.extents.x1);
81803b705cfSriastradh		assert(damage->region.extents.y2 > damage->region.extents.y1);
81903b705cfSriastradh	}
82003b705cfSriastradh
82103b705cfSriastradh	return damage;
82203b705cfSriastradh}
82303b705cfSriastradh#else
82403b705cfSriastradhstruct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
82503b705cfSriastradh					 const BoxRec *b, int n,
82603b705cfSriastradh					 int16_t dx, int16_t dy)
82703b705cfSriastradh{
82803b705cfSriastradh	return __sna_damage_add_boxes(damage, b, n, dx, dy);
82903b705cfSriastradh}
83003b705cfSriastradh#endif
83103b705cfSriastradh
83203b705cfSriastradhinline static struct sna_damage *
83303b705cfSriastradh__sna_damage_add_rectangles(struct sna_damage *damage,
83403b705cfSriastradh			    const xRectangle *r, int n,
83503b705cfSriastradh			    int16_t dx, int16_t dy)
83603b705cfSriastradh{
83703b705cfSriastradh	BoxRec extents;
83803b705cfSriastradh	int i;
83903b705cfSriastradh
84003b705cfSriastradh	assert(n);
84103b705cfSriastradh
84203b705cfSriastradh	assert(r[0].width && r[0].height);
84303b705cfSriastradh	extents.x1 = r[0].x;
84403b705cfSriastradh	extents.x2 = r[0].x + r[0].width;
84503b705cfSriastradh	extents.y1 = r[0].y;
84603b705cfSriastradh	extents.y2 = r[0].y + r[0].height;
84703b705cfSriastradh	for (i = 1; i < n; i++) {
84803b705cfSriastradh		assert(r[i].width && r[i].height);
84903b705cfSriastradh		if (extents.x1 > r[i].x)
85003b705cfSriastradh			extents.x1 = r[i].x;
85103b705cfSriastradh		if (extents.x2 < r[i].x + r[i].width)
85203b705cfSriastradh			extents.x2 = r[i].x + r[i].width;
85303b705cfSriastradh		if (extents.y1 > r[i].y)
85403b705cfSriastradh			extents.y1 = r[i].y;
85503b705cfSriastradh		if (extents.y2 < r[i].y + r[i].height)
85603b705cfSriastradh			extents.y2 = r[i].y + r[i].height;
85703b705cfSriastradh	}
85803b705cfSriastradh
85903b705cfSriastradh	assert(extents.y2 > extents.y1 && extents.x2 > extents.x1);
86003b705cfSriastradh
86103b705cfSriastradh	extents.x1 += dx;
86203b705cfSriastradh	extents.x2 += dx;
86303b705cfSriastradh	extents.y1 += dy;
86403b705cfSriastradh	extents.y2 += dy;
86503b705cfSriastradh
86603b705cfSriastradh	if (n == 1)
86703b705cfSriastradh		return __sna_damage_add_box(damage, &extents);
86803b705cfSriastradh
86903b705cfSriastradh	if (!damage) {
87003b705cfSriastradh		damage = _sna_damage_create();
87103b705cfSriastradh		if (damage == NULL)
87203b705cfSriastradh			return NULL;
87303b705cfSriastradh	} else switch (damage->mode) {
87403b705cfSriastradh	case DAMAGE_ALL:
87503b705cfSriastradh		return damage;
87603b705cfSriastradh	case DAMAGE_SUBTRACT:
87703b705cfSriastradh		__sna_damage_reduce(damage);
87803b705cfSriastradh	case DAMAGE_ADD:
87903b705cfSriastradh		break;
88003b705cfSriastradh	}
88103b705cfSriastradh
88203b705cfSriastradh	if (pixman_region_contains_rectangle(&damage->region,
88303b705cfSriastradh					     &extents) == PIXMAN_REGION_IN)
88403b705cfSriastradh		return damage;
88503b705cfSriastradh
88603b705cfSriastradh	damage_union(damage, &extents);
88703b705cfSriastradh	return _sna_damage_create_elt_from_rectangles(damage, r, n, dx, dy);
88803b705cfSriastradh}
88903b705cfSriastradh
89003b705cfSriastradh#if HAS_DEBUG_FULL
89103b705cfSriastradhstruct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage,
89203b705cfSriastradh					      const xRectangle *r, int n,
89303b705cfSriastradh					      int16_t dx, int16_t dy)
89403b705cfSriastradh{
89503b705cfSriastradh	char damage_buf[1000];
89603b705cfSriastradh
89703b705cfSriastradh	DBG(("%s(%s + [(%d, %d)x(%d, %d) ... x %d])\n", __FUNCTION__,
89803b705cfSriastradh	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
89903b705cfSriastradh	     r->x, r->y, r->width, r->height, n));
90003b705cfSriastradh
90103b705cfSriastradh	damage = __sna_damage_add_rectangles(damage, r, n, dx, dy);
90203b705cfSriastradh
90342542f5fSchristos	DBG(("  = %s\n",
90442542f5fSchristos	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
90542542f5fSchristos	if (region_num_rects(&damage->region)) {
90603b705cfSriastradh		assert(damage->region.extents.x2 > damage->region.extents.x1);
90703b705cfSriastradh		assert(damage->region.extents.y2 > damage->region.extents.y1);
90803b705cfSriastradh	}
90903b705cfSriastradh
91003b705cfSriastradh	return damage;
91103b705cfSriastradh}
91203b705cfSriastradh#else
91303b705cfSriastradhstruct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage,
91403b705cfSriastradh					      const xRectangle *r, int n,
91503b705cfSriastradh					      int16_t dx, int16_t dy)
91603b705cfSriastradh{
91703b705cfSriastradh	return __sna_damage_add_rectangles(damage, r, n, dx, dy);
91803b705cfSriastradh}
91903b705cfSriastradh#endif
92003b705cfSriastradh
92103b705cfSriastradh/* XXX pass in extents? */
92203b705cfSriastradhinline static struct sna_damage *
92303b705cfSriastradh__sna_damage_add_points(struct sna_damage *damage,
92403b705cfSriastradh			const DDXPointRec *p, int n,
92503b705cfSriastradh			int16_t dx, int16_t dy)
92603b705cfSriastradh{
92703b705cfSriastradh	BoxRec extents;
92803b705cfSriastradh	int i;
92903b705cfSriastradh
93003b705cfSriastradh	assert(n);
93103b705cfSriastradh
93203b705cfSriastradh	extents.x2 = extents.x1 = p[0].x;
93303b705cfSriastradh	extents.y2 = extents.y1 = p[0].y;
93403b705cfSriastradh	for (i = 1; i < n; i++) {
93503b705cfSriastradh		if (extents.x1 > p[i].x)
93603b705cfSriastradh			extents.x1 = p[i].x;
93703b705cfSriastradh		else if (extents.x2 < p[i].x)
93803b705cfSriastradh			extents.x2 = p[i].x;
93903b705cfSriastradh		if (extents.y1 > p[i].y)
94003b705cfSriastradh			extents.y1 = p[i].y;
94103b705cfSriastradh		else if (extents.y2 < p[i].y)
94203b705cfSriastradh			extents.y2 = p[i].y;
94303b705cfSriastradh	}
94403b705cfSriastradh
94503b705cfSriastradh	extents.x1 += dx;
94603b705cfSriastradh	extents.x2 += dx + 1;
94703b705cfSriastradh	extents.y1 += dy;
94803b705cfSriastradh	extents.y2 += dy + 1;
94903b705cfSriastradh
95003b705cfSriastradh	if (n == 1)
95103b705cfSriastradh		return __sna_damage_add_box(damage, &extents);
95203b705cfSriastradh
95303b705cfSriastradh	if (!damage) {
95403b705cfSriastradh		damage = _sna_damage_create();
95503b705cfSriastradh		if (damage == NULL)
95603b705cfSriastradh			return NULL;
95703b705cfSriastradh	} else switch (damage->mode) {
95803b705cfSriastradh	case DAMAGE_ALL:
95903b705cfSriastradh		return damage;
96003b705cfSriastradh	case DAMAGE_SUBTRACT:
96103b705cfSriastradh		__sna_damage_reduce(damage);
96203b705cfSriastradh	case DAMAGE_ADD:
96303b705cfSriastradh		break;
96403b705cfSriastradh	}
96503b705cfSriastradh
96603b705cfSriastradh	if (pixman_region_contains_rectangle(&damage->region,
96703b705cfSriastradh					     &extents) == PIXMAN_REGION_IN)
96803b705cfSriastradh		return damage;
96903b705cfSriastradh
97003b705cfSriastradh	damage_union(damage, &extents);
97142542f5fSchristos	return _sna_damage_create_elt_from_points(damage, p, n, dx, dy);
97203b705cfSriastradh}
97303b705cfSriastradh
97403b705cfSriastradh#if HAS_DEBUG_FULL
97503b705cfSriastradhstruct sna_damage *_sna_damage_add_points(struct sna_damage *damage,
97603b705cfSriastradh					  const DDXPointRec *p, int n,
97703b705cfSriastradh					  int16_t dx, int16_t dy)
97803b705cfSriastradh{
97903b705cfSriastradh	char damage_buf[1000];
98003b705cfSriastradh
98103b705cfSriastradh	DBG(("%s(%s + [(%d, %d) ... x %d])\n", __FUNCTION__,
98203b705cfSriastradh	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
98303b705cfSriastradh	     p->x, p->y, n));
98403b705cfSriastradh
98503b705cfSriastradh	damage = __sna_damage_add_points(damage, p, n, dx, dy);
98603b705cfSriastradh
98742542f5fSchristos	DBG(("  = %s\n",
98842542f5fSchristos	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
98942542f5fSchristos	if (region_num_rects(&damage->region)) {
99003b705cfSriastradh		assert(damage->region.extents.x2 > damage->region.extents.x1);
99103b705cfSriastradh		assert(damage->region.extents.y2 > damage->region.extents.y1);
99203b705cfSriastradh	}
99303b705cfSriastradh
99403b705cfSriastradh	return damage;
99503b705cfSriastradh}
99603b705cfSriastradh#else
99703b705cfSriastradhstruct sna_damage *_sna_damage_add_points(struct sna_damage *damage,
99803b705cfSriastradh					  const DDXPointRec *p, int n,
99903b705cfSriastradh					  int16_t dx, int16_t dy)
100003b705cfSriastradh{
100103b705cfSriastradh	return __sna_damage_add_points(damage, p, n, dx, dy);
100203b705cfSriastradh}
100303b705cfSriastradh#endif
100403b705cfSriastradh
100503b705cfSriastradh#if HAS_DEBUG_FULL
100603b705cfSriastradhfastcall struct sna_damage *_sna_damage_add_box(struct sna_damage *damage,
100703b705cfSriastradh						const BoxRec *box)
100803b705cfSriastradh{
100903b705cfSriastradh	char damage_buf[1000];
101003b705cfSriastradh
101103b705cfSriastradh	DBG(("%s(%s + [(%d, %d), (%d, %d)])\n", __FUNCTION__,
101203b705cfSriastradh	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
101303b705cfSriastradh	     box->x1, box->y1, box->x2, box->y2));
101403b705cfSriastradh
101503b705cfSriastradh	damage = __sna_damage_add_box(damage, box);
101603b705cfSriastradh
101742542f5fSchristos	DBG(("  = %s\n",
101842542f5fSchristos	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
101942542f5fSchristos	assert(region_num_rects(&damage->region));
102003b705cfSriastradh	assert(damage->region.extents.x2 > damage->region.extents.x1);
102103b705cfSriastradh	assert(damage->region.extents.y2 > damage->region.extents.y1);
102203b705cfSriastradh
102303b705cfSriastradh	return damage;
102403b705cfSriastradh}
102503b705cfSriastradh#else
102603b705cfSriastradhfastcall struct sna_damage *_sna_damage_add_box(struct sna_damage *damage,
102703b705cfSriastradh						const BoxRec *box)
102803b705cfSriastradh{
102903b705cfSriastradh	return __sna_damage_add_box(damage, box);
103003b705cfSriastradh}
103103b705cfSriastradh#endif
103203b705cfSriastradh
103303b705cfSriastradhstruct sna_damage *__sna_damage_all(struct sna_damage *damage,
103403b705cfSriastradh				    int width, int height)
103503b705cfSriastradh{
103603b705cfSriastradh	DBG(("%s(%d, %d)\n", __FUNCTION__, width, height));
103703b705cfSriastradh
103803b705cfSriastradh	if (damage) {
103903b705cfSriastradh		pixman_region_fini(&damage->region);
104003b705cfSriastradh		free_list(&damage->embedded_box.list);
104103b705cfSriastradh		reset_embedded_box(damage);
104203b705cfSriastradh	} else {
104303b705cfSriastradh		damage = _sna_damage_create();
104403b705cfSriastradh		if (damage == NULL)
104503b705cfSriastradh			return NULL;
104603b705cfSriastradh	}
104703b705cfSriastradh
104803b705cfSriastradh	pixman_region_init_rect(&damage->region, 0, 0, width, height);
104903b705cfSriastradh	damage->extents = damage->region.extents;
105003b705cfSriastradh	damage->mode = DAMAGE_ALL;
105103b705cfSriastradh
105203b705cfSriastradh	return damage;
105303b705cfSriastradh}
105403b705cfSriastradh
105503b705cfSriastradhstruct sna_damage *_sna_damage_is_all(struct sna_damage *damage,
105603b705cfSriastradh				      int width, int height)
105703b705cfSriastradh{
105803b705cfSriastradh	DBG(("%s(%d, %d)%s?\n", __FUNCTION__, width, height,
105903b705cfSriastradh	     damage->dirty ? "*" : ""));
106003b705cfSriastradh	DBG(("%s: (%d, %d), (%d, %d)\n", __FUNCTION__,
106103b705cfSriastradh	     damage->extents.x1, damage->extents.y1,
106203b705cfSriastradh	     damage->extents.x2, damage->extents.y2));
106303b705cfSriastradh
106403b705cfSriastradh	assert(damage->mode == DAMAGE_ADD);
106503b705cfSriastradh	assert(damage->extents.x1 == 0 &&
106603b705cfSriastradh	       damage->extents.y1 == 0 &&
106703b705cfSriastradh	       damage->extents.x2 == width &&
106803b705cfSriastradh	       damage->extents.y2 == height);
106903b705cfSriastradh
107003b705cfSriastradh	if (damage->dirty) {
107103b705cfSriastradh		__sna_damage_reduce(damage);
107203b705cfSriastradh		assert(RegionNotEmpty(&damage->region));
107303b705cfSriastradh	}
107403b705cfSriastradh
107503b705cfSriastradh	if (damage->region.data) {
107603b705cfSriastradh		DBG(("%s: no, not singular\n", __FUNCTION__));
107703b705cfSriastradh		return damage;
107803b705cfSriastradh	}
107903b705cfSriastradh
108003b705cfSriastradh	assert(damage->extents.x1 == 0 &&
108103b705cfSriastradh	       damage->extents.y1 == 0 &&
108203b705cfSriastradh	       damage->extents.x2 == width &&
108303b705cfSriastradh	       damage->extents.y2 == height);
108403b705cfSriastradh
108503b705cfSriastradh	return __sna_damage_all(damage, width, height);
108603b705cfSriastradh}
108703b705cfSriastradh
108803b705cfSriastradhstatic bool box_contains(const BoxRec *a, const BoxRec *b)
108903b705cfSriastradh{
109003b705cfSriastradh	if (b->x1 < a->x1 || b->x2 > a->x2)
109103b705cfSriastradh		return false;
109203b705cfSriastradh
109303b705cfSriastradh	if (b->y1 < a->y1 || b->y2 > a->y2)
109403b705cfSriastradh		return false;
109503b705cfSriastradh
109603b705cfSriastradh	return true;
109703b705cfSriastradh}
109803b705cfSriastradh
109903b705cfSriastradhstatic struct sna_damage *__sna_damage_subtract(struct sna_damage *damage,
110003b705cfSriastradh						RegionPtr region)
110103b705cfSriastradh{
110203b705cfSriastradh	if (damage == NULL)
110303b705cfSriastradh		return NULL;
110403b705cfSriastradh
110503b705cfSriastradh	if (RegionNil(&damage->region)) {
110603b705cfSriastradhno_damage:
110703b705cfSriastradh		__sna_damage_destroy(damage);
110803b705cfSriastradh		return NULL;
110903b705cfSriastradh	}
111003b705cfSriastradh
111103b705cfSriastradh	assert(RegionNotEmpty(region));
111203b705cfSriastradh
111303b705cfSriastradh	if (!sna_damage_overlaps_box(damage, &region->extents))
111403b705cfSriastradh		return damage;
111503b705cfSriastradh
111603b705cfSriastradh	if (region_is_singular(region) &&
111703b705cfSriastradh	    box_contains(&region->extents, &damage->extents))
111803b705cfSriastradh		goto no_damage;
111903b705cfSriastradh
112003b705cfSriastradh	if (damage->mode == DAMAGE_ALL) {
112103b705cfSriastradh		pixman_region_subtract(&damage->region,
112203b705cfSriastradh				       &damage->region,
112303b705cfSriastradh				       region);
112403b705cfSriastradh		if (damage->region.extents.x2 <= damage->region.extents.x1 ||
112503b705cfSriastradh		    damage->region.extents.y2 <= damage->region.extents.y1)
112603b705cfSriastradh			goto no_damage;
112703b705cfSriastradh
112803b705cfSriastradh		damage->extents = damage->region.extents;
112903b705cfSriastradh		damage->mode = DAMAGE_ADD;
113003b705cfSriastradh		return damage;
113103b705cfSriastradh	}
113203b705cfSriastradh
113303b705cfSriastradh	if (damage->mode != DAMAGE_SUBTRACT) {
113403b705cfSriastradh		if (damage->dirty) {
113503b705cfSriastradh			__sna_damage_reduce(damage);
113603b705cfSriastradh			assert(RegionNotEmpty(&damage->region));
113703b705cfSriastradh		}
113803b705cfSriastradh
113903b705cfSriastradh		if (pixman_region_equal(region, &damage->region))
114003b705cfSriastradh			goto no_damage;
114103b705cfSriastradh
114203b705cfSriastradh		if (region_is_singular(&damage->region) &&
114303b705cfSriastradh		    region_is_singular(region)) {
114403b705cfSriastradh			pixman_region_subtract(&damage->region,
114503b705cfSriastradh					       &damage->region,
114603b705cfSriastradh					       region);
114703b705cfSriastradh			if (damage->region.extents.x2 <= damage->region.extents.x1 ||
114803b705cfSriastradh			    damage->region.extents.y2 <= damage->region.extents.y1)
114903b705cfSriastradh				goto no_damage;
115003b705cfSriastradh
115103b705cfSriastradh			damage->extents = damage->region.extents;
115203b705cfSriastradh			assert(pixman_region_not_empty(&damage->region));
115303b705cfSriastradh			return damage;
115403b705cfSriastradh		}
115503b705cfSriastradh
115603b705cfSriastradh		damage->mode = DAMAGE_SUBTRACT;
115703b705cfSriastradh	}
115803b705cfSriastradh
115903b705cfSriastradh	return _sna_damage_create_elt(damage,
116042542f5fSchristos				      region_rects(region),
116142542f5fSchristos				      region_num_rects(region));
116203b705cfSriastradh}
116303b705cfSriastradh
116403b705cfSriastradh#if HAS_DEBUG_FULL
116503b705cfSriastradhfastcall struct sna_damage *_sna_damage_subtract(struct sna_damage *damage,
116603b705cfSriastradh						 RegionPtr region)
116703b705cfSriastradh{
116803b705cfSriastradh	char damage_buf[1000];
116903b705cfSriastradh	char region_buf[120];
117003b705cfSriastradh
117142542f5fSchristos	DBG(("%s(%s - %s)...\n", __FUNCTION__,
117203b705cfSriastradh	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
117342542f5fSchristos	       _debug_describe_region(region_buf, sizeof(region_buf), region)));
117403b705cfSriastradh
117503b705cfSriastradh	damage = __sna_damage_subtract(damage, region);
117603b705cfSriastradh
117742542f5fSchristos	DBG(("  = %s\n",
117842542f5fSchristos	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
117903b705cfSriastradh
118003b705cfSriastradh	return damage;
118103b705cfSriastradh}
118203b705cfSriastradh#else
118303b705cfSriastradhfastcall struct sna_damage *_sna_damage_subtract(struct sna_damage *damage,
118403b705cfSriastradh						 RegionPtr region)
118503b705cfSriastradh{
118603b705cfSriastradh	return __sna_damage_subtract(damage, region);
118703b705cfSriastradh}
118803b705cfSriastradh#endif
118903b705cfSriastradh
119003b705cfSriastradhinline static struct sna_damage *__sna_damage_subtract_box(struct sna_damage *damage,
119103b705cfSriastradh							   const BoxRec *box)
119203b705cfSriastradh{
119303b705cfSriastradh	assert(box->x2 > box->x1 && box->y2 > box->y1);
119403b705cfSriastradh
119503b705cfSriastradh	if (damage == NULL)
119603b705cfSriastradh		return NULL;
119703b705cfSriastradh
119803b705cfSriastradh	if (RegionNil(&damage->region)) {
119903b705cfSriastradh		__sna_damage_destroy(damage);
120003b705cfSriastradh		return NULL;
120103b705cfSriastradh	}
120203b705cfSriastradh
120303b705cfSriastradh	if (!sna_damage_overlaps_box(damage, box))
120403b705cfSriastradh		return damage;
120503b705cfSriastradh
120603b705cfSriastradh	if (box_contains(box, &damage->extents)) {
120703b705cfSriastradh		__sna_damage_destroy(damage);
120803b705cfSriastradh		return NULL;
120903b705cfSriastradh	}
121003b705cfSriastradh
121103b705cfSriastradh	if (damage->mode != DAMAGE_SUBTRACT) {
121203b705cfSriastradh		if (damage->dirty) {
121303b705cfSriastradh			__sna_damage_reduce(damage);
121403b705cfSriastradh			assert(RegionNotEmpty(&damage->region));
121503b705cfSriastradh		}
121603b705cfSriastradh
121703b705cfSriastradh		if (region_is_singular(&damage->region)) {
121803b705cfSriastradh			pixman_region16_t region;
121903b705cfSriastradh
122003b705cfSriastradh			pixman_region_init_rects(&region, box, 1);
122103b705cfSriastradh			pixman_region_subtract(&damage->region,
122203b705cfSriastradh					       &damage->region,
122303b705cfSriastradh					       &region);
122403b705cfSriastradh			damage->extents = damage->region.extents;
122503b705cfSriastradh			damage->mode = DAMAGE_ADD;
122603b705cfSriastradh			return damage;
122703b705cfSriastradh		}
122803b705cfSriastradh
122903b705cfSriastradh		damage->mode = DAMAGE_SUBTRACT;
123003b705cfSriastradh	}
123103b705cfSriastradh
123203b705cfSriastradh	return _sna_damage_create_elt(damage, box, 1);
123303b705cfSriastradh}
123403b705cfSriastradh
123503b705cfSriastradh#if HAS_DEBUG_FULL
123603b705cfSriastradhfastcall struct sna_damage *_sna_damage_subtract_box(struct sna_damage *damage,
123703b705cfSriastradh						     const BoxRec *box)
123803b705cfSriastradh{
123903b705cfSriastradh	char damage_buf[1000];
124003b705cfSriastradh
124142542f5fSchristos	DBG(("%s(%s - (%d, %d), (%d, %d))...\n", __FUNCTION__,
124242542f5fSchristos	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
124342542f5fSchristos	     box->x1, box->y1, box->x2, box->y2));
124403b705cfSriastradh
124503b705cfSriastradh	damage = __sna_damage_subtract_box(damage, box);
124603b705cfSriastradh
124742542f5fSchristos	DBG(("  = %s\n",
124842542f5fSchristos	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
124903b705cfSriastradh
125003b705cfSriastradh	return damage;
125103b705cfSriastradh}
125203b705cfSriastradh#else
125303b705cfSriastradhfastcall struct sna_damage *_sna_damage_subtract_box(struct sna_damage *damage,
125403b705cfSriastradh						     const BoxRec *box)
125503b705cfSriastradh{
125603b705cfSriastradh	return __sna_damage_subtract_box(damage, box);
125703b705cfSriastradh}
125803b705cfSriastradh#endif
125903b705cfSriastradh
126003b705cfSriastradhstatic struct sna_damage *__sna_damage_subtract_boxes(struct sna_damage *damage,
126103b705cfSriastradh						      const BoxRec *box, int n,
126203b705cfSriastradh						      int dx, int dy)
126303b705cfSriastradh{
126403b705cfSriastradh	BoxRec extents;
126503b705cfSriastradh	int i;
126603b705cfSriastradh
126703b705cfSriastradh	if (damage == NULL)
126803b705cfSriastradh		return NULL;
126903b705cfSriastradh
127003b705cfSriastradh	if (RegionNil(&damage->region)) {
127103b705cfSriastradh		__sna_damage_destroy(damage);
127203b705cfSriastradh		return NULL;
127303b705cfSriastradh	}
127403b705cfSriastradh
127503b705cfSriastradh	assert(n);
127603b705cfSriastradh
127703b705cfSriastradh	assert(box[0].x2 > box[0].x1 && box[0].y2 > box[0].y1);
127803b705cfSriastradh	extents = box[0];
127903b705cfSriastradh	for (i = 1; i < n; i++) {
128003b705cfSriastradh		assert(box[i].x2 > box[i].x1 && box[i].y2 > box[i].y1);
128103b705cfSriastradh		if (extents.x1 > box[i].x1)
128203b705cfSriastradh			extents.x1 = box[i].x1;
128303b705cfSriastradh		if (extents.x2 < box[i].x2)
128403b705cfSriastradh			extents.x2 = box[i].x2;
128503b705cfSriastradh		if (extents.y1 > box[i].y1)
128603b705cfSriastradh			extents.y1 = box[i].y1;
128703b705cfSriastradh		if (extents.y2 < box[i].y2)
128803b705cfSriastradh			extents.y2 = box[i].y2;
128903b705cfSriastradh	}
129003b705cfSriastradh
129103b705cfSriastradh	assert(extents.y2 > extents.y1 && extents.x2 > extents.x1);
129203b705cfSriastradh
129303b705cfSriastradh	extents.x1 += dx;
129403b705cfSriastradh	extents.x2 += dx;
129503b705cfSriastradh	extents.y1 += dy;
129603b705cfSriastradh	extents.y2 += dy;
129703b705cfSriastradh
129803b705cfSriastradh	if (!sna_damage_overlaps_box(damage, &extents))
129903b705cfSriastradh		return damage;
130003b705cfSriastradh
130103b705cfSriastradh	if (n == 1)
130203b705cfSriastradh		return __sna_damage_subtract_box(damage, &extents);
130303b705cfSriastradh
130403b705cfSriastradh	if (damage->mode != DAMAGE_SUBTRACT) {
130503b705cfSriastradh		if (damage->dirty) {
130603b705cfSriastradh			__sna_damage_reduce(damage);
130703b705cfSriastradh			assert(RegionNotEmpty(&damage->region));
130803b705cfSriastradh		}
130903b705cfSriastradh
131003b705cfSriastradh		damage->mode = DAMAGE_SUBTRACT;
131103b705cfSriastradh	}
131203b705cfSriastradh
131303b705cfSriastradh	return _sna_damage_create_elt_from_boxes(damage, box, n, dx, dy);
131403b705cfSriastradh}
131503b705cfSriastradh
131603b705cfSriastradh#if HAS_DEBUG_FULL
131703b705cfSriastradhfastcall struct sna_damage *_sna_damage_subtract_boxes(struct sna_damage *damage,
131803b705cfSriastradh						       const BoxRec *box, int n,
131903b705cfSriastradh						       int dx, int dy)
132003b705cfSriastradh{
132103b705cfSriastradh	char damage_buf[1000];
132203b705cfSriastradh
132342542f5fSchristos	DBG(("%s(%s - [(%d,%d), (%d,%d)...x%d])...\n", __FUNCTION__,
132442542f5fSchristos	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
132542542f5fSchristos	     box->x1 + dx, box->y1 + dy,
132642542f5fSchristos	     box->x2 + dx, box->y2 + dy,
132742542f5fSchristos	     n));
132803b705cfSriastradh
132903b705cfSriastradh	damage = __sna_damage_subtract_boxes(damage, box, n, dx, dy);
133003b705cfSriastradh
133142542f5fSchristos	DBG(("  = %s\n",
133242542f5fSchristos	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
133303b705cfSriastradh
133403b705cfSriastradh	return damage;
133503b705cfSriastradh}
133603b705cfSriastradh#else
133703b705cfSriastradhfastcall struct sna_damage *_sna_damage_subtract_boxes(struct sna_damage *damage,
133803b705cfSriastradh						       const BoxRec *box, int n,
133903b705cfSriastradh						       int dx, int dy)
134003b705cfSriastradh{
134103b705cfSriastradh	return __sna_damage_subtract_boxes(damage, box, n, dx, dy);
134203b705cfSriastradh}
134303b705cfSriastradh#endif
134403b705cfSriastradh
134542542f5fSchristosstatic int __sna_damage_contains_box(struct sna_damage **_damage,
134603b705cfSriastradh				     const BoxRec *box)
134703b705cfSriastradh{
134842542f5fSchristos	struct sna_damage *damage = *_damage;
134942542f5fSchristos	const BoxRec *b;
135042542f5fSchristos	int n, count, ret;
135103b705cfSriastradh
135203b705cfSriastradh	if (damage->mode == DAMAGE_ALL)
135303b705cfSriastradh		return PIXMAN_REGION_IN;
135403b705cfSriastradh
135503b705cfSriastradh	if (!sna_damage_overlaps_box(damage, box))
135603b705cfSriastradh		return PIXMAN_REGION_OUT;
135703b705cfSriastradh
135803b705cfSriastradh	ret = pixman_region_contains_rectangle(&damage->region, (BoxPtr)box);
135903b705cfSriastradh	if (!damage->dirty)
136003b705cfSriastradh		return ret;
136103b705cfSriastradh
136203b705cfSriastradh	if (damage->mode == DAMAGE_ADD) {
136303b705cfSriastradh		if (ret == PIXMAN_REGION_IN)
136403b705cfSriastradh			return ret;
136542542f5fSchristos
136642542f5fSchristos		count = damage->embedded_box.size;
136742542f5fSchristos		if (list_is_empty(&damage->embedded_box.list))
136842542f5fSchristos			count -= damage->remain;
136942542f5fSchristos
137042542f5fSchristos		b = damage->embedded_box.box;
137142542f5fSchristos		for (n = 0; n < count; n++) {
137242542f5fSchristos			if (box_contains(&b[n], box))
137342542f5fSchristos				return PIXMAN_REGION_IN;
137442542f5fSchristos		}
137503b705cfSriastradh	} else {
137603b705cfSriastradh		if (ret == PIXMAN_REGION_OUT)
137703b705cfSriastradh			return ret;
137842542f5fSchristos
137942542f5fSchristos		count = damage->embedded_box.size;
138042542f5fSchristos		if (list_is_empty(&damage->embedded_box.list))
138142542f5fSchristos			count -= damage->remain;
138242542f5fSchristos
138342542f5fSchristos		b = damage->embedded_box.box;
138442542f5fSchristos		for (n = 0; n < count; n++) {
138542542f5fSchristos			if (box_contains(&b[n], box))
138642542f5fSchristos				return PIXMAN_REGION_OUT;
138742542f5fSchristos		}
138803b705cfSriastradh	}
138903b705cfSriastradh
139003b705cfSriastradh	__sna_damage_reduce(damage);
139142542f5fSchristos	if (!pixman_region_not_empty(&damage->region)) {
139242542f5fSchristos		__sna_damage_destroy(damage);
139342542f5fSchristos		*_damage = NULL;
139442542f5fSchristos		return PIXMAN_REGION_OUT;
139542542f5fSchristos	}
139642542f5fSchristos
139703b705cfSriastradh	return pixman_region_contains_rectangle(&damage->region, (BoxPtr)box);
139803b705cfSriastradh}
139903b705cfSriastradh
140003b705cfSriastradh#if HAS_DEBUG_FULL
140142542f5fSchristosint _sna_damage_contains_box(struct sna_damage **damage,
140203b705cfSriastradh			     const BoxRec *box)
140303b705cfSriastradh{
140403b705cfSriastradh	char damage_buf[1000];
140503b705cfSriastradh	int ret;
140603b705cfSriastradh
140703b705cfSriastradh	DBG(("%s(%s, [(%d, %d), (%d, %d)])\n", __FUNCTION__,
140842542f5fSchristos	     _debug_describe_damage(damage_buf, sizeof(damage_buf), *damage),
140903b705cfSriastradh	     box->x1, box->y1, box->x2, box->y2));
141003b705cfSriastradh
141103b705cfSriastradh	ret = __sna_damage_contains_box(damage, box);
141242542f5fSchristos	DBG(("  = %d", ret));
141303b705cfSriastradh	if (ret)
141442542f5fSchristos		DBG((" [(%d, %d), (%d, %d)...]",
141542542f5fSchristos		     box->x1, box->y1, box->x2, box->y2));
141642542f5fSchristos	DBG(("\n"));
141703b705cfSriastradh
141803b705cfSriastradh	return ret;
141903b705cfSriastradh}
142003b705cfSriastradh#else
142142542f5fSchristosint _sna_damage_contains_box(struct sna_damage **damage,
142203b705cfSriastradh			     const BoxRec *box)
142303b705cfSriastradh{
142403b705cfSriastradh	return __sna_damage_contains_box(damage, box);
142503b705cfSriastradh}
142603b705cfSriastradh#endif
142703b705cfSriastradh
142803b705cfSriastradhstatic bool box_overlaps(const BoxRec *a, const BoxRec *b)
142903b705cfSriastradh{
143003b705cfSriastradh	return (a->x1 < b->x2 && a->x2 > b->x1 &&
143103b705cfSriastradh		a->y1 < b->y2 && a->y2 > b->y1);
143203b705cfSriastradh}
143303b705cfSriastradh
143403b705cfSriastradhbool _sna_damage_contains_box__no_reduce(const struct sna_damage *damage,
143503b705cfSriastradh					 const BoxRec *box)
143603b705cfSriastradh{
143703b705cfSriastradh	int n, count;
143803b705cfSriastradh	const BoxRec *b;
143903b705cfSriastradh
144003b705cfSriastradh	assert(damage && damage->mode != DAMAGE_ALL);
144103b705cfSriastradh	if (!box_contains(&damage->extents, box))
144203b705cfSriastradh		return false;
144303b705cfSriastradh
144403b705cfSriastradh	n = pixman_region_contains_rectangle((pixman_region16_t *)&damage->region, (BoxPtr)box);
144503b705cfSriastradh	if (!damage->dirty)
144603b705cfSriastradh		return n == PIXMAN_REGION_IN;
144703b705cfSriastradh
144803b705cfSriastradh	if (damage->mode == DAMAGE_ADD) {
144903b705cfSriastradh		if (n == PIXMAN_REGION_IN)
145003b705cfSriastradh			return true;
145103b705cfSriastradh
145203b705cfSriastradh		count = damage->embedded_box.size;
145303b705cfSriastradh		if (list_is_empty(&damage->embedded_box.list))
145403b705cfSriastradh			count -= damage->remain;
145503b705cfSriastradh
145603b705cfSriastradh		b = damage->embedded_box.box;
145703b705cfSriastradh		for (n = 0; n < count; n++) {
145803b705cfSriastradh			if (box_contains(&b[n], box))
145903b705cfSriastradh				return true;
146003b705cfSriastradh		}
146103b705cfSriastradh
146203b705cfSriastradh		return false;
146303b705cfSriastradh	} else {
146403b705cfSriastradh		if (n != PIXMAN_REGION_IN)
146503b705cfSriastradh			return false;
146603b705cfSriastradh
146703b705cfSriastradh		if (!list_is_empty(&damage->embedded_box.list))
146803b705cfSriastradh			return false;
146903b705cfSriastradh
147003b705cfSriastradh		count = damage->embedded_box.size - damage->remain;
147103b705cfSriastradh		b = damage->embedded_box.box;
147203b705cfSriastradh		for (n = 0; n < count; n++) {
147303b705cfSriastradh			if (box_overlaps(&b[n], box))
147403b705cfSriastradh				return false;
147503b705cfSriastradh		}
147603b705cfSriastradh
147703b705cfSriastradh		return true;
147803b705cfSriastradh	}
147903b705cfSriastradh}
148003b705cfSriastradh
148103b705cfSriastradhstatic bool __sna_damage_intersect(struct sna_damage *damage,
148203b705cfSriastradh				   RegionPtr region, RegionPtr result)
148303b705cfSriastradh{
148403b705cfSriastradh	assert(damage && damage->mode != DAMAGE_ALL);
148503b705cfSriastradh	assert(RegionNotEmpty(region));
148603b705cfSriastradh
148703b705cfSriastradh	if (region->extents.x2 <= damage->extents.x1 ||
148803b705cfSriastradh	    region->extents.x1 >= damage->extents.x2)
148903b705cfSriastradh		return false;
149003b705cfSriastradh
149103b705cfSriastradh	if (region->extents.y2 <= damage->extents.y1 ||
149203b705cfSriastradh	    region->extents.y1 >= damage->extents.y2)
149303b705cfSriastradh		return false;
149403b705cfSriastradh
149503b705cfSriastradh	if (damage->dirty)
149603b705cfSriastradh		__sna_damage_reduce(damage);
149703b705cfSriastradh
149803b705cfSriastradh	if (!pixman_region_not_empty(&damage->region))
149903b705cfSriastradh		return false;
150003b705cfSriastradh
150103b705cfSriastradh	RegionNull(result);
150203b705cfSriastradh	RegionIntersect(result, &damage->region, region);
150303b705cfSriastradh
150403b705cfSriastradh	return RegionNotEmpty(result);
150503b705cfSriastradh}
150603b705cfSriastradh
150703b705cfSriastradh#if HAS_DEBUG_FULL
150803b705cfSriastradhbool _sna_damage_intersect(struct sna_damage *damage,
150903b705cfSriastradh			   RegionPtr region, RegionPtr result)
151003b705cfSriastradh{
151103b705cfSriastradh	char damage_buf[1000];
151203b705cfSriastradh	char region_buf[120];
151303b705cfSriastradh	bool ret;
151403b705cfSriastradh
151542542f5fSchristos	DBG(("%s(%s, %s)...\n", __FUNCTION__,
151642542f5fSchristos	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
151742542f5fSchristos	     _debug_describe_region(region_buf, sizeof(region_buf), region)));
151803b705cfSriastradh
151903b705cfSriastradh	ret = __sna_damage_intersect(damage, region, result);
152003b705cfSriastradh	if (ret)
152142542f5fSchristos		DBG(("  = %s\n",
152242542f5fSchristos		     _debug_describe_region(region_buf, sizeof(region_buf), result)));
152303b705cfSriastradh	else
152442542f5fSchristos		DBG(("  = none\n"));
152503b705cfSriastradh
152603b705cfSriastradh	return ret;
152703b705cfSriastradh}
152803b705cfSriastradh#else
152903b705cfSriastradhbool _sna_damage_intersect(struct sna_damage *damage,
153003b705cfSriastradh			  RegionPtr region, RegionPtr result)
153103b705cfSriastradh{
153203b705cfSriastradh	return __sna_damage_intersect(damage, region, result);
153303b705cfSriastradh}
153403b705cfSriastradh#endif
153503b705cfSriastradh
153642542f5fSchristosstatic int __sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes)
153703b705cfSriastradh{
153803b705cfSriastradh	assert(damage && damage->mode != DAMAGE_ALL);
153903b705cfSriastradh
154003b705cfSriastradh	if (damage->dirty)
154103b705cfSriastradh		__sna_damage_reduce(damage);
154203b705cfSriastradh
154342542f5fSchristos	assert(!damage->dirty);
154442542f5fSchristos	assert(damage->mode == DAMAGE_ADD);
154542542f5fSchristos
154642542f5fSchristos	*boxes = region_rects(&damage->region);
154742542f5fSchristos	return region_num_rects(&damage->region);
154803b705cfSriastradh}
154903b705cfSriastradh
155003b705cfSriastradhstruct sna_damage *_sna_damage_reduce(struct sna_damage *damage)
155103b705cfSriastradh{
155203b705cfSriastradh	DBG(("%s\n", __FUNCTION__));
155303b705cfSriastradh
155403b705cfSriastradh	__sna_damage_reduce(damage);
155542542f5fSchristos
155642542f5fSchristos	assert(!damage->dirty);
155742542f5fSchristos	assert(damage->mode == DAMAGE_ADD);
155842542f5fSchristos
155903b705cfSriastradh	if (!pixman_region_not_empty(&damage->region)) {
156003b705cfSriastradh		__sna_damage_destroy(damage);
156103b705cfSriastradh		damage = NULL;
156203b705cfSriastradh	}
156303b705cfSriastradh
156403b705cfSriastradh	return damage;
156503b705cfSriastradh}
156603b705cfSriastradh
156703b705cfSriastradh#if HAS_DEBUG_FULL
156842542f5fSchristosint _sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes)
156903b705cfSriastradh{
157003b705cfSriastradh	char damage_buf[1000];
157103b705cfSriastradh	int count;
157203b705cfSriastradh
157342542f5fSchristos	DBG(("%s(%s)...\n", __FUNCTION__,
157442542f5fSchristos	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
157503b705cfSriastradh
157603b705cfSriastradh	count = __sna_damage_get_boxes(damage, boxes);
157742542f5fSchristos	DBG(("  = %d\n", count));
157803b705cfSriastradh
157903b705cfSriastradh	return count;
158003b705cfSriastradh}
158103b705cfSriastradh#else
158242542f5fSchristosint _sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes)
158303b705cfSriastradh{
158403b705cfSriastradh	return __sna_damage_get_boxes(damage, boxes);
158503b705cfSriastradh}
158603b705cfSriastradh#endif
158703b705cfSriastradh
158803b705cfSriastradhstruct sna_damage *_sna_damage_combine(struct sna_damage *l,
158903b705cfSriastradh				       struct sna_damage *r,
159003b705cfSriastradh				       int dx, int dy)
159103b705cfSriastradh{
159203b705cfSriastradh	if (r->dirty)
159303b705cfSriastradh		__sna_damage_reduce(r);
159403b705cfSriastradh
159503b705cfSriastradh	if (pixman_region_not_empty(&r->region)) {
159603b705cfSriastradh		pixman_region_translate(&r->region, dx, dy);
159703b705cfSriastradh		l = __sna_damage_add(l, &r->region);
159803b705cfSriastradh	}
159903b705cfSriastradh
160003b705cfSriastradh	return l;
160103b705cfSriastradh}
160203b705cfSriastradh
160303b705cfSriastradhvoid __sna_damage_destroy(struct sna_damage *damage)
160403b705cfSriastradh{
160503b705cfSriastradh	free_list(&damage->embedded_box.list);
160603b705cfSriastradh
160703b705cfSriastradh	pixman_region_fini(&damage->region);
160803b705cfSriastradh	*(void **)damage = __freed_damage;
160903b705cfSriastradh	__freed_damage = damage;
161003b705cfSriastradh}
161103b705cfSriastradh
161203b705cfSriastradh#if TEST_DAMAGE && HAS_DEBUG_FULL
161303b705cfSriastradhstruct sna_damage_selftest{
161403b705cfSriastradh	int width, height;
161503b705cfSriastradh};
161603b705cfSriastradh
161703b705cfSriastradhstatic void st_damage_init_random_box(struct sna_damage_selftest *test,
161803b705cfSriastradh				      BoxPtr box)
161903b705cfSriastradh{
162003b705cfSriastradh	int x, y, w, h;
162103b705cfSriastradh
162203b705cfSriastradh	if (test->width == 1) {
162303b705cfSriastradh		x = 0, w = 1;
162403b705cfSriastradh	} else {
162503b705cfSriastradh		x = rand() % (test->width - 1);
162603b705cfSriastradh		w = 1 + rand() % (test->width - x - 1);
162703b705cfSriastradh	}
162803b705cfSriastradh
162903b705cfSriastradh	if (test->height == 1) {
163003b705cfSriastradh		y = 0, h = 1;
163103b705cfSriastradh	} else {
163203b705cfSriastradh		y = rand() % (test->height - 1);
163303b705cfSriastradh		h = 1 + rand() % (test->height - y - 1);
163403b705cfSriastradh	}
163503b705cfSriastradh
163603b705cfSriastradh	box->x1 = x;
163703b705cfSriastradh	box->x2 = x+w;
163803b705cfSriastradh
163903b705cfSriastradh	box->y1 = y;
164003b705cfSriastradh	box->y2 = y+h;
164103b705cfSriastradh}
164203b705cfSriastradh
164303b705cfSriastradhstatic void st_damage_init_random_region1(struct sna_damage_selftest *test,
164403b705cfSriastradh					  pixman_region16_t *region)
164503b705cfSriastradh{
164603b705cfSriastradh	int x, y, w, h;
164703b705cfSriastradh
164803b705cfSriastradh	if (test->width == 1) {
164903b705cfSriastradh		x = 0, w = 1;
165003b705cfSriastradh	} else {
165103b705cfSriastradh		x = rand() % (test->width - 1);
165203b705cfSriastradh		w = 1 + rand() % (test->width - x - 1);
165303b705cfSriastradh	}
165403b705cfSriastradh
165503b705cfSriastradh	if (test->height == 1) {
165603b705cfSriastradh		y = 0, h = 1;
165703b705cfSriastradh	} else {
165803b705cfSriastradh		y = rand() % (test->height - 1);
165903b705cfSriastradh		h = 1 + rand() % (test->height - y - 1);
166003b705cfSriastradh	}
166103b705cfSriastradh
166203b705cfSriastradh	pixman_region_init_rect(region, x, y, w, h);
166303b705cfSriastradh}
166403b705cfSriastradh
166503b705cfSriastradhstatic void st_damage_add(struct sna_damage_selftest *test,
166603b705cfSriastradh			  struct sna_damage **damage,
166703b705cfSriastradh			  pixman_region16_t *region)
166803b705cfSriastradh{
166903b705cfSriastradh	pixman_region16_t tmp;
167003b705cfSriastradh
167103b705cfSriastradh	st_damage_init_random_region1(test, &tmp);
167203b705cfSriastradh
167303b705cfSriastradh	if (!DAMAGE_IS_ALL(*damage))
167403b705cfSriastradh		sna_damage_add(damage, &tmp);
167503b705cfSriastradh	pixman_region_union(region, region, &tmp);
167603b705cfSriastradh}
167703b705cfSriastradh
167803b705cfSriastradhstatic void st_damage_add_box(struct sna_damage_selftest *test,
167903b705cfSriastradh			      struct sna_damage **damage,
168003b705cfSriastradh			      pixman_region16_t *region)
168103b705cfSriastradh{
168203b705cfSriastradh	RegionRec r;
168303b705cfSriastradh
168403b705cfSriastradh	st_damage_init_random_box(test, &r.extents);
168503b705cfSriastradh	r.data = NULL;
168603b705cfSriastradh
168703b705cfSriastradh	if (!DAMAGE_IS_ALL(*damage))
168803b705cfSriastradh		sna_damage_add_box(damage, &r.extents);
168903b705cfSriastradh	pixman_region_union(region, region, &r);
169003b705cfSriastradh}
169103b705cfSriastradh
169203b705cfSriastradhstatic void st_damage_subtract(struct sna_damage_selftest *test,
169303b705cfSriastradh			       struct sna_damage **damage,
169403b705cfSriastradh			       pixman_region16_t *region)
169503b705cfSriastradh{
169603b705cfSriastradh	pixman_region16_t tmp;
169703b705cfSriastradh
169803b705cfSriastradh	st_damage_init_random_region1(test, &tmp);
169903b705cfSriastradh
170003b705cfSriastradh	sna_damage_subtract(damage, &tmp);
170103b705cfSriastradh	pixman_region_subtract(region, region, &tmp);
170203b705cfSriastradh}
170303b705cfSriastradh
170403b705cfSriastradhstatic void st_damage_subtract_box(struct sna_damage_selftest *test,
170503b705cfSriastradh				   struct sna_damage **damage,
170603b705cfSriastradh				   pixman_region16_t *region)
170703b705cfSriastradh{
170803b705cfSriastradh	RegionRec r;
170903b705cfSriastradh
171003b705cfSriastradh	st_damage_init_random_box(test, &r.extents);
171103b705cfSriastradh	r.data = NULL;
171203b705cfSriastradh
171303b705cfSriastradh	sna_damage_subtract_box(damage, &r.extents);
171403b705cfSriastradh	pixman_region_subtract(region, region, &r);
171503b705cfSriastradh}
171603b705cfSriastradh
171703b705cfSriastradhstatic void st_damage_all(struct sna_damage_selftest *test,
171803b705cfSriastradh			  struct sna_damage **damage,
171903b705cfSriastradh			  pixman_region16_t *region)
172003b705cfSriastradh{
172103b705cfSriastradh	pixman_region16_t tmp;
172203b705cfSriastradh
172303b705cfSriastradh	pixman_region_init_rect(&tmp, 0, 0, test->width, test->height);
172403b705cfSriastradh
172503b705cfSriastradh	if (!DAMAGE_IS_ALL(*damage))
172603b705cfSriastradh		sna_damage_all(damage, test->width, test->height);
172703b705cfSriastradh	pixman_region_union(region, region, &tmp);
172803b705cfSriastradh}
172903b705cfSriastradh
173003b705cfSriastradhstatic bool st_check_equal(struct sna_damage_selftest *test,
173103b705cfSriastradh			   struct sna_damage **damage,
173203b705cfSriastradh			   pixman_region16_t *region)
173303b705cfSriastradh{
173403b705cfSriastradh	int d_num, r_num;
173503b705cfSriastradh	BoxPtr d_boxes, r_boxes;
173603b705cfSriastradh
173703b705cfSriastradh	d_num = *damage ? sna_damage_get_boxes(*damage, &d_boxes) : 0;
173803b705cfSriastradh	r_boxes = pixman_region_rectangles(region, &r_num);
173903b705cfSriastradh
174003b705cfSriastradh	if (d_num != r_num) {
174142542f5fSchristos		ERR(("%s: damage and ref contain different number of rectangles\n",
174242542f5fSchristos		     __FUNCTION__));
174303b705cfSriastradh		return false;
174403b705cfSriastradh	}
174503b705cfSriastradh
174603b705cfSriastradh	if (memcmp(d_boxes, r_boxes, d_num*sizeof(BoxRec))) {
174742542f5fSchristos		ERR(("%s: damage and ref contain different rectangles\n",
174842542f5fSchristos		     __FUNCTION__));
174903b705cfSriastradh		return false;
175003b705cfSriastradh	}
175103b705cfSriastradh
175203b705cfSriastradh	return true;
175303b705cfSriastradh}
175403b705cfSriastradh
175503b705cfSriastradhvoid sna_damage_selftest(void)
175603b705cfSriastradh{
175703b705cfSriastradh	void (*const op[])(struct sna_damage_selftest *test,
175803b705cfSriastradh			   struct sna_damage **damage,
175903b705cfSriastradh			   pixman_region16_t *region) = {
176003b705cfSriastradh		st_damage_add,
176103b705cfSriastradh		st_damage_add_box,
176203b705cfSriastradh		st_damage_subtract,
176303b705cfSriastradh		st_damage_subtract_box,
176403b705cfSriastradh		st_damage_all
176503b705cfSriastradh	};
176603b705cfSriastradh	bool (*const check[])(struct sna_damage_selftest *test,
176703b705cfSriastradh			      struct sna_damage **damage,
176803b705cfSriastradh			      pixman_region16_t *region) = {
176903b705cfSriastradh		st_check_equal,
177003b705cfSriastradh		//st_check_contains,
177103b705cfSriastradh	};
177203b705cfSriastradh	char region_buf[120];
177303b705cfSriastradh	char damage_buf[1000];
177403b705cfSriastradh	int pass;
177503b705cfSriastradh
177603b705cfSriastradh	for (pass = 0; pass < 16384; pass++) {
177703b705cfSriastradh		struct sna_damage_selftest test;
177803b705cfSriastradh		struct sna_damage *damage;
177903b705cfSriastradh		pixman_region16_t ref;
178003b705cfSriastradh		int iter, i;
178103b705cfSriastradh
178203b705cfSriastradh		iter = 1 + rand() % (1 + (pass / 64));
178342542f5fSchristos		DBG(("%s: pass %d, iters=%d\n", __FUNCTION__, pass, iter));
178403b705cfSriastradh
178503b705cfSriastradh		test.width = 1 + rand() % 2048;
178603b705cfSriastradh		test.height = 1 + rand() % 2048;
178703b705cfSriastradh
178803b705cfSriastradh		damage = _sna_damage_create();
178903b705cfSriastradh		pixman_region_init(&ref);
179003b705cfSriastradh
179103b705cfSriastradh		for (i = 0; i < iter; i++) {
179203b705cfSriastradh			op[rand() % ARRAY_SIZE(op)](&test, &damage, &ref);
179303b705cfSriastradh		}
179403b705cfSriastradh
179503b705cfSriastradh		if (!check[rand() % ARRAY_SIZE(check)](&test, &damage, &ref)) {
179642542f5fSchristos			FatalError("%s: failed - region = %s, damage = %s\n", __FUNCTION__,
179742542f5fSchristos				   _debug_describe_region(region_buf, sizeof(region_buf), &ref),
179842542f5fSchristos				   _debug_describe_damage(damage_buf, sizeof(damage_buf), damage));
179903b705cfSriastradh		}
180003b705cfSriastradh
180103b705cfSriastradh		pixman_region_fini(&ref);
180203b705cfSriastradh		sna_damage_destroy(&damage);
180303b705cfSriastradh	}
180403b705cfSriastradh}
180503b705cfSriastradh#endif
180603b705cfSriastradh
180703b705cfSriastradhvoid _sna_damage_debug_get_region(struct sna_damage *damage, RegionRec *r)
180803b705cfSriastradh{
180903b705cfSriastradh	int n, nboxes;
181003b705cfSriastradh	BoxPtr boxes;
181103b705cfSriastradh	struct sna_damage_box *iter;
181203b705cfSriastradh
181303b705cfSriastradh	RegionCopy(r, &damage->region);
181403b705cfSriastradh	if (!damage->dirty)
181503b705cfSriastradh		return;
181603b705cfSriastradh
181703b705cfSriastradh	nboxes = damage->embedded_box.size;
181803b705cfSriastradh	list_for_each_entry(iter, &damage->embedded_box.list, list)
181903b705cfSriastradh		nboxes += iter->size;
182003b705cfSriastradh	nboxes -= damage->remain;
182103b705cfSriastradh	if (nboxes == 0)
182203b705cfSriastradh		return;
182303b705cfSriastradh
182403b705cfSriastradh	if (nboxes == 1) {
182503b705cfSriastradh		pixman_region16_t tmp;
182603b705cfSriastradh
182703b705cfSriastradh		tmp.extents = damage->embedded_box.box[0];
182803b705cfSriastradh		tmp.data = NULL;
182903b705cfSriastradh
183003b705cfSriastradh		if (damage->mode == DAMAGE_ADD)
183103b705cfSriastradh			pixman_region_union(r, r, &tmp);
183203b705cfSriastradh		else
183303b705cfSriastradh			pixman_region_subtract(r, r, &tmp);
183403b705cfSriastradh
183503b705cfSriastradh		return;
183603b705cfSriastradh	}
183703b705cfSriastradh
183803b705cfSriastradh	if (damage->mode == DAMAGE_ADD)
183942542f5fSchristos		nboxes += region_num_rects(r);
184003b705cfSriastradh
184142542f5fSchristos	iter = last_box(damage);
184203b705cfSriastradh	n = iter->size - damage->remain;
184303b705cfSriastradh	boxes = malloc(sizeof(BoxRec)*nboxes);
184403b705cfSriastradh	if (boxes == NULL)
184503b705cfSriastradh		return;
184603b705cfSriastradh
184703b705cfSriastradh	if (list_is_empty(&damage->embedded_box.list)) {
184803b705cfSriastradh		memcpy(boxes,
184903b705cfSriastradh		       damage->embedded_box.box,
185003b705cfSriastradh		       n*sizeof(BoxRec));
185103b705cfSriastradh	} else {
185203b705cfSriastradh		if (boxes != (BoxPtr)(iter+1))
185303b705cfSriastradh			memcpy(boxes, iter+1, n*sizeof(BoxRec));
185403b705cfSriastradh
185503b705cfSriastradh		iter = list_entry(iter->list.prev,
185603b705cfSriastradh				  struct sna_damage_box,
185703b705cfSriastradh				  list);
185803b705cfSriastradh		while (&iter->list != &damage->embedded_box.list) {
185903b705cfSriastradh			memcpy(boxes + n, iter+1,
186003b705cfSriastradh			       iter->size * sizeof(BoxRec));
186103b705cfSriastradh			n += iter->size;
186203b705cfSriastradh
186303b705cfSriastradh			iter = list_entry(iter->list.prev,
186403b705cfSriastradh					  struct sna_damage_box,
186503b705cfSriastradh					  list);
186603b705cfSriastradh		}
186703b705cfSriastradh
186803b705cfSriastradh		memcpy(boxes + n,
186903b705cfSriastradh		       damage->embedded_box.box,
187003b705cfSriastradh		       sizeof(damage->embedded_box.box));
187103b705cfSriastradh		n += damage->embedded_box.size;
187203b705cfSriastradh	}
187303b705cfSriastradh
187403b705cfSriastradh	if (damage->mode == DAMAGE_ADD) {
187503b705cfSriastradh		memcpy(boxes + n,
187642542f5fSchristos		       region_rects(r),
187742542f5fSchristos		       region_num_rects(r)*sizeof(BoxRec));
187842542f5fSchristos		assert(n + region_num_rects(r) == nboxes);
187903b705cfSriastradh		pixman_region_fini(r);
188003b705cfSriastradh		pixman_region_init_rects(r, boxes, nboxes);
188103b705cfSriastradh
188203b705cfSriastradh		assert(pixman_region_not_empty(r));
188303b705cfSriastradh		assert(damage->extents.x1 == r->extents.x1 &&
188403b705cfSriastradh		       damage->extents.y1 == r->extents.y1 &&
188503b705cfSriastradh		       damage->extents.x2 == r->extents.x2 &&
188603b705cfSriastradh		       damage->extents.y2 == r->extents.y2);
188703b705cfSriastradh	} else {
188803b705cfSriastradh		pixman_region16_t tmp;
188903b705cfSriastradh
189003b705cfSriastradh		pixman_region_init_rects(&tmp, boxes, nboxes);
189103b705cfSriastradh		pixman_region_subtract(r, r, &tmp);
189203b705cfSriastradh		pixman_region_fini(&tmp);
189303b705cfSriastradh
189403b705cfSriastradh		assert(damage->extents.x1 <= r->extents.x1 &&
189503b705cfSriastradh		       damage->extents.y1 <= r->extents.y1 &&
189603b705cfSriastradh		       damage->extents.x2 >= r->extents.x2 &&
189703b705cfSriastradh		       damage->extents.y2 >= r->extents.y2);
189803b705cfSriastradh	}
189903b705cfSriastradh
190003b705cfSriastradh	free(boxes);
190103b705cfSriastradh}
1902