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