sna: Remove the independent tracking of elts from boxes

Following the switch to a global mode for damage, the elts array became
redundant and all that is required is the list of boxes.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson 2011-12-24 02:49:24 +00:00
parent 73df0c7ab7
commit 098592ca5d
2 changed files with 161 additions and 253 deletions

View File

@ -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;
int n;
DBG((" %s: n=%d, prev=(remain %d)\n", __FUNCTION__,
damage->n,
damage->last_box ? damage->last_box->remain : 0));
DBG((" %s: prev=(remain %d)\n", __FUNCTION__, damage->remain));
if (damage->last_box) {
int n;
n = count;
if (n > damage->last_box->remain)
n = damage->last_box->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;
int i, n;
DBG((" %s: n=%d, prev=(remain %d)\n", __FUNCTION__,
damage->n,
damage->last_box ? damage->last_box->remain : 0));
DBG((" %s: prev=(remain %d)\n", __FUNCTION__, damage->remain));
if (damage->last_box) {
int n;
BoxRec *b;
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 = 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;
int i, n;
DBG((" %s: n=%d, prev=(remain %d)\n", __FUNCTION__,
damage->n,
damage->last_box ? damage->last_box->remain : 0));
DBG((" %s: prev=(remain %d)\n", __FUNCTION__, damage->remain));
if (damage->last_box) {
int n;
BoxRec *b;
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 = 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;
int i, n;
DBG((" %s: n=%d, prev=(remain %d)\n", __FUNCTION__,
damage->n,
damage->last_box ? damage->last_box->remain : 0));
DBG((" %s: prev=(remain %d)\n", __FUNCTION__, damage->remain));
if (damage->last_box) {
int n;
BoxRec *b;
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);
assert(damage->dirty);
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;
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)

View File

@ -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 &&