diff options
-rw-r--r-- | src/sna/sna_damage.c | 402 | ||||
-rw-r--r-- | src/sna/sna_damage.h | 16 |
2 files changed, 163 insertions, 255 deletions
diff --git a/src/sna/sna_damage.c b/src/sna/sna_damage.c index b194e93b..85d9d691 100644 --- a/src/sna/sna_damage.c +++ b/src/sna/sna_damage.c @@ -125,15 +125,17 @@ static const char *_debug_describe_damage(char *buf, int max, snprintf(buf, max, "[[(%d, %d), (%d, %d)]: all]", damage->extents.x1, damage->extents.y1, damage->extents.x2, damage->extents.y2); - assert(damage->n == 0); } else { - sprintf(damage_str, "[%d : ...]", damage->n); - snprintf(buf, max, "[[(%d, %d), (%d, %d)]: %s %c %s]", + if (damage->dirty) { + sprintf(damage_str, "%c[ ...]", + damage->mode == DAMAGE_SUBTRACT ? '-' : '+'); + } else + damage_str = ""; + snprintf(buf, max, "[[(%d, %d), (%d, %d)]: %s %s]", damage->extents.x1, damage->extents.y1, damage->extents.x2, damage->extents.y2, _debug_describe_region(region_str, str_max, &damage->region), - damage->mode == DAMAGE_SUBTRACT ? '-' : '+', damage_str); } @@ -142,15 +144,17 @@ static const char *_debug_describe_damage(char *buf, int max, #endif -struct sna_damage_box { - struct list list; - uint16_t size, remain; -}; +static struct sna_damage_box * +reset_embedded_box(struct sna_damage *damage) +{ + damage->dirty = false; + damage->box = damage->embedded_box.box; + damage->embedded_box.size = + damage->remain = ARRAY_SIZE(damage->embedded_box.box); + list_init(&damage->embedded_box.list); -struct sna_damage_elt { - BoxPtr box; - uint16_t n; -}; + return (struct sna_damage_box *)&damage->embedded_box; +} static struct sna_damage *_sna_damage_create(void) { @@ -164,80 +168,62 @@ static struct sna_damage *_sna_damage_create(void) if (damage == NULL) return NULL; } - list_init(&damage->boxes); - damage->last_box = NULL; + reset_embedded_box(damage); damage->mode = DAMAGE_ADD; pixman_region_init(&damage->region); damage->extents.x1 = damage->extents.y1 = MAXSHORT; damage->extents.x2 = damage->extents.y2 = MINSHORT; - damage->n = 0; - damage->size = 16; - damage->elts = malloc(sizeof(*damage->elts) * damage->size); - if (damage->elts == NULL) { - __freed_damage = damage; - return NULL; - } - return damage; } -static BoxPtr _sna_damage_create_boxes(struct sna_damage *damage, - int count) +struct sna_damage_box { + struct list list; + int size; +}; + +static bool _sna_damage_create_boxes(struct sna_damage *damage, + int count) { struct sna_damage_box *box; int n; - if (damage->last_box && damage->last_box->remain >= count) { - box = damage->last_box; - n = box->size - box->remain; - DBG((" %s(%d): reuse last box, used=%d, remain=%d\n", - __FUNCTION__, count, n, box->remain)); - box->remain -= count; - if (box->remain == 0) - damage->last_box = NULL; - return (BoxPtr)(box+1) + n; - } - - n = ALIGN(count, 64); + box = list_entry(damage->embedded_box.list.prev, + struct sna_damage_box, + list); + n = 2*box->size; + if (n < count) + n = ALIGN(count, 64); DBG((" %s(%d->%d): new\n", __FUNCTION__, count, n)); box = malloc(sizeof(*box) + sizeof(BoxRec)*n); if (box == NULL) - return NULL; + return false; - box->size = n; - box->remain = n - count; - list_add(&box->list, &damage->boxes); + list_add(&box->list, &damage->embedded_box.list); - damage->last_box = box; - return (BoxPtr)(box+1); + box->size = damage->remain = n; + damage->box = (BoxRec *)(box + 1); + return true; } static void _sna_damage_create_elt(struct sna_damage *damage, const BoxRec *boxes, int count) { - struct sna_damage_elt *elt; - - DBG((" %s: n=%d, prev=(remain %d)\n", __FUNCTION__, - damage->n, - damage->last_box ? damage->last_box->remain : 0)); - - if (damage->last_box) { - int n; + int n; - n = count; - if (n > damage->last_box->remain) - n = damage->last_box->remain; + DBG((" %s: prev=(remain %d)\n", __FUNCTION__, damage->remain)); - elt = damage->elts + damage->n-1; - memcpy(elt->box + elt->n, boxes, n * sizeof(BoxRec)); - elt->n += n; - damage->last_box->remain -= n; - if (damage->last_box->remain == 0) - damage->last_box = NULL; + damage->dirty = true; + n = count; + if (n > damage->remain) + n = damage->remain; + if (n) { + memcpy(damage->box, boxes, n * sizeof(BoxRec)); + damage->box += n; + damage->remain -= n; count -=n; boxes += n; @@ -245,28 +231,14 @@ _sna_damage_create_elt(struct sna_damage *damage, return; } - if (damage->n == damage->size) { - int newsize = damage->size * 2; - struct sna_damage_elt *newelts = realloc(damage->elts, - newsize*sizeof(*elt)); - if (newelts == NULL) - return; - - damage->elts = newelts; - damage->size = newsize; - } - DBG((" %s(): new elt\n", __FUNCTION__)); - elt = damage->elts + damage->n++; - elt->n = count; - elt->box = _sna_damage_create_boxes(damage, count); - if (elt->box == NULL){ - damage->n--; + if (!_sna_damage_create_boxes(damage, count)) return; - } - memcpy(elt->box, boxes, count * sizeof(BoxRec)); + memcpy(damage->box, boxes, count * sizeof(BoxRec)); + damage->box += count; + damage->remain -= count; } static void @@ -274,33 +246,22 @@ _sna_damage_create_elt_from_boxes(struct sna_damage *damage, const BoxRec *boxes, int count, int16_t dx, int16_t dy) { - struct sna_damage_elt *elt; - int i; - - DBG((" %s: n=%d, prev=(remain %d)\n", __FUNCTION__, - damage->n, - damage->last_box ? damage->last_box->remain : 0)); - - if (damage->last_box) { - int n; - BoxRec *b; + int i, n; - n = count; - if (n > damage->last_box->remain) - n = damage->last_box->remain; + DBG((" %s: prev=(remain %d)\n", __FUNCTION__, damage->remain)); - elt = damage->elts + damage->n-1; - b = elt->box + elt->n; + n = count; + if (n > damage->remain) + n = damage->remain; + if (n) { for (i = 0; i < n; i++) { - b[i].x1 = boxes[i].x1 + dx; - b[i].x2 = boxes[i].x2 + dx; - b[i].y1 = boxes[i].y1 + dy; - b[i].y2 = boxes[i].y2 + dy; + damage->box[i].x1 = boxes[i].x1 + dx; + damage->box[i].x2 = boxes[i].x2 + dx; + damage->box[i].y1 = boxes[i].y1 + dy; + damage->box[i].y2 = boxes[i].y2 + dy; } - elt->n += n; - damage->last_box->remain -= n; - if (damage->last_box->remain == 0) - damage->last_box = NULL; + damage->box += n; + damage->remain -= n; count -=n; boxes += n; @@ -308,33 +269,19 @@ _sna_damage_create_elt_from_boxes(struct sna_damage *damage, return; } - if (damage->n == damage->size) { - int newsize = damage->size * 2; - struct sna_damage_elt *newelts = realloc(damage->elts, - newsize*sizeof(*elt)); - if (newelts == NULL) - return; - - damage->elts = newelts; - damage->size = newsize; - } - DBG((" %s(): new elt\n", __FUNCTION__)); - elt = damage->elts + damage->n++; - elt->n = count; - elt->box = _sna_damage_create_boxes(damage, count); - if (elt->box == NULL) { - damage->n--; + if (!_sna_damage_create_boxes(damage, count)) return; - } for (i = 0; i < count; i++) { - elt->box[i].x1 = boxes[i].x1 + dx; - elt->box[i].x2 = boxes[i].x2 + dx; - elt->box[i].y1 = boxes[i].y1 + dy; - elt->box[i].y2 = boxes[i].y2 + dy; + damage->box[i].x1 = boxes[i].x1 + dx; + damage->box[i].x2 = boxes[i].x2 + dx; + damage->box[i].y1 = boxes[i].y1 + dy; + damage->box[i].y2 = boxes[i].y2 + dy; } + damage->box += i; + damage->remain -= i; } static void @@ -342,33 +289,22 @@ _sna_damage_create_elt_from_rectangles(struct sna_damage *damage, const xRectangle *r, int count, int16_t dx, int16_t dy) { - struct sna_damage_elt *elt; - int i; - - DBG((" %s: n=%d, prev=(remain %d)\n", __FUNCTION__, - damage->n, - damage->last_box ? damage->last_box->remain : 0)); - - if (damage->last_box) { - int n; - BoxRec *b; + int i, n; - n = count; - if (n > damage->last_box->remain) - n = damage->last_box->remain; + DBG((" %s: prev=(remain %d)\n", __FUNCTION__, damage->remain)); - elt = damage->elts + damage->n-1; - b = elt->box + elt->n; + n = count; + if (n > damage->remain) + n = damage->remain; + if (n) { for (i = 0; i < n; i++) { - b[i].x1 = r[i].x + dx; - b[i].x2 = b[i].x1 + r[i].width; - b[i].y1 = r[i].y + dy; - b[i].y2 = b[i].y1 + r[i].height; + damage->box[i].x1 = r[i].x + dx; + damage->box[i].x2 = damage->box[i].x1 + r[i].width; + damage->box[i].y1 = r[i].y + dy; + damage->box[i].y2 = damage->box[i].y1 + r[i].height; } - elt->n += n; - damage->last_box->remain -= n; - if (damage->last_box->remain == 0) - damage->last_box = NULL; + damage->box += n; + damage->remain -= n; count -=n; r += n; @@ -376,33 +312,19 @@ _sna_damage_create_elt_from_rectangles(struct sna_damage *damage, return; } - if (damage->n == damage->size) { - int newsize = damage->size * 2; - struct sna_damage_elt *newelts = realloc(damage->elts, - newsize*sizeof(*elt)); - if (newelts == NULL) - return; - - damage->elts = newelts; - damage->size = newsize; - } - DBG((" %s(): new elt\n", __FUNCTION__)); - elt = damage->elts + damage->n++; - elt->n = count; - elt->box = _sna_damage_create_boxes(damage, count); - if (elt->box == NULL) { - damage->n--; + if (!_sna_damage_create_boxes(damage, count)) return; - } for (i = 0; i < count; i++) { - elt->box[i].x1 = r[i].x + dx; - elt->box[i].x2 = elt->box[i].x1 + r[i].width; - elt->box[i].y1 = r[i].y + dy; - elt->box[i].y2 = elt->box[i].y1 + r[i].height; + damage->box[i].x1 = r[i].x + dx; + damage->box[i].x2 = damage->box[i].x1 + r[i].width; + damage->box[i].y1 = r[i].y + dy; + damage->box[i].y2 = damage->box[i].y1 + r[i].height; } + damage->box += n; + damage->remain -= n; } static void @@ -410,33 +332,22 @@ _sna_damage_create_elt_from_points(struct sna_damage *damage, const DDXPointRec *p, int count, int16_t dx, int16_t dy) { - struct sna_damage_elt *elt; - int i; - - DBG((" %s: n=%d, prev=(remain %d)\n", __FUNCTION__, - damage->n, - damage->last_box ? damage->last_box->remain : 0)); + int i, n; - if (damage->last_box) { - int n; - BoxRec *b; + DBG((" %s: prev=(remain %d)\n", __FUNCTION__, damage->remain)); - n = count; - if (n > damage->last_box->remain) - n = damage->last_box->remain; - - elt = damage->elts + damage->n-1; - b = elt->box + elt->n; + n = count; + if (n > damage->remain) + n = damage->remain; + if (n) { for (i = 0; i < n; i++) { - b[i].x1 = p[i].x + dx; - b[i].x2 = b[i].x1 + 1; - b[i].y1 = p[i].y + dy; - b[i].y2 = b[i].y1 + 1; + damage->box[i].x1 = p[i].x + dx; + damage->box[i].x2 = damage->box[i].x1 + 1; + damage->box[i].y1 = p[i].y + dy; + damage->box[i].y2 = damage->box[i].y1 + 1; } - elt->n += n; - damage->last_box->remain -= n; - if (damage->last_box->remain == 0) - damage->last_box = NULL; + damage->box += n; + damage->remain -= n; count -=n; p += n; @@ -444,33 +355,19 @@ _sna_damage_create_elt_from_points(struct sna_damage *damage, return; } - if (damage->n == damage->size) { - int newsize = damage->size * 2; - struct sna_damage_elt *newelts = realloc(damage->elts, - newsize*sizeof(*elt)); - if (newelts == NULL) - return; - - damage->elts = newelts; - damage->size = newsize; - } - DBG((" %s(): new elt\n", __FUNCTION__)); - elt = damage->elts + damage->n++; - elt->n = count; - elt->box = _sna_damage_create_boxes(damage, count); - if (elt->box == NULL) { - damage->n--; + if (! _sna_damage_create_boxes(damage, count)) return; - } for (i = 0; i < count; i++) { - elt->box[i].x1 = p[i].x + dx; - elt->box[i].x2 = elt->box[i].x1 + 1; - elt->box[i].y1 = p[i].y + dy; - elt->box[i].y2 = elt->box[i].y1 + 1; + damage->box[i].x1 = p[i].x + dx; + damage->box[i].x2 = damage->box[i].x1 + 1; + damage->box[i].y1 = p[i].y + dy; + damage->box[i].y2 = damage->box[i].y1 + 1; } + damage->box += count; + damage->remain -= count; } static void free_list(struct list *head) @@ -487,28 +384,35 @@ static void __sna_damage_reduce(struct sna_damage *damage) int n, nboxes; BoxPtr boxes; pixman_region16_t tmp, *region = &damage->region; + struct sna_damage_box *iter; assert(damage->mode != DAMAGE_ALL); - assert(damage->n); - - DBG((" reduce: before damage.n=%d region.n=%d\n", - damage->n, REGION_NUM_RECTS(region))); - - nboxes = damage->elts[0].n; - if (damage->n == 1) { - boxes = damage->elts[0].box; - } else { - for (n = 1; n < damage->n; n++) - nboxes += damage->elts[n].n; - + assert(damage->dirty); + + DBG((" reduce: before region.n=%d\n", REGION_NUM_RECTS(region))); + + nboxes = damage->embedded_box.size; + boxes = damage->embedded_box.box; + list_for_each_entry(iter, &damage->embedded_box.list, list) + nboxes += iter->size; + nboxes -= damage->remain; + if (nboxes == 0) + goto done; + if (nboxes > damage->embedded_box.size) { boxes = malloc(sizeof(BoxRec)*nboxes); - nboxes = 0; - for (n = 0; n < damage->n; n++) { - memcpy(boxes+nboxes, - damage->elts[n].box, - damage->elts[n].n*sizeof(BoxRec)); - nboxes += damage->elts[n].n; + if (boxes == NULL) + goto done; + + memcpy(boxes, damage->embedded_box.box, sizeof(damage->embedded_box.box)); + n = damage->embedded_box.size; + list_for_each_entry(iter, &damage->embedded_box.list, list) { + int len = iter->size; + if (n + len > nboxes) + len = nboxes - n; + memcpy(boxes + n, iter+1, len * sizeof(BoxRec)); + n += len; } + assert(n == nboxes); } pixman_region_init_rects(&tmp, boxes, nboxes); @@ -517,16 +421,15 @@ static void __sna_damage_reduce(struct sna_damage *damage) else pixman_region_subtract(region, region, &tmp); pixman_region_fini(&tmp); + if (boxes != damage->embedded_box.box) + free(boxes); damage->extents = region->extents; - if (boxes != damage->elts[0].box) - free(boxes); - - damage->n = 0; +done: damage->mode = DAMAGE_ADD; - free_list(&damage->boxes); - damage->last_box = NULL; + free_list(&damage->embedded_box.list); + reset_embedded_box(damage); DBG((" reduce: after region.n=%d\n", REGION_NUM_RECTS(region))); } @@ -651,7 +554,7 @@ __sna_damage_add_boxes(struct sna_damage *damage, _sna_damage_create_elt_from_boxes(damage, box, n, dx, dy); if (REGION_NUM_RECTS(&damage->region) == 0) { - damage->region.extents = *damage->elts[0].box; + damage->region.extents = box[0]; damage->region.data = NULL; damage->extents = extents; } else { @@ -754,7 +657,10 @@ __sna_damage_add_rectangles(struct sna_damage *damage, _sna_damage_create_elt_from_rectangles(damage, r, n, dx, dy); if (REGION_NUM_RECTS(&damage->region) == 0) { - damage->region.extents = *damage->elts[0].box; + damage->region.extents.x1 = r[0].x + dx; + damage->region.extents.x2 = r[0].x + r[0].width + dx; + damage->region.extents.y1 = r[0].y + dy; + damage->region.extents.y2 = r[0].y + r[0].height + dy; damage->region.data = NULL; damage->extents = extents; } else { @@ -848,7 +754,10 @@ __sna_damage_add_points(struct sna_damage *damage, _sna_damage_create_elt_from_points(damage, p, n, dx, dy); if (REGION_NUM_RECTS(&damage->region) == 0) { - damage->region.extents = *damage->elts[0].box; + damage->region.extents.x1 = p[0].x + dx; + damage->region.extents.x2 = p[0].x + dx + 1; + damage->region.extents.y1 = p[0].y + dy; + damage->region.extents.y2 = p[0].y + dy + 1; damage->region.data = NULL; damage->extents = extents; } else { @@ -973,10 +882,9 @@ struct sna_damage *_sna_damage_all(struct sna_damage *damage, DBG(("%s(%d, %d)\n", __FUNCTION__, width, height)); if (damage) { - free_list(&damage->boxes); pixman_region_fini(&damage->region); - damage->n = 0; - damage->last_box = NULL; + free_list(&damage->embedded_box.list); + reset_embedded_box(damage); } else { damage = _sna_damage_create(); if (damage == NULL) @@ -993,7 +901,7 @@ struct sna_damage *_sna_damage_all(struct sna_damage *damage, struct sna_damage *_sna_damage_is_all(struct sna_damage *damage, int width, int height) { - if (damage->n) + if (damage->dirty) __sna_damage_reduce(damage); if (damage->region.data) @@ -1039,7 +947,7 @@ static struct sna_damage *__sna_damage_subtract(struct sna_damage *damage, return damage; if (damage->mode != DAMAGE_SUBTRACT) { - if (damage->n) + if (damage->dirty) __sna_damage_reduce(damage); if (pixman_region_equal(region, &damage->region)) { @@ -1112,7 +1020,7 @@ inline static struct sna_damage *__sna_damage_subtract_box(struct sna_damage *da return damage; if (damage->mode != DAMAGE_SUBTRACT) { - if (damage->n) + if (damage->dirty) __sna_damage_reduce(damage); if (!pixman_region_not_empty(&damage->region)) { @@ -1182,7 +1090,7 @@ static int _sna_damage_contains_box(struct sna_damage *damage, __sna_damage_reduce(damage); ret = pixman_region_contains_rectangle(&damage->region, (BoxPtr)box); - if (ret != PIXMAN_REGION_OUT || damage->n == 0) + if (ret != PIXMAN_REGION_OUT || !damage->dirty) return ret; __sna_damage_reduce(damage); @@ -1236,7 +1144,7 @@ static Bool _sna_damage_intersect(struct sna_damage *damage, region->extents.y1 >= damage->extents.y2) return FALSE; - if (damage->n) + if (damage->dirty) __sna_damage_reduce(damage); if (!pixman_region_not_empty(&damage->region)) @@ -1280,7 +1188,7 @@ static int _sna_damage_get_boxes(struct sna_damage *damage, BoxPtr *boxes) if (!damage) return 0; - if (damage->n) + if (damage->dirty) __sna_damage_reduce(damage); *boxes = REGION_RECTS(&damage->region); @@ -1323,9 +1231,7 @@ int sna_damage_get_boxes(struct sna_damage *damage, BoxPtr *boxes) void __sna_damage_destroy(struct sna_damage *damage) { - free(damage->elts); - - free_list(&damage->boxes); + free_list(&damage->embedded_box.list); pixman_region_fini(&damage->region); if (__freed_damage == NULL) diff --git a/src/sna/sna_damage.h b/src/sna/sna_damage.h index 0e681b79..d74d5de4 100644 --- a/src/sna/sna_damage.h +++ b/src/sna/sna_damage.h @@ -6,7 +6,6 @@ #include "compiler.h" -struct sna_damage_elt; struct sna_damage_box; struct sna_damage { @@ -17,10 +16,13 @@ struct sna_damage { DAMAGE_SUBTRACT, DAMAGE_ALL, } mode; - int n, size; - struct sna_damage_elt *elts; - struct sna_damage_box *last_box; - struct list boxes; + int remain, dirty; + BoxPtr box; + struct { + struct list list; + int size; + BoxRec box[8]; + } embedded_box; }; fastcall struct sna_damage *_sna_damage_add(struct sna_damage *damage, @@ -133,7 +135,7 @@ static inline void sna_damage_reduce(struct sna_damage **damage) if (*damage == NULL) return; - if ((*damage)->n) + if ((*damage)->dirty) *damage = _sna_damage_reduce(*damage); } @@ -145,7 +147,7 @@ static inline void sna_damage_reduce_all(struct sna_damage **damage, if (*damage == NULL) return; - if ((*damage)->n && (*damage = _sna_damage_reduce(*damage)) == NULL) + if ((*damage)->dirty && (*damage = _sna_damage_reduce(*damage)) == NULL) return; if ((*damage)->mode == DAMAGE_ADD && |