sna_damage.c revision 03b705cf
11.13Sjmmv/**************************************************************************
21.1Sjmmv
31.1SjmmvCopyright (c) 2011 Intel Corporation
41.13Sjmmv
51.1SjmmvPermission is hereby granted, free of charge, to any person obtaining a
61.1Sjmmvcopy of this software and associated documentation files (the
71.1Sjmmv"Software"), to deal in the Software without restriction, including
81.3Sjmmvwithout limitation the rights to use, copy, modify, merge, publish,
91.3Sjmmvdistribute, sub license, and/or sell copies of the Software, and to
101.1Sjmmvpermit persons to whom the Software is furnished to do so, subject to
111.1Sjmmvthe following conditions:
121.1Sjmmv
131.1SjmmvThe above copyright notice and this permission notice (including the
141.1Sjmmvnext paragraph) shall be included in all copies or substantial portions
151.1Sjmmvof the Software.
161.1Sjmmv
171.1SjmmvTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
181.1SjmmvOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
191.1SjmmvMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
201.1SjmmvIN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
211.1SjmmvANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
221.1SjmmvTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
231.1SjmmvSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
241.1Sjmmv
251.1Sjmmv **************************************************************************/
261.1Sjmmv
271.1Sjmmv#ifdef HAVE_CONFIG_H
281.1Sjmmv#include "config.h"
291.1Sjmmv#endif
301.1Sjmmv
311.1Sjmmv#include "sna.h"
321.1Sjmmv#include "sna_damage.h"
331.1Sjmmv
341.1Sjmmv/*
351.1Sjmmv * sna_damage is a batching layer on top of the regular pixman_region_t.
361.1Sjmmv * It is required as the ever-growing accumulation of invidual small
371.1Sjmmv * damage regions is an O(n^2) operation. Instead the accumulation of a
381.1Sjmmv * batch can be done in closer to O(n.lgn), and so prevents abysmal
391.1Sjmmv * performance in x11perf -copywinwin10.
401.1Sjmmv *
411.1Sjmmv * As with the core of SNA, damage is handled modally. That is, it
421.13Sjmmv * accumulates whilst rendering and then subtracts during migration of the
431.1Sjmmv * pixmap from GPU to CPU or vice versa. As such we can track the current
441.1Sjmmv * mode globally and when that mode switches perform the update of the region
451.11Schristos * in a single operation.
461.1Sjmmv *
471.1Sjmmv * Furthermore, we can track whether the whole pixmap is damaged and so
481.4Sjmmv * cheapy discard no-ops.
491.1Sjmmv */
501.1Sjmmv
511.1Sjmmvstruct sna_damage_box {
521.1Sjmmv	struct list list;
531.1Sjmmv	int size;
541.1Sjmmv} __attribute__((packed));
551.1Sjmmv
561.1Sjmmvstatic struct sna_damage *__freed_damage;
571.1Sjmmv
581.1Sjmmvstatic inline bool region_is_singular(RegionRec *r)
591.1Sjmmv{
601.1Sjmmv	return r->data == NULL;
611.1Sjmmv}
621.1Sjmmv
631.1Sjmmv#if HAS_DEBUG_FULL
641.1Sjmmvstatic const char *_debug_describe_region(char *buf, int max,
651.1Sjmmv					  RegionPtr region)
661.1Sjmmv{
671.8Sjmmv	BoxPtr extents;
681.1Sjmmv	BoxPtr box;
691.1Sjmmv	int n;
701.1Sjmmv	int len;
711.1Sjmmv
721.1Sjmmv	if (region == NULL)
731.1Sjmmv		return "nil";
741.1Sjmmv
751.1Sjmmv	n = REGION_NUM_RECTS(region);
761.1Sjmmv	if (n == 0)
771.1Sjmmv		return "[0]";
781.1Sjmmv
791.1Sjmmv	extents = REGION_EXTENTS(NULL, region);
801.1Sjmmv	if (n == 1) {
811.1Sjmmv		sprintf(buf,
821.1Sjmmv			"[(%d, %d), (%d, %d)]",
831.1Sjmmv			extents->x1, extents->y1,
841.1Sjmmv			extents->x2, extents->y2);
851.1Sjmmv		return buf;
861.10Sjmmv	}
871.1Sjmmv
881.4Sjmmv	len = sprintf(buf,
891.4Sjmmv		      "[(%d, %d), (%d, %d) x %d: ",
901.4Sjmmv		      extents->x1, extents->y1,
911.1Sjmmv		      extents->x2, extents->y2,
921.12Schristos		      n) + 3;
931.1Sjmmv	max -= 2;
941.4Sjmmv	box = REGION_RECTS(region);
951.1Sjmmv	while (n--) {
961.1Sjmmv		char tmp[80];
971.1Sjmmv		int this;
981.1Sjmmv
991.1Sjmmv		this = snprintf(tmp, sizeof(tmp),
1001.1Sjmmv				"((%d, %d), (%d, %d))%s",
1011.1Sjmmv				box->x1, box->y1,
1021.1Sjmmv				box->x2, box->y2,
1031.1Sjmmv				n ? ", ..." : "");
1041.10Sjmmv		box++;
1051.10Sjmmv
1061.10Sjmmv		if (this > max - len)
1071.4Sjmmv			break;
1081.1Sjmmv
1091.1Sjmmv		len -= 3;
1101.1Sjmmv		memcpy(buf + len, tmp, this);
1111.1Sjmmv		len += this;
1121.4Sjmmv	}
1131.1Sjmmv	buf[len++] = ']';
1141.1Sjmmv	buf[len] = '\0';
1151.1Sjmmv	return buf;
1161.1Sjmmv}
1171.10Sjmmv
1181.1Sjmmvstatic const char *_debug_describe_damage(char *buf, int max,
1191.1Sjmmv					  const struct sna_damage *damage)
1201.1Sjmmv{
1211.4Sjmmv	char damage_str[500], region_str[500];
1221.1Sjmmv	int str_max;
1231.1Sjmmv
1241.1Sjmmv	if (damage == NULL)
1251.1Sjmmv		return "None";
1261.10Sjmmv
1271.1Sjmmv	str_max = max/2 - 6;
1281.1Sjmmv	if (str_max > sizeof(damage_str))
1291.1Sjmmv		str_max = sizeof(damage_str);
1301.1Sjmmv
1311.1Sjmmv	if (damage->mode == DAMAGE_ALL) {
1321.1Sjmmv		snprintf(buf, max, "[[(%d, %d), (%d, %d)]: all]",
1331.1Sjmmv			 damage->extents.x1, damage->extents.y1,
1341.1Sjmmv			 damage->extents.x2, damage->extents.y2);
1351.1Sjmmv	} else {
1361.1Sjmmv		if (damage->dirty) {
1371.1Sjmmv			sprintf(damage_str, "%c[ ...]",
1381.1Sjmmv				damage->mode == DAMAGE_SUBTRACT ? '-' : '+');
1391.12Schristos		} else
1401.12Schristos			damage_str[0] = '\0';
1411.12Schristos		snprintf(buf, max, "[[(%d, %d), (%d, %d)]: %s %s]%c",
1421.12Schristos			 damage->extents.x1, damage->extents.y1,
1431.1Sjmmv			 damage->extents.x2, damage->extents.y2,
1441.1Sjmmv			 _debug_describe_region(region_str, str_max,
1451.1Sjmmv						&damage->region),
1461.1Sjmmv			 damage_str, damage->dirty ? '*' : ' ');
1471.1Sjmmv	}
1481.1Sjmmv
1491.1Sjmmv	return buf;
1501.1Sjmmv}
1511.1Sjmmv#endif
1521.1Sjmmv
1531.1Sjmmvstatic void
1541.1Sjmmvreset_embedded_box(struct sna_damage *damage)
1551.4Sjmmv{
1561.1Sjmmv	damage->dirty = false;
1571.1Sjmmv	damage->box = damage->embedded_box.box;
1581.1Sjmmv	damage->embedded_box.size =
1591.1Sjmmv		damage->remain = ARRAY_SIZE(damage->embedded_box.box);
1601.10Sjmmv	list_init(&damage->embedded_box.list);
1611.1Sjmmv}
1621.1Sjmmv
1631.1Sjmmvstatic void reset_extents(struct sna_damage *damage)
1641.1Sjmmv{
1651.1Sjmmv	damage->extents.x1 = damage->extents.y1 = MAXSHORT;
1661.1Sjmmv	damage->extents.x2 = damage->extents.y2 = MINSHORT;
1671.1Sjmmv}
1681.1Sjmmv
1691.1Sjmmvstatic struct sna_damage *_sna_damage_create(void)
1701.1Sjmmv{
1711.1Sjmmv	struct sna_damage *damage;
1721.1Sjmmv
1731.1Sjmmv	if (__freed_damage) {
1741.1Sjmmv		damage = __freed_damage;
1751.1Sjmmv		__freed_damage = *(void **)__freed_damage;
1761.1Sjmmv	} else {
1771.1Sjmmv		damage = malloc(sizeof(*damage));
1781.1Sjmmv		if (damage == NULL)
1791.1Sjmmv			return NULL;
1801.1Sjmmv	}
1811.1Sjmmv	reset_embedded_box(damage);
1821.1Sjmmv	damage->mode = DAMAGE_ADD;
1831.1Sjmmv	pixman_region_init(&damage->region);
1841.1Sjmmv	reset_extents(damage);
1851.1Sjmmv
1861.1Sjmmv	return damage;
1871.4Sjmmv}
1881.4Sjmmv
1891.4Sjmmvstruct sna_damage *sna_damage_create(void)
1901.4Sjmmv{
1911.4Sjmmv	return _sna_damage_create();
1921.4Sjmmv}
1931.4Sjmmv
1941.4Sjmmvstatic bool _sna_damage_create_boxes(struct sna_damage *damage,
1951.1Sjmmv				     int count)
1961.1Sjmmv{
1971.1Sjmmv	struct sna_damage_box *box;
1981.1Sjmmv	int n;
1991.8Sjmmv
2001.8Sjmmv	box = list_entry(damage->embedded_box.list.prev,
2011.8Sjmmv			 struct sna_damage_box,
2021.8Sjmmv			 list);
2031.8Sjmmv	n = 4*box->size;
2041.8Sjmmv	if (n < count)
2051.8Sjmmv		n = ALIGN(count, 64);
2061.8Sjmmv
2071.8Sjmmv	DBG(("    %s(%d->%d): new\n", __FUNCTION__, count, n));
2081.8Sjmmv
2091.8Sjmmv	box = malloc(sizeof(*box) + sizeof(BoxRec)*n);
2101.8Sjmmv	if (box == NULL)
2111.8Sjmmv		return false;
2121.8Sjmmv
2131.8Sjmmv	list_add_tail(&box->list, &damage->embedded_box.list);
2141.8Sjmmv
2151.8Sjmmv	box->size = damage->remain = n;
2161.8Sjmmv	damage->box = (BoxRec *)(box + 1);
2171.8Sjmmv	return true;
2181.8Sjmmv}
2191.8Sjmmv
2201.8Sjmmvstatic struct sna_damage *
2211.8Sjmmv_sna_damage_create_elt(struct sna_damage *damage,
2221.8Sjmmv		       const BoxRec *boxes, int count)
2231.8Sjmmv{
2241.8Sjmmv	int n;
2251.1Sjmmv
2261.1Sjmmv	DBG(("    %s: prev=(remain %d), count=%d\n",
2271.1Sjmmv	     __FUNCTION__, damage->remain, count));
2281.1Sjmmv
2291.1Sjmmv	damage->dirty = true;
2301.1Sjmmv	n = count;
2311.1Sjmmv	if (n > damage->remain)
2321.1Sjmmv		n = damage->remain;
2331.1Sjmmv	if (n) {
2341.1Sjmmv		memcpy(damage->box, boxes, n * sizeof(BoxRec));
2351.1Sjmmv		damage->box += n;
2361.1Sjmmv		damage->remain -= n;
2371.1Sjmmv
2381.1Sjmmv		count -= n;
2391.1Sjmmv		boxes += n;
2401.1Sjmmv		if (count == 0)
2411.1Sjmmv			return damage;
2421.1Sjmmv	}
2431.1Sjmmv
2441.1Sjmmv	DBG(("    %s(): new elt\n", __FUNCTION__));
2451.1Sjmmv
2461.1Sjmmv	if (_sna_damage_create_boxes(damage, count)) {
2471.1Sjmmv		memcpy(damage->box, boxes, count * sizeof(BoxRec));
2481.1Sjmmv		damage->box += count;
2491.1Sjmmv		damage->remain -= count;
2501.1Sjmmv	}
2511.1Sjmmv	assert(damage->remain >= 0);
2521.1Sjmmv
2531.1Sjmmv	return damage;
2541.1Sjmmv}
2551.1Sjmmv
2561.1Sjmmvstatic struct sna_damage *
2571.1Sjmmv_sna_damage_create_elt_from_boxes(struct sna_damage *damage,
2581.1Sjmmv				  const BoxRec *boxes, int count,
2591.1Sjmmv				  int16_t dx, int16_t dy)
2601.1Sjmmv{
2611.7Sjmmv	int i, n;
2621.1Sjmmv
2631.1Sjmmv	DBG(("    %s: prev=(remain %d)\n", __FUNCTION__, damage->remain));
2641.7Sjmmv
2651.1Sjmmv	damage->dirty = true;
2661.1Sjmmv	n = count;
2671.13Sjmmv	if (n > damage->remain)
2681.1Sjmmv		n = damage->remain;
2691.1Sjmmv	if (n) {
2701.1Sjmmv		for (i = 0; i < n; i++) {
2711.1Sjmmv			damage->box[i].x1 = boxes[i].x1 + dx;
2721.1Sjmmv			damage->box[i].x2 = boxes[i].x2 + dx;
2731.1Sjmmv			damage->box[i].y1 = boxes[i].y1 + dy;
2741.1Sjmmv			damage->box[i].y2 = boxes[i].y2 + dy;
2751.1Sjmmv		}
2761.1Sjmmv		damage->box += n;
2771.1Sjmmv		damage->remain -= n;
2781.1Sjmmv
2791.1Sjmmv		count -= n;
2801.1Sjmmv		boxes += n;
2811.1Sjmmv		if (count == 0)
2821.1Sjmmv			return damage;
2831.1Sjmmv	}
2841.1Sjmmv
2851.1Sjmmv	DBG(("    %s(): new elt\n", __FUNCTION__));
2861.1Sjmmv
2871.1Sjmmv	if (!_sna_damage_create_boxes(damage, count))
2881.1Sjmmv		return damage;
2891.1Sjmmv
2901.1Sjmmv	for (i = 0; i < count; i++) {
2911.1Sjmmv		damage->box[i].x1 = boxes[i].x1 + dx;
2921.1Sjmmv		damage->box[i].x2 = boxes[i].x2 + dx;
2931.1Sjmmv		damage->box[i].y1 = boxes[i].y1 + dy;
2941.1Sjmmv		damage->box[i].y2 = boxes[i].y2 + dy;
2951.1Sjmmv	}
2961.13Sjmmv	damage->box += count;
2971.1Sjmmv	damage->remain -= count;
2981.1Sjmmv	assert(damage->remain >= 0);
2991.1Sjmmv
3001.1Sjmmv	return damage;
3011.1Sjmmv}
3021.1Sjmmv
3031.1Sjmmvstatic struct sna_damage *
3041.1Sjmmv_sna_damage_create_elt_from_rectangles(struct sna_damage *damage,
3051.1Sjmmv				       const xRectangle *r, int count,
3061.1Sjmmv				       int16_t dx, int16_t dy)
3071.1Sjmmv{
3081.1Sjmmv	int i, n;
3091.1Sjmmv
3101.1Sjmmv	DBG(("    %s: prev=(remain %d), count=%d\n",
3111.1Sjmmv	     __FUNCTION__, damage->remain, count));
3121.1Sjmmv
3131.1Sjmmv	damage->dirty = true;
3141.1Sjmmv	n = count;
3151.1Sjmmv	if (n > damage->remain)
3161.1Sjmmv		n = damage->remain;
3171.1Sjmmv	if (n) {
3181.1Sjmmv		for (i = 0; i < n; i++) {
3191.1Sjmmv			damage->box[i].x1 = r[i].x + dx;
3201.9Sjmmv			damage->box[i].x2 = damage->box[i].x1 + r[i].width;
3211.9Sjmmv			damage->box[i].y1 = r[i].y + dy;
3221.6Sjmmv			damage->box[i].y2 = damage->box[i].y1 + r[i].height;
3231.1Sjmmv		}
3241.1Sjmmv		damage->box += n;
3251.1Sjmmv		damage->remain -= n;
3261.1Sjmmv
3271.1Sjmmv		count -= n;
3281.1Sjmmv		r += n;
3291.1Sjmmv		if (count == 0)
3301.1Sjmmv			return damage;
3311.1Sjmmv	}
3321.5Sjmmv
3331.1Sjmmv	DBG(("    %s(): new elt\n", __FUNCTION__));
3341.1Sjmmv
3351.1Sjmmv	if (!_sna_damage_create_boxes(damage, count))
3361.1Sjmmv		return damage;
3371.1Sjmmv
3381.1Sjmmv	for (i = 0; i < count; i++) {
3391.1Sjmmv		damage->box[i].x1 = r[i].x + dx;
3401.1Sjmmv		damage->box[i].x2 = damage->box[i].x1 + r[i].width;
3411.5Sjmmv		damage->box[i].y1 = r[i].y + dy;
3421.1Sjmmv		damage->box[i].y2 = damage->box[i].y1 + r[i].height;
3431.1Sjmmv	}
3441.1Sjmmv	damage->box += count;
3451.5Sjmmv	damage->remain -= count;
3461.1Sjmmv	assert(damage->remain >= 0);
3471.1Sjmmv
3481.1Sjmmv	return damage;
3491.1Sjmmv}
3501.1Sjmmv
3511.1Sjmmvstatic struct sna_damage *
3521.1Sjmmv_sna_damage_create_elt_from_points(struct sna_damage *damage,
3531.1Sjmmv				   const DDXPointRec *p, int count,
3541.1Sjmmv				   int16_t dx, int16_t dy)
3551.1Sjmmv{
3561.1Sjmmv	int i, n;
3571.1Sjmmv
3581.9Sjmmv	DBG(("    %s: prev=(remain %d), count=%d\n",
3591.1Sjmmv	     __FUNCTION__, damage->remain, count));
3601.1Sjmmv
3611.13Sjmmv	damage->dirty = true;
3621.1Sjmmv	n = count;
3631.1Sjmmv	if (n > damage->remain)
3641.9Sjmmv		n = damage->remain;
3651.9Sjmmv	if (n) {
3661.9Sjmmv		for (i = 0; i < n; i++) {
3671.9Sjmmv			damage->box[i].x1 = p[i].x + dx;
3681.1Sjmmv			damage->box[i].x2 = damage->box[i].x1 + 1;
3691.1Sjmmv			damage->box[i].y1 = p[i].y + dy;
3701.1Sjmmv			damage->box[i].y2 = damage->box[i].y1 + 1;
3711.1Sjmmv		}
3721.1Sjmmv		damage->box += n;
3731.1Sjmmv		damage->remain -= n;
3741.1Sjmmv
3751.1Sjmmv		count -= n;
3761.1Sjmmv		p += n;
3771.1Sjmmv		if (count == 0)
3781.1Sjmmv			return damage;
3791.1Sjmmv	}
3801.1Sjmmv
3811.1Sjmmv	DBG(("    %s(): new elt\n", __FUNCTION__));
3821.1Sjmmv
3831.1Sjmmv	if (! _sna_damage_create_boxes(damage, count))
3841.1Sjmmv		return damage;
3851.1Sjmmv
3861.1Sjmmv	for (i = 0; i < count; i++) {
3871.1Sjmmv		damage->box[i].x1 = p[i].x + dx;
3881.1Sjmmv		damage->box[i].x2 = damage->box[i].x1 + 1;
3891.1Sjmmv		damage->box[i].y1 = p[i].y + dy;
3901.1Sjmmv		damage->box[i].y2 = damage->box[i].y1 + 1;
3911.1Sjmmv	}
3921.1Sjmmv	damage->box += count;
3931.1Sjmmv	damage->remain -= count;
3941.7Sjmmv	assert(damage->remain >= 0);
3951.1Sjmmv
3961.1Sjmmv	return damage;
3971.7Sjmmv}
3981.1Sjmmv
3991.1Sjmmvstatic void free_list(struct list *head)
4001.13Sjmmv{
4011.1Sjmmv	while (!list_is_empty(head)) {
4021.1Sjmmv		struct list *l = head->next;
4031.1Sjmmv		list_del(l);
4041.1Sjmmv		free(l);
4051.1Sjmmv	}
4061.1Sjmmv}
4071.1Sjmmv
4081.1Sjmmvstatic void __sna_damage_reduce(struct sna_damage *damage)
4091.1Sjmmv{
4101.1Sjmmv	int n, nboxes;
4111.1Sjmmv	BoxPtr boxes, free_boxes = NULL;
4121.1Sjmmv	pixman_region16_t *region = &damage->region;
4131.1Sjmmv	struct sna_damage_box *iter;
4141.1Sjmmv
4151.1Sjmmv	assert(damage->mode != DAMAGE_ALL);
4161.1Sjmmv	assert(damage->dirty);
4171.1Sjmmv
4181.1Sjmmv	DBG(("    reduce: before region.n=%ld\n", (long)REGION_NUM_RECTS(region)));
4191.1Sjmmv
4201.1Sjmmv	nboxes = damage->embedded_box.size;
421	list_for_each_entry(iter, &damage->embedded_box.list, list)
422		nboxes += iter->size;
423	DBG(("   nboxes=%d, residual=%d\n", nboxes, damage->remain));
424	nboxes -= damage->remain;
425	if (nboxes == 0)
426		goto done;
427	if (nboxes == 1) {
428		pixman_region16_t tmp;
429
430		tmp.extents = damage->embedded_box.box[0];
431		tmp.data = NULL;
432
433		if (damage->mode == DAMAGE_ADD)
434			pixman_region_union(region, region, &tmp);
435		else
436			pixman_region_subtract(region, region, &tmp);
437		damage->extents = region->extents;
438
439		goto done;
440	}
441
442	if (damage->mode == DAMAGE_ADD)
443		nboxes += REGION_NUM_RECTS(region);
444
445	iter = list_entry(damage->embedded_box.list.prev,
446			  struct sna_damage_box,
447			  list);
448	n = iter->size - damage->remain;
449	boxes = (BoxRec *)(iter+1);
450	DBG(("   last box count=%d/%d, need=%d\n", n, iter->size, nboxes));
451	if (nboxes > iter->size) {
452		boxes = malloc(sizeof(BoxRec)*nboxes);
453		if (boxes == NULL)
454			goto done;
455
456		free_boxes = boxes;
457	}
458
459	if (boxes != damage->embedded_box.box) {
460		if (list_is_empty(&damage->embedded_box.list)) {
461			DBG(("   copying embedded boxes\n"));
462			memcpy(boxes,
463			       damage->embedded_box.box,
464			       n*sizeof(BoxRec));
465		} else {
466			if (boxes != (BoxPtr)(iter+1)) {
467				DBG(("   copying %d boxes from last\n", n));
468				memcpy(boxes, iter+1, n*sizeof(BoxRec));
469			}
470
471			iter = list_entry(iter->list.prev,
472					  struct sna_damage_box,
473					  list);
474			while (&iter->list != &damage->embedded_box.list) {
475				DBG(("   copy %d boxes from %d\n",
476				     iter->size, n));
477				memcpy(boxes + n, iter+1,
478				       iter->size * sizeof(BoxRec));
479				n += iter->size;
480
481				iter = list_entry(iter->list.prev,
482						  struct sna_damage_box,
483						  list);
484			}
485
486			DBG(("   copying embedded boxes to %d\n", n));
487			memcpy(boxes + n,
488			       damage->embedded_box.box,
489			       sizeof(damage->embedded_box.box));
490			n += damage->embedded_box.size;
491		}
492	}
493
494	if (damage->mode == DAMAGE_ADD) {
495		memcpy(boxes + n,
496		       REGION_RECTS(region),
497		       REGION_NUM_RECTS(region)*sizeof(BoxRec));
498		assert(n + REGION_NUM_RECTS(region) == nboxes);
499		pixman_region_fini(region);
500		pixman_region_init_rects(region, boxes, nboxes);
501
502		assert(pixman_region_not_empty(region));
503		assert(damage->extents.x1 == region->extents.x1 &&
504		       damage->extents.y1 == region->extents.y1 &&
505		       damage->extents.x2 == region->extents.x2 &&
506		       damage->extents.y2 == region->extents.y2);
507	} else {
508		pixman_region16_t tmp;
509
510		assert(n == nboxes);
511		pixman_region_init_rects(&tmp, boxes, nboxes);
512		pixman_region_subtract(region, region, &tmp);
513		pixman_region_fini(&tmp);
514
515		assert(damage->extents.x1 <= region->extents.x1 &&
516		       damage->extents.y1 <= region->extents.y1 &&
517		       damage->extents.x2 >= region->extents.x2 &&
518		       damage->extents.y2 >= region->extents.y2);
519		if (pixman_region_not_empty(region))
520			damage->extents = region->extents;
521		else
522			reset_extents(damage);
523	}
524
525	free(free_boxes);
526
527done:
528	damage->mode = DAMAGE_ADD;
529	free_list(&damage->embedded_box.list);
530	reset_embedded_box(damage);
531
532	DBG(("    reduce: after region.n=%ld\n", (long)REGION_NUM_RECTS(region)));
533}
534
535static void damage_union(struct sna_damage *damage, const BoxRec *box)
536{
537	DBG(("%s: extending damage (%d, %d), (%d, %d) by (%d, %d), (%d, %d)\n",
538	     __FUNCTION__,
539	     damage->extents.x1, damage->extents.y1,
540	     damage->extents.x2, damage->extents.y2,
541	     box->x1, box->y1, box->x2, box->y2));
542	assert(box->x2 > box->x1 && box->y2 > box->y1);
543	if (damage->extents.x2 < damage->extents.x1) {
544		damage->extents = *box;
545	} else {
546		if (damage->extents.x1 > box->x1)
547			damage->extents.x1 = box->x1;
548		if (damage->extents.x2 < box->x2)
549			damage->extents.x2 = box->x2;
550
551		if (damage->extents.y1 > box->y1)
552			damage->extents.y1 = box->y1;
553		if (damage->extents.y2 < box->y2)
554			damage->extents.y2 = box->y2;
555	}
556	assert(damage->extents.x2 > damage->extents.x1);
557	assert(damage->extents.y2 > damage->extents.y1);
558}
559
560static void _pixman_region_union_box(RegionRec *region, const BoxRec *box)
561{
562	RegionRec u = { *box, NULL };
563	pixman_region_union(region, region, &u);
564}
565
566static bool box_contains_region(const BoxRec *b, const RegionRec *r)
567{
568	return (b->x1 <= r->extents.x1 && b->x2 >= r->extents.x2 &&
569		b->y1 <= r->extents.y1 && b->y2 >= r->extents.y2);
570}
571
572static struct sna_damage *__sna_damage_add_box(struct sna_damage *damage,
573					       const BoxRec *box)
574{
575	if (box->y2 <= box->y1 || box->x2 <= box->x1)
576		return damage;
577
578	if (!damage) {
579		damage = _sna_damage_create();
580		if (damage == NULL)
581			return NULL;
582	} else switch (damage->mode) {
583	case DAMAGE_ALL:
584		return damage;
585	case DAMAGE_SUBTRACT:
586		__sna_damage_reduce(damage);
587	case DAMAGE_ADD:
588		break;
589	}
590
591	if (REGION_NUM_RECTS(&damage->region) <= 1 ||
592	    box_contains_region(box, &damage->region)) {
593		_pixman_region_union_box(&damage->region, box);
594		assert(damage->region.extents.x2 > damage->region.extents.x1);
595		assert(damage->region.extents.y2 > damage->region.extents.y1);
596		damage_union(damage, box);
597		return damage;
598	}
599
600	if (pixman_region_contains_rectangle(&damage->region,
601					     (BoxPtr)box) == PIXMAN_REGION_IN)
602		return damage;
603
604	damage_union(damage, box);
605	return _sna_damage_create_elt(damage, box, 1);
606}
607
608inline static struct sna_damage *__sna_damage_add(struct sna_damage *damage,
609						  RegionPtr region)
610{
611	assert(RegionNotEmpty(region));
612
613	if (!damage) {
614		damage = _sna_damage_create();
615		if (damage == NULL)
616			return NULL;
617	} else switch (damage->mode) {
618	case DAMAGE_ALL:
619		return damage;
620	case DAMAGE_SUBTRACT:
621		__sna_damage_reduce(damage);
622	case DAMAGE_ADD:
623		break;
624	}
625
626	if (region->data == NULL)
627		return __sna_damage_add_box(damage, &region->extents);
628
629	if (REGION_NUM_RECTS(&damage->region) <= 1) {
630		pixman_region_union(&damage->region, &damage->region, region);
631		assert(damage->region.extents.x2 > damage->region.extents.x1);
632		assert(damage->region.extents.y2 > damage->region.extents.y1);
633		damage_union(damage, &region->extents);
634		return damage;
635	}
636
637	if (pixman_region_contains_rectangle(&damage->region,
638					     &region->extents) == PIXMAN_REGION_IN)
639		return damage;
640
641	damage_union(damage, &region->extents);
642	return _sna_damage_create_elt(damage,
643				      REGION_RECTS(region),
644				      REGION_NUM_RECTS(region));
645}
646
647#if HAS_DEBUG_FULL
648fastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage,
649					    RegionPtr region)
650{
651	char region_buf[120];
652	char damage_buf[1000];
653
654	DBG(("%s(%s + %s)\n", __FUNCTION__,
655	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
656	     _debug_describe_region(region_buf, sizeof(region_buf), region)));
657
658	damage = __sna_damage_add(damage, region);
659
660	ErrorF("  = %s\n",
661	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage));
662	assert(RegionNumRects(&damage->region));
663	assert(damage->region.extents.x2 > damage->region.extents.x1);
664	assert(damage->region.extents.y2 > damage->region.extents.y1);
665
666	return damage;
667}
668#else
669fastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage,
670					    RegionPtr region)
671{
672	return __sna_damage_add(damage, region);
673}
674#endif
675
676inline static struct sna_damage *
677__sna_damage_add_boxes(struct sna_damage *damage,
678		       const BoxRec *box, int n,
679		       int16_t dx, int16_t dy)
680{
681	BoxRec extents;
682	int i;
683
684	assert(n);
685
686	if (!damage) {
687		damage = _sna_damage_create();
688		if (damage == NULL)
689			return NULL;
690	} else switch (damage->mode) {
691	case DAMAGE_ALL:
692		return damage;
693	case DAMAGE_SUBTRACT:
694		__sna_damage_reduce(damage);
695	case DAMAGE_ADD:
696		break;
697	}
698
699	assert(box[0].x2 > box[0].x1 && box[0].y2 > box[0].y1);
700	extents = box[0];
701	for (i = 1; i < n; i++) {
702		assert(box[i].x2 > box[i].x1 && box[i].y2 > box[i].y1);
703		if (extents.x1 > box[i].x1)
704			extents.x1 = box[i].x1;
705		if (extents.x2 < box[i].x2)
706			extents.x2 = box[i].x2;
707		if (extents.y1 > box[i].y1)
708			extents.y1 = box[i].y1;
709		if (extents.y2 < box[i].y2)
710			extents.y2 = box[i].y2;
711	}
712
713	assert(extents.y2 > extents.y1 && extents.x2 > extents.x1);
714
715	extents.x1 += dx;
716	extents.x2 += dx;
717	extents.y1 += dy;
718	extents.y2 += dy;
719
720	if (n == 1)
721		return __sna_damage_add_box(damage, &extents);
722
723	if (pixman_region_contains_rectangle(&damage->region,
724					     &extents) == PIXMAN_REGION_IN)
725		return damage;
726
727	damage_union(damage, &extents);
728	return _sna_damage_create_elt_from_boxes(damage, box, n, dx, dy);
729}
730
731#if HAS_DEBUG_FULL
732struct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
733					 const BoxRec *b, int n,
734					 int16_t dx, int16_t dy)
735{
736	char damage_buf[1000];
737
738	DBG(("%s(%s + [(%d, %d), (%d, %d) ... x %d])\n", __FUNCTION__,
739	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
740	     b->x1, b->y1, b->x2, b->y2, n));
741
742	damage = __sna_damage_add_boxes(damage, b, n, dx, dy);
743
744	ErrorF("  = %s\n",
745	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage));
746	if (RegionNumRects(&damage->region)) {
747		assert(damage->region.extents.x2 > damage->region.extents.x1);
748		assert(damage->region.extents.y2 > damage->region.extents.y1);
749	}
750
751	return damage;
752}
753#else
754struct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
755					 const BoxRec *b, int n,
756					 int16_t dx, int16_t dy)
757{
758	return __sna_damage_add_boxes(damage, b, n, dx, dy);
759}
760#endif
761
762inline static struct sna_damage *
763__sna_damage_add_rectangles(struct sna_damage *damage,
764			    const xRectangle *r, int n,
765			    int16_t dx, int16_t dy)
766{
767	BoxRec extents;
768	int i;
769
770	assert(n);
771
772	assert(r[0].width && r[0].height);
773	extents.x1 = r[0].x;
774	extents.x2 = r[0].x + r[0].width;
775	extents.y1 = r[0].y;
776	extents.y2 = r[0].y + r[0].height;
777	for (i = 1; i < n; i++) {
778		assert(r[i].width && r[i].height);
779		if (extents.x1 > r[i].x)
780			extents.x1 = r[i].x;
781		if (extents.x2 < r[i].x + r[i].width)
782			extents.x2 = r[i].x + r[i].width;
783		if (extents.y1 > r[i].y)
784			extents.y1 = r[i].y;
785		if (extents.y2 < r[i].y + r[i].height)
786			extents.y2 = r[i].y + r[i].height;
787	}
788
789	assert(extents.y2 > extents.y1 && extents.x2 > extents.x1);
790
791	extents.x1 += dx;
792	extents.x2 += dx;
793	extents.y1 += dy;
794	extents.y2 += dy;
795
796	if (n == 1)
797		return __sna_damage_add_box(damage, &extents);
798
799	if (!damage) {
800		damage = _sna_damage_create();
801		if (damage == NULL)
802			return NULL;
803	} else switch (damage->mode) {
804	case DAMAGE_ALL:
805		return damage;
806	case DAMAGE_SUBTRACT:
807		__sna_damage_reduce(damage);
808	case DAMAGE_ADD:
809		break;
810	}
811
812	if (pixman_region_contains_rectangle(&damage->region,
813					     &extents) == PIXMAN_REGION_IN)
814		return damage;
815
816	damage_union(damage, &extents);
817	return _sna_damage_create_elt_from_rectangles(damage, r, n, dx, dy);
818}
819
820#if HAS_DEBUG_FULL
821struct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage,
822					      const xRectangle *r, int n,
823					      int16_t dx, int16_t dy)
824{
825	char damage_buf[1000];
826
827	DBG(("%s(%s + [(%d, %d)x(%d, %d) ... x %d])\n", __FUNCTION__,
828	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
829	     r->x, r->y, r->width, r->height, n));
830
831	damage = __sna_damage_add_rectangles(damage, r, n, dx, dy);
832
833	ErrorF("  = %s\n",
834	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage));
835	if (RegionNumRects(&damage->region)) {
836		assert(damage->region.extents.x2 > damage->region.extents.x1);
837		assert(damage->region.extents.y2 > damage->region.extents.y1);
838	}
839
840	return damage;
841}
842#else
843struct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage,
844					      const xRectangle *r, int n,
845					      int16_t dx, int16_t dy)
846{
847	return __sna_damage_add_rectangles(damage, r, n, dx, dy);
848}
849#endif
850
851/* XXX pass in extents? */
852inline static struct sna_damage *
853__sna_damage_add_points(struct sna_damage *damage,
854			const DDXPointRec *p, int n,
855			int16_t dx, int16_t dy)
856{
857	BoxRec extents;
858	int i;
859
860	assert(n);
861
862	extents.x2 = extents.x1 = p[0].x;
863	extents.y2 = extents.y1 = p[0].y;
864	for (i = 1; i < n; i++) {
865		if (extents.x1 > p[i].x)
866			extents.x1 = p[i].x;
867		else if (extents.x2 < p[i].x)
868			extents.x2 = p[i].x;
869		if (extents.y1 > p[i].y)
870			extents.y1 = p[i].y;
871		else if (extents.y2 < p[i].y)
872			extents.y2 = p[i].y;
873	}
874
875	extents.x1 += dx;
876	extents.x2 += dx + 1;
877	extents.y1 += dy;
878	extents.y2 += dy + 1;
879
880	if (n == 1)
881		return __sna_damage_add_box(damage, &extents);
882
883	if (!damage) {
884		damage = _sna_damage_create();
885		if (damage == NULL)
886			return NULL;
887	} else switch (damage->mode) {
888	case DAMAGE_ALL:
889		return damage;
890	case DAMAGE_SUBTRACT:
891		__sna_damage_reduce(damage);
892	case DAMAGE_ADD:
893		break;
894	}
895
896	if (pixman_region_contains_rectangle(&damage->region,
897					     &extents) == PIXMAN_REGION_IN)
898		return damage;
899
900	damage_union(damage, &extents);
901	_sna_damage_create_elt_from_points(damage, p, n, dx, dy);
902
903	return damage;
904}
905
906#if HAS_DEBUG_FULL
907struct sna_damage *_sna_damage_add_points(struct sna_damage *damage,
908					  const DDXPointRec *p, int n,
909					  int16_t dx, int16_t dy)
910{
911	char damage_buf[1000];
912
913	DBG(("%s(%s + [(%d, %d) ... x %d])\n", __FUNCTION__,
914	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
915	     p->x, p->y, n));
916
917	damage = __sna_damage_add_points(damage, p, n, dx, dy);
918
919	ErrorF("  = %s\n",
920	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage));
921	if (RegionNumRects(&damage->region)) {
922		assert(damage->region.extents.x2 > damage->region.extents.x1);
923		assert(damage->region.extents.y2 > damage->region.extents.y1);
924	}
925
926	return damage;
927}
928#else
929struct sna_damage *_sna_damage_add_points(struct sna_damage *damage,
930					  const DDXPointRec *p, int n,
931					  int16_t dx, int16_t dy)
932{
933	return __sna_damage_add_points(damage, p, n, dx, dy);
934}
935#endif
936
937#if HAS_DEBUG_FULL
938fastcall struct sna_damage *_sna_damage_add_box(struct sna_damage *damage,
939						const BoxRec *box)
940{
941	char damage_buf[1000];
942
943	DBG(("%s(%s + [(%d, %d), (%d, %d)])\n", __FUNCTION__,
944	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
945	     box->x1, box->y1, box->x2, box->y2));
946
947	damage = __sna_damage_add_box(damage, box);
948
949	ErrorF("  = %s\n",
950	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage));
951	assert(RegionNumRects(&damage->region));
952	assert(damage->region.extents.x2 > damage->region.extents.x1);
953	assert(damage->region.extents.y2 > damage->region.extents.y1);
954
955	return damage;
956}
957#else
958fastcall struct sna_damage *_sna_damage_add_box(struct sna_damage *damage,
959						const BoxRec *box)
960{
961	return __sna_damage_add_box(damage, box);
962}
963#endif
964
965struct sna_damage *__sna_damage_all(struct sna_damage *damage,
966				    int width, int height)
967{
968	DBG(("%s(%d, %d)\n", __FUNCTION__, width, height));
969
970	if (damage) {
971		pixman_region_fini(&damage->region);
972		free_list(&damage->embedded_box.list);
973		reset_embedded_box(damage);
974	} else {
975		damage = _sna_damage_create();
976		if (damage == NULL)
977			return NULL;
978	}
979
980	pixman_region_init_rect(&damage->region, 0, 0, width, height);
981	damage->extents = damage->region.extents;
982	damage->mode = DAMAGE_ALL;
983
984	return damage;
985}
986
987struct sna_damage *_sna_damage_is_all(struct sna_damage *damage,
988				      int width, int height)
989{
990	DBG(("%s(%d, %d)%s?\n", __FUNCTION__, width, height,
991	     damage->dirty ? "*" : ""));
992	DBG(("%s: (%d, %d), (%d, %d)\n", __FUNCTION__,
993	     damage->extents.x1, damage->extents.y1,
994	     damage->extents.x2, damage->extents.y2));
995
996	assert(damage->mode == DAMAGE_ADD);
997	assert(damage->extents.x1 == 0 &&
998	       damage->extents.y1 == 0 &&
999	       damage->extents.x2 == width &&
1000	       damage->extents.y2 == height);
1001
1002	if (damage->dirty) {
1003		__sna_damage_reduce(damage);
1004		assert(RegionNotEmpty(&damage->region));
1005	}
1006
1007	if (damage->region.data) {
1008		DBG(("%s: no, not singular\n", __FUNCTION__));
1009		return damage;
1010	}
1011
1012	assert(damage->extents.x1 == 0 &&
1013	       damage->extents.y1 == 0 &&
1014	       damage->extents.x2 == width &&
1015	       damage->extents.y2 == height);
1016
1017	return __sna_damage_all(damage, width, height);
1018}
1019
1020static bool box_contains(const BoxRec *a, const BoxRec *b)
1021{
1022	if (b->x1 < a->x1 || b->x2 > a->x2)
1023		return false;
1024
1025	if (b->y1 < a->y1 || b->y2 > a->y2)
1026		return false;
1027
1028	return true;
1029}
1030
1031static struct sna_damage *__sna_damage_subtract(struct sna_damage *damage,
1032						RegionPtr region)
1033{
1034	if (damage == NULL)
1035		return NULL;
1036
1037	if (RegionNil(&damage->region)) {
1038no_damage:
1039		__sna_damage_destroy(damage);
1040		return NULL;
1041	}
1042
1043	assert(RegionNotEmpty(region));
1044
1045	if (!sna_damage_overlaps_box(damage, &region->extents))
1046		return damage;
1047
1048	if (region_is_singular(region) &&
1049	    box_contains(&region->extents, &damage->extents))
1050		goto no_damage;
1051
1052	if (damage->mode == DAMAGE_ALL) {
1053		pixman_region_subtract(&damage->region,
1054				       &damage->region,
1055				       region);
1056		if (damage->region.extents.x2 <= damage->region.extents.x1 ||
1057		    damage->region.extents.y2 <= damage->region.extents.y1)
1058			goto no_damage;
1059
1060		damage->extents = damage->region.extents;
1061		damage->mode = DAMAGE_ADD;
1062		return damage;
1063	}
1064
1065	if (damage->mode != DAMAGE_SUBTRACT) {
1066		if (damage->dirty) {
1067			__sna_damage_reduce(damage);
1068			assert(RegionNotEmpty(&damage->region));
1069		}
1070
1071		if (pixman_region_equal(region, &damage->region))
1072			goto no_damage;
1073
1074		if (region_is_singular(&damage->region) &&
1075		    region_is_singular(region)) {
1076			pixman_region_subtract(&damage->region,
1077					       &damage->region,
1078					       region);
1079			if (damage->region.extents.x2 <= damage->region.extents.x1 ||
1080			    damage->region.extents.y2 <= damage->region.extents.y1)
1081				goto no_damage;
1082
1083			damage->extents = damage->region.extents;
1084			assert(pixman_region_not_empty(&damage->region));
1085			return damage;
1086		}
1087
1088		damage->mode = DAMAGE_SUBTRACT;
1089	}
1090
1091	return _sna_damage_create_elt(damage,
1092				      REGION_RECTS(region),
1093				      REGION_NUM_RECTS(region));
1094}
1095
1096#if HAS_DEBUG_FULL
1097fastcall struct sna_damage *_sna_damage_subtract(struct sna_damage *damage,
1098						 RegionPtr region)
1099{
1100	char damage_buf[1000];
1101	char region_buf[120];
1102
1103	ErrorF("%s(%s - %s)...\n", __FUNCTION__,
1104	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
1105	       _debug_describe_region(region_buf, sizeof(region_buf), region));
1106
1107	damage = __sna_damage_subtract(damage, region);
1108
1109	ErrorF("  = %s\n",
1110	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage));
1111
1112	return damage;
1113}
1114#else
1115fastcall struct sna_damage *_sna_damage_subtract(struct sna_damage *damage,
1116						 RegionPtr region)
1117{
1118	return __sna_damage_subtract(damage, region);
1119}
1120#endif
1121
1122inline static struct sna_damage *__sna_damage_subtract_box(struct sna_damage *damage,
1123							   const BoxRec *box)
1124{
1125	assert(box->x2 > box->x1 && box->y2 > box->y1);
1126
1127	if (damage == NULL)
1128		return NULL;
1129
1130	if (RegionNil(&damage->region)) {
1131		__sna_damage_destroy(damage);
1132		return NULL;
1133	}
1134
1135	if (!sna_damage_overlaps_box(damage, box))
1136		return damage;
1137
1138	if (box_contains(box, &damage->extents)) {
1139		__sna_damage_destroy(damage);
1140		return NULL;
1141	}
1142
1143	if (damage->mode != DAMAGE_SUBTRACT) {
1144		if (damage->dirty) {
1145			__sna_damage_reduce(damage);
1146			assert(RegionNotEmpty(&damage->region));
1147		}
1148
1149		if (region_is_singular(&damage->region)) {
1150			pixman_region16_t region;
1151
1152			pixman_region_init_rects(&region, box, 1);
1153			pixman_region_subtract(&damage->region,
1154					       &damage->region,
1155					       &region);
1156			damage->extents = damage->region.extents;
1157			damage->mode = DAMAGE_ADD;
1158			return damage;
1159		}
1160
1161		damage->mode = DAMAGE_SUBTRACT;
1162	}
1163
1164	return _sna_damage_create_elt(damage, box, 1);
1165}
1166
1167#if HAS_DEBUG_FULL
1168fastcall struct sna_damage *_sna_damage_subtract_box(struct sna_damage *damage,
1169						     const BoxRec *box)
1170{
1171	char damage_buf[1000];
1172
1173	ErrorF("%s(%s - (%d, %d), (%d, %d))...\n", __FUNCTION__,
1174	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
1175	       box->x1, box->y1, box->x2, box->y2);
1176
1177	damage = __sna_damage_subtract_box(damage, box);
1178
1179	ErrorF("  = %s\n",
1180	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage));
1181
1182	return damage;
1183}
1184#else
1185fastcall struct sna_damage *_sna_damage_subtract_box(struct sna_damage *damage,
1186						     const BoxRec *box)
1187{
1188	return __sna_damage_subtract_box(damage, box);
1189}
1190#endif
1191
1192static struct sna_damage *__sna_damage_subtract_boxes(struct sna_damage *damage,
1193						      const BoxRec *box, int n,
1194						      int dx, int dy)
1195{
1196	BoxRec extents;
1197	int i;
1198
1199	if (damage == NULL)
1200		return NULL;
1201
1202	if (RegionNil(&damage->region)) {
1203		__sna_damage_destroy(damage);
1204		return NULL;
1205	}
1206
1207	assert(n);
1208
1209	assert(box[0].x2 > box[0].x1 && box[0].y2 > box[0].y1);
1210	extents = box[0];
1211	for (i = 1; i < n; i++) {
1212		assert(box[i].x2 > box[i].x1 && box[i].y2 > box[i].y1);
1213		if (extents.x1 > box[i].x1)
1214			extents.x1 = box[i].x1;
1215		if (extents.x2 < box[i].x2)
1216			extents.x2 = box[i].x2;
1217		if (extents.y1 > box[i].y1)
1218			extents.y1 = box[i].y1;
1219		if (extents.y2 < box[i].y2)
1220			extents.y2 = box[i].y2;
1221	}
1222
1223	assert(extents.y2 > extents.y1 && extents.x2 > extents.x1);
1224
1225	extents.x1 += dx;
1226	extents.x2 += dx;
1227	extents.y1 += dy;
1228	extents.y2 += dy;
1229
1230	if (!sna_damage_overlaps_box(damage, &extents))
1231		return damage;
1232
1233	if (n == 1)
1234		return __sna_damage_subtract_box(damage, &extents);
1235
1236	if (damage->mode != DAMAGE_SUBTRACT) {
1237		if (damage->dirty) {
1238			__sna_damage_reduce(damage);
1239			assert(RegionNotEmpty(&damage->region));
1240		}
1241
1242		damage->mode = DAMAGE_SUBTRACT;
1243	}
1244
1245	return _sna_damage_create_elt_from_boxes(damage, box, n, dx, dy);
1246}
1247
1248#if HAS_DEBUG_FULL
1249fastcall struct sna_damage *_sna_damage_subtract_boxes(struct sna_damage *damage,
1250						       const BoxRec *box, int n,
1251						       int dx, int dy)
1252{
1253	char damage_buf[1000];
1254
1255	ErrorF("%s(%s - [(%d,%d), (%d,%d)...x%d])...\n", __FUNCTION__,
1256	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
1257	       box->x1 + dx, box->y1 + dy,
1258	       box->x2 + dx, box->y2 + dy,
1259	       n);
1260
1261	damage = __sna_damage_subtract_boxes(damage, box, n, dx, dy);
1262
1263	ErrorF("  = %s\n",
1264	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage));
1265
1266	return damage;
1267}
1268#else
1269fastcall struct sna_damage *_sna_damage_subtract_boxes(struct sna_damage *damage,
1270						       const BoxRec *box, int n,
1271						       int dx, int dy)
1272{
1273	return __sna_damage_subtract_boxes(damage, box, n, dx, dy);
1274}
1275#endif
1276
1277static int __sna_damage_contains_box(struct sna_damage *damage,
1278				     const BoxRec *box)
1279{
1280	int ret;
1281
1282	if (!damage)
1283		return PIXMAN_REGION_OUT;
1284
1285	if (damage->mode == DAMAGE_ALL)
1286		return PIXMAN_REGION_IN;
1287
1288	if (!sna_damage_overlaps_box(damage, box))
1289		return PIXMAN_REGION_OUT;
1290
1291	ret = pixman_region_contains_rectangle(&damage->region, (BoxPtr)box);
1292	if (!damage->dirty)
1293		return ret;
1294
1295	if (damage->mode == DAMAGE_ADD) {
1296		if (ret == PIXMAN_REGION_IN)
1297			return ret;
1298	} else {
1299		if (ret == PIXMAN_REGION_OUT)
1300			return ret;
1301	}
1302
1303	__sna_damage_reduce(damage);
1304	return pixman_region_contains_rectangle(&damage->region, (BoxPtr)box);
1305}
1306
1307#if HAS_DEBUG_FULL
1308int _sna_damage_contains_box(struct sna_damage *damage,
1309			     const BoxRec *box)
1310{
1311	char damage_buf[1000];
1312	int ret;
1313
1314	DBG(("%s(%s, [(%d, %d), (%d, %d)])\n", __FUNCTION__,
1315	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
1316	     box->x1, box->y1, box->x2, box->y2));
1317
1318	ret = __sna_damage_contains_box(damage, box);
1319	ErrorF("  = %d", ret);
1320	if (ret)
1321		ErrorF(" [(%d, %d), (%d, %d)...]",
1322		       box->x1, box->y1, box->x2, box->y2);
1323	ErrorF("\n");
1324
1325	return ret;
1326}
1327#else
1328int _sna_damage_contains_box(struct sna_damage *damage,
1329			     const BoxRec *box)
1330{
1331	return __sna_damage_contains_box(damage, box);
1332}
1333#endif
1334
1335static bool box_overlaps(const BoxRec *a, const BoxRec *b)
1336{
1337	return (a->x1 < b->x2 && a->x2 > b->x1 &&
1338		a->y1 < b->y2 && a->y2 > b->y1);
1339}
1340
1341bool _sna_damage_contains_box__no_reduce(const struct sna_damage *damage,
1342					 const BoxRec *box)
1343{
1344	int n, count;
1345	const BoxRec *b;
1346
1347	assert(damage && damage->mode != DAMAGE_ALL);
1348	if (!box_contains(&damage->extents, box))
1349		return false;
1350
1351	n = pixman_region_contains_rectangle((pixman_region16_t *)&damage->region, (BoxPtr)box);
1352	if (!damage->dirty)
1353		return n == PIXMAN_REGION_IN;
1354
1355	if (damage->mode == DAMAGE_ADD) {
1356		if (n == PIXMAN_REGION_IN)
1357			return true;
1358
1359		count = damage->embedded_box.size;
1360		if (list_is_empty(&damage->embedded_box.list))
1361			count -= damage->remain;
1362
1363		b = damage->embedded_box.box;
1364		for (n = 0; n < count; n++) {
1365			if (box_contains(&b[n], box))
1366				return true;
1367		}
1368
1369		return false;
1370	} else {
1371		if (n != PIXMAN_REGION_IN)
1372			return false;
1373
1374		if (!list_is_empty(&damage->embedded_box.list))
1375			return false;
1376
1377		count = damage->embedded_box.size - damage->remain;
1378		b = damage->embedded_box.box;
1379		for (n = 0; n < count; n++) {
1380			if (box_overlaps(&b[n], box))
1381				return false;
1382		}
1383
1384		return true;
1385	}
1386}
1387
1388static bool __sna_damage_intersect(struct sna_damage *damage,
1389				   RegionPtr region, RegionPtr result)
1390{
1391	assert(damage && damage->mode != DAMAGE_ALL);
1392	assert(RegionNotEmpty(region));
1393
1394	if (region->extents.x2 <= damage->extents.x1 ||
1395	    region->extents.x1 >= damage->extents.x2)
1396		return false;
1397
1398	if (region->extents.y2 <= damage->extents.y1 ||
1399	    region->extents.y1 >= damage->extents.y2)
1400		return false;
1401
1402	if (damage->dirty)
1403		__sna_damage_reduce(damage);
1404
1405	if (!pixman_region_not_empty(&damage->region))
1406		return false;
1407
1408	RegionNull(result);
1409	RegionIntersect(result, &damage->region, region);
1410
1411	return RegionNotEmpty(result);
1412}
1413
1414#if HAS_DEBUG_FULL
1415bool _sna_damage_intersect(struct sna_damage *damage,
1416			   RegionPtr region, RegionPtr result)
1417{
1418	char damage_buf[1000];
1419	char region_buf[120];
1420	bool ret;
1421
1422	ErrorF("%s(%s, %s)...\n", __FUNCTION__,
1423	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
1424	       _debug_describe_region(region_buf, sizeof(region_buf), region));
1425
1426	ret = __sna_damage_intersect(damage, region, result);
1427	if (ret)
1428		ErrorF("  = %s\n",
1429		       _debug_describe_region(region_buf, sizeof(region_buf), result));
1430	else
1431		ErrorF("  = none\n");
1432
1433	return ret;
1434}
1435#else
1436bool _sna_damage_intersect(struct sna_damage *damage,
1437			  RegionPtr region, RegionPtr result)
1438{
1439	return __sna_damage_intersect(damage, region, result);
1440}
1441#endif
1442
1443static int __sna_damage_get_boxes(struct sna_damage *damage, BoxPtr *boxes)
1444{
1445	assert(damage && damage->mode != DAMAGE_ALL);
1446
1447	if (damage->dirty)
1448		__sna_damage_reduce(damage);
1449
1450	*boxes = REGION_RECTS(&damage->region);
1451	return REGION_NUM_RECTS(&damage->region);
1452}
1453
1454struct sna_damage *_sna_damage_reduce(struct sna_damage *damage)
1455{
1456	DBG(("%s\n", __FUNCTION__));
1457
1458	__sna_damage_reduce(damage);
1459	if (!pixman_region_not_empty(&damage->region)) {
1460		__sna_damage_destroy(damage);
1461		damage = NULL;
1462	}
1463
1464	return damage;
1465}
1466
1467#if HAS_DEBUG_FULL
1468int _sna_damage_get_boxes(struct sna_damage *damage, BoxPtr *boxes)
1469{
1470	char damage_buf[1000];
1471	int count;
1472
1473	ErrorF("%s(%s)...\n", __FUNCTION__,
1474	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage));
1475
1476	count = __sna_damage_get_boxes(damage, boxes);
1477	ErrorF("  = %d\n", count);
1478
1479	return count;
1480}
1481#else
1482int _sna_damage_get_boxes(struct sna_damage *damage, BoxPtr *boxes)
1483{
1484	return __sna_damage_get_boxes(damage, boxes);
1485}
1486#endif
1487
1488struct sna_damage *_sna_damage_combine(struct sna_damage *l,
1489				       struct sna_damage *r,
1490				       int dx, int dy)
1491{
1492	if (r->dirty)
1493		__sna_damage_reduce(r);
1494
1495	if (pixman_region_not_empty(&r->region)) {
1496		pixman_region_translate(&r->region, dx, dy);
1497		l = __sna_damage_add(l, &r->region);
1498	}
1499
1500	return l;
1501}
1502
1503void __sna_damage_destroy(struct sna_damage *damage)
1504{
1505	free_list(&damage->embedded_box.list);
1506
1507	pixman_region_fini(&damage->region);
1508	*(void **)damage = __freed_damage;
1509	__freed_damage = damage;
1510}
1511
1512#if TEST_DAMAGE && HAS_DEBUG_FULL
1513struct sna_damage_selftest{
1514	int width, height;
1515};
1516
1517static void st_damage_init_random_box(struct sna_damage_selftest *test,
1518				      BoxPtr box)
1519{
1520	int x, y, w, h;
1521
1522	if (test->width == 1) {
1523		x = 0, w = 1;
1524	} else {
1525		x = rand() % (test->width - 1);
1526		w = 1 + rand() % (test->width - x - 1);
1527	}
1528
1529	if (test->height == 1) {
1530		y = 0, h = 1;
1531	} else {
1532		y = rand() % (test->height - 1);
1533		h = 1 + rand() % (test->height - y - 1);
1534	}
1535
1536	box->x1 = x;
1537	box->x2 = x+w;
1538
1539	box->y1 = y;
1540	box->y2 = y+h;
1541}
1542
1543static void st_damage_init_random_region1(struct sna_damage_selftest *test,
1544					  pixman_region16_t *region)
1545{
1546	int x, y, w, h;
1547
1548	if (test->width == 1) {
1549		x = 0, w = 1;
1550	} else {
1551		x = rand() % (test->width - 1);
1552		w = 1 + rand() % (test->width - x - 1);
1553	}
1554
1555	if (test->height == 1) {
1556		y = 0, h = 1;
1557	} else {
1558		y = rand() % (test->height - 1);
1559		h = 1 + rand() % (test->height - y - 1);
1560	}
1561
1562	pixman_region_init_rect(region, x, y, w, h);
1563}
1564
1565static void st_damage_add(struct sna_damage_selftest *test,
1566			  struct sna_damage **damage,
1567			  pixman_region16_t *region)
1568{
1569	pixman_region16_t tmp;
1570
1571	st_damage_init_random_region1(test, &tmp);
1572
1573	if (!DAMAGE_IS_ALL(*damage))
1574		sna_damage_add(damage, &tmp);
1575	pixman_region_union(region, region, &tmp);
1576}
1577
1578static void st_damage_add_box(struct sna_damage_selftest *test,
1579			      struct sna_damage **damage,
1580			      pixman_region16_t *region)
1581{
1582	RegionRec r;
1583
1584	st_damage_init_random_box(test, &r.extents);
1585	r.data = NULL;
1586
1587	if (!DAMAGE_IS_ALL(*damage))
1588		sna_damage_add_box(damage, &r.extents);
1589	pixman_region_union(region, region, &r);
1590}
1591
1592static void st_damage_subtract(struct sna_damage_selftest *test,
1593			       struct sna_damage **damage,
1594			       pixman_region16_t *region)
1595{
1596	pixman_region16_t tmp;
1597
1598	st_damage_init_random_region1(test, &tmp);
1599
1600	sna_damage_subtract(damage, &tmp);
1601	pixman_region_subtract(region, region, &tmp);
1602}
1603
1604static void st_damage_subtract_box(struct sna_damage_selftest *test,
1605				   struct sna_damage **damage,
1606				   pixman_region16_t *region)
1607{
1608	RegionRec r;
1609
1610	st_damage_init_random_box(test, &r.extents);
1611	r.data = NULL;
1612
1613	sna_damage_subtract_box(damage, &r.extents);
1614	pixman_region_subtract(region, region, &r);
1615}
1616
1617static void st_damage_all(struct sna_damage_selftest *test,
1618			  struct sna_damage **damage,
1619			  pixman_region16_t *region)
1620{
1621	pixman_region16_t tmp;
1622
1623	pixman_region_init_rect(&tmp, 0, 0, test->width, test->height);
1624
1625	if (!DAMAGE_IS_ALL(*damage))
1626		sna_damage_all(damage, test->width, test->height);
1627	pixman_region_union(region, region, &tmp);
1628}
1629
1630static bool st_check_equal(struct sna_damage_selftest *test,
1631			   struct sna_damage **damage,
1632			   pixman_region16_t *region)
1633{
1634	int d_num, r_num;
1635	BoxPtr d_boxes, r_boxes;
1636
1637	d_num = *damage ? sna_damage_get_boxes(*damage, &d_boxes) : 0;
1638	r_boxes = pixman_region_rectangles(region, &r_num);
1639
1640	if (d_num != r_num) {
1641		ErrorF("%s: damage and ref contain different number of rectangles\n",
1642		       __FUNCTION__);
1643		return false;
1644	}
1645
1646	if (memcmp(d_boxes, r_boxes, d_num*sizeof(BoxRec))) {
1647		ErrorF("%s: damage and ref contain different rectangles\n",
1648		       __FUNCTION__);
1649		return false;
1650	}
1651
1652	return true;
1653}
1654
1655void sna_damage_selftest(void)
1656{
1657	void (*const op[])(struct sna_damage_selftest *test,
1658			   struct sna_damage **damage,
1659			   pixman_region16_t *region) = {
1660		st_damage_add,
1661		st_damage_add_box,
1662		st_damage_subtract,
1663		st_damage_subtract_box,
1664		st_damage_all
1665	};
1666	bool (*const check[])(struct sna_damage_selftest *test,
1667			      struct sna_damage **damage,
1668			      pixman_region16_t *region) = {
1669		st_check_equal,
1670		//st_check_contains,
1671	};
1672	char region_buf[120];
1673	char damage_buf[1000];
1674	int pass;
1675
1676	for (pass = 0; pass < 16384; pass++) {
1677		struct sna_damage_selftest test;
1678		struct sna_damage *damage;
1679		pixman_region16_t ref;
1680		int iter, i;
1681
1682		iter = 1 + rand() % (1 + (pass / 64));
1683		ErrorF("%s: pass %d, iters=%d\n", __FUNCTION__, pass, iter);
1684
1685		test.width = 1 + rand() % 2048;
1686		test.height = 1 + rand() % 2048;
1687
1688		damage = _sna_damage_create();
1689		pixman_region_init(&ref);
1690
1691		for (i = 0; i < iter; i++) {
1692			op[rand() % ARRAY_SIZE(op)](&test, &damage, &ref);
1693		}
1694
1695		if (!check[rand() % ARRAY_SIZE(check)](&test, &damage, &ref)) {
1696			ErrorF("%s: failed - region = %s, damage = %s\n", __FUNCTION__,
1697			       _debug_describe_region(region_buf, sizeof(region_buf), &ref),
1698			       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage));
1699			assert(0);
1700		}
1701
1702		pixman_region_fini(&ref);
1703		sna_damage_destroy(&damage);
1704	}
1705}
1706#endif
1707
1708void _sna_damage_debug_get_region(struct sna_damage *damage, RegionRec *r)
1709{
1710	int n, nboxes;
1711	BoxPtr boxes;
1712	struct sna_damage_box *iter;
1713
1714	RegionCopy(r, &damage->region);
1715	if (!damage->dirty)
1716		return;
1717
1718	nboxes = damage->embedded_box.size;
1719	list_for_each_entry(iter, &damage->embedded_box.list, list)
1720		nboxes += iter->size;
1721	nboxes -= damage->remain;
1722	if (nboxes == 0)
1723		return;
1724
1725	if (nboxes == 1) {
1726		pixman_region16_t tmp;
1727
1728		tmp.extents = damage->embedded_box.box[0];
1729		tmp.data = NULL;
1730
1731		if (damage->mode == DAMAGE_ADD)
1732			pixman_region_union(r, r, &tmp);
1733		else
1734			pixman_region_subtract(r, r, &tmp);
1735
1736		return;
1737	}
1738
1739	if (damage->mode == DAMAGE_ADD)
1740		nboxes += REGION_NUM_RECTS(r);
1741
1742	iter = list_entry(damage->embedded_box.list.prev,
1743			  struct sna_damage_box,
1744			  list);
1745	n = iter->size - damage->remain;
1746	boxes = malloc(sizeof(BoxRec)*nboxes);
1747	if (boxes == NULL)
1748		return;
1749
1750	if (list_is_empty(&damage->embedded_box.list)) {
1751		memcpy(boxes,
1752		       damage->embedded_box.box,
1753		       n*sizeof(BoxRec));
1754	} else {
1755		if (boxes != (BoxPtr)(iter+1))
1756			memcpy(boxes, iter+1, n*sizeof(BoxRec));
1757
1758		iter = list_entry(iter->list.prev,
1759				  struct sna_damage_box,
1760				  list);
1761		while (&iter->list != &damage->embedded_box.list) {
1762			memcpy(boxes + n, iter+1,
1763			       iter->size * sizeof(BoxRec));
1764			n += iter->size;
1765
1766			iter = list_entry(iter->list.prev,
1767					  struct sna_damage_box,
1768					  list);
1769		}
1770
1771		memcpy(boxes + n,
1772		       damage->embedded_box.box,
1773		       sizeof(damage->embedded_box.box));
1774		n += damage->embedded_box.size;
1775	}
1776
1777	if (damage->mode == DAMAGE_ADD) {
1778		memcpy(boxes + n,
1779		       REGION_RECTS(r),
1780		       REGION_NUM_RECTS(r)*sizeof(BoxRec));
1781		assert(n + REGION_NUM_RECTS(r) == nboxes);
1782		pixman_region_fini(r);
1783		pixman_region_init_rects(r, boxes, nboxes);
1784
1785		assert(pixman_region_not_empty(r));
1786		assert(damage->extents.x1 == r->extents.x1 &&
1787		       damage->extents.y1 == r->extents.y1 &&
1788		       damage->extents.x2 == r->extents.x2 &&
1789		       damage->extents.y2 == r->extents.y2);
1790	} else {
1791		pixman_region16_t tmp;
1792
1793		pixman_region_init_rects(&tmp, boxes, nboxes);
1794		pixman_region_subtract(r, r, &tmp);
1795		pixman_region_fini(&tmp);
1796
1797		assert(damage->extents.x1 <= r->extents.x1 &&
1798		       damage->extents.y1 <= r->extents.y1 &&
1799		       damage->extents.x2 >= r->extents.x2 &&
1800		       damage->extents.y2 >= r->extents.y2);
1801	}
1802
1803	free(boxes);
1804}
1805