1/**************************************************************************
2
3Copyright (c) 2011 Intel Corporation
4
5Permission is hereby granted, free of charge, to any person obtaining a
6copy of this software and associated documentation files (the
7"Software"), to deal in the Software without restriction, including
8without limitation the rights to use, copy, modify, merge, publish,
9distribute, sub license, and/or sell copies of the Software, and to
10permit persons to whom the Software is furnished to do so, subject to
11the following conditions:
12
13The above copyright notice and this permission notice (including the
14next paragraph) shall be included in all copies or substantial portions
15of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
21ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25 **************************************************************************/
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#include "sna.h"
32#include "sna_damage.h"
33
34/*
35 * sna_damage is a batching layer on top of the regular pixman_region_t.
36 * It is required as the ever-growing accumulation of invidual small
37 * damage regions is an O(n^2) operation. Instead the accumulation of a
38 * batch can be done in closer to O(n.lgn), and so prevents abysmal
39 * performance in x11perf -copywinwin10.
40 *
41 * As with the core of SNA, damage is handled modally. That is, it
42 * accumulates whilst rendering and then subtracts during migration of the
43 * pixmap from GPU to CPU or vice versa. As such we can track the current
44 * mode globally and when that mode switches perform the update of the region
45 * in a single operation.
46 *
47 * Furthermore, we can track whether the whole pixmap is damaged and so
48 * cheapy discard no-ops.
49 */
50
51struct sna_damage_box {
52	struct list list;
53	int size;
54} __attribute__((packed));
55
56static struct sna_damage *__freed_damage;
57
58static inline bool region_is_singular(const RegionRec *r)
59{
60	return r->data == NULL;
61}
62
63static inline bool region_is_singular_or_empty(const RegionRec *r)
64{
65	return r->data == NULL || r->data->numRects == 0;
66}
67
68#if HAS_DEBUG_FULL
69static const char *_debug_describe_region(char *buf, int max,
70					  const RegionRec *region)
71{
72	const BoxRec *box;
73	int n, len;
74
75	if (region == NULL)
76		return "nil";
77
78	n = region_num_rects(region);
79	if (n == 0)
80		return "[0]";
81
82	if (n == 1) {
83		sprintf(buf,
84			"[(%d, %d), (%d, %d)]",
85			region->extents.x1, region->extents.y1,
86			region->extents.x2, region->extents.y2);
87		return buf;
88	}
89
90	len = sprintf(buf,
91		      "[(%d, %d), (%d, %d) x %d: ",
92		      region->extents.x1, region->extents.y1,
93		      region->extents.x2, region->extents.y2,
94		      n) + 3;
95	max -= 2;
96	box = region_rects(region);
97	while (n--) {
98		char tmp[80];
99		int this;
100
101		this = snprintf(tmp, sizeof(tmp),
102				"((%d, %d), (%d, %d))%s",
103				box->x1, box->y1,
104				box->x2, box->y2,
105				n ? ", ..." : "");
106		box++;
107
108		if (this > max - len)
109			break;
110
111		len -= 3;
112		memcpy(buf + len, tmp, this);
113		len += this;
114	}
115	buf[len++] = ']';
116	buf[len] = '\0';
117	return buf;
118}
119
120static const char *_debug_describe_damage(char *buf, int max,
121					  const struct sna_damage *damage)
122{
123	char damage_str[500], region_str[500];
124	int str_max;
125
126	if (damage == NULL)
127		return "None";
128
129	str_max = max/2 - 6;
130	if (str_max > sizeof(damage_str))
131		str_max = sizeof(damage_str);
132
133	if (damage->mode == DAMAGE_ALL) {
134		snprintf(buf, max, "[[(%d, %d), (%d, %d)]: all]",
135			 damage->extents.x1, damage->extents.y1,
136			 damage->extents.x2, damage->extents.y2);
137	} else {
138		if (damage->dirty) {
139			sprintf(damage_str, "%c[ ...]",
140				damage->mode == DAMAGE_SUBTRACT ? '-' : '+');
141		} else
142			damage_str[0] = '\0';
143		snprintf(buf, max, "[[(%d, %d), (%d, %d)]: %s %s]%c",
144			 damage->extents.x1, damage->extents.y1,
145			 damage->extents.x2, damage->extents.y2,
146			 _debug_describe_region(region_str, str_max,
147						&damage->region),
148			 damage_str, damage->dirty ? '*' : ' ');
149	}
150
151	return buf;
152}
153#endif
154
155static struct sna_damage_box *
156last_box(struct sna_damage *damage)
157{
158	return list_entry(damage->embedded_box.list.prev,
159			  struct sna_damage_box,
160			  list);
161}
162
163static void
164reset_embedded_box(struct sna_damage *damage)
165{
166	damage->dirty = false;
167	damage->box = damage->embedded_box.box;
168	damage->embedded_box.size =
169		damage->remain = ARRAY_SIZE(damage->embedded_box.box);
170	list_init(&damage->embedded_box.list);
171}
172
173static void reset_extents(struct sna_damage *damage)
174{
175	damage->extents.x1 = damage->extents.y1 = MAXSHORT;
176	damage->extents.x2 = damage->extents.y2 = MINSHORT;
177}
178
179static struct sna_damage *_sna_damage_create(void)
180{
181	struct sna_damage *damage;
182
183	if (__freed_damage) {
184		damage = __freed_damage;
185		__freed_damage = *(void **)__freed_damage;
186	} else {
187		damage = malloc(sizeof(*damage));
188		if (damage == NULL)
189			return NULL;
190	}
191	reset_embedded_box(damage);
192	damage->mode = DAMAGE_ADD;
193	pixman_region_init(&damage->region);
194	reset_extents(damage);
195
196	return damage;
197}
198
199struct sna_damage *sna_damage_create(void)
200{
201	return _sna_damage_create();
202}
203
204static void free_list(struct list *head)
205{
206	while (!list_is_empty(head)) {
207		struct list *l = head->next;
208		list_del(l);
209		free(l);
210	}
211}
212
213static void __sna_damage_reduce(struct sna_damage *damage)
214{
215	int n, nboxes;
216	BoxPtr boxes, free_boxes = NULL;
217	pixman_region16_t *region = &damage->region;
218	struct sna_damage_box *iter;
219
220	assert(damage->mode != DAMAGE_ALL);
221	assert(damage->dirty);
222
223	DBG(("    reduce: before region.n=%d\n", region_num_rects(region)));
224
225	nboxes = damage->embedded_box.size;
226	list_for_each_entry(iter, &damage->embedded_box.list, list)
227		nboxes += iter->size;
228	DBG(("   nboxes=%d, residual=%d\n", nboxes, damage->remain));
229	nboxes -= damage->remain;
230	if (nboxes == 0)
231		goto done;
232	if (nboxes == 1) {
233		pixman_region16_t tmp;
234
235		tmp.extents = damage->embedded_box.box[0];
236		tmp.data = NULL;
237
238		if (damage->mode == DAMAGE_ADD)
239			pixman_region_union(region, region, &tmp);
240		else
241			pixman_region_subtract(region, region, &tmp);
242		damage->extents = region->extents;
243
244		goto done;
245	}
246
247	if (damage->mode == DAMAGE_ADD)
248		nboxes += region_num_rects(region);
249
250	iter = last_box(damage);
251	n = iter->size - damage->remain;
252	boxes = (BoxRec *)(iter+1);
253	DBG(("   last box count=%d/%d, need=%d\n", n, iter->size, nboxes));
254	if (nboxes > iter->size) {
255		boxes = malloc(sizeof(BoxRec)*nboxes);
256		if (boxes == NULL)
257			goto done;
258
259		free_boxes = boxes;
260	}
261
262	if (boxes != damage->embedded_box.box) {
263		if (list_is_empty(&damage->embedded_box.list)) {
264			DBG(("   copying embedded boxes\n"));
265			memcpy(boxes,
266			       damage->embedded_box.box,
267			       n*sizeof(BoxRec));
268		} else {
269			if (boxes != (BoxPtr)(iter+1)) {
270				DBG(("   copying %d boxes from last\n", n));
271				memcpy(boxes, iter+1, n*sizeof(BoxRec));
272			}
273
274			iter = list_entry(iter->list.prev,
275					  struct sna_damage_box,
276					  list);
277			while (&iter->list != &damage->embedded_box.list) {
278				DBG(("   copy %d boxes from %d\n",
279				     iter->size, n));
280				memcpy(boxes + n, iter+1,
281				       iter->size * sizeof(BoxRec));
282				n += iter->size;
283
284				iter = list_entry(iter->list.prev,
285						  struct sna_damage_box,
286						  list);
287			}
288
289			DBG(("   copying embedded boxes to %d\n", n));
290			memcpy(boxes + n,
291			       damage->embedded_box.box,
292			       sizeof(damage->embedded_box.box));
293			n += damage->embedded_box.size;
294		}
295	}
296
297	if (damage->mode == DAMAGE_ADD) {
298		memcpy(boxes + n,
299		       region_rects(region),
300		       region_num_rects(region)*sizeof(BoxRec));
301		assert(n + region_num_rects(region) == nboxes);
302		pixman_region_fini(region);
303		pixman_region_init_rects(region, boxes, nboxes);
304
305		assert(pixman_region_not_empty(region));
306		assert(damage->extents.x1 == region->extents.x1 &&
307		       damage->extents.y1 == region->extents.y1 &&
308		       damage->extents.x2 == region->extents.x2 &&
309		       damage->extents.y2 == region->extents.y2);
310	} else {
311		pixman_region16_t tmp;
312
313		assert(n == nboxes);
314		pixman_region_init_rects(&tmp, boxes, nboxes);
315		pixman_region_subtract(region, region, &tmp);
316		pixman_region_fini(&tmp);
317
318		assert(damage->extents.x1 <= region->extents.x1 &&
319		       damage->extents.y1 <= region->extents.y1 &&
320		       damage->extents.x2 >= region->extents.x2 &&
321		       damage->extents.y2 >= region->extents.y2);
322		if (pixman_region_not_empty(region))
323			damage->extents = region->extents;
324		else
325			reset_extents(damage);
326	}
327
328	free(free_boxes);
329
330done:
331	damage->mode = DAMAGE_ADD;
332	free_list(&damage->embedded_box.list);
333	reset_embedded_box(damage);
334
335	DBG(("    reduce: after region.n=%d\n", region_num_rects(region)));
336}
337
338static bool _sna_damage_create_boxes(struct sna_damage *damage,
339				     int count)
340{
341	struct sna_damage_box *box;
342	int n;
343
344	box = last_box(damage);
345	n = 4*box->size;
346	if (n < count)
347		n = ALIGN(count, 64);
348
349	DBG(("    %s(%d->%d): new\n", __FUNCTION__, count, n));
350
351	if (n >= (INT_MAX - sizeof(*box)) / sizeof(BoxRec))
352		return false;
353
354	box = malloc(sizeof(*box) + sizeof(BoxRec)*n);
355	if (box == NULL)
356		return false;
357
358	list_add_tail(&box->list, &damage->embedded_box.list);
359
360	box->size = damage->remain = n;
361	damage->box = (BoxRec *)(box + 1);
362	return true;
363}
364
365static struct sna_damage *
366_sna_damage_create_elt(struct sna_damage *damage,
367		       const BoxRec *boxes, int count)
368{
369	int n;
370
371	DBG(("    %s: prev=(remain %d), count=%d\n",
372	     __FUNCTION__, damage->remain, count));
373	assert(count);
374
375restart:
376	n = count;
377	if (n > damage->remain)
378		n = damage->remain;
379	if (n) {
380		memcpy(damage->box, boxes, n * sizeof(BoxRec));
381		damage->box += n;
382		damage->remain -= n;
383		damage->dirty = true;
384
385		count -= n;
386		boxes += n;
387		if (count == 0)
388			return damage;
389	}
390
391	DBG(("    %s(): new elt\n", __FUNCTION__));
392	assert(damage->remain == 0);
393	assert(damage->box - (BoxRec *)(last_box(damage)+1) == last_box(damage)->size);
394
395	if (!_sna_damage_create_boxes(damage, count)) {
396		unsigned mode;
397
398		if (!damage->dirty)
399			return damage;
400
401		mode = damage->mode;
402		__sna_damage_reduce(damage);
403		damage->mode = mode;
404
405		goto restart;
406	}
407
408	memcpy(damage->box, boxes, count * sizeof(BoxRec));
409	damage->box += count;
410	damage->remain -= count;
411	damage->dirty = true;
412	assert(damage->remain >= 0);
413
414	return damage;
415}
416
417static struct sna_damage *
418_sna_damage_create_elt_from_boxes(struct sna_damage *damage,
419				  const BoxRec *boxes, int count,
420				  int16_t dx, int16_t dy)
421{
422	int i, n;
423
424	DBG(("    %s: prev=(remain %d)\n", __FUNCTION__, damage->remain));
425	assert(count);
426
427restart:
428	n = count;
429	if (n > damage->remain)
430		n = damage->remain;
431	if (n) {
432		for (i = 0; i < n; i++) {
433			damage->box[i].x1 = boxes[i].x1 + dx;
434			damage->box[i].x2 = boxes[i].x2 + dx;
435			damage->box[i].y1 = boxes[i].y1 + dy;
436			damage->box[i].y2 = boxes[i].y2 + dy;
437		}
438		damage->box += n;
439		damage->remain -= n;
440		damage->dirty = true;
441
442		count -= n;
443		boxes += n;
444		if (count == 0)
445			return damage;
446	}
447
448	DBG(("    %s(): new elt\n", __FUNCTION__));
449	assert(damage->remain == 0);
450	assert(damage->box - (BoxRec *)(last_box(damage)+1) == last_box(damage)->size);
451
452	if (!_sna_damage_create_boxes(damage, count)) {
453		unsigned mode;
454
455		if (!damage->dirty)
456			return damage;
457
458		mode = damage->mode;
459		__sna_damage_reduce(damage);
460		damage->mode = mode;
461
462		goto restart;
463	}
464
465	for (i = 0; i < count; i++) {
466		damage->box[i].x1 = boxes[i].x1 + dx;
467		damage->box[i].x2 = boxes[i].x2 + dx;
468		damage->box[i].y1 = boxes[i].y1 + dy;
469		damage->box[i].y2 = boxes[i].y2 + dy;
470	}
471	damage->box += count;
472	damage->remain -= count;
473	damage->dirty = true;
474	assert(damage->remain >= 0);
475
476	return damage;
477}
478
479static struct sna_damage *
480_sna_damage_create_elt_from_rectangles(struct sna_damage *damage,
481				       const xRectangle *r, int count,
482				       int16_t dx, int16_t dy)
483{
484	int i, n;
485
486	DBG(("    %s: prev=(remain %d), count=%d\n",
487	     __FUNCTION__, damage->remain, count));
488	assert(count);
489
490restart:
491	n = count;
492	if (n > damage->remain)
493		n = damage->remain;
494	if (n) {
495		for (i = 0; i < n; i++) {
496			damage->box[i].x1 = r[i].x + dx;
497			damage->box[i].x2 = damage->box[i].x1 + r[i].width;
498			damage->box[i].y1 = r[i].y + dy;
499			damage->box[i].y2 = damage->box[i].y1 + r[i].height;
500		}
501		damage->box += n;
502		damage->remain -= n;
503		damage->dirty = true;
504
505		count -= n;
506		r += n;
507		if (count == 0)
508			return damage;
509	}
510
511	DBG(("    %s(): new elt\n", __FUNCTION__));
512	assert(damage->remain == 0);
513	assert(damage->box - (BoxRec *)(last_box(damage)+1) == last_box(damage)->size);
514
515	if (!_sna_damage_create_boxes(damage, count)) {
516		unsigned mode;
517
518		if (!damage->dirty)
519			return damage;
520
521		mode = damage->mode;
522		__sna_damage_reduce(damage);
523		damage->mode = mode;
524
525		goto restart;
526	}
527
528	for (i = 0; i < count; i++) {
529		damage->box[i].x1 = r[i].x + dx;
530		damage->box[i].x2 = damage->box[i].x1 + r[i].width;
531		damage->box[i].y1 = r[i].y + dy;
532		damage->box[i].y2 = damage->box[i].y1 + r[i].height;
533	}
534	damage->box += count;
535	damage->remain -= count;
536	damage->dirty = true;
537	assert(damage->remain >= 0);
538
539	return damage;
540}
541
542static struct sna_damage *
543_sna_damage_create_elt_from_points(struct sna_damage *damage,
544				   const DDXPointRec *p, int count,
545				   int16_t dx, int16_t dy)
546{
547	int i, n;
548
549	DBG(("    %s: prev=(remain %d), count=%d\n",
550	     __FUNCTION__, damage->remain, count));
551	assert(count);
552
553restart:
554	n = count;
555	if (n > damage->remain)
556		n = damage->remain;
557	if (n) {
558		for (i = 0; i < n; i++) {
559			damage->box[i].x1 = p[i].x + dx;
560			damage->box[i].x2 = damage->box[i].x1 + 1;
561			damage->box[i].y1 = p[i].y + dy;
562			damage->box[i].y2 = damage->box[i].y1 + 1;
563		}
564		damage->box += n;
565		damage->remain -= n;
566		damage->dirty = true;
567
568		count -= n;
569		p += n;
570		if (count == 0)
571			return damage;
572	}
573
574	DBG(("    %s(): new elt\n", __FUNCTION__));
575	assert(damage->remain == 0);
576	assert(damage->box - (BoxRec *)(last_box(damage)+1) == last_box(damage)->size);
577
578	if (!_sna_damage_create_boxes(damage, count)) {
579		unsigned mode;
580
581		if (!damage->dirty)
582			return damage;
583
584		mode = damage->mode;
585		__sna_damage_reduce(damage);
586		damage->mode = mode;
587
588		goto restart;
589	}
590
591	for (i = 0; i < count; i++) {
592		damage->box[i].x1 = p[i].x + dx;
593		damage->box[i].x2 = damage->box[i].x1 + 1;
594		damage->box[i].y1 = p[i].y + dy;
595		damage->box[i].y2 = damage->box[i].y1 + 1;
596	}
597	damage->box += count;
598	damage->remain -= count;
599	damage->dirty = true;
600	assert(damage->remain >= 0);
601
602	return damage;
603}
604
605static void damage_union(struct sna_damage *damage, const BoxRec *box)
606{
607	DBG(("%s: extending damage (%d, %d), (%d, %d) by (%d, %d), (%d, %d)\n",
608	     __FUNCTION__,
609	     damage->extents.x1, damage->extents.y1,
610	     damage->extents.x2, damage->extents.y2,
611	     box->x1, box->y1, box->x2, box->y2));
612	assert(box->x2 > box->x1 && box->y2 > box->y1);
613	if (damage->extents.x2 < damage->extents.x1) {
614		damage->extents = *box;
615	} else {
616		if (damage->extents.x1 > box->x1)
617			damage->extents.x1 = box->x1;
618		if (damage->extents.x2 < box->x2)
619			damage->extents.x2 = box->x2;
620
621		if (damage->extents.y1 > box->y1)
622			damage->extents.y1 = box->y1;
623		if (damage->extents.y2 < box->y2)
624			damage->extents.y2 = box->y2;
625	}
626	assert(damage->extents.x2 > damage->extents.x1);
627	assert(damage->extents.y2 > damage->extents.y1);
628}
629
630static void _pixman_region_union_box(RegionRec *region, const BoxRec *box)
631{
632	RegionRec u = { *box, NULL };
633	pixman_region_union(region, region, &u);
634}
635
636static bool box_contains_region(const BoxRec *b, const RegionRec *r)
637{
638	return (b->x1 <= r->extents.x1 && b->x2 >= r->extents.x2 &&
639		b->y1 <= r->extents.y1 && b->y2 >= r->extents.y2);
640}
641
642static struct sna_damage *__sna_damage_add_box(struct sna_damage *damage,
643					       const BoxRec *box)
644{
645	if (box->y2 <= box->y1 || box->x2 <= box->x1)
646		return damage;
647
648	if (!damage) {
649		damage = _sna_damage_create();
650		if (damage == NULL)
651			return NULL;
652	} else switch (damage->mode) {
653	case DAMAGE_ALL:
654		return damage;
655	case DAMAGE_SUBTRACT:
656		__sna_damage_reduce(damage);
657	case DAMAGE_ADD:
658		break;
659	}
660
661	if (region_is_singular_or_empty(&damage->region) ||
662	    box_contains_region(box, &damage->region)) {
663		_pixman_region_union_box(&damage->region, box);
664		assert(damage->region.extents.x2 > damage->region.extents.x1);
665		assert(damage->region.extents.y2 > damage->region.extents.y1);
666		damage_union(damage, box);
667		return damage;
668	}
669
670	if (pixman_region_contains_rectangle(&damage->region,
671					     (BoxPtr)box) == PIXMAN_REGION_IN)
672		return damage;
673
674	damage_union(damage, box);
675	return _sna_damage_create_elt(damage, box, 1);
676}
677
678inline static struct sna_damage *__sna_damage_add(struct sna_damage *damage,
679						  RegionPtr region)
680{
681	assert(RegionNotEmpty(region));
682
683	if (!damage) {
684		damage = _sna_damage_create();
685		if (damage == NULL)
686			return NULL;
687	} else switch (damage->mode) {
688	case DAMAGE_ALL:
689		return damage;
690	case DAMAGE_SUBTRACT:
691		__sna_damage_reduce(damage);
692	case DAMAGE_ADD:
693		break;
694	}
695
696	if (region_is_singular(region))
697		return __sna_damage_add_box(damage, &region->extents);
698
699	if (region_is_singular_or_empty(&damage->region)) {
700		pixman_region_union(&damage->region, &damage->region, region);
701		assert(damage->region.extents.x2 > damage->region.extents.x1);
702		assert(damage->region.extents.y2 > damage->region.extents.y1);
703		damage_union(damage, &region->extents);
704		return damage;
705	}
706
707	if (pixman_region_contains_rectangle(&damage->region,
708					     &region->extents) == PIXMAN_REGION_IN)
709		return damage;
710
711	damage_union(damage, &region->extents);
712	return _sna_damage_create_elt(damage,
713				      region_rects(region),
714				      region_num_rects(region));
715}
716
717#if HAS_DEBUG_FULL
718fastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage,
719					    RegionPtr region)
720{
721	char region_buf[120];
722	char damage_buf[1000];
723
724	DBG(("%s(%s + %s)\n", __FUNCTION__,
725	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
726	     _debug_describe_region(region_buf, sizeof(region_buf), region)));
727
728	damage = __sna_damage_add(damage, region);
729
730	DBG(("  = %s\n",
731	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
732	assert(region_num_rects(&damage->region));
733	assert(damage->region.extents.x2 > damage->region.extents.x1);
734	assert(damage->region.extents.y2 > damage->region.extents.y1);
735
736	return damage;
737}
738#else
739fastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage,
740					    RegionPtr region)
741{
742	return __sna_damage_add(damage, region);
743}
744#endif
745
746inline static struct sna_damage *
747__sna_damage_add_boxes(struct sna_damage *damage,
748		       const BoxRec *box, int n,
749		       int16_t dx, int16_t dy)
750{
751	BoxRec extents;
752	int i;
753
754	assert(n);
755
756	if (!damage) {
757		damage = _sna_damage_create();
758		if (damage == NULL)
759			return NULL;
760	} else switch (damage->mode) {
761	case DAMAGE_ALL:
762		return damage;
763	case DAMAGE_SUBTRACT:
764		__sna_damage_reduce(damage);
765	case DAMAGE_ADD:
766		break;
767	}
768
769	assert(box[0].x2 > box[0].x1 && box[0].y2 > box[0].y1);
770	extents = box[0];
771	for (i = 1; i < n; i++) {
772		assert(box[i].x2 > box[i].x1 && box[i].y2 > box[i].y1);
773		if (extents.x1 > box[i].x1)
774			extents.x1 = box[i].x1;
775		if (extents.x2 < box[i].x2)
776			extents.x2 = box[i].x2;
777		if (extents.y1 > box[i].y1)
778			extents.y1 = box[i].y1;
779		if (extents.y2 < box[i].y2)
780			extents.y2 = box[i].y2;
781	}
782
783	assert(extents.y2 > extents.y1 && extents.x2 > extents.x1);
784
785	extents.x1 += dx;
786	extents.x2 += dx;
787	extents.y1 += dy;
788	extents.y2 += dy;
789
790	if (n == 1)
791		return __sna_damage_add_box(damage, &extents);
792
793	if (pixman_region_contains_rectangle(&damage->region,
794					     &extents) == PIXMAN_REGION_IN)
795		return damage;
796
797	damage_union(damage, &extents);
798	return _sna_damage_create_elt_from_boxes(damage, box, n, dx, dy);
799}
800
801#if HAS_DEBUG_FULL
802struct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
803					 const BoxRec *b, int n,
804					 int16_t dx, int16_t dy)
805{
806	char damage_buf[1000];
807
808	DBG(("%s(%s + [(%d, %d), (%d, %d) ... x %d])\n", __FUNCTION__,
809	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
810	     b->x1, b->y1, b->x2, b->y2, n));
811
812	damage = __sna_damage_add_boxes(damage, b, n, dx, dy);
813
814	DBG(("  = %s\n",
815	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
816	if (region_num_rects(&damage->region)) {
817		assert(damage->region.extents.x2 > damage->region.extents.x1);
818		assert(damage->region.extents.y2 > damage->region.extents.y1);
819	}
820
821	return damage;
822}
823#else
824struct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage,
825					 const BoxRec *b, int n,
826					 int16_t dx, int16_t dy)
827{
828	return __sna_damage_add_boxes(damage, b, n, dx, dy);
829}
830#endif
831
832inline static struct sna_damage *
833__sna_damage_add_rectangles(struct sna_damage *damage,
834			    const xRectangle *r, int n,
835			    int16_t dx, int16_t dy)
836{
837	BoxRec extents;
838	int i;
839
840	assert(n);
841
842	assert(r[0].width && r[0].height);
843	extents.x1 = r[0].x;
844	extents.x2 = r[0].x + r[0].width;
845	extents.y1 = r[0].y;
846	extents.y2 = r[0].y + r[0].height;
847	for (i = 1; i < n; i++) {
848		assert(r[i].width && r[i].height);
849		if (extents.x1 > r[i].x)
850			extents.x1 = r[i].x;
851		if (extents.x2 < r[i].x + r[i].width)
852			extents.x2 = r[i].x + r[i].width;
853		if (extents.y1 > r[i].y)
854			extents.y1 = r[i].y;
855		if (extents.y2 < r[i].y + r[i].height)
856			extents.y2 = r[i].y + r[i].height;
857	}
858
859	assert(extents.y2 > extents.y1 && extents.x2 > extents.x1);
860
861	extents.x1 += dx;
862	extents.x2 += dx;
863	extents.y1 += dy;
864	extents.y2 += dy;
865
866	if (n == 1)
867		return __sna_damage_add_box(damage, &extents);
868
869	if (!damage) {
870		damage = _sna_damage_create();
871		if (damage == NULL)
872			return NULL;
873	} else switch (damage->mode) {
874	case DAMAGE_ALL:
875		return damage;
876	case DAMAGE_SUBTRACT:
877		__sna_damage_reduce(damage);
878	case DAMAGE_ADD:
879		break;
880	}
881
882	if (pixman_region_contains_rectangle(&damage->region,
883					     &extents) == PIXMAN_REGION_IN)
884		return damage;
885
886	damage_union(damage, &extents);
887	return _sna_damage_create_elt_from_rectangles(damage, r, n, dx, dy);
888}
889
890#if HAS_DEBUG_FULL
891struct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage,
892					      const xRectangle *r, int n,
893					      int16_t dx, int16_t dy)
894{
895	char damage_buf[1000];
896
897	DBG(("%s(%s + [(%d, %d)x(%d, %d) ... x %d])\n", __FUNCTION__,
898	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
899	     r->x, r->y, r->width, r->height, n));
900
901	damage = __sna_damage_add_rectangles(damage, r, n, dx, dy);
902
903	DBG(("  = %s\n",
904	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
905	if (region_num_rects(&damage->region)) {
906		assert(damage->region.extents.x2 > damage->region.extents.x1);
907		assert(damage->region.extents.y2 > damage->region.extents.y1);
908	}
909
910	return damage;
911}
912#else
913struct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage,
914					      const xRectangle *r, int n,
915					      int16_t dx, int16_t dy)
916{
917	return __sna_damage_add_rectangles(damage, r, n, dx, dy);
918}
919#endif
920
921/* XXX pass in extents? */
922inline static struct sna_damage *
923__sna_damage_add_points(struct sna_damage *damage,
924			const DDXPointRec *p, int n,
925			int16_t dx, int16_t dy)
926{
927	BoxRec extents;
928	int i;
929
930	assert(n);
931
932	extents.x2 = extents.x1 = p[0].x;
933	extents.y2 = extents.y1 = p[0].y;
934	for (i = 1; i < n; i++) {
935		if (extents.x1 > p[i].x)
936			extents.x1 = p[i].x;
937		else if (extents.x2 < p[i].x)
938			extents.x2 = p[i].x;
939		if (extents.y1 > p[i].y)
940			extents.y1 = p[i].y;
941		else if (extents.y2 < p[i].y)
942			extents.y2 = p[i].y;
943	}
944
945	extents.x1 += dx;
946	extents.x2 += dx + 1;
947	extents.y1 += dy;
948	extents.y2 += dy + 1;
949
950	if (n == 1)
951		return __sna_damage_add_box(damage, &extents);
952
953	if (!damage) {
954		damage = _sna_damage_create();
955		if (damage == NULL)
956			return NULL;
957	} else switch (damage->mode) {
958	case DAMAGE_ALL:
959		return damage;
960	case DAMAGE_SUBTRACT:
961		__sna_damage_reduce(damage);
962	case DAMAGE_ADD:
963		break;
964	}
965
966	if (pixman_region_contains_rectangle(&damage->region,
967					     &extents) == PIXMAN_REGION_IN)
968		return damage;
969
970	damage_union(damage, &extents);
971	return _sna_damage_create_elt_from_points(damage, p, n, dx, dy);
972}
973
974#if HAS_DEBUG_FULL
975struct sna_damage *_sna_damage_add_points(struct sna_damage *damage,
976					  const DDXPointRec *p, int n,
977					  int16_t dx, int16_t dy)
978{
979	char damage_buf[1000];
980
981	DBG(("%s(%s + [(%d, %d) ... x %d])\n", __FUNCTION__,
982	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
983	     p->x, p->y, n));
984
985	damage = __sna_damage_add_points(damage, p, n, dx, dy);
986
987	DBG(("  = %s\n",
988	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
989	if (region_num_rects(&damage->region)) {
990		assert(damage->region.extents.x2 > damage->region.extents.x1);
991		assert(damage->region.extents.y2 > damage->region.extents.y1);
992	}
993
994	return damage;
995}
996#else
997struct sna_damage *_sna_damage_add_points(struct sna_damage *damage,
998					  const DDXPointRec *p, int n,
999					  int16_t dx, int16_t dy)
1000{
1001	return __sna_damage_add_points(damage, p, n, dx, dy);
1002}
1003#endif
1004
1005#if HAS_DEBUG_FULL
1006fastcall struct sna_damage *_sna_damage_add_box(struct sna_damage *damage,
1007						const BoxRec *box)
1008{
1009	char damage_buf[1000];
1010
1011	DBG(("%s(%s + [(%d, %d), (%d, %d)])\n", __FUNCTION__,
1012	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
1013	     box->x1, box->y1, box->x2, box->y2));
1014
1015	damage = __sna_damage_add_box(damage, box);
1016
1017	DBG(("  = %s\n",
1018	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
1019	assert(region_num_rects(&damage->region));
1020	assert(damage->region.extents.x2 > damage->region.extents.x1);
1021	assert(damage->region.extents.y2 > damage->region.extents.y1);
1022
1023	return damage;
1024}
1025#else
1026fastcall struct sna_damage *_sna_damage_add_box(struct sna_damage *damage,
1027						const BoxRec *box)
1028{
1029	return __sna_damage_add_box(damage, box);
1030}
1031#endif
1032
1033struct sna_damage *__sna_damage_all(struct sna_damage *damage,
1034				    int width, int height)
1035{
1036	DBG(("%s(%d, %d)\n", __FUNCTION__, width, height));
1037
1038	if (damage) {
1039		pixman_region_fini(&damage->region);
1040		free_list(&damage->embedded_box.list);
1041		reset_embedded_box(damage);
1042	} else {
1043		damage = _sna_damage_create();
1044		if (damage == NULL)
1045			return NULL;
1046	}
1047
1048	pixman_region_init_rect(&damage->region, 0, 0, width, height);
1049	damage->extents = damage->region.extents;
1050	damage->mode = DAMAGE_ALL;
1051
1052	return damage;
1053}
1054
1055struct sna_damage *_sna_damage_is_all(struct sna_damage *damage,
1056				      int width, int height)
1057{
1058	DBG(("%s(%d, %d)%s?\n", __FUNCTION__, width, height,
1059	     damage->dirty ? "*" : ""));
1060	DBG(("%s: (%d, %d), (%d, %d)\n", __FUNCTION__,
1061	     damage->extents.x1, damage->extents.y1,
1062	     damage->extents.x2, damage->extents.y2));
1063
1064	assert(damage->mode == DAMAGE_ADD);
1065	assert(damage->extents.x1 == 0 &&
1066	       damage->extents.y1 == 0 &&
1067	       damage->extents.x2 == width &&
1068	       damage->extents.y2 == height);
1069
1070	if (damage->dirty) {
1071		__sna_damage_reduce(damage);
1072		assert(RegionNotEmpty(&damage->region));
1073	}
1074
1075	if (damage->region.data) {
1076		DBG(("%s: no, not singular\n", __FUNCTION__));
1077		return damage;
1078	}
1079
1080	assert(damage->extents.x1 == 0 &&
1081	       damage->extents.y1 == 0 &&
1082	       damage->extents.x2 == width &&
1083	       damage->extents.y2 == height);
1084
1085	return __sna_damage_all(damage, width, height);
1086}
1087
1088static bool box_contains(const BoxRec *a, const BoxRec *b)
1089{
1090	if (b->x1 < a->x1 || b->x2 > a->x2)
1091		return false;
1092
1093	if (b->y1 < a->y1 || b->y2 > a->y2)
1094		return false;
1095
1096	return true;
1097}
1098
1099static struct sna_damage *__sna_damage_subtract(struct sna_damage *damage,
1100						RegionPtr region)
1101{
1102	if (damage == NULL)
1103		return NULL;
1104
1105	if (RegionNil(&damage->region)) {
1106no_damage:
1107		__sna_damage_destroy(damage);
1108		return NULL;
1109	}
1110
1111	assert(RegionNotEmpty(region));
1112
1113	if (!sna_damage_overlaps_box(damage, &region->extents))
1114		return damage;
1115
1116	if (region_is_singular(region) &&
1117	    box_contains(&region->extents, &damage->extents))
1118		goto no_damage;
1119
1120	if (damage->mode == DAMAGE_ALL) {
1121		pixman_region_subtract(&damage->region,
1122				       &damage->region,
1123				       region);
1124		if (damage->region.extents.x2 <= damage->region.extents.x1 ||
1125		    damage->region.extents.y2 <= damage->region.extents.y1)
1126			goto no_damage;
1127
1128		damage->extents = damage->region.extents;
1129		damage->mode = DAMAGE_ADD;
1130		return damage;
1131	}
1132
1133	if (damage->mode != DAMAGE_SUBTRACT) {
1134		if (damage->dirty) {
1135			__sna_damage_reduce(damage);
1136			assert(RegionNotEmpty(&damage->region));
1137		}
1138
1139		if (pixman_region_equal(region, &damage->region))
1140			goto no_damage;
1141
1142		if (region_is_singular(&damage->region) &&
1143		    region_is_singular(region)) {
1144			pixman_region_subtract(&damage->region,
1145					       &damage->region,
1146					       region);
1147			if (damage->region.extents.x2 <= damage->region.extents.x1 ||
1148			    damage->region.extents.y2 <= damage->region.extents.y1)
1149				goto no_damage;
1150
1151			damage->extents = damage->region.extents;
1152			assert(pixman_region_not_empty(&damage->region));
1153			return damage;
1154		}
1155
1156		damage->mode = DAMAGE_SUBTRACT;
1157	}
1158
1159	return _sna_damage_create_elt(damage,
1160				      region_rects(region),
1161				      region_num_rects(region));
1162}
1163
1164#if HAS_DEBUG_FULL
1165fastcall struct sna_damage *_sna_damage_subtract(struct sna_damage *damage,
1166						 RegionPtr region)
1167{
1168	char damage_buf[1000];
1169	char region_buf[120];
1170
1171	DBG(("%s(%s - %s)...\n", __FUNCTION__,
1172	       _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
1173	       _debug_describe_region(region_buf, sizeof(region_buf), region)));
1174
1175	damage = __sna_damage_subtract(damage, region);
1176
1177	DBG(("  = %s\n",
1178	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
1179
1180	return damage;
1181}
1182#else
1183fastcall struct sna_damage *_sna_damage_subtract(struct sna_damage *damage,
1184						 RegionPtr region)
1185{
1186	return __sna_damage_subtract(damage, region);
1187}
1188#endif
1189
1190inline static struct sna_damage *__sna_damage_subtract_box(struct sna_damage *damage,
1191							   const BoxRec *box)
1192{
1193	assert(box->x2 > box->x1 && box->y2 > box->y1);
1194
1195	if (damage == NULL)
1196		return NULL;
1197
1198	if (RegionNil(&damage->region)) {
1199		__sna_damage_destroy(damage);
1200		return NULL;
1201	}
1202
1203	if (!sna_damage_overlaps_box(damage, box))
1204		return damage;
1205
1206	if (box_contains(box, &damage->extents)) {
1207		__sna_damage_destroy(damage);
1208		return NULL;
1209	}
1210
1211	if (damage->mode != DAMAGE_SUBTRACT) {
1212		if (damage->dirty) {
1213			__sna_damage_reduce(damage);
1214			assert(RegionNotEmpty(&damage->region));
1215		}
1216
1217		if (region_is_singular(&damage->region)) {
1218			pixman_region16_t region;
1219
1220			pixman_region_init_rects(&region, box, 1);
1221			pixman_region_subtract(&damage->region,
1222					       &damage->region,
1223					       &region);
1224			damage->extents = damage->region.extents;
1225			damage->mode = DAMAGE_ADD;
1226			return damage;
1227		}
1228
1229		damage->mode = DAMAGE_SUBTRACT;
1230	}
1231
1232	return _sna_damage_create_elt(damage, box, 1);
1233}
1234
1235#if HAS_DEBUG_FULL
1236fastcall struct sna_damage *_sna_damage_subtract_box(struct sna_damage *damage,
1237						     const BoxRec *box)
1238{
1239	char damage_buf[1000];
1240
1241	DBG(("%s(%s - (%d, %d), (%d, %d))...\n", __FUNCTION__,
1242	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
1243	     box->x1, box->y1, box->x2, box->y2));
1244
1245	damage = __sna_damage_subtract_box(damage, box);
1246
1247	DBG(("  = %s\n",
1248	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
1249
1250	return damage;
1251}
1252#else
1253fastcall struct sna_damage *_sna_damage_subtract_box(struct sna_damage *damage,
1254						     const BoxRec *box)
1255{
1256	return __sna_damage_subtract_box(damage, box);
1257}
1258#endif
1259
1260static struct sna_damage *__sna_damage_subtract_boxes(struct sna_damage *damage,
1261						      const BoxRec *box, int n,
1262						      int dx, int dy)
1263{
1264	BoxRec extents;
1265	int i;
1266
1267	if (damage == NULL)
1268		return NULL;
1269
1270	if (RegionNil(&damage->region)) {
1271		__sna_damage_destroy(damage);
1272		return NULL;
1273	}
1274
1275	assert(n);
1276
1277	assert(box[0].x2 > box[0].x1 && box[0].y2 > box[0].y1);
1278	extents = box[0];
1279	for (i = 1; i < n; i++) {
1280		assert(box[i].x2 > box[i].x1 && box[i].y2 > box[i].y1);
1281		if (extents.x1 > box[i].x1)
1282			extents.x1 = box[i].x1;
1283		if (extents.x2 < box[i].x2)
1284			extents.x2 = box[i].x2;
1285		if (extents.y1 > box[i].y1)
1286			extents.y1 = box[i].y1;
1287		if (extents.y2 < box[i].y2)
1288			extents.y2 = box[i].y2;
1289	}
1290
1291	assert(extents.y2 > extents.y1 && extents.x2 > extents.x1);
1292
1293	extents.x1 += dx;
1294	extents.x2 += dx;
1295	extents.y1 += dy;
1296	extents.y2 += dy;
1297
1298	if (!sna_damage_overlaps_box(damage, &extents))
1299		return damage;
1300
1301	if (n == 1)
1302		return __sna_damage_subtract_box(damage, &extents);
1303
1304	if (damage->mode != DAMAGE_SUBTRACT) {
1305		if (damage->dirty) {
1306			__sna_damage_reduce(damage);
1307			assert(RegionNotEmpty(&damage->region));
1308		}
1309
1310		damage->mode = DAMAGE_SUBTRACT;
1311	}
1312
1313	return _sna_damage_create_elt_from_boxes(damage, box, n, dx, dy);
1314}
1315
1316#if HAS_DEBUG_FULL
1317fastcall struct sna_damage *_sna_damage_subtract_boxes(struct sna_damage *damage,
1318						       const BoxRec *box, int n,
1319						       int dx, int dy)
1320{
1321	char damage_buf[1000];
1322
1323	DBG(("%s(%s - [(%d,%d), (%d,%d)...x%d])...\n", __FUNCTION__,
1324	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
1325	     box->x1 + dx, box->y1 + dy,
1326	     box->x2 + dx, box->y2 + dy,
1327	     n));
1328
1329	damage = __sna_damage_subtract_boxes(damage, box, n, dx, dy);
1330
1331	DBG(("  = %s\n",
1332	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
1333
1334	return damage;
1335}
1336#else
1337fastcall struct sna_damage *_sna_damage_subtract_boxes(struct sna_damage *damage,
1338						       const BoxRec *box, int n,
1339						       int dx, int dy)
1340{
1341	return __sna_damage_subtract_boxes(damage, box, n, dx, dy);
1342}
1343#endif
1344
1345static int __sna_damage_contains_box(struct sna_damage **_damage,
1346				     const BoxRec *box)
1347{
1348	struct sna_damage *damage = *_damage;
1349	const BoxRec *b;
1350	int n, count, ret;
1351
1352	if (damage->mode == DAMAGE_ALL)
1353		return PIXMAN_REGION_IN;
1354
1355	if (!sna_damage_overlaps_box(damage, box))
1356		return PIXMAN_REGION_OUT;
1357
1358	ret = pixman_region_contains_rectangle(&damage->region, (BoxPtr)box);
1359	if (!damage->dirty)
1360		return ret;
1361
1362	if (damage->mode == DAMAGE_ADD) {
1363		if (ret == PIXMAN_REGION_IN)
1364			return ret;
1365
1366		count = damage->embedded_box.size;
1367		if (list_is_empty(&damage->embedded_box.list))
1368			count -= damage->remain;
1369
1370		b = damage->embedded_box.box;
1371		for (n = 0; n < count; n++) {
1372			if (box_contains(&b[n], box))
1373				return PIXMAN_REGION_IN;
1374		}
1375	} else {
1376		if (ret == PIXMAN_REGION_OUT)
1377			return ret;
1378
1379		count = damage->embedded_box.size;
1380		if (list_is_empty(&damage->embedded_box.list))
1381			count -= damage->remain;
1382
1383		b = damage->embedded_box.box;
1384		for (n = 0; n < count; n++) {
1385			if (box_contains(&b[n], box))
1386				return PIXMAN_REGION_OUT;
1387		}
1388	}
1389
1390	__sna_damage_reduce(damage);
1391	if (!pixman_region_not_empty(&damage->region)) {
1392		__sna_damage_destroy(damage);
1393		*_damage = NULL;
1394		return PIXMAN_REGION_OUT;
1395	}
1396
1397	return pixman_region_contains_rectangle(&damage->region, (BoxPtr)box);
1398}
1399
1400#if HAS_DEBUG_FULL
1401int _sna_damage_contains_box(struct sna_damage **damage,
1402			     const BoxRec *box)
1403{
1404	char damage_buf[1000];
1405	int ret;
1406
1407	DBG(("%s(%s, [(%d, %d), (%d, %d)])\n", __FUNCTION__,
1408	     _debug_describe_damage(damage_buf, sizeof(damage_buf), *damage),
1409	     box->x1, box->y1, box->x2, box->y2));
1410
1411	ret = __sna_damage_contains_box(damage, box);
1412	DBG(("  = %d", ret));
1413	if (ret)
1414		DBG((" [(%d, %d), (%d, %d)...]",
1415		     box->x1, box->y1, box->x2, box->y2));
1416	DBG(("\n"));
1417
1418	return ret;
1419}
1420#else
1421int _sna_damage_contains_box(struct sna_damage **damage,
1422			     const BoxRec *box)
1423{
1424	return __sna_damage_contains_box(damage, box);
1425}
1426#endif
1427
1428static bool box_overlaps(const BoxRec *a, const BoxRec *b)
1429{
1430	return (a->x1 < b->x2 && a->x2 > b->x1 &&
1431		a->y1 < b->y2 && a->y2 > b->y1);
1432}
1433
1434bool _sna_damage_contains_box__no_reduce(const struct sna_damage *damage,
1435					 const BoxRec *box)
1436{
1437	int n, count;
1438	const BoxRec *b;
1439
1440	assert(damage && damage->mode != DAMAGE_ALL);
1441	if (!box_contains(&damage->extents, box))
1442		return false;
1443
1444	n = pixman_region_contains_rectangle((pixman_region16_t *)&damage->region, (BoxPtr)box);
1445	if (!damage->dirty)
1446		return n == PIXMAN_REGION_IN;
1447
1448	if (damage->mode == DAMAGE_ADD) {
1449		if (n == PIXMAN_REGION_IN)
1450			return true;
1451
1452		count = damage->embedded_box.size;
1453		if (list_is_empty(&damage->embedded_box.list))
1454			count -= damage->remain;
1455
1456		b = damage->embedded_box.box;
1457		for (n = 0; n < count; n++) {
1458			if (box_contains(&b[n], box))
1459				return true;
1460		}
1461
1462		return false;
1463	} else {
1464		if (n != PIXMAN_REGION_IN)
1465			return false;
1466
1467		if (!list_is_empty(&damage->embedded_box.list))
1468			return false;
1469
1470		count = damage->embedded_box.size - damage->remain;
1471		b = damage->embedded_box.box;
1472		for (n = 0; n < count; n++) {
1473			if (box_overlaps(&b[n], box))
1474				return false;
1475		}
1476
1477		return true;
1478	}
1479}
1480
1481static bool __sna_damage_intersect(struct sna_damage *damage,
1482				   RegionPtr region, RegionPtr result)
1483{
1484	assert(damage && damage->mode != DAMAGE_ALL);
1485	assert(RegionNotEmpty(region));
1486
1487	if (region->extents.x2 <= damage->extents.x1 ||
1488	    region->extents.x1 >= damage->extents.x2)
1489		return false;
1490
1491	if (region->extents.y2 <= damage->extents.y1 ||
1492	    region->extents.y1 >= damage->extents.y2)
1493		return false;
1494
1495	if (damage->dirty)
1496		__sna_damage_reduce(damage);
1497
1498	if (!pixman_region_not_empty(&damage->region))
1499		return false;
1500
1501	RegionNull(result);
1502	RegionIntersect(result, &damage->region, region);
1503
1504	return RegionNotEmpty(result);
1505}
1506
1507#if HAS_DEBUG_FULL
1508bool _sna_damage_intersect(struct sna_damage *damage,
1509			   RegionPtr region, RegionPtr result)
1510{
1511	char damage_buf[1000];
1512	char region_buf[120];
1513	bool ret;
1514
1515	DBG(("%s(%s, %s)...\n", __FUNCTION__,
1516	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage),
1517	     _debug_describe_region(region_buf, sizeof(region_buf), region)));
1518
1519	ret = __sna_damage_intersect(damage, region, result);
1520	if (ret)
1521		DBG(("  = %s\n",
1522		     _debug_describe_region(region_buf, sizeof(region_buf), result)));
1523	else
1524		DBG(("  = none\n"));
1525
1526	return ret;
1527}
1528#else
1529bool _sna_damage_intersect(struct sna_damage *damage,
1530			  RegionPtr region, RegionPtr result)
1531{
1532	return __sna_damage_intersect(damage, region, result);
1533}
1534#endif
1535
1536static int __sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes)
1537{
1538	assert(damage && damage->mode != DAMAGE_ALL);
1539
1540	if (damage->dirty)
1541		__sna_damage_reduce(damage);
1542
1543	assert(!damage->dirty);
1544	assert(damage->mode == DAMAGE_ADD);
1545
1546	*boxes = region_rects(&damage->region);
1547	return region_num_rects(&damage->region);
1548}
1549
1550struct sna_damage *_sna_damage_reduce(struct sna_damage *damage)
1551{
1552	DBG(("%s\n", __FUNCTION__));
1553
1554	__sna_damage_reduce(damage);
1555
1556	assert(!damage->dirty);
1557	assert(damage->mode == DAMAGE_ADD);
1558
1559	if (!pixman_region_not_empty(&damage->region)) {
1560		__sna_damage_destroy(damage);
1561		damage = NULL;
1562	}
1563
1564	return damage;
1565}
1566
1567#if HAS_DEBUG_FULL
1568int _sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes)
1569{
1570	char damage_buf[1000];
1571	int count;
1572
1573	DBG(("%s(%s)...\n", __FUNCTION__,
1574	     _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)));
1575
1576	count = __sna_damage_get_boxes(damage, boxes);
1577	DBG(("  = %d\n", count));
1578
1579	return count;
1580}
1581#else
1582int _sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes)
1583{
1584	return __sna_damage_get_boxes(damage, boxes);
1585}
1586#endif
1587
1588struct sna_damage *_sna_damage_combine(struct sna_damage *l,
1589				       struct sna_damage *r,
1590				       int dx, int dy)
1591{
1592	if (r->dirty)
1593		__sna_damage_reduce(r);
1594
1595	if (pixman_region_not_empty(&r->region)) {
1596		pixman_region_translate(&r->region, dx, dy);
1597		l = __sna_damage_add(l, &r->region);
1598	}
1599
1600	return l;
1601}
1602
1603void __sna_damage_destroy(struct sna_damage *damage)
1604{
1605	free_list(&damage->embedded_box.list);
1606
1607	pixman_region_fini(&damage->region);
1608	*(void **)damage = __freed_damage;
1609	__freed_damage = damage;
1610}
1611
1612#if TEST_DAMAGE && HAS_DEBUG_FULL
1613struct sna_damage_selftest{
1614	int width, height;
1615};
1616
1617static void st_damage_init_random_box(struct sna_damage_selftest *test,
1618				      BoxPtr box)
1619{
1620	int x, y, w, h;
1621
1622	if (test->width == 1) {
1623		x = 0, w = 1;
1624	} else {
1625		x = rand() % (test->width - 1);
1626		w = 1 + rand() % (test->width - x - 1);
1627	}
1628
1629	if (test->height == 1) {
1630		y = 0, h = 1;
1631	} else {
1632		y = rand() % (test->height - 1);
1633		h = 1 + rand() % (test->height - y - 1);
1634	}
1635
1636	box->x1 = x;
1637	box->x2 = x+w;
1638
1639	box->y1 = y;
1640	box->y2 = y+h;
1641}
1642
1643static void st_damage_init_random_region1(struct sna_damage_selftest *test,
1644					  pixman_region16_t *region)
1645{
1646	int x, y, w, h;
1647
1648	if (test->width == 1) {
1649		x = 0, w = 1;
1650	} else {
1651		x = rand() % (test->width - 1);
1652		w = 1 + rand() % (test->width - x - 1);
1653	}
1654
1655	if (test->height == 1) {
1656		y = 0, h = 1;
1657	} else {
1658		y = rand() % (test->height - 1);
1659		h = 1 + rand() % (test->height - y - 1);
1660	}
1661
1662	pixman_region_init_rect(region, x, y, w, h);
1663}
1664
1665static void st_damage_add(struct sna_damage_selftest *test,
1666			  struct sna_damage **damage,
1667			  pixman_region16_t *region)
1668{
1669	pixman_region16_t tmp;
1670
1671	st_damage_init_random_region1(test, &tmp);
1672
1673	if (!DAMAGE_IS_ALL(*damage))
1674		sna_damage_add(damage, &tmp);
1675	pixman_region_union(region, region, &tmp);
1676}
1677
1678static void st_damage_add_box(struct sna_damage_selftest *test,
1679			      struct sna_damage **damage,
1680			      pixman_region16_t *region)
1681{
1682	RegionRec r;
1683
1684	st_damage_init_random_box(test, &r.extents);
1685	r.data = NULL;
1686
1687	if (!DAMAGE_IS_ALL(*damage))
1688		sna_damage_add_box(damage, &r.extents);
1689	pixman_region_union(region, region, &r);
1690}
1691
1692static void st_damage_subtract(struct sna_damage_selftest *test,
1693			       struct sna_damage **damage,
1694			       pixman_region16_t *region)
1695{
1696	pixman_region16_t tmp;
1697
1698	st_damage_init_random_region1(test, &tmp);
1699
1700	sna_damage_subtract(damage, &tmp);
1701	pixman_region_subtract(region, region, &tmp);
1702}
1703
1704static void st_damage_subtract_box(struct sna_damage_selftest *test,
1705				   struct sna_damage **damage,
1706				   pixman_region16_t *region)
1707{
1708	RegionRec r;
1709
1710	st_damage_init_random_box(test, &r.extents);
1711	r.data = NULL;
1712
1713	sna_damage_subtract_box(damage, &r.extents);
1714	pixman_region_subtract(region, region, &r);
1715}
1716
1717static void st_damage_all(struct sna_damage_selftest *test,
1718			  struct sna_damage **damage,
1719			  pixman_region16_t *region)
1720{
1721	pixman_region16_t tmp;
1722
1723	pixman_region_init_rect(&tmp, 0, 0, test->width, test->height);
1724
1725	if (!DAMAGE_IS_ALL(*damage))
1726		sna_damage_all(damage, test->width, test->height);
1727	pixman_region_union(region, region, &tmp);
1728}
1729
1730static bool st_check_equal(struct sna_damage_selftest *test,
1731			   struct sna_damage **damage,
1732			   pixman_region16_t *region)
1733{
1734	int d_num, r_num;
1735	BoxPtr d_boxes, r_boxes;
1736
1737	d_num = *damage ? sna_damage_get_boxes(*damage, &d_boxes) : 0;
1738	r_boxes = pixman_region_rectangles(region, &r_num);
1739
1740	if (d_num != r_num) {
1741		ERR(("%s: damage and ref contain different number of rectangles\n",
1742		     __FUNCTION__));
1743		return false;
1744	}
1745
1746	if (memcmp(d_boxes, r_boxes, d_num*sizeof(BoxRec))) {
1747		ERR(("%s: damage and ref contain different rectangles\n",
1748		     __FUNCTION__));
1749		return false;
1750	}
1751
1752	return true;
1753}
1754
1755void sna_damage_selftest(void)
1756{
1757	void (*const op[])(struct sna_damage_selftest *test,
1758			   struct sna_damage **damage,
1759			   pixman_region16_t *region) = {
1760		st_damage_add,
1761		st_damage_add_box,
1762		st_damage_subtract,
1763		st_damage_subtract_box,
1764		st_damage_all
1765	};
1766	bool (*const check[])(struct sna_damage_selftest *test,
1767			      struct sna_damage **damage,
1768			      pixman_region16_t *region) = {
1769		st_check_equal,
1770		//st_check_contains,
1771	};
1772	char region_buf[120];
1773	char damage_buf[1000];
1774	int pass;
1775
1776	for (pass = 0; pass < 16384; pass++) {
1777		struct sna_damage_selftest test;
1778		struct sna_damage *damage;
1779		pixman_region16_t ref;
1780		int iter, i;
1781
1782		iter = 1 + rand() % (1 + (pass / 64));
1783		DBG(("%s: pass %d, iters=%d\n", __FUNCTION__, pass, iter));
1784
1785		test.width = 1 + rand() % 2048;
1786		test.height = 1 + rand() % 2048;
1787
1788		damage = _sna_damage_create();
1789		pixman_region_init(&ref);
1790
1791		for (i = 0; i < iter; i++) {
1792			op[rand() % ARRAY_SIZE(op)](&test, &damage, &ref);
1793		}
1794
1795		if (!check[rand() % ARRAY_SIZE(check)](&test, &damage, &ref)) {
1796			FatalError("%s: failed - region = %s, damage = %s\n", __FUNCTION__,
1797				   _debug_describe_region(region_buf, sizeof(region_buf), &ref),
1798				   _debug_describe_damage(damage_buf, sizeof(damage_buf), damage));
1799		}
1800
1801		pixman_region_fini(&ref);
1802		sna_damage_destroy(&damage);
1803	}
1804}
1805#endif
1806
1807void _sna_damage_debug_get_region(struct sna_damage *damage, RegionRec *r)
1808{
1809	int n, nboxes;
1810	BoxPtr boxes;
1811	struct sna_damage_box *iter;
1812
1813	RegionCopy(r, &damage->region);
1814	if (!damage->dirty)
1815		return;
1816
1817	nboxes = damage->embedded_box.size;
1818	list_for_each_entry(iter, &damage->embedded_box.list, list)
1819		nboxes += iter->size;
1820	nboxes -= damage->remain;
1821	if (nboxes == 0)
1822		return;
1823
1824	if (nboxes == 1) {
1825		pixman_region16_t tmp;
1826
1827		tmp.extents = damage->embedded_box.box[0];
1828		tmp.data = NULL;
1829
1830		if (damage->mode == DAMAGE_ADD)
1831			pixman_region_union(r, r, &tmp);
1832		else
1833			pixman_region_subtract(r, r, &tmp);
1834
1835		return;
1836	}
1837
1838	if (damage->mode == DAMAGE_ADD)
1839		nboxes += region_num_rects(r);
1840
1841	iter = last_box(damage);
1842	n = iter->size - damage->remain;
1843	boxes = malloc(sizeof(BoxRec)*nboxes);
1844	if (boxes == NULL)
1845		return;
1846
1847	if (list_is_empty(&damage->embedded_box.list)) {
1848		memcpy(boxes,
1849		       damage->embedded_box.box,
1850		       n*sizeof(BoxRec));
1851	} else {
1852		if (boxes != (BoxPtr)(iter+1))
1853			memcpy(boxes, iter+1, n*sizeof(BoxRec));
1854
1855		iter = list_entry(iter->list.prev,
1856				  struct sna_damage_box,
1857				  list);
1858		while (&iter->list != &damage->embedded_box.list) {
1859			memcpy(boxes + n, iter+1,
1860			       iter->size * sizeof(BoxRec));
1861			n += iter->size;
1862
1863			iter = list_entry(iter->list.prev,
1864					  struct sna_damage_box,
1865					  list);
1866		}
1867
1868		memcpy(boxes + n,
1869		       damage->embedded_box.box,
1870		       sizeof(damage->embedded_box.box));
1871		n += damage->embedded_box.size;
1872	}
1873
1874	if (damage->mode == DAMAGE_ADD) {
1875		memcpy(boxes + n,
1876		       region_rects(r),
1877		       region_num_rects(r)*sizeof(BoxRec));
1878		assert(n + region_num_rects(r) == nboxes);
1879		pixman_region_fini(r);
1880		pixman_region_init_rects(r, boxes, nboxes);
1881
1882		assert(pixman_region_not_empty(r));
1883		assert(damage->extents.x1 == r->extents.x1 &&
1884		       damage->extents.y1 == r->extents.y1 &&
1885		       damage->extents.x2 == r->extents.x2 &&
1886		       damage->extents.y2 == r->extents.y2);
1887	} else {
1888		pixman_region16_t tmp;
1889
1890		pixman_region_init_rects(&tmp, boxes, nboxes);
1891		pixman_region_subtract(r, r, &tmp);
1892		pixman_region_fini(&tmp);
1893
1894		assert(damage->extents.x1 <= r->extents.x1 &&
1895		       damage->extents.y1 <= r->extents.y1 &&
1896		       damage->extents.x2 >= r->extents.x2 &&
1897		       damage->extents.y2 >= r->extents.y2);
1898	}
1899
1900	free(boxes);
1901}
1902