1428d7b3dSmrg/************************************************************************** 2428d7b3dSmrg 3428d7b3dSmrgCopyright (c) 2011 Intel Corporation 4428d7b3dSmrg 5428d7b3dSmrgPermission is hereby granted, free of charge, to any person obtaining a 6428d7b3dSmrgcopy of this software and associated documentation files (the 7428d7b3dSmrg"Software"), to deal in the Software without restriction, including 8428d7b3dSmrgwithout limitation the rights to use, copy, modify, merge, publish, 9428d7b3dSmrgdistribute, sub license, and/or sell copies of the Software, and to 10428d7b3dSmrgpermit persons to whom the Software is furnished to do so, subject to 11428d7b3dSmrgthe following conditions: 12428d7b3dSmrg 13428d7b3dSmrgThe above copyright notice and this permission notice (including the 14428d7b3dSmrgnext paragraph) shall be included in all copies or substantial portions 15428d7b3dSmrgof the Software. 16428d7b3dSmrg 17428d7b3dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18428d7b3dSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19428d7b3dSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20428d7b3dSmrgIN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR 21428d7b3dSmrgANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22428d7b3dSmrgTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23428d7b3dSmrgSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24428d7b3dSmrg 25428d7b3dSmrg **************************************************************************/ 26428d7b3dSmrg 27428d7b3dSmrg#ifdef HAVE_CONFIG_H 28428d7b3dSmrg#include "config.h" 29428d7b3dSmrg#endif 30428d7b3dSmrg 31428d7b3dSmrg#include "sna.h" 32428d7b3dSmrg#include "sna_damage.h" 33428d7b3dSmrg 34428d7b3dSmrg/* 35428d7b3dSmrg * sna_damage is a batching layer on top of the regular pixman_region_t. 36428d7b3dSmrg * It is required as the ever-growing accumulation of invidual small 37428d7b3dSmrg * damage regions is an O(n^2) operation. Instead the accumulation of a 38428d7b3dSmrg * batch can be done in closer to O(n.lgn), and so prevents abysmal 39428d7b3dSmrg * performance in x11perf -copywinwin10. 40428d7b3dSmrg * 41428d7b3dSmrg * As with the core of SNA, damage is handled modally. That is, it 42428d7b3dSmrg * accumulates whilst rendering and then subtracts during migration of the 43428d7b3dSmrg * pixmap from GPU to CPU or vice versa. As such we can track the current 44428d7b3dSmrg * mode globally and when that mode switches perform the update of the region 45428d7b3dSmrg * in a single operation. 46428d7b3dSmrg * 47428d7b3dSmrg * Furthermore, we can track whether the whole pixmap is damaged and so 48428d7b3dSmrg * cheapy discard no-ops. 49428d7b3dSmrg */ 50428d7b3dSmrg 51428d7b3dSmrgstruct sna_damage_box { 52428d7b3dSmrg struct list list; 53428d7b3dSmrg int size; 54428d7b3dSmrg} __attribute__((packed)); 55428d7b3dSmrg 56428d7b3dSmrgstatic struct sna_damage *__freed_damage; 57428d7b3dSmrg 58428d7b3dSmrgstatic inline bool region_is_singular(const RegionRec *r) 59428d7b3dSmrg{ 60428d7b3dSmrg return r->data == NULL; 61428d7b3dSmrg} 62428d7b3dSmrg 63428d7b3dSmrgstatic inline bool region_is_singular_or_empty(const RegionRec *r) 64428d7b3dSmrg{ 65428d7b3dSmrg return r->data == NULL || r->data->numRects == 0; 66428d7b3dSmrg} 67428d7b3dSmrg 68428d7b3dSmrg#if HAS_DEBUG_FULL 69428d7b3dSmrgstatic const char *_debug_describe_region(char *buf, int max, 70428d7b3dSmrg const RegionRec *region) 71428d7b3dSmrg{ 72428d7b3dSmrg const BoxRec *box; 73428d7b3dSmrg int n, len; 74428d7b3dSmrg 75428d7b3dSmrg if (region == NULL) 76428d7b3dSmrg return "nil"; 77428d7b3dSmrg 78428d7b3dSmrg n = region_num_rects(region); 79428d7b3dSmrg if (n == 0) 80428d7b3dSmrg return "[0]"; 81428d7b3dSmrg 82428d7b3dSmrg if (n == 1) { 83428d7b3dSmrg sprintf(buf, 84428d7b3dSmrg "[(%d, %d), (%d, %d)]", 85428d7b3dSmrg region->extents.x1, region->extents.y1, 86428d7b3dSmrg region->extents.x2, region->extents.y2); 87428d7b3dSmrg return buf; 88428d7b3dSmrg } 89428d7b3dSmrg 90428d7b3dSmrg len = sprintf(buf, 91428d7b3dSmrg "[(%d, %d), (%d, %d) x %d: ", 92428d7b3dSmrg region->extents.x1, region->extents.y1, 93428d7b3dSmrg region->extents.x2, region->extents.y2, 94428d7b3dSmrg n) + 3; 95428d7b3dSmrg max -= 2; 96428d7b3dSmrg box = region_rects(region); 97428d7b3dSmrg while (n--) { 98428d7b3dSmrg char tmp[80]; 99428d7b3dSmrg int this; 100428d7b3dSmrg 101428d7b3dSmrg this = snprintf(tmp, sizeof(tmp), 102428d7b3dSmrg "((%d, %d), (%d, %d))%s", 103428d7b3dSmrg box->x1, box->y1, 104428d7b3dSmrg box->x2, box->y2, 105428d7b3dSmrg n ? ", ..." : ""); 106428d7b3dSmrg box++; 107428d7b3dSmrg 108428d7b3dSmrg if (this > max - len) 109428d7b3dSmrg break; 110428d7b3dSmrg 111428d7b3dSmrg len -= 3; 112428d7b3dSmrg memcpy(buf + len, tmp, this); 113428d7b3dSmrg len += this; 114428d7b3dSmrg } 115428d7b3dSmrg buf[len++] = ']'; 116428d7b3dSmrg buf[len] = '\0'; 117428d7b3dSmrg return buf; 118428d7b3dSmrg} 119428d7b3dSmrg 120428d7b3dSmrgstatic const char *_debug_describe_damage(char *buf, int max, 121428d7b3dSmrg const struct sna_damage *damage) 122428d7b3dSmrg{ 123428d7b3dSmrg char damage_str[500], region_str[500]; 124428d7b3dSmrg int str_max; 125428d7b3dSmrg 126428d7b3dSmrg if (damage == NULL) 127428d7b3dSmrg return "None"; 128428d7b3dSmrg 129428d7b3dSmrg str_max = max/2 - 6; 130428d7b3dSmrg if (str_max > sizeof(damage_str)) 131428d7b3dSmrg str_max = sizeof(damage_str); 132428d7b3dSmrg 133428d7b3dSmrg if (damage->mode == DAMAGE_ALL) { 134428d7b3dSmrg snprintf(buf, max, "[[(%d, %d), (%d, %d)]: all]", 135428d7b3dSmrg damage->extents.x1, damage->extents.y1, 136428d7b3dSmrg damage->extents.x2, damage->extents.y2); 137428d7b3dSmrg } else { 138428d7b3dSmrg if (damage->dirty) { 139428d7b3dSmrg sprintf(damage_str, "%c[ ...]", 140428d7b3dSmrg damage->mode == DAMAGE_SUBTRACT ? '-' : '+'); 141428d7b3dSmrg } else 142428d7b3dSmrg damage_str[0] = '\0'; 143428d7b3dSmrg snprintf(buf, max, "[[(%d, %d), (%d, %d)]: %s %s]%c", 144428d7b3dSmrg damage->extents.x1, damage->extents.y1, 145428d7b3dSmrg damage->extents.x2, damage->extents.y2, 146428d7b3dSmrg _debug_describe_region(region_str, str_max, 147428d7b3dSmrg &damage->region), 148428d7b3dSmrg damage_str, damage->dirty ? '*' : ' '); 149428d7b3dSmrg } 150428d7b3dSmrg 151428d7b3dSmrg return buf; 152428d7b3dSmrg} 153428d7b3dSmrg#endif 154428d7b3dSmrg 155428d7b3dSmrgstatic struct sna_damage_box * 156428d7b3dSmrglast_box(struct sna_damage *damage) 157428d7b3dSmrg{ 158428d7b3dSmrg return list_entry(damage->embedded_box.list.prev, 159428d7b3dSmrg struct sna_damage_box, 160428d7b3dSmrg list); 161428d7b3dSmrg} 162428d7b3dSmrg 163428d7b3dSmrgstatic void 164428d7b3dSmrgreset_embedded_box(struct sna_damage *damage) 165428d7b3dSmrg{ 166428d7b3dSmrg damage->dirty = false; 167428d7b3dSmrg damage->box = damage->embedded_box.box; 168428d7b3dSmrg damage->embedded_box.size = 169428d7b3dSmrg damage->remain = ARRAY_SIZE(damage->embedded_box.box); 170428d7b3dSmrg list_init(&damage->embedded_box.list); 171428d7b3dSmrg} 172428d7b3dSmrg 173428d7b3dSmrgstatic void reset_extents(struct sna_damage *damage) 174428d7b3dSmrg{ 175428d7b3dSmrg damage->extents.x1 = damage->extents.y1 = MAXSHORT; 176428d7b3dSmrg damage->extents.x2 = damage->extents.y2 = MINSHORT; 177428d7b3dSmrg} 178428d7b3dSmrg 179428d7b3dSmrgstatic struct sna_damage *_sna_damage_create(void) 180428d7b3dSmrg{ 181428d7b3dSmrg struct sna_damage *damage; 182428d7b3dSmrg 183428d7b3dSmrg if (__freed_damage) { 184428d7b3dSmrg damage = __freed_damage; 185428d7b3dSmrg __freed_damage = *(void **)__freed_damage; 186428d7b3dSmrg } else { 187428d7b3dSmrg damage = malloc(sizeof(*damage)); 188428d7b3dSmrg if (damage == NULL) 189428d7b3dSmrg return NULL; 190428d7b3dSmrg } 191428d7b3dSmrg reset_embedded_box(damage); 192428d7b3dSmrg damage->mode = DAMAGE_ADD; 193428d7b3dSmrg pixman_region_init(&damage->region); 194428d7b3dSmrg reset_extents(damage); 195428d7b3dSmrg 196428d7b3dSmrg return damage; 197428d7b3dSmrg} 198428d7b3dSmrg 199428d7b3dSmrgstruct sna_damage *sna_damage_create(void) 200428d7b3dSmrg{ 201428d7b3dSmrg return _sna_damage_create(); 202428d7b3dSmrg} 203428d7b3dSmrg 204428d7b3dSmrgstatic void free_list(struct list *head) 205428d7b3dSmrg{ 206428d7b3dSmrg while (!list_is_empty(head)) { 207428d7b3dSmrg struct list *l = head->next; 208428d7b3dSmrg list_del(l); 209428d7b3dSmrg free(l); 210428d7b3dSmrg } 211428d7b3dSmrg} 212428d7b3dSmrg 213428d7b3dSmrgstatic void __sna_damage_reduce(struct sna_damage *damage) 214428d7b3dSmrg{ 215428d7b3dSmrg int n, nboxes; 216428d7b3dSmrg BoxPtr boxes, free_boxes = NULL; 217428d7b3dSmrg pixman_region16_t *region = &damage->region; 218428d7b3dSmrg struct sna_damage_box *iter; 219428d7b3dSmrg 220428d7b3dSmrg assert(damage->mode != DAMAGE_ALL); 221428d7b3dSmrg assert(damage->dirty); 222428d7b3dSmrg 223428d7b3dSmrg DBG((" reduce: before region.n=%d\n", region_num_rects(region))); 224428d7b3dSmrg 225428d7b3dSmrg nboxes = damage->embedded_box.size; 226428d7b3dSmrg list_for_each_entry(iter, &damage->embedded_box.list, list) 227428d7b3dSmrg nboxes += iter->size; 228428d7b3dSmrg DBG((" nboxes=%d, residual=%d\n", nboxes, damage->remain)); 229428d7b3dSmrg nboxes -= damage->remain; 230428d7b3dSmrg if (nboxes == 0) 231428d7b3dSmrg goto done; 232428d7b3dSmrg if (nboxes == 1) { 233428d7b3dSmrg pixman_region16_t tmp; 234428d7b3dSmrg 235428d7b3dSmrg tmp.extents = damage->embedded_box.box[0]; 236428d7b3dSmrg tmp.data = NULL; 237428d7b3dSmrg 238428d7b3dSmrg if (damage->mode == DAMAGE_ADD) 239428d7b3dSmrg pixman_region_union(region, region, &tmp); 240428d7b3dSmrg else 241428d7b3dSmrg pixman_region_subtract(region, region, &tmp); 242428d7b3dSmrg damage->extents = region->extents; 243428d7b3dSmrg 244428d7b3dSmrg goto done; 245428d7b3dSmrg } 246428d7b3dSmrg 247428d7b3dSmrg if (damage->mode == DAMAGE_ADD) 248428d7b3dSmrg nboxes += region_num_rects(region); 249428d7b3dSmrg 250428d7b3dSmrg iter = last_box(damage); 251428d7b3dSmrg n = iter->size - damage->remain; 252428d7b3dSmrg boxes = (BoxRec *)(iter+1); 253428d7b3dSmrg DBG((" last box count=%d/%d, need=%d\n", n, iter->size, nboxes)); 254428d7b3dSmrg if (nboxes > iter->size) { 255428d7b3dSmrg boxes = malloc(sizeof(BoxRec)*nboxes); 256428d7b3dSmrg if (boxes == NULL) 257428d7b3dSmrg goto done; 258428d7b3dSmrg 259428d7b3dSmrg free_boxes = boxes; 260428d7b3dSmrg } 261428d7b3dSmrg 262428d7b3dSmrg if (boxes != damage->embedded_box.box) { 263428d7b3dSmrg if (list_is_empty(&damage->embedded_box.list)) { 264428d7b3dSmrg DBG((" copying embedded boxes\n")); 265428d7b3dSmrg memcpy(boxes, 266428d7b3dSmrg damage->embedded_box.box, 267428d7b3dSmrg n*sizeof(BoxRec)); 268428d7b3dSmrg } else { 269428d7b3dSmrg if (boxes != (BoxPtr)(iter+1)) { 270428d7b3dSmrg DBG((" copying %d boxes from last\n", n)); 271428d7b3dSmrg memcpy(boxes, iter+1, n*sizeof(BoxRec)); 272428d7b3dSmrg } 273428d7b3dSmrg 274428d7b3dSmrg iter = list_entry(iter->list.prev, 275428d7b3dSmrg struct sna_damage_box, 276428d7b3dSmrg list); 277428d7b3dSmrg while (&iter->list != &damage->embedded_box.list) { 278428d7b3dSmrg DBG((" copy %d boxes from %d\n", 279428d7b3dSmrg iter->size, n)); 280428d7b3dSmrg memcpy(boxes + n, iter+1, 281428d7b3dSmrg iter->size * sizeof(BoxRec)); 282428d7b3dSmrg n += iter->size; 283428d7b3dSmrg 284428d7b3dSmrg iter = list_entry(iter->list.prev, 285428d7b3dSmrg struct sna_damage_box, 286428d7b3dSmrg list); 287428d7b3dSmrg } 288428d7b3dSmrg 289428d7b3dSmrg DBG((" copying embedded boxes to %d\n", n)); 290428d7b3dSmrg memcpy(boxes + n, 291428d7b3dSmrg damage->embedded_box.box, 292428d7b3dSmrg sizeof(damage->embedded_box.box)); 293428d7b3dSmrg n += damage->embedded_box.size; 294428d7b3dSmrg } 295428d7b3dSmrg } 296428d7b3dSmrg 297428d7b3dSmrg if (damage->mode == DAMAGE_ADD) { 298428d7b3dSmrg memcpy(boxes + n, 299428d7b3dSmrg region_rects(region), 300428d7b3dSmrg region_num_rects(region)*sizeof(BoxRec)); 301428d7b3dSmrg assert(n + region_num_rects(region) == nboxes); 302428d7b3dSmrg pixman_region_fini(region); 303428d7b3dSmrg pixman_region_init_rects(region, boxes, nboxes); 304428d7b3dSmrg 305428d7b3dSmrg assert(pixman_region_not_empty(region)); 306428d7b3dSmrg assert(damage->extents.x1 == region->extents.x1 && 307428d7b3dSmrg damage->extents.y1 == region->extents.y1 && 308428d7b3dSmrg damage->extents.x2 == region->extents.x2 && 309428d7b3dSmrg damage->extents.y2 == region->extents.y2); 310428d7b3dSmrg } else { 311428d7b3dSmrg pixman_region16_t tmp; 312428d7b3dSmrg 313428d7b3dSmrg assert(n == nboxes); 314428d7b3dSmrg pixman_region_init_rects(&tmp, boxes, nboxes); 315428d7b3dSmrg pixman_region_subtract(region, region, &tmp); 316428d7b3dSmrg pixman_region_fini(&tmp); 317428d7b3dSmrg 318428d7b3dSmrg assert(damage->extents.x1 <= region->extents.x1 && 319428d7b3dSmrg damage->extents.y1 <= region->extents.y1 && 320428d7b3dSmrg damage->extents.x2 >= region->extents.x2 && 321428d7b3dSmrg damage->extents.y2 >= region->extents.y2); 322428d7b3dSmrg if (pixman_region_not_empty(region)) 323428d7b3dSmrg damage->extents = region->extents; 324428d7b3dSmrg else 325428d7b3dSmrg reset_extents(damage); 326428d7b3dSmrg } 327428d7b3dSmrg 328428d7b3dSmrg free(free_boxes); 329428d7b3dSmrg 330428d7b3dSmrgdone: 331428d7b3dSmrg damage->mode = DAMAGE_ADD; 332428d7b3dSmrg free_list(&damage->embedded_box.list); 333428d7b3dSmrg reset_embedded_box(damage); 334428d7b3dSmrg 335428d7b3dSmrg DBG((" reduce: after region.n=%d\n", region_num_rects(region))); 336428d7b3dSmrg} 337428d7b3dSmrg 338428d7b3dSmrgstatic bool _sna_damage_create_boxes(struct sna_damage *damage, 339428d7b3dSmrg int count) 340428d7b3dSmrg{ 341428d7b3dSmrg struct sna_damage_box *box; 342428d7b3dSmrg int n; 343428d7b3dSmrg 344428d7b3dSmrg box = last_box(damage); 345428d7b3dSmrg n = 4*box->size; 346428d7b3dSmrg if (n < count) 347428d7b3dSmrg n = ALIGN(count, 64); 348428d7b3dSmrg 349428d7b3dSmrg DBG((" %s(%d->%d): new\n", __FUNCTION__, count, n)); 350428d7b3dSmrg 351428d7b3dSmrg if (n >= (INT_MAX - sizeof(*box)) / sizeof(BoxRec)) 352428d7b3dSmrg return false; 353428d7b3dSmrg 354428d7b3dSmrg box = malloc(sizeof(*box) + sizeof(BoxRec)*n); 355428d7b3dSmrg if (box == NULL) 356428d7b3dSmrg return false; 357428d7b3dSmrg 358428d7b3dSmrg list_add_tail(&box->list, &damage->embedded_box.list); 359428d7b3dSmrg 360428d7b3dSmrg box->size = damage->remain = n; 361428d7b3dSmrg damage->box = (BoxRec *)(box + 1); 362428d7b3dSmrg return true; 363428d7b3dSmrg} 364428d7b3dSmrg 365428d7b3dSmrgstatic struct sna_damage * 366428d7b3dSmrg_sna_damage_create_elt(struct sna_damage *damage, 367428d7b3dSmrg const BoxRec *boxes, int count) 368428d7b3dSmrg{ 369428d7b3dSmrg int n; 370428d7b3dSmrg 371428d7b3dSmrg DBG((" %s: prev=(remain %d), count=%d\n", 372428d7b3dSmrg __FUNCTION__, damage->remain, count)); 373428d7b3dSmrg assert(count); 374428d7b3dSmrg 375428d7b3dSmrgrestart: 376428d7b3dSmrg n = count; 377428d7b3dSmrg if (n > damage->remain) 378428d7b3dSmrg n = damage->remain; 379428d7b3dSmrg if (n) { 380428d7b3dSmrg memcpy(damage->box, boxes, n * sizeof(BoxRec)); 381428d7b3dSmrg damage->box += n; 382428d7b3dSmrg damage->remain -= n; 383428d7b3dSmrg damage->dirty = true; 384428d7b3dSmrg 385428d7b3dSmrg count -= n; 386428d7b3dSmrg boxes += n; 387428d7b3dSmrg if (count == 0) 388428d7b3dSmrg return damage; 389428d7b3dSmrg } 390428d7b3dSmrg 391428d7b3dSmrg DBG((" %s(): new elt\n", __FUNCTION__)); 392428d7b3dSmrg assert(damage->remain == 0); 393428d7b3dSmrg assert(damage->box - (BoxRec *)(last_box(damage)+1) == last_box(damage)->size); 394428d7b3dSmrg 395428d7b3dSmrg if (!_sna_damage_create_boxes(damage, count)) { 396428d7b3dSmrg unsigned mode; 397428d7b3dSmrg 398428d7b3dSmrg if (!damage->dirty) 399428d7b3dSmrg return damage; 400428d7b3dSmrg 401428d7b3dSmrg mode = damage->mode; 402428d7b3dSmrg __sna_damage_reduce(damage); 403428d7b3dSmrg damage->mode = mode; 404428d7b3dSmrg 405428d7b3dSmrg goto restart; 406428d7b3dSmrg } 407428d7b3dSmrg 408428d7b3dSmrg memcpy(damage->box, boxes, count * sizeof(BoxRec)); 409428d7b3dSmrg damage->box += count; 410428d7b3dSmrg damage->remain -= count; 411428d7b3dSmrg damage->dirty = true; 412428d7b3dSmrg assert(damage->remain >= 0); 413428d7b3dSmrg 414428d7b3dSmrg return damage; 415428d7b3dSmrg} 416428d7b3dSmrg 417428d7b3dSmrgstatic struct sna_damage * 418428d7b3dSmrg_sna_damage_create_elt_from_boxes(struct sna_damage *damage, 419428d7b3dSmrg const BoxRec *boxes, int count, 420428d7b3dSmrg int16_t dx, int16_t dy) 421428d7b3dSmrg{ 422428d7b3dSmrg int i, n; 423428d7b3dSmrg 424428d7b3dSmrg DBG((" %s: prev=(remain %d)\n", __FUNCTION__, damage->remain)); 425428d7b3dSmrg assert(count); 426428d7b3dSmrg 427428d7b3dSmrgrestart: 428428d7b3dSmrg n = count; 429428d7b3dSmrg if (n > damage->remain) 430428d7b3dSmrg n = damage->remain; 431428d7b3dSmrg if (n) { 432428d7b3dSmrg for (i = 0; i < n; i++) { 433428d7b3dSmrg damage->box[i].x1 = boxes[i].x1 + dx; 434428d7b3dSmrg damage->box[i].x2 = boxes[i].x2 + dx; 435428d7b3dSmrg damage->box[i].y1 = boxes[i].y1 + dy; 436428d7b3dSmrg damage->box[i].y2 = boxes[i].y2 + dy; 437428d7b3dSmrg } 438428d7b3dSmrg damage->box += n; 439428d7b3dSmrg damage->remain -= n; 440428d7b3dSmrg damage->dirty = true; 441428d7b3dSmrg 442428d7b3dSmrg count -= n; 443428d7b3dSmrg boxes += n; 444428d7b3dSmrg if (count == 0) 445428d7b3dSmrg return damage; 446428d7b3dSmrg } 447428d7b3dSmrg 448428d7b3dSmrg DBG((" %s(): new elt\n", __FUNCTION__)); 449428d7b3dSmrg assert(damage->remain == 0); 450428d7b3dSmrg assert(damage->box - (BoxRec *)(last_box(damage)+1) == last_box(damage)->size); 451428d7b3dSmrg 452428d7b3dSmrg if (!_sna_damage_create_boxes(damage, count)) { 453428d7b3dSmrg unsigned mode; 454428d7b3dSmrg 455428d7b3dSmrg if (!damage->dirty) 456428d7b3dSmrg return damage; 457428d7b3dSmrg 458428d7b3dSmrg mode = damage->mode; 459428d7b3dSmrg __sna_damage_reduce(damage); 460428d7b3dSmrg damage->mode = mode; 461428d7b3dSmrg 462428d7b3dSmrg goto restart; 463428d7b3dSmrg } 464428d7b3dSmrg 465428d7b3dSmrg for (i = 0; i < count; i++) { 466428d7b3dSmrg damage->box[i].x1 = boxes[i].x1 + dx; 467428d7b3dSmrg damage->box[i].x2 = boxes[i].x2 + dx; 468428d7b3dSmrg damage->box[i].y1 = boxes[i].y1 + dy; 469428d7b3dSmrg damage->box[i].y2 = boxes[i].y2 + dy; 470428d7b3dSmrg } 471428d7b3dSmrg damage->box += count; 472428d7b3dSmrg damage->remain -= count; 473428d7b3dSmrg damage->dirty = true; 474428d7b3dSmrg assert(damage->remain >= 0); 475428d7b3dSmrg 476428d7b3dSmrg return damage; 477428d7b3dSmrg} 478428d7b3dSmrg 479428d7b3dSmrgstatic struct sna_damage * 480428d7b3dSmrg_sna_damage_create_elt_from_rectangles(struct sna_damage *damage, 481428d7b3dSmrg const xRectangle *r, int count, 482428d7b3dSmrg int16_t dx, int16_t dy) 483428d7b3dSmrg{ 484428d7b3dSmrg int i, n; 485428d7b3dSmrg 486428d7b3dSmrg DBG((" %s: prev=(remain %d), count=%d\n", 487428d7b3dSmrg __FUNCTION__, damage->remain, count)); 488428d7b3dSmrg assert(count); 489428d7b3dSmrg 490428d7b3dSmrgrestart: 491428d7b3dSmrg n = count; 492428d7b3dSmrg if (n > damage->remain) 493428d7b3dSmrg n = damage->remain; 494428d7b3dSmrg if (n) { 495428d7b3dSmrg for (i = 0; i < n; i++) { 496428d7b3dSmrg damage->box[i].x1 = r[i].x + dx; 497428d7b3dSmrg damage->box[i].x2 = damage->box[i].x1 + r[i].width; 498428d7b3dSmrg damage->box[i].y1 = r[i].y + dy; 499428d7b3dSmrg damage->box[i].y2 = damage->box[i].y1 + r[i].height; 500428d7b3dSmrg } 501428d7b3dSmrg damage->box += n; 502428d7b3dSmrg damage->remain -= n; 503428d7b3dSmrg damage->dirty = true; 504428d7b3dSmrg 505428d7b3dSmrg count -= n; 506428d7b3dSmrg r += n; 507428d7b3dSmrg if (count == 0) 508428d7b3dSmrg return damage; 509428d7b3dSmrg } 510428d7b3dSmrg 511428d7b3dSmrg DBG((" %s(): new elt\n", __FUNCTION__)); 512428d7b3dSmrg assert(damage->remain == 0); 513428d7b3dSmrg assert(damage->box - (BoxRec *)(last_box(damage)+1) == last_box(damage)->size); 514428d7b3dSmrg 515428d7b3dSmrg if (!_sna_damage_create_boxes(damage, count)) { 516428d7b3dSmrg unsigned mode; 517428d7b3dSmrg 518428d7b3dSmrg if (!damage->dirty) 519428d7b3dSmrg return damage; 520428d7b3dSmrg 521428d7b3dSmrg mode = damage->mode; 522428d7b3dSmrg __sna_damage_reduce(damage); 523428d7b3dSmrg damage->mode = mode; 524428d7b3dSmrg 525428d7b3dSmrg goto restart; 526428d7b3dSmrg } 527428d7b3dSmrg 528428d7b3dSmrg for (i = 0; i < count; i++) { 529428d7b3dSmrg damage->box[i].x1 = r[i].x + dx; 530428d7b3dSmrg damage->box[i].x2 = damage->box[i].x1 + r[i].width; 531428d7b3dSmrg damage->box[i].y1 = r[i].y + dy; 532428d7b3dSmrg damage->box[i].y2 = damage->box[i].y1 + r[i].height; 533428d7b3dSmrg } 534428d7b3dSmrg damage->box += count; 535428d7b3dSmrg damage->remain -= count; 536428d7b3dSmrg damage->dirty = true; 537428d7b3dSmrg assert(damage->remain >= 0); 538428d7b3dSmrg 539428d7b3dSmrg return damage; 540428d7b3dSmrg} 541428d7b3dSmrg 542428d7b3dSmrgstatic struct sna_damage * 543428d7b3dSmrg_sna_damage_create_elt_from_points(struct sna_damage *damage, 544428d7b3dSmrg const DDXPointRec *p, int count, 545428d7b3dSmrg int16_t dx, int16_t dy) 546428d7b3dSmrg{ 547428d7b3dSmrg int i, n; 548428d7b3dSmrg 549428d7b3dSmrg DBG((" %s: prev=(remain %d), count=%d\n", 550428d7b3dSmrg __FUNCTION__, damage->remain, count)); 551428d7b3dSmrg assert(count); 552428d7b3dSmrg 553428d7b3dSmrgrestart: 554428d7b3dSmrg n = count; 555428d7b3dSmrg if (n > damage->remain) 556428d7b3dSmrg n = damage->remain; 557428d7b3dSmrg if (n) { 558428d7b3dSmrg for (i = 0; i < n; i++) { 559428d7b3dSmrg damage->box[i].x1 = p[i].x + dx; 560428d7b3dSmrg damage->box[i].x2 = damage->box[i].x1 + 1; 561428d7b3dSmrg damage->box[i].y1 = p[i].y + dy; 562428d7b3dSmrg damage->box[i].y2 = damage->box[i].y1 + 1; 563428d7b3dSmrg } 564428d7b3dSmrg damage->box += n; 565428d7b3dSmrg damage->remain -= n; 566428d7b3dSmrg damage->dirty = true; 567428d7b3dSmrg 568428d7b3dSmrg count -= n; 569428d7b3dSmrg p += n; 570428d7b3dSmrg if (count == 0) 571428d7b3dSmrg return damage; 572428d7b3dSmrg } 573428d7b3dSmrg 574428d7b3dSmrg DBG((" %s(): new elt\n", __FUNCTION__)); 575428d7b3dSmrg assert(damage->remain == 0); 576428d7b3dSmrg assert(damage->box - (BoxRec *)(last_box(damage)+1) == last_box(damage)->size); 577428d7b3dSmrg 578428d7b3dSmrg if (!_sna_damage_create_boxes(damage, count)) { 579428d7b3dSmrg unsigned mode; 580428d7b3dSmrg 581428d7b3dSmrg if (!damage->dirty) 582428d7b3dSmrg return damage; 583428d7b3dSmrg 584428d7b3dSmrg mode = damage->mode; 585428d7b3dSmrg __sna_damage_reduce(damage); 586428d7b3dSmrg damage->mode = mode; 587428d7b3dSmrg 588428d7b3dSmrg goto restart; 589428d7b3dSmrg } 590428d7b3dSmrg 591428d7b3dSmrg for (i = 0; i < count; i++) { 592428d7b3dSmrg damage->box[i].x1 = p[i].x + dx; 593428d7b3dSmrg damage->box[i].x2 = damage->box[i].x1 + 1; 594428d7b3dSmrg damage->box[i].y1 = p[i].y + dy; 595428d7b3dSmrg damage->box[i].y2 = damage->box[i].y1 + 1; 596428d7b3dSmrg } 597428d7b3dSmrg damage->box += count; 598428d7b3dSmrg damage->remain -= count; 599428d7b3dSmrg damage->dirty = true; 600428d7b3dSmrg assert(damage->remain >= 0); 601428d7b3dSmrg 602428d7b3dSmrg return damage; 603428d7b3dSmrg} 604428d7b3dSmrg 605428d7b3dSmrgstatic void damage_union(struct sna_damage *damage, const BoxRec *box) 606428d7b3dSmrg{ 607428d7b3dSmrg DBG(("%s: extending damage (%d, %d), (%d, %d) by (%d, %d), (%d, %d)\n", 608428d7b3dSmrg __FUNCTION__, 609428d7b3dSmrg damage->extents.x1, damage->extents.y1, 610428d7b3dSmrg damage->extents.x2, damage->extents.y2, 611428d7b3dSmrg box->x1, box->y1, box->x2, box->y2)); 612428d7b3dSmrg assert(box->x2 > box->x1 && box->y2 > box->y1); 613428d7b3dSmrg if (damage->extents.x2 < damage->extents.x1) { 614428d7b3dSmrg damage->extents = *box; 615428d7b3dSmrg } else { 616428d7b3dSmrg if (damage->extents.x1 > box->x1) 617428d7b3dSmrg damage->extents.x1 = box->x1; 618428d7b3dSmrg if (damage->extents.x2 < box->x2) 619428d7b3dSmrg damage->extents.x2 = box->x2; 620428d7b3dSmrg 621428d7b3dSmrg if (damage->extents.y1 > box->y1) 622428d7b3dSmrg damage->extents.y1 = box->y1; 623428d7b3dSmrg if (damage->extents.y2 < box->y2) 624428d7b3dSmrg damage->extents.y2 = box->y2; 625428d7b3dSmrg } 626428d7b3dSmrg assert(damage->extents.x2 > damage->extents.x1); 627428d7b3dSmrg assert(damage->extents.y2 > damage->extents.y1); 628428d7b3dSmrg} 629428d7b3dSmrg 630428d7b3dSmrgstatic void _pixman_region_union_box(RegionRec *region, const BoxRec *box) 631428d7b3dSmrg{ 632428d7b3dSmrg RegionRec u = { *box, NULL }; 633428d7b3dSmrg pixman_region_union(region, region, &u); 634428d7b3dSmrg} 635428d7b3dSmrg 636428d7b3dSmrgstatic bool box_contains_region(const BoxRec *b, const RegionRec *r) 637428d7b3dSmrg{ 638428d7b3dSmrg return (b->x1 <= r->extents.x1 && b->x2 >= r->extents.x2 && 639428d7b3dSmrg b->y1 <= r->extents.y1 && b->y2 >= r->extents.y2); 640428d7b3dSmrg} 641428d7b3dSmrg 642428d7b3dSmrgstatic struct sna_damage *__sna_damage_add_box(struct sna_damage *damage, 643428d7b3dSmrg const BoxRec *box) 644428d7b3dSmrg{ 645428d7b3dSmrg if (box->y2 <= box->y1 || box->x2 <= box->x1) 646428d7b3dSmrg return damage; 647428d7b3dSmrg 648428d7b3dSmrg if (!damage) { 649428d7b3dSmrg damage = _sna_damage_create(); 650428d7b3dSmrg if (damage == NULL) 651428d7b3dSmrg return NULL; 652428d7b3dSmrg } else switch (damage->mode) { 653428d7b3dSmrg case DAMAGE_ALL: 654428d7b3dSmrg return damage; 655428d7b3dSmrg case DAMAGE_SUBTRACT: 656428d7b3dSmrg __sna_damage_reduce(damage); 657428d7b3dSmrg case DAMAGE_ADD: 658428d7b3dSmrg break; 659428d7b3dSmrg } 660428d7b3dSmrg 661428d7b3dSmrg if (region_is_singular_or_empty(&damage->region) || 662428d7b3dSmrg box_contains_region(box, &damage->region)) { 663428d7b3dSmrg _pixman_region_union_box(&damage->region, box); 664428d7b3dSmrg assert(damage->region.extents.x2 > damage->region.extents.x1); 665428d7b3dSmrg assert(damage->region.extents.y2 > damage->region.extents.y1); 666428d7b3dSmrg damage_union(damage, box); 667428d7b3dSmrg return damage; 668428d7b3dSmrg } 669428d7b3dSmrg 670428d7b3dSmrg if (pixman_region_contains_rectangle(&damage->region, 671428d7b3dSmrg (BoxPtr)box) == PIXMAN_REGION_IN) 672428d7b3dSmrg return damage; 673428d7b3dSmrg 674428d7b3dSmrg damage_union(damage, box); 675428d7b3dSmrg return _sna_damage_create_elt(damage, box, 1); 676428d7b3dSmrg} 677428d7b3dSmrg 678428d7b3dSmrginline static struct sna_damage *__sna_damage_add(struct sna_damage *damage, 679428d7b3dSmrg RegionPtr region) 680428d7b3dSmrg{ 681428d7b3dSmrg assert(RegionNotEmpty(region)); 682428d7b3dSmrg 683428d7b3dSmrg if (!damage) { 684428d7b3dSmrg damage = _sna_damage_create(); 685428d7b3dSmrg if (damage == NULL) 686428d7b3dSmrg return NULL; 687428d7b3dSmrg } else switch (damage->mode) { 688428d7b3dSmrg case DAMAGE_ALL: 689428d7b3dSmrg return damage; 690428d7b3dSmrg case DAMAGE_SUBTRACT: 691428d7b3dSmrg __sna_damage_reduce(damage); 692428d7b3dSmrg case DAMAGE_ADD: 693428d7b3dSmrg break; 694428d7b3dSmrg } 695428d7b3dSmrg 696428d7b3dSmrg if (region_is_singular(region)) 697428d7b3dSmrg return __sna_damage_add_box(damage, ®ion->extents); 698428d7b3dSmrg 699428d7b3dSmrg if (region_is_singular_or_empty(&damage->region)) { 700428d7b3dSmrg pixman_region_union(&damage->region, &damage->region, region); 701428d7b3dSmrg assert(damage->region.extents.x2 > damage->region.extents.x1); 702428d7b3dSmrg assert(damage->region.extents.y2 > damage->region.extents.y1); 703428d7b3dSmrg damage_union(damage, ®ion->extents); 704428d7b3dSmrg return damage; 705428d7b3dSmrg } 706428d7b3dSmrg 707428d7b3dSmrg if (pixman_region_contains_rectangle(&damage->region, 708428d7b3dSmrg ®ion->extents) == PIXMAN_REGION_IN) 709428d7b3dSmrg return damage; 710428d7b3dSmrg 711428d7b3dSmrg damage_union(damage, ®ion->extents); 712428d7b3dSmrg return _sna_damage_create_elt(damage, 713428d7b3dSmrg region_rects(region), 714428d7b3dSmrg region_num_rects(region)); 715428d7b3dSmrg} 716428d7b3dSmrg 717428d7b3dSmrg#if HAS_DEBUG_FULL 718428d7b3dSmrgfastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage, 719428d7b3dSmrg RegionPtr region) 720428d7b3dSmrg{ 721428d7b3dSmrg char region_buf[120]; 722428d7b3dSmrg char damage_buf[1000]; 723428d7b3dSmrg 724428d7b3dSmrg DBG(("%s(%s + %s)\n", __FUNCTION__, 725428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage), 726428d7b3dSmrg _debug_describe_region(region_buf, sizeof(region_buf), region))); 727428d7b3dSmrg 728428d7b3dSmrg damage = __sna_damage_add(damage, region); 729428d7b3dSmrg 730428d7b3dSmrg DBG((" = %s\n", 731428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage))); 732428d7b3dSmrg assert(region_num_rects(&damage->region)); 733428d7b3dSmrg assert(damage->region.extents.x2 > damage->region.extents.x1); 734428d7b3dSmrg assert(damage->region.extents.y2 > damage->region.extents.y1); 735428d7b3dSmrg 736428d7b3dSmrg return damage; 737428d7b3dSmrg} 738428d7b3dSmrg#else 739428d7b3dSmrgfastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage, 740428d7b3dSmrg RegionPtr region) 741428d7b3dSmrg{ 742428d7b3dSmrg return __sna_damage_add(damage, region); 743428d7b3dSmrg} 744428d7b3dSmrg#endif 745428d7b3dSmrg 746428d7b3dSmrginline static struct sna_damage * 747428d7b3dSmrg__sna_damage_add_boxes(struct sna_damage *damage, 748428d7b3dSmrg const BoxRec *box, int n, 749428d7b3dSmrg int16_t dx, int16_t dy) 750428d7b3dSmrg{ 751428d7b3dSmrg BoxRec extents; 752428d7b3dSmrg int i; 753428d7b3dSmrg 754428d7b3dSmrg assert(n); 755428d7b3dSmrg 756428d7b3dSmrg if (!damage) { 757428d7b3dSmrg damage = _sna_damage_create(); 758428d7b3dSmrg if (damage == NULL) 759428d7b3dSmrg return NULL; 760428d7b3dSmrg } else switch (damage->mode) { 761428d7b3dSmrg case DAMAGE_ALL: 762428d7b3dSmrg return damage; 763428d7b3dSmrg case DAMAGE_SUBTRACT: 764428d7b3dSmrg __sna_damage_reduce(damage); 765428d7b3dSmrg case DAMAGE_ADD: 766428d7b3dSmrg break; 767428d7b3dSmrg } 768428d7b3dSmrg 769428d7b3dSmrg assert(box[0].x2 > box[0].x1 && box[0].y2 > box[0].y1); 770428d7b3dSmrg extents = box[0]; 771428d7b3dSmrg for (i = 1; i < n; i++) { 772428d7b3dSmrg assert(box[i].x2 > box[i].x1 && box[i].y2 > box[i].y1); 773428d7b3dSmrg if (extents.x1 > box[i].x1) 774428d7b3dSmrg extents.x1 = box[i].x1; 775428d7b3dSmrg if (extents.x2 < box[i].x2) 776428d7b3dSmrg extents.x2 = box[i].x2; 777428d7b3dSmrg if (extents.y1 > box[i].y1) 778428d7b3dSmrg extents.y1 = box[i].y1; 779428d7b3dSmrg if (extents.y2 < box[i].y2) 780428d7b3dSmrg extents.y2 = box[i].y2; 781428d7b3dSmrg } 782428d7b3dSmrg 783428d7b3dSmrg assert(extents.y2 > extents.y1 && extents.x2 > extents.x1); 784428d7b3dSmrg 785428d7b3dSmrg extents.x1 += dx; 786428d7b3dSmrg extents.x2 += dx; 787428d7b3dSmrg extents.y1 += dy; 788428d7b3dSmrg extents.y2 += dy; 789428d7b3dSmrg 790428d7b3dSmrg if (n == 1) 791428d7b3dSmrg return __sna_damage_add_box(damage, &extents); 792428d7b3dSmrg 793428d7b3dSmrg if (pixman_region_contains_rectangle(&damage->region, 794428d7b3dSmrg &extents) == PIXMAN_REGION_IN) 795428d7b3dSmrg return damage; 796428d7b3dSmrg 797428d7b3dSmrg damage_union(damage, &extents); 798428d7b3dSmrg return _sna_damage_create_elt_from_boxes(damage, box, n, dx, dy); 799428d7b3dSmrg} 800428d7b3dSmrg 801428d7b3dSmrg#if HAS_DEBUG_FULL 802428d7b3dSmrgstruct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage, 803428d7b3dSmrg const BoxRec *b, int n, 804428d7b3dSmrg int16_t dx, int16_t dy) 805428d7b3dSmrg{ 806428d7b3dSmrg char damage_buf[1000]; 807428d7b3dSmrg 808428d7b3dSmrg DBG(("%s(%s + [(%d, %d), (%d, %d) ... x %d])\n", __FUNCTION__, 809428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage), 810428d7b3dSmrg b->x1, b->y1, b->x2, b->y2, n)); 811428d7b3dSmrg 812428d7b3dSmrg damage = __sna_damage_add_boxes(damage, b, n, dx, dy); 813428d7b3dSmrg 814428d7b3dSmrg DBG((" = %s\n", 815428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage))); 816428d7b3dSmrg if (region_num_rects(&damage->region)) { 817428d7b3dSmrg assert(damage->region.extents.x2 > damage->region.extents.x1); 818428d7b3dSmrg assert(damage->region.extents.y2 > damage->region.extents.y1); 819428d7b3dSmrg } 820428d7b3dSmrg 821428d7b3dSmrg return damage; 822428d7b3dSmrg} 823428d7b3dSmrg#else 824428d7b3dSmrgstruct sna_damage *_sna_damage_add_boxes(struct sna_damage *damage, 825428d7b3dSmrg const BoxRec *b, int n, 826428d7b3dSmrg int16_t dx, int16_t dy) 827428d7b3dSmrg{ 828428d7b3dSmrg return __sna_damage_add_boxes(damage, b, n, dx, dy); 829428d7b3dSmrg} 830428d7b3dSmrg#endif 831428d7b3dSmrg 832428d7b3dSmrginline static struct sna_damage * 833428d7b3dSmrg__sna_damage_add_rectangles(struct sna_damage *damage, 834428d7b3dSmrg const xRectangle *r, int n, 835428d7b3dSmrg int16_t dx, int16_t dy) 836428d7b3dSmrg{ 837428d7b3dSmrg BoxRec extents; 838428d7b3dSmrg int i; 839428d7b3dSmrg 840428d7b3dSmrg assert(n); 841428d7b3dSmrg 842428d7b3dSmrg assert(r[0].width && r[0].height); 843428d7b3dSmrg extents.x1 = r[0].x; 844428d7b3dSmrg extents.x2 = r[0].x + r[0].width; 845428d7b3dSmrg extents.y1 = r[0].y; 846428d7b3dSmrg extents.y2 = r[0].y + r[0].height; 847428d7b3dSmrg for (i = 1; i < n; i++) { 848428d7b3dSmrg assert(r[i].width && r[i].height); 849428d7b3dSmrg if (extents.x1 > r[i].x) 850428d7b3dSmrg extents.x1 = r[i].x; 851428d7b3dSmrg if (extents.x2 < r[i].x + r[i].width) 852428d7b3dSmrg extents.x2 = r[i].x + r[i].width; 853428d7b3dSmrg if (extents.y1 > r[i].y) 854428d7b3dSmrg extents.y1 = r[i].y; 855428d7b3dSmrg if (extents.y2 < r[i].y + r[i].height) 856428d7b3dSmrg extents.y2 = r[i].y + r[i].height; 857428d7b3dSmrg } 858428d7b3dSmrg 859428d7b3dSmrg assert(extents.y2 > extents.y1 && extents.x2 > extents.x1); 860428d7b3dSmrg 861428d7b3dSmrg extents.x1 += dx; 862428d7b3dSmrg extents.x2 += dx; 863428d7b3dSmrg extents.y1 += dy; 864428d7b3dSmrg extents.y2 += dy; 865428d7b3dSmrg 866428d7b3dSmrg if (n == 1) 867428d7b3dSmrg return __sna_damage_add_box(damage, &extents); 868428d7b3dSmrg 869428d7b3dSmrg if (!damage) { 870428d7b3dSmrg damage = _sna_damage_create(); 871428d7b3dSmrg if (damage == NULL) 872428d7b3dSmrg return NULL; 873428d7b3dSmrg } else switch (damage->mode) { 874428d7b3dSmrg case DAMAGE_ALL: 875428d7b3dSmrg return damage; 876428d7b3dSmrg case DAMAGE_SUBTRACT: 877428d7b3dSmrg __sna_damage_reduce(damage); 878428d7b3dSmrg case DAMAGE_ADD: 879428d7b3dSmrg break; 880428d7b3dSmrg } 881428d7b3dSmrg 882428d7b3dSmrg if (pixman_region_contains_rectangle(&damage->region, 883428d7b3dSmrg &extents) == PIXMAN_REGION_IN) 884428d7b3dSmrg return damage; 885428d7b3dSmrg 886428d7b3dSmrg damage_union(damage, &extents); 887428d7b3dSmrg return _sna_damage_create_elt_from_rectangles(damage, r, n, dx, dy); 888428d7b3dSmrg} 889428d7b3dSmrg 890428d7b3dSmrg#if HAS_DEBUG_FULL 891428d7b3dSmrgstruct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage, 892428d7b3dSmrg const xRectangle *r, int n, 893428d7b3dSmrg int16_t dx, int16_t dy) 894428d7b3dSmrg{ 895428d7b3dSmrg char damage_buf[1000]; 896428d7b3dSmrg 897428d7b3dSmrg DBG(("%s(%s + [(%d, %d)x(%d, %d) ... x %d])\n", __FUNCTION__, 898428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage), 899428d7b3dSmrg r->x, r->y, r->width, r->height, n)); 900428d7b3dSmrg 901428d7b3dSmrg damage = __sna_damage_add_rectangles(damage, r, n, dx, dy); 902428d7b3dSmrg 903428d7b3dSmrg DBG((" = %s\n", 904428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage))); 905428d7b3dSmrg if (region_num_rects(&damage->region)) { 906428d7b3dSmrg assert(damage->region.extents.x2 > damage->region.extents.x1); 907428d7b3dSmrg assert(damage->region.extents.y2 > damage->region.extents.y1); 908428d7b3dSmrg } 909428d7b3dSmrg 910428d7b3dSmrg return damage; 911428d7b3dSmrg} 912428d7b3dSmrg#else 913428d7b3dSmrgstruct sna_damage *_sna_damage_add_rectangles(struct sna_damage *damage, 914428d7b3dSmrg const xRectangle *r, int n, 915428d7b3dSmrg int16_t dx, int16_t dy) 916428d7b3dSmrg{ 917428d7b3dSmrg return __sna_damage_add_rectangles(damage, r, n, dx, dy); 918428d7b3dSmrg} 919428d7b3dSmrg#endif 920428d7b3dSmrg 921428d7b3dSmrg/* XXX pass in extents? */ 922428d7b3dSmrginline static struct sna_damage * 923428d7b3dSmrg__sna_damage_add_points(struct sna_damage *damage, 924428d7b3dSmrg const DDXPointRec *p, int n, 925428d7b3dSmrg int16_t dx, int16_t dy) 926428d7b3dSmrg{ 927428d7b3dSmrg BoxRec extents; 928428d7b3dSmrg int i; 929428d7b3dSmrg 930428d7b3dSmrg assert(n); 931428d7b3dSmrg 932428d7b3dSmrg extents.x2 = extents.x1 = p[0].x; 933428d7b3dSmrg extents.y2 = extents.y1 = p[0].y; 934428d7b3dSmrg for (i = 1; i < n; i++) { 935428d7b3dSmrg if (extents.x1 > p[i].x) 936428d7b3dSmrg extents.x1 = p[i].x; 937428d7b3dSmrg else if (extents.x2 < p[i].x) 938428d7b3dSmrg extents.x2 = p[i].x; 939428d7b3dSmrg if (extents.y1 > p[i].y) 940428d7b3dSmrg extents.y1 = p[i].y; 941428d7b3dSmrg else if (extents.y2 < p[i].y) 942428d7b3dSmrg extents.y2 = p[i].y; 943428d7b3dSmrg } 944428d7b3dSmrg 945428d7b3dSmrg extents.x1 += dx; 946428d7b3dSmrg extents.x2 += dx + 1; 947428d7b3dSmrg extents.y1 += dy; 948428d7b3dSmrg extents.y2 += dy + 1; 949428d7b3dSmrg 950428d7b3dSmrg if (n == 1) 951428d7b3dSmrg return __sna_damage_add_box(damage, &extents); 952428d7b3dSmrg 953428d7b3dSmrg if (!damage) { 954428d7b3dSmrg damage = _sna_damage_create(); 955428d7b3dSmrg if (damage == NULL) 956428d7b3dSmrg return NULL; 957428d7b3dSmrg } else switch (damage->mode) { 958428d7b3dSmrg case DAMAGE_ALL: 959428d7b3dSmrg return damage; 960428d7b3dSmrg case DAMAGE_SUBTRACT: 961428d7b3dSmrg __sna_damage_reduce(damage); 962428d7b3dSmrg case DAMAGE_ADD: 963428d7b3dSmrg break; 964428d7b3dSmrg } 965428d7b3dSmrg 966428d7b3dSmrg if (pixman_region_contains_rectangle(&damage->region, 967428d7b3dSmrg &extents) == PIXMAN_REGION_IN) 968428d7b3dSmrg return damage; 969428d7b3dSmrg 970428d7b3dSmrg damage_union(damage, &extents); 971428d7b3dSmrg return _sna_damage_create_elt_from_points(damage, p, n, dx, dy); 972428d7b3dSmrg} 973428d7b3dSmrg 974428d7b3dSmrg#if HAS_DEBUG_FULL 975428d7b3dSmrgstruct sna_damage *_sna_damage_add_points(struct sna_damage *damage, 976428d7b3dSmrg const DDXPointRec *p, int n, 977428d7b3dSmrg int16_t dx, int16_t dy) 978428d7b3dSmrg{ 979428d7b3dSmrg char damage_buf[1000]; 980428d7b3dSmrg 981428d7b3dSmrg DBG(("%s(%s + [(%d, %d) ... x %d])\n", __FUNCTION__, 982428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage), 983428d7b3dSmrg p->x, p->y, n)); 984428d7b3dSmrg 985428d7b3dSmrg damage = __sna_damage_add_points(damage, p, n, dx, dy); 986428d7b3dSmrg 987428d7b3dSmrg DBG((" = %s\n", 988428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage))); 989428d7b3dSmrg if (region_num_rects(&damage->region)) { 990428d7b3dSmrg assert(damage->region.extents.x2 > damage->region.extents.x1); 991428d7b3dSmrg assert(damage->region.extents.y2 > damage->region.extents.y1); 992428d7b3dSmrg } 993428d7b3dSmrg 994428d7b3dSmrg return damage; 995428d7b3dSmrg} 996428d7b3dSmrg#else 997428d7b3dSmrgstruct sna_damage *_sna_damage_add_points(struct sna_damage *damage, 998428d7b3dSmrg const DDXPointRec *p, int n, 999428d7b3dSmrg int16_t dx, int16_t dy) 1000428d7b3dSmrg{ 1001428d7b3dSmrg return __sna_damage_add_points(damage, p, n, dx, dy); 1002428d7b3dSmrg} 1003428d7b3dSmrg#endif 1004428d7b3dSmrg 1005428d7b3dSmrg#if HAS_DEBUG_FULL 1006428d7b3dSmrgfastcall struct sna_damage *_sna_damage_add_box(struct sna_damage *damage, 1007428d7b3dSmrg const BoxRec *box) 1008428d7b3dSmrg{ 1009428d7b3dSmrg char damage_buf[1000]; 1010428d7b3dSmrg 1011428d7b3dSmrg DBG(("%s(%s + [(%d, %d), (%d, %d)])\n", __FUNCTION__, 1012428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage), 1013428d7b3dSmrg box->x1, box->y1, box->x2, box->y2)); 1014428d7b3dSmrg 1015428d7b3dSmrg damage = __sna_damage_add_box(damage, box); 1016428d7b3dSmrg 1017428d7b3dSmrg DBG((" = %s\n", 1018428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage))); 1019428d7b3dSmrg assert(region_num_rects(&damage->region)); 1020428d7b3dSmrg assert(damage->region.extents.x2 > damage->region.extents.x1); 1021428d7b3dSmrg assert(damage->region.extents.y2 > damage->region.extents.y1); 1022428d7b3dSmrg 1023428d7b3dSmrg return damage; 1024428d7b3dSmrg} 1025428d7b3dSmrg#else 1026428d7b3dSmrgfastcall struct sna_damage *_sna_damage_add_box(struct sna_damage *damage, 1027428d7b3dSmrg const BoxRec *box) 1028428d7b3dSmrg{ 1029428d7b3dSmrg return __sna_damage_add_box(damage, box); 1030428d7b3dSmrg} 1031428d7b3dSmrg#endif 1032428d7b3dSmrg 1033428d7b3dSmrgstruct sna_damage *__sna_damage_all(struct sna_damage *damage, 1034428d7b3dSmrg int width, int height) 1035428d7b3dSmrg{ 1036428d7b3dSmrg DBG(("%s(%d, %d)\n", __FUNCTION__, width, height)); 1037428d7b3dSmrg 1038428d7b3dSmrg if (damage) { 1039428d7b3dSmrg pixman_region_fini(&damage->region); 1040428d7b3dSmrg free_list(&damage->embedded_box.list); 1041428d7b3dSmrg reset_embedded_box(damage); 1042428d7b3dSmrg } else { 1043428d7b3dSmrg damage = _sna_damage_create(); 1044428d7b3dSmrg if (damage == NULL) 1045428d7b3dSmrg return NULL; 1046428d7b3dSmrg } 1047428d7b3dSmrg 1048428d7b3dSmrg pixman_region_init_rect(&damage->region, 0, 0, width, height); 1049428d7b3dSmrg damage->extents = damage->region.extents; 1050428d7b3dSmrg damage->mode = DAMAGE_ALL; 1051428d7b3dSmrg 1052428d7b3dSmrg return damage; 1053428d7b3dSmrg} 1054428d7b3dSmrg 1055428d7b3dSmrgstruct sna_damage *_sna_damage_is_all(struct sna_damage *damage, 1056428d7b3dSmrg int width, int height) 1057428d7b3dSmrg{ 1058428d7b3dSmrg DBG(("%s(%d, %d)%s?\n", __FUNCTION__, width, height, 1059428d7b3dSmrg damage->dirty ? "*" : "")); 1060428d7b3dSmrg DBG(("%s: (%d, %d), (%d, %d)\n", __FUNCTION__, 1061428d7b3dSmrg damage->extents.x1, damage->extents.y1, 1062428d7b3dSmrg damage->extents.x2, damage->extents.y2)); 1063428d7b3dSmrg 1064428d7b3dSmrg assert(damage->mode == DAMAGE_ADD); 1065428d7b3dSmrg assert(damage->extents.x1 == 0 && 1066428d7b3dSmrg damage->extents.y1 == 0 && 1067428d7b3dSmrg damage->extents.x2 == width && 1068428d7b3dSmrg damage->extents.y2 == height); 1069428d7b3dSmrg 1070428d7b3dSmrg if (damage->dirty) { 1071428d7b3dSmrg __sna_damage_reduce(damage); 1072428d7b3dSmrg assert(RegionNotEmpty(&damage->region)); 1073428d7b3dSmrg } 1074428d7b3dSmrg 1075428d7b3dSmrg if (damage->region.data) { 1076428d7b3dSmrg DBG(("%s: no, not singular\n", __FUNCTION__)); 1077428d7b3dSmrg return damage; 1078428d7b3dSmrg } 1079428d7b3dSmrg 1080428d7b3dSmrg assert(damage->extents.x1 == 0 && 1081428d7b3dSmrg damage->extents.y1 == 0 && 1082428d7b3dSmrg damage->extents.x2 == width && 1083428d7b3dSmrg damage->extents.y2 == height); 1084428d7b3dSmrg 1085428d7b3dSmrg return __sna_damage_all(damage, width, height); 1086428d7b3dSmrg} 1087428d7b3dSmrg 1088428d7b3dSmrgstatic bool box_contains(const BoxRec *a, const BoxRec *b) 1089428d7b3dSmrg{ 1090428d7b3dSmrg if (b->x1 < a->x1 || b->x2 > a->x2) 1091428d7b3dSmrg return false; 1092428d7b3dSmrg 1093428d7b3dSmrg if (b->y1 < a->y1 || b->y2 > a->y2) 1094428d7b3dSmrg return false; 1095428d7b3dSmrg 1096428d7b3dSmrg return true; 1097428d7b3dSmrg} 1098428d7b3dSmrg 1099428d7b3dSmrgstatic struct sna_damage *__sna_damage_subtract(struct sna_damage *damage, 1100428d7b3dSmrg RegionPtr region) 1101428d7b3dSmrg{ 1102428d7b3dSmrg if (damage == NULL) 1103428d7b3dSmrg return NULL; 1104428d7b3dSmrg 1105428d7b3dSmrg if (RegionNil(&damage->region)) { 1106428d7b3dSmrgno_damage: 1107428d7b3dSmrg __sna_damage_destroy(damage); 1108428d7b3dSmrg return NULL; 1109428d7b3dSmrg } 1110428d7b3dSmrg 1111428d7b3dSmrg assert(RegionNotEmpty(region)); 1112428d7b3dSmrg 1113428d7b3dSmrg if (!sna_damage_overlaps_box(damage, ®ion->extents)) 1114428d7b3dSmrg return damage; 1115428d7b3dSmrg 1116428d7b3dSmrg if (region_is_singular(region) && 1117428d7b3dSmrg box_contains(®ion->extents, &damage->extents)) 1118428d7b3dSmrg goto no_damage; 1119428d7b3dSmrg 1120428d7b3dSmrg if (damage->mode == DAMAGE_ALL) { 1121428d7b3dSmrg pixman_region_subtract(&damage->region, 1122428d7b3dSmrg &damage->region, 1123428d7b3dSmrg region); 1124428d7b3dSmrg if (damage->region.extents.x2 <= damage->region.extents.x1 || 1125428d7b3dSmrg damage->region.extents.y2 <= damage->region.extents.y1) 1126428d7b3dSmrg goto no_damage; 1127428d7b3dSmrg 1128428d7b3dSmrg damage->extents = damage->region.extents; 1129428d7b3dSmrg damage->mode = DAMAGE_ADD; 1130428d7b3dSmrg return damage; 1131428d7b3dSmrg } 1132428d7b3dSmrg 1133428d7b3dSmrg if (damage->mode != DAMAGE_SUBTRACT) { 1134428d7b3dSmrg if (damage->dirty) { 1135428d7b3dSmrg __sna_damage_reduce(damage); 1136428d7b3dSmrg assert(RegionNotEmpty(&damage->region)); 1137428d7b3dSmrg } 1138428d7b3dSmrg 1139428d7b3dSmrg if (pixman_region_equal(region, &damage->region)) 1140428d7b3dSmrg goto no_damage; 1141428d7b3dSmrg 1142428d7b3dSmrg if (region_is_singular(&damage->region) && 1143428d7b3dSmrg region_is_singular(region)) { 1144428d7b3dSmrg pixman_region_subtract(&damage->region, 1145428d7b3dSmrg &damage->region, 1146428d7b3dSmrg region); 1147428d7b3dSmrg if (damage->region.extents.x2 <= damage->region.extents.x1 || 1148428d7b3dSmrg damage->region.extents.y2 <= damage->region.extents.y1) 1149428d7b3dSmrg goto no_damage; 1150428d7b3dSmrg 1151428d7b3dSmrg damage->extents = damage->region.extents; 1152428d7b3dSmrg assert(pixman_region_not_empty(&damage->region)); 1153428d7b3dSmrg return damage; 1154428d7b3dSmrg } 1155428d7b3dSmrg 1156428d7b3dSmrg damage->mode = DAMAGE_SUBTRACT; 1157428d7b3dSmrg } 1158428d7b3dSmrg 1159428d7b3dSmrg return _sna_damage_create_elt(damage, 1160428d7b3dSmrg region_rects(region), 1161428d7b3dSmrg region_num_rects(region)); 1162428d7b3dSmrg} 1163428d7b3dSmrg 1164428d7b3dSmrg#if HAS_DEBUG_FULL 1165428d7b3dSmrgfastcall struct sna_damage *_sna_damage_subtract(struct sna_damage *damage, 1166428d7b3dSmrg RegionPtr region) 1167428d7b3dSmrg{ 1168428d7b3dSmrg char damage_buf[1000]; 1169428d7b3dSmrg char region_buf[120]; 1170428d7b3dSmrg 1171428d7b3dSmrg DBG(("%s(%s - %s)...\n", __FUNCTION__, 1172428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage), 1173428d7b3dSmrg _debug_describe_region(region_buf, sizeof(region_buf), region))); 1174428d7b3dSmrg 1175428d7b3dSmrg damage = __sna_damage_subtract(damage, region); 1176428d7b3dSmrg 1177428d7b3dSmrg DBG((" = %s\n", 1178428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage))); 1179428d7b3dSmrg 1180428d7b3dSmrg return damage; 1181428d7b3dSmrg} 1182428d7b3dSmrg#else 1183428d7b3dSmrgfastcall struct sna_damage *_sna_damage_subtract(struct sna_damage *damage, 1184428d7b3dSmrg RegionPtr region) 1185428d7b3dSmrg{ 1186428d7b3dSmrg return __sna_damage_subtract(damage, region); 1187428d7b3dSmrg} 1188428d7b3dSmrg#endif 1189428d7b3dSmrg 1190428d7b3dSmrginline static struct sna_damage *__sna_damage_subtract_box(struct sna_damage *damage, 1191428d7b3dSmrg const BoxRec *box) 1192428d7b3dSmrg{ 1193428d7b3dSmrg assert(box->x2 > box->x1 && box->y2 > box->y1); 1194428d7b3dSmrg 1195428d7b3dSmrg if (damage == NULL) 1196428d7b3dSmrg return NULL; 1197428d7b3dSmrg 1198428d7b3dSmrg if (RegionNil(&damage->region)) { 1199428d7b3dSmrg __sna_damage_destroy(damage); 1200428d7b3dSmrg return NULL; 1201428d7b3dSmrg } 1202428d7b3dSmrg 1203428d7b3dSmrg if (!sna_damage_overlaps_box(damage, box)) 1204428d7b3dSmrg return damage; 1205428d7b3dSmrg 1206428d7b3dSmrg if (box_contains(box, &damage->extents)) { 1207428d7b3dSmrg __sna_damage_destroy(damage); 1208428d7b3dSmrg return NULL; 1209428d7b3dSmrg } 1210428d7b3dSmrg 1211428d7b3dSmrg if (damage->mode != DAMAGE_SUBTRACT) { 1212428d7b3dSmrg if (damage->dirty) { 1213428d7b3dSmrg __sna_damage_reduce(damage); 1214428d7b3dSmrg assert(RegionNotEmpty(&damage->region)); 1215428d7b3dSmrg } 1216428d7b3dSmrg 1217428d7b3dSmrg if (region_is_singular(&damage->region)) { 1218428d7b3dSmrg pixman_region16_t region; 1219428d7b3dSmrg 1220428d7b3dSmrg pixman_region_init_rects(®ion, box, 1); 1221428d7b3dSmrg pixman_region_subtract(&damage->region, 1222428d7b3dSmrg &damage->region, 1223428d7b3dSmrg ®ion); 1224428d7b3dSmrg damage->extents = damage->region.extents; 1225428d7b3dSmrg damage->mode = DAMAGE_ADD; 1226428d7b3dSmrg return damage; 1227428d7b3dSmrg } 1228428d7b3dSmrg 1229428d7b3dSmrg damage->mode = DAMAGE_SUBTRACT; 1230428d7b3dSmrg } 1231428d7b3dSmrg 1232428d7b3dSmrg return _sna_damage_create_elt(damage, box, 1); 1233428d7b3dSmrg} 1234428d7b3dSmrg 1235428d7b3dSmrg#if HAS_DEBUG_FULL 1236428d7b3dSmrgfastcall struct sna_damage *_sna_damage_subtract_box(struct sna_damage *damage, 1237428d7b3dSmrg const BoxRec *box) 1238428d7b3dSmrg{ 1239428d7b3dSmrg char damage_buf[1000]; 1240428d7b3dSmrg 1241428d7b3dSmrg DBG(("%s(%s - (%d, %d), (%d, %d))...\n", __FUNCTION__, 1242428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage), 1243428d7b3dSmrg box->x1, box->y1, box->x2, box->y2)); 1244428d7b3dSmrg 1245428d7b3dSmrg damage = __sna_damage_subtract_box(damage, box); 1246428d7b3dSmrg 1247428d7b3dSmrg DBG((" = %s\n", 1248428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage))); 1249428d7b3dSmrg 1250428d7b3dSmrg return damage; 1251428d7b3dSmrg} 1252428d7b3dSmrg#else 1253428d7b3dSmrgfastcall struct sna_damage *_sna_damage_subtract_box(struct sna_damage *damage, 1254428d7b3dSmrg const BoxRec *box) 1255428d7b3dSmrg{ 1256428d7b3dSmrg return __sna_damage_subtract_box(damage, box); 1257428d7b3dSmrg} 1258428d7b3dSmrg#endif 1259428d7b3dSmrg 1260428d7b3dSmrgstatic struct sna_damage *__sna_damage_subtract_boxes(struct sna_damage *damage, 1261428d7b3dSmrg const BoxRec *box, int n, 1262428d7b3dSmrg int dx, int dy) 1263428d7b3dSmrg{ 1264428d7b3dSmrg BoxRec extents; 1265428d7b3dSmrg int i; 1266428d7b3dSmrg 1267428d7b3dSmrg if (damage == NULL) 1268428d7b3dSmrg return NULL; 1269428d7b3dSmrg 1270428d7b3dSmrg if (RegionNil(&damage->region)) { 1271428d7b3dSmrg __sna_damage_destroy(damage); 1272428d7b3dSmrg return NULL; 1273428d7b3dSmrg } 1274428d7b3dSmrg 1275428d7b3dSmrg assert(n); 1276428d7b3dSmrg 1277428d7b3dSmrg assert(box[0].x2 > box[0].x1 && box[0].y2 > box[0].y1); 1278428d7b3dSmrg extents = box[0]; 1279428d7b3dSmrg for (i = 1; i < n; i++) { 1280428d7b3dSmrg assert(box[i].x2 > box[i].x1 && box[i].y2 > box[i].y1); 1281428d7b3dSmrg if (extents.x1 > box[i].x1) 1282428d7b3dSmrg extents.x1 = box[i].x1; 1283428d7b3dSmrg if (extents.x2 < box[i].x2) 1284428d7b3dSmrg extents.x2 = box[i].x2; 1285428d7b3dSmrg if (extents.y1 > box[i].y1) 1286428d7b3dSmrg extents.y1 = box[i].y1; 1287428d7b3dSmrg if (extents.y2 < box[i].y2) 1288428d7b3dSmrg extents.y2 = box[i].y2; 1289428d7b3dSmrg } 1290428d7b3dSmrg 1291428d7b3dSmrg assert(extents.y2 > extents.y1 && extents.x2 > extents.x1); 1292428d7b3dSmrg 1293428d7b3dSmrg extents.x1 += dx; 1294428d7b3dSmrg extents.x2 += dx; 1295428d7b3dSmrg extents.y1 += dy; 1296428d7b3dSmrg extents.y2 += dy; 1297428d7b3dSmrg 1298428d7b3dSmrg if (!sna_damage_overlaps_box(damage, &extents)) 1299428d7b3dSmrg return damage; 1300428d7b3dSmrg 1301428d7b3dSmrg if (n == 1) 1302428d7b3dSmrg return __sna_damage_subtract_box(damage, &extents); 1303428d7b3dSmrg 1304428d7b3dSmrg if (damage->mode != DAMAGE_SUBTRACT) { 1305428d7b3dSmrg if (damage->dirty) { 1306428d7b3dSmrg __sna_damage_reduce(damage); 1307428d7b3dSmrg assert(RegionNotEmpty(&damage->region)); 1308428d7b3dSmrg } 1309428d7b3dSmrg 1310428d7b3dSmrg damage->mode = DAMAGE_SUBTRACT; 1311428d7b3dSmrg } 1312428d7b3dSmrg 1313428d7b3dSmrg return _sna_damage_create_elt_from_boxes(damage, box, n, dx, dy); 1314428d7b3dSmrg} 1315428d7b3dSmrg 1316428d7b3dSmrg#if HAS_DEBUG_FULL 1317428d7b3dSmrgfastcall struct sna_damage *_sna_damage_subtract_boxes(struct sna_damage *damage, 1318428d7b3dSmrg const BoxRec *box, int n, 1319428d7b3dSmrg int dx, int dy) 1320428d7b3dSmrg{ 1321428d7b3dSmrg char damage_buf[1000]; 1322428d7b3dSmrg 1323428d7b3dSmrg DBG(("%s(%s - [(%d,%d), (%d,%d)...x%d])...\n", __FUNCTION__, 1324428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage), 1325428d7b3dSmrg box->x1 + dx, box->y1 + dy, 1326428d7b3dSmrg box->x2 + dx, box->y2 + dy, 1327428d7b3dSmrg n)); 1328428d7b3dSmrg 1329428d7b3dSmrg damage = __sna_damage_subtract_boxes(damage, box, n, dx, dy); 1330428d7b3dSmrg 1331428d7b3dSmrg DBG((" = %s\n", 1332428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage))); 1333428d7b3dSmrg 1334428d7b3dSmrg return damage; 1335428d7b3dSmrg} 1336428d7b3dSmrg#else 1337428d7b3dSmrgfastcall struct sna_damage *_sna_damage_subtract_boxes(struct sna_damage *damage, 1338428d7b3dSmrg const BoxRec *box, int n, 1339428d7b3dSmrg int dx, int dy) 1340428d7b3dSmrg{ 1341428d7b3dSmrg return __sna_damage_subtract_boxes(damage, box, n, dx, dy); 1342428d7b3dSmrg} 1343428d7b3dSmrg#endif 1344428d7b3dSmrg 1345428d7b3dSmrgstatic int __sna_damage_contains_box(struct sna_damage **_damage, 1346428d7b3dSmrg const BoxRec *box) 1347428d7b3dSmrg{ 1348428d7b3dSmrg struct sna_damage *damage = *_damage; 1349428d7b3dSmrg const BoxRec *b; 1350428d7b3dSmrg int n, count, ret; 1351428d7b3dSmrg 1352428d7b3dSmrg if (damage->mode == DAMAGE_ALL) 1353428d7b3dSmrg return PIXMAN_REGION_IN; 1354428d7b3dSmrg 1355428d7b3dSmrg if (!sna_damage_overlaps_box(damage, box)) 1356428d7b3dSmrg return PIXMAN_REGION_OUT; 1357428d7b3dSmrg 1358428d7b3dSmrg ret = pixman_region_contains_rectangle(&damage->region, (BoxPtr)box); 1359428d7b3dSmrg if (!damage->dirty) 1360428d7b3dSmrg return ret; 1361428d7b3dSmrg 1362428d7b3dSmrg if (damage->mode == DAMAGE_ADD) { 1363428d7b3dSmrg if (ret == PIXMAN_REGION_IN) 1364428d7b3dSmrg return ret; 1365428d7b3dSmrg 1366428d7b3dSmrg count = damage->embedded_box.size; 1367428d7b3dSmrg if (list_is_empty(&damage->embedded_box.list)) 1368428d7b3dSmrg count -= damage->remain; 1369428d7b3dSmrg 1370428d7b3dSmrg b = damage->embedded_box.box; 1371428d7b3dSmrg for (n = 0; n < count; n++) { 1372428d7b3dSmrg if (box_contains(&b[n], box)) 1373428d7b3dSmrg return PIXMAN_REGION_IN; 1374428d7b3dSmrg } 1375428d7b3dSmrg } else { 1376428d7b3dSmrg if (ret == PIXMAN_REGION_OUT) 1377428d7b3dSmrg return ret; 1378428d7b3dSmrg 1379428d7b3dSmrg count = damage->embedded_box.size; 1380428d7b3dSmrg if (list_is_empty(&damage->embedded_box.list)) 1381428d7b3dSmrg count -= damage->remain; 1382428d7b3dSmrg 1383428d7b3dSmrg b = damage->embedded_box.box; 1384428d7b3dSmrg for (n = 0; n < count; n++) { 1385428d7b3dSmrg if (box_contains(&b[n], box)) 1386428d7b3dSmrg return PIXMAN_REGION_OUT; 1387428d7b3dSmrg } 1388428d7b3dSmrg } 1389428d7b3dSmrg 1390428d7b3dSmrg __sna_damage_reduce(damage); 1391428d7b3dSmrg if (!pixman_region_not_empty(&damage->region)) { 1392428d7b3dSmrg __sna_damage_destroy(damage); 1393428d7b3dSmrg *_damage = NULL; 1394428d7b3dSmrg return PIXMAN_REGION_OUT; 1395428d7b3dSmrg } 1396428d7b3dSmrg 1397428d7b3dSmrg return pixman_region_contains_rectangle(&damage->region, (BoxPtr)box); 1398428d7b3dSmrg} 1399428d7b3dSmrg 1400428d7b3dSmrg#if HAS_DEBUG_FULL 1401428d7b3dSmrgint _sna_damage_contains_box(struct sna_damage **damage, 1402428d7b3dSmrg const BoxRec *box) 1403428d7b3dSmrg{ 1404428d7b3dSmrg char damage_buf[1000]; 1405428d7b3dSmrg int ret; 1406428d7b3dSmrg 1407428d7b3dSmrg DBG(("%s(%s, [(%d, %d), (%d, %d)])\n", __FUNCTION__, 1408428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), *damage), 1409428d7b3dSmrg box->x1, box->y1, box->x2, box->y2)); 1410428d7b3dSmrg 1411428d7b3dSmrg ret = __sna_damage_contains_box(damage, box); 1412428d7b3dSmrg DBG((" = %d", ret)); 1413428d7b3dSmrg if (ret) 1414428d7b3dSmrg DBG((" [(%d, %d), (%d, %d)...]", 1415428d7b3dSmrg box->x1, box->y1, box->x2, box->y2)); 1416428d7b3dSmrg DBG(("\n")); 1417428d7b3dSmrg 1418428d7b3dSmrg return ret; 1419428d7b3dSmrg} 1420428d7b3dSmrg#else 1421428d7b3dSmrgint _sna_damage_contains_box(struct sna_damage **damage, 1422428d7b3dSmrg const BoxRec *box) 1423428d7b3dSmrg{ 1424428d7b3dSmrg return __sna_damage_contains_box(damage, box); 1425428d7b3dSmrg} 1426428d7b3dSmrg#endif 1427428d7b3dSmrg 1428428d7b3dSmrgstatic bool box_overlaps(const BoxRec *a, const BoxRec *b) 1429428d7b3dSmrg{ 1430428d7b3dSmrg return (a->x1 < b->x2 && a->x2 > b->x1 && 1431428d7b3dSmrg a->y1 < b->y2 && a->y2 > b->y1); 1432428d7b3dSmrg} 1433428d7b3dSmrg 1434428d7b3dSmrgbool _sna_damage_contains_box__no_reduce(const struct sna_damage *damage, 1435428d7b3dSmrg const BoxRec *box) 1436428d7b3dSmrg{ 1437428d7b3dSmrg int n, count; 1438428d7b3dSmrg const BoxRec *b; 1439428d7b3dSmrg 1440428d7b3dSmrg assert(damage && damage->mode != DAMAGE_ALL); 1441428d7b3dSmrg if (!box_contains(&damage->extents, box)) 1442428d7b3dSmrg return false; 1443428d7b3dSmrg 1444428d7b3dSmrg n = pixman_region_contains_rectangle((pixman_region16_t *)&damage->region, (BoxPtr)box); 1445428d7b3dSmrg if (!damage->dirty) 1446428d7b3dSmrg return n == PIXMAN_REGION_IN; 1447428d7b3dSmrg 1448428d7b3dSmrg if (damage->mode == DAMAGE_ADD) { 1449428d7b3dSmrg if (n == PIXMAN_REGION_IN) 1450428d7b3dSmrg return true; 1451428d7b3dSmrg 1452428d7b3dSmrg count = damage->embedded_box.size; 1453428d7b3dSmrg if (list_is_empty(&damage->embedded_box.list)) 1454428d7b3dSmrg count -= damage->remain; 1455428d7b3dSmrg 1456428d7b3dSmrg b = damage->embedded_box.box; 1457428d7b3dSmrg for (n = 0; n < count; n++) { 1458428d7b3dSmrg if (box_contains(&b[n], box)) 1459428d7b3dSmrg return true; 1460428d7b3dSmrg } 1461428d7b3dSmrg 1462428d7b3dSmrg return false; 1463428d7b3dSmrg } else { 1464428d7b3dSmrg if (n != PIXMAN_REGION_IN) 1465428d7b3dSmrg return false; 1466428d7b3dSmrg 1467428d7b3dSmrg if (!list_is_empty(&damage->embedded_box.list)) 1468428d7b3dSmrg return false; 1469428d7b3dSmrg 1470428d7b3dSmrg count = damage->embedded_box.size - damage->remain; 1471428d7b3dSmrg b = damage->embedded_box.box; 1472428d7b3dSmrg for (n = 0; n < count; n++) { 1473428d7b3dSmrg if (box_overlaps(&b[n], box)) 1474428d7b3dSmrg return false; 1475428d7b3dSmrg } 1476428d7b3dSmrg 1477428d7b3dSmrg return true; 1478428d7b3dSmrg } 1479428d7b3dSmrg} 1480428d7b3dSmrg 1481428d7b3dSmrgstatic bool __sna_damage_intersect(struct sna_damage *damage, 1482428d7b3dSmrg RegionPtr region, RegionPtr result) 1483428d7b3dSmrg{ 1484428d7b3dSmrg assert(damage && damage->mode != DAMAGE_ALL); 1485428d7b3dSmrg assert(RegionNotEmpty(region)); 1486428d7b3dSmrg 1487428d7b3dSmrg if (region->extents.x2 <= damage->extents.x1 || 1488428d7b3dSmrg region->extents.x1 >= damage->extents.x2) 1489428d7b3dSmrg return false; 1490428d7b3dSmrg 1491428d7b3dSmrg if (region->extents.y2 <= damage->extents.y1 || 1492428d7b3dSmrg region->extents.y1 >= damage->extents.y2) 1493428d7b3dSmrg return false; 1494428d7b3dSmrg 1495428d7b3dSmrg if (damage->dirty) 1496428d7b3dSmrg __sna_damage_reduce(damage); 1497428d7b3dSmrg 1498428d7b3dSmrg if (!pixman_region_not_empty(&damage->region)) 1499428d7b3dSmrg return false; 1500428d7b3dSmrg 1501428d7b3dSmrg RegionNull(result); 1502428d7b3dSmrg RegionIntersect(result, &damage->region, region); 1503428d7b3dSmrg 1504428d7b3dSmrg return RegionNotEmpty(result); 1505428d7b3dSmrg} 1506428d7b3dSmrg 1507428d7b3dSmrg#if HAS_DEBUG_FULL 1508428d7b3dSmrgbool _sna_damage_intersect(struct sna_damage *damage, 1509428d7b3dSmrg RegionPtr region, RegionPtr result) 1510428d7b3dSmrg{ 1511428d7b3dSmrg char damage_buf[1000]; 1512428d7b3dSmrg char region_buf[120]; 1513428d7b3dSmrg bool ret; 1514428d7b3dSmrg 1515428d7b3dSmrg DBG(("%s(%s, %s)...\n", __FUNCTION__, 1516428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage), 1517428d7b3dSmrg _debug_describe_region(region_buf, sizeof(region_buf), region))); 1518428d7b3dSmrg 1519428d7b3dSmrg ret = __sna_damage_intersect(damage, region, result); 1520428d7b3dSmrg if (ret) 1521428d7b3dSmrg DBG((" = %s\n", 1522428d7b3dSmrg _debug_describe_region(region_buf, sizeof(region_buf), result))); 1523428d7b3dSmrg else 1524428d7b3dSmrg DBG((" = none\n")); 1525428d7b3dSmrg 1526428d7b3dSmrg return ret; 1527428d7b3dSmrg} 1528428d7b3dSmrg#else 1529428d7b3dSmrgbool _sna_damage_intersect(struct sna_damage *damage, 1530428d7b3dSmrg RegionPtr region, RegionPtr result) 1531428d7b3dSmrg{ 1532428d7b3dSmrg return __sna_damage_intersect(damage, region, result); 1533428d7b3dSmrg} 1534428d7b3dSmrg#endif 1535428d7b3dSmrg 1536428d7b3dSmrgstatic int __sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes) 1537428d7b3dSmrg{ 1538428d7b3dSmrg assert(damage && damage->mode != DAMAGE_ALL); 1539428d7b3dSmrg 1540428d7b3dSmrg if (damage->dirty) 1541428d7b3dSmrg __sna_damage_reduce(damage); 1542428d7b3dSmrg 1543428d7b3dSmrg assert(!damage->dirty); 1544428d7b3dSmrg assert(damage->mode == DAMAGE_ADD); 1545428d7b3dSmrg 1546428d7b3dSmrg *boxes = region_rects(&damage->region); 1547428d7b3dSmrg return region_num_rects(&damage->region); 1548428d7b3dSmrg} 1549428d7b3dSmrg 1550428d7b3dSmrgstruct sna_damage *_sna_damage_reduce(struct sna_damage *damage) 1551428d7b3dSmrg{ 1552428d7b3dSmrg DBG(("%s\n", __FUNCTION__)); 1553428d7b3dSmrg 1554428d7b3dSmrg __sna_damage_reduce(damage); 1555428d7b3dSmrg 1556428d7b3dSmrg assert(!damage->dirty); 1557428d7b3dSmrg assert(damage->mode == DAMAGE_ADD); 1558428d7b3dSmrg 1559428d7b3dSmrg if (!pixman_region_not_empty(&damage->region)) { 1560428d7b3dSmrg __sna_damage_destroy(damage); 1561428d7b3dSmrg damage = NULL; 1562428d7b3dSmrg } 1563428d7b3dSmrg 1564428d7b3dSmrg return damage; 1565428d7b3dSmrg} 1566428d7b3dSmrg 1567428d7b3dSmrg#if HAS_DEBUG_FULL 1568428d7b3dSmrgint _sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes) 1569428d7b3dSmrg{ 1570428d7b3dSmrg char damage_buf[1000]; 1571428d7b3dSmrg int count; 1572428d7b3dSmrg 1573428d7b3dSmrg DBG(("%s(%s)...\n", __FUNCTION__, 1574428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage))); 1575428d7b3dSmrg 1576428d7b3dSmrg count = __sna_damage_get_boxes(damage, boxes); 1577428d7b3dSmrg DBG((" = %d\n", count)); 1578428d7b3dSmrg 1579428d7b3dSmrg return count; 1580428d7b3dSmrg} 1581428d7b3dSmrg#else 1582428d7b3dSmrgint _sna_damage_get_boxes(struct sna_damage *damage, const BoxRec **boxes) 1583428d7b3dSmrg{ 1584428d7b3dSmrg return __sna_damage_get_boxes(damage, boxes); 1585428d7b3dSmrg} 1586428d7b3dSmrg#endif 1587428d7b3dSmrg 1588428d7b3dSmrgstruct sna_damage *_sna_damage_combine(struct sna_damage *l, 1589428d7b3dSmrg struct sna_damage *r, 1590428d7b3dSmrg int dx, int dy) 1591428d7b3dSmrg{ 1592428d7b3dSmrg if (r->dirty) 1593428d7b3dSmrg __sna_damage_reduce(r); 1594428d7b3dSmrg 1595428d7b3dSmrg if (pixman_region_not_empty(&r->region)) { 1596428d7b3dSmrg pixman_region_translate(&r->region, dx, dy); 1597428d7b3dSmrg l = __sna_damage_add(l, &r->region); 1598428d7b3dSmrg } 1599428d7b3dSmrg 1600428d7b3dSmrg return l; 1601428d7b3dSmrg} 1602428d7b3dSmrg 1603428d7b3dSmrgvoid __sna_damage_destroy(struct sna_damage *damage) 1604428d7b3dSmrg{ 1605428d7b3dSmrg free_list(&damage->embedded_box.list); 1606428d7b3dSmrg 1607428d7b3dSmrg pixman_region_fini(&damage->region); 1608428d7b3dSmrg *(void **)damage = __freed_damage; 1609428d7b3dSmrg __freed_damage = damage; 1610428d7b3dSmrg} 1611428d7b3dSmrg 1612428d7b3dSmrg#if TEST_DAMAGE && HAS_DEBUG_FULL 1613428d7b3dSmrgstruct sna_damage_selftest{ 1614428d7b3dSmrg int width, height; 1615428d7b3dSmrg}; 1616428d7b3dSmrg 1617428d7b3dSmrgstatic void st_damage_init_random_box(struct sna_damage_selftest *test, 1618428d7b3dSmrg BoxPtr box) 1619428d7b3dSmrg{ 1620428d7b3dSmrg int x, y, w, h; 1621428d7b3dSmrg 1622428d7b3dSmrg if (test->width == 1) { 1623428d7b3dSmrg x = 0, w = 1; 1624428d7b3dSmrg } else { 1625428d7b3dSmrg x = rand() % (test->width - 1); 1626428d7b3dSmrg w = 1 + rand() % (test->width - x - 1); 1627428d7b3dSmrg } 1628428d7b3dSmrg 1629428d7b3dSmrg if (test->height == 1) { 1630428d7b3dSmrg y = 0, h = 1; 1631428d7b3dSmrg } else { 1632428d7b3dSmrg y = rand() % (test->height - 1); 1633428d7b3dSmrg h = 1 + rand() % (test->height - y - 1); 1634428d7b3dSmrg } 1635428d7b3dSmrg 1636428d7b3dSmrg box->x1 = x; 1637428d7b3dSmrg box->x2 = x+w; 1638428d7b3dSmrg 1639428d7b3dSmrg box->y1 = y; 1640428d7b3dSmrg box->y2 = y+h; 1641428d7b3dSmrg} 1642428d7b3dSmrg 1643428d7b3dSmrgstatic void st_damage_init_random_region1(struct sna_damage_selftest *test, 1644428d7b3dSmrg pixman_region16_t *region) 1645428d7b3dSmrg{ 1646428d7b3dSmrg int x, y, w, h; 1647428d7b3dSmrg 1648428d7b3dSmrg if (test->width == 1) { 1649428d7b3dSmrg x = 0, w = 1; 1650428d7b3dSmrg } else { 1651428d7b3dSmrg x = rand() % (test->width - 1); 1652428d7b3dSmrg w = 1 + rand() % (test->width - x - 1); 1653428d7b3dSmrg } 1654428d7b3dSmrg 1655428d7b3dSmrg if (test->height == 1) { 1656428d7b3dSmrg y = 0, h = 1; 1657428d7b3dSmrg } else { 1658428d7b3dSmrg y = rand() % (test->height - 1); 1659428d7b3dSmrg h = 1 + rand() % (test->height - y - 1); 1660428d7b3dSmrg } 1661428d7b3dSmrg 1662428d7b3dSmrg pixman_region_init_rect(region, x, y, w, h); 1663428d7b3dSmrg} 1664428d7b3dSmrg 1665428d7b3dSmrgstatic void st_damage_add(struct sna_damage_selftest *test, 1666428d7b3dSmrg struct sna_damage **damage, 1667428d7b3dSmrg pixman_region16_t *region) 1668428d7b3dSmrg{ 1669428d7b3dSmrg pixman_region16_t tmp; 1670428d7b3dSmrg 1671428d7b3dSmrg st_damage_init_random_region1(test, &tmp); 1672428d7b3dSmrg 1673428d7b3dSmrg if (!DAMAGE_IS_ALL(*damage)) 1674428d7b3dSmrg sna_damage_add(damage, &tmp); 1675428d7b3dSmrg pixman_region_union(region, region, &tmp); 1676428d7b3dSmrg} 1677428d7b3dSmrg 1678428d7b3dSmrgstatic void st_damage_add_box(struct sna_damage_selftest *test, 1679428d7b3dSmrg struct sna_damage **damage, 1680428d7b3dSmrg pixman_region16_t *region) 1681428d7b3dSmrg{ 1682428d7b3dSmrg RegionRec r; 1683428d7b3dSmrg 1684428d7b3dSmrg st_damage_init_random_box(test, &r.extents); 1685428d7b3dSmrg r.data = NULL; 1686428d7b3dSmrg 1687428d7b3dSmrg if (!DAMAGE_IS_ALL(*damage)) 1688428d7b3dSmrg sna_damage_add_box(damage, &r.extents); 1689428d7b3dSmrg pixman_region_union(region, region, &r); 1690428d7b3dSmrg} 1691428d7b3dSmrg 1692428d7b3dSmrgstatic void st_damage_subtract(struct sna_damage_selftest *test, 1693428d7b3dSmrg struct sna_damage **damage, 1694428d7b3dSmrg pixman_region16_t *region) 1695428d7b3dSmrg{ 1696428d7b3dSmrg pixman_region16_t tmp; 1697428d7b3dSmrg 1698428d7b3dSmrg st_damage_init_random_region1(test, &tmp); 1699428d7b3dSmrg 1700428d7b3dSmrg sna_damage_subtract(damage, &tmp); 1701428d7b3dSmrg pixman_region_subtract(region, region, &tmp); 1702428d7b3dSmrg} 1703428d7b3dSmrg 1704428d7b3dSmrgstatic void st_damage_subtract_box(struct sna_damage_selftest *test, 1705428d7b3dSmrg struct sna_damage **damage, 1706428d7b3dSmrg pixman_region16_t *region) 1707428d7b3dSmrg{ 1708428d7b3dSmrg RegionRec r; 1709428d7b3dSmrg 1710428d7b3dSmrg st_damage_init_random_box(test, &r.extents); 1711428d7b3dSmrg r.data = NULL; 1712428d7b3dSmrg 1713428d7b3dSmrg sna_damage_subtract_box(damage, &r.extents); 1714428d7b3dSmrg pixman_region_subtract(region, region, &r); 1715428d7b3dSmrg} 1716428d7b3dSmrg 1717428d7b3dSmrgstatic void st_damage_all(struct sna_damage_selftest *test, 1718428d7b3dSmrg struct sna_damage **damage, 1719428d7b3dSmrg pixman_region16_t *region) 1720428d7b3dSmrg{ 1721428d7b3dSmrg pixman_region16_t tmp; 1722428d7b3dSmrg 1723428d7b3dSmrg pixman_region_init_rect(&tmp, 0, 0, test->width, test->height); 1724428d7b3dSmrg 1725428d7b3dSmrg if (!DAMAGE_IS_ALL(*damage)) 1726428d7b3dSmrg sna_damage_all(damage, test->width, test->height); 1727428d7b3dSmrg pixman_region_union(region, region, &tmp); 1728428d7b3dSmrg} 1729428d7b3dSmrg 1730428d7b3dSmrgstatic bool st_check_equal(struct sna_damage_selftest *test, 1731428d7b3dSmrg struct sna_damage **damage, 1732428d7b3dSmrg pixman_region16_t *region) 1733428d7b3dSmrg{ 1734428d7b3dSmrg int d_num, r_num; 1735428d7b3dSmrg BoxPtr d_boxes, r_boxes; 1736428d7b3dSmrg 1737428d7b3dSmrg d_num = *damage ? sna_damage_get_boxes(*damage, &d_boxes) : 0; 1738428d7b3dSmrg r_boxes = pixman_region_rectangles(region, &r_num); 1739428d7b3dSmrg 1740428d7b3dSmrg if (d_num != r_num) { 1741428d7b3dSmrg ERR(("%s: damage and ref contain different number of rectangles\n", 1742428d7b3dSmrg __FUNCTION__)); 1743428d7b3dSmrg return false; 1744428d7b3dSmrg } 1745428d7b3dSmrg 1746428d7b3dSmrg if (memcmp(d_boxes, r_boxes, d_num*sizeof(BoxRec))) { 1747428d7b3dSmrg ERR(("%s: damage and ref contain different rectangles\n", 1748428d7b3dSmrg __FUNCTION__)); 1749428d7b3dSmrg return false; 1750428d7b3dSmrg } 1751428d7b3dSmrg 1752428d7b3dSmrg return true; 1753428d7b3dSmrg} 1754428d7b3dSmrg 1755428d7b3dSmrgvoid sna_damage_selftest(void) 1756428d7b3dSmrg{ 1757428d7b3dSmrg void (*const op[])(struct sna_damage_selftest *test, 1758428d7b3dSmrg struct sna_damage **damage, 1759428d7b3dSmrg pixman_region16_t *region) = { 1760428d7b3dSmrg st_damage_add, 1761428d7b3dSmrg st_damage_add_box, 1762428d7b3dSmrg st_damage_subtract, 1763428d7b3dSmrg st_damage_subtract_box, 1764428d7b3dSmrg st_damage_all 1765428d7b3dSmrg }; 1766428d7b3dSmrg bool (*const check[])(struct sna_damage_selftest *test, 1767428d7b3dSmrg struct sna_damage **damage, 1768428d7b3dSmrg pixman_region16_t *region) = { 1769428d7b3dSmrg st_check_equal, 1770428d7b3dSmrg //st_check_contains, 1771428d7b3dSmrg }; 1772428d7b3dSmrg char region_buf[120]; 1773428d7b3dSmrg char damage_buf[1000]; 1774428d7b3dSmrg int pass; 1775428d7b3dSmrg 1776428d7b3dSmrg for (pass = 0; pass < 16384; pass++) { 1777428d7b3dSmrg struct sna_damage_selftest test; 1778428d7b3dSmrg struct sna_damage *damage; 1779428d7b3dSmrg pixman_region16_t ref; 1780428d7b3dSmrg int iter, i; 1781428d7b3dSmrg 1782428d7b3dSmrg iter = 1 + rand() % (1 + (pass / 64)); 1783428d7b3dSmrg DBG(("%s: pass %d, iters=%d\n", __FUNCTION__, pass, iter)); 1784428d7b3dSmrg 1785428d7b3dSmrg test.width = 1 + rand() % 2048; 1786428d7b3dSmrg test.height = 1 + rand() % 2048; 1787428d7b3dSmrg 1788428d7b3dSmrg damage = _sna_damage_create(); 1789428d7b3dSmrg pixman_region_init(&ref); 1790428d7b3dSmrg 1791428d7b3dSmrg for (i = 0; i < iter; i++) { 1792428d7b3dSmrg op[rand() % ARRAY_SIZE(op)](&test, &damage, &ref); 1793428d7b3dSmrg } 1794428d7b3dSmrg 1795428d7b3dSmrg if (!check[rand() % ARRAY_SIZE(check)](&test, &damage, &ref)) { 1796428d7b3dSmrg FatalError("%s: failed - region = %s, damage = %s\n", __FUNCTION__, 1797428d7b3dSmrg _debug_describe_region(region_buf, sizeof(region_buf), &ref), 1798428d7b3dSmrg _debug_describe_damage(damage_buf, sizeof(damage_buf), damage)); 1799428d7b3dSmrg } 1800428d7b3dSmrg 1801428d7b3dSmrg pixman_region_fini(&ref); 1802428d7b3dSmrg sna_damage_destroy(&damage); 1803428d7b3dSmrg } 1804428d7b3dSmrg} 1805428d7b3dSmrg#endif 1806428d7b3dSmrg 1807428d7b3dSmrgvoid _sna_damage_debug_get_region(struct sna_damage *damage, RegionRec *r) 1808428d7b3dSmrg{ 1809428d7b3dSmrg int n, nboxes; 1810428d7b3dSmrg BoxPtr boxes; 1811428d7b3dSmrg struct sna_damage_box *iter; 1812428d7b3dSmrg 1813428d7b3dSmrg RegionCopy(r, &damage->region); 1814428d7b3dSmrg if (!damage->dirty) 1815428d7b3dSmrg return; 1816428d7b3dSmrg 1817428d7b3dSmrg nboxes = damage->embedded_box.size; 1818428d7b3dSmrg list_for_each_entry(iter, &damage->embedded_box.list, list) 1819428d7b3dSmrg nboxes += iter->size; 1820428d7b3dSmrg nboxes -= damage->remain; 1821428d7b3dSmrg if (nboxes == 0) 1822428d7b3dSmrg return; 1823428d7b3dSmrg 1824428d7b3dSmrg if (nboxes == 1) { 1825428d7b3dSmrg pixman_region16_t tmp; 1826428d7b3dSmrg 1827428d7b3dSmrg tmp.extents = damage->embedded_box.box[0]; 1828428d7b3dSmrg tmp.data = NULL; 1829428d7b3dSmrg 1830428d7b3dSmrg if (damage->mode == DAMAGE_ADD) 1831428d7b3dSmrg pixman_region_union(r, r, &tmp); 1832428d7b3dSmrg else 1833428d7b3dSmrg pixman_region_subtract(r, r, &tmp); 1834428d7b3dSmrg 1835428d7b3dSmrg return; 1836428d7b3dSmrg } 1837428d7b3dSmrg 1838428d7b3dSmrg if (damage->mode == DAMAGE_ADD) 1839428d7b3dSmrg nboxes += region_num_rects(r); 1840428d7b3dSmrg 1841428d7b3dSmrg iter = last_box(damage); 1842428d7b3dSmrg n = iter->size - damage->remain; 1843428d7b3dSmrg boxes = malloc(sizeof(BoxRec)*nboxes); 1844428d7b3dSmrg if (boxes == NULL) 1845428d7b3dSmrg return; 1846428d7b3dSmrg 1847428d7b3dSmrg if (list_is_empty(&damage->embedded_box.list)) { 1848428d7b3dSmrg memcpy(boxes, 1849428d7b3dSmrg damage->embedded_box.box, 1850428d7b3dSmrg n*sizeof(BoxRec)); 1851428d7b3dSmrg } else { 1852428d7b3dSmrg if (boxes != (BoxPtr)(iter+1)) 1853428d7b3dSmrg memcpy(boxes, iter+1, n*sizeof(BoxRec)); 1854428d7b3dSmrg 1855428d7b3dSmrg iter = list_entry(iter->list.prev, 1856428d7b3dSmrg struct sna_damage_box, 1857428d7b3dSmrg list); 1858428d7b3dSmrg while (&iter->list != &damage->embedded_box.list) { 1859428d7b3dSmrg memcpy(boxes + n, iter+1, 1860428d7b3dSmrg iter->size * sizeof(BoxRec)); 1861428d7b3dSmrg n += iter->size; 1862428d7b3dSmrg 1863428d7b3dSmrg iter = list_entry(iter->list.prev, 1864428d7b3dSmrg struct sna_damage_box, 1865428d7b3dSmrg list); 1866428d7b3dSmrg } 1867428d7b3dSmrg 1868428d7b3dSmrg memcpy(boxes + n, 1869428d7b3dSmrg damage->embedded_box.box, 1870428d7b3dSmrg sizeof(damage->embedded_box.box)); 1871428d7b3dSmrg n += damage->embedded_box.size; 1872428d7b3dSmrg } 1873428d7b3dSmrg 1874428d7b3dSmrg if (damage->mode == DAMAGE_ADD) { 1875428d7b3dSmrg memcpy(boxes + n, 1876428d7b3dSmrg region_rects(r), 1877428d7b3dSmrg region_num_rects(r)*sizeof(BoxRec)); 1878428d7b3dSmrg assert(n + region_num_rects(r) == nboxes); 1879428d7b3dSmrg pixman_region_fini(r); 1880428d7b3dSmrg pixman_region_init_rects(r, boxes, nboxes); 1881428d7b3dSmrg 1882428d7b3dSmrg assert(pixman_region_not_empty(r)); 1883428d7b3dSmrg assert(damage->extents.x1 == r->extents.x1 && 1884428d7b3dSmrg damage->extents.y1 == r->extents.y1 && 1885428d7b3dSmrg damage->extents.x2 == r->extents.x2 && 1886428d7b3dSmrg damage->extents.y2 == r->extents.y2); 1887428d7b3dSmrg } else { 1888428d7b3dSmrg pixman_region16_t tmp; 1889428d7b3dSmrg 1890428d7b3dSmrg pixman_region_init_rects(&tmp, boxes, nboxes); 1891428d7b3dSmrg pixman_region_subtract(r, r, &tmp); 1892428d7b3dSmrg pixman_region_fini(&tmp); 1893428d7b3dSmrg 1894428d7b3dSmrg assert(damage->extents.x1 <= r->extents.x1 && 1895428d7b3dSmrg damage->extents.y1 <= r->extents.y1 && 1896428d7b3dSmrg damage->extents.x2 >= r->extents.x2 && 1897428d7b3dSmrg damage->extents.y2 >= r->extents.y2); 1898428d7b3dSmrg } 1899428d7b3dSmrg 1900428d7b3dSmrg free(boxes); 1901428d7b3dSmrg} 1902