* eina: Faster Eina_Rectangle_Pool (should be used by OpenGL engine).

SVN revision: 41185
This commit is contained in:
Cedric BAIL 2009-06-24 13:38:25 +00:00
parent 8a363fec23
commit 3b384b323c
2 changed files with 123 additions and 104 deletions

View File

@ -54,6 +54,8 @@ struct _Eina_Rectangle_Pool
unsigned int references; unsigned int references;
int w; int w;
int h; int h;
Eina_Bool sorted;
EINA_MAGIC EINA_MAGIC
}; };
@ -80,122 +82,122 @@ static int _eina_rectangle_init_count = 0;
static Eina_Mempool *_eina_rectangle_alloc_mp = NULL; static Eina_Mempool *_eina_rectangle_alloc_mp = NULL;
static Eina_Mempool *_eina_rectangle_mp = NULL; static Eina_Mempool *_eina_rectangle_mp = NULL;
static inline Eina_Bool static int
_eina_rectangle_pool_collide(Eina_Rectangle_Alloc *head, Eina_Rectangle_Alloc *current, Eina_Rectangle *test) _eina_rectangle_cmp(const Eina_Rectangle *r1, const Eina_Rectangle *r2)
{ {
Eina_Rectangle_Alloc *collide; return (r2->w * r2->h) - (r1->w * r1->h);
EINA_INLIST_FOREACH(head, collide)
{
Eina_Rectangle *colliding_rect = (Eina_Rectangle*) (collide + 1);
if (collide == current) continue;
if (eina_rectangles_intersect(colliding_rect, test))
return EINA_TRUE;
}
return EINA_FALSE;
} }
static Eina_Bool static Eina_List *
_eina_rectangle_pool_find(Eina_Rectangle_Alloc *head, int poolw, int poolh, int w, int h, int *x, int *y) _eina_rectangle_merge_list(Eina_List *empty, Eina_Rectangle *r)
{ {
Eina_Rectangle_Alloc *item; Eina_Rectangle *match;
Eina_Rectangle tmp = { 0, 0, 0, 0 }; Eina_List *l;
if (head == NULL) goto on_intersect; if (r->w == 0 || r->h == 0)
EINA_INLIST_FOREACH(head, item)
{ {
Eina_Rectangle *rect = (Eina_Rectangle*) (item + 1); eina_rectangle_free(r);
Eina_Bool t1 = EINA_TRUE; return empty;
Eina_Bool t2 = EINA_TRUE; }
Eina_Bool t3 = EINA_TRUE;
Eina_Bool t4 = EINA_TRUE;
if ((rect->x + rect->w + w) > poolw) t1 = EINA_FALSE; EINA_LIST_FOREACH(empty, l, match)
if ((rect->y + h) > poolh) t1 = EINA_FALSE; {
if ((rect->y + rect->h + h) > poolh) t2 = EINA_FALSE; if (match->x == r->x && match->w == r->w)
if ((rect->x + w) > poolw) t2 = EINA_FALSE;
if ((rect->x - w) < 0) t3 = EINA_FALSE;
if ((rect->y + h) > poolh) t3 = EINA_FALSE;
if ((rect->x + w) > poolw) t4 = EINA_FALSE;
if ((rect->y - h) < 0) t4 = EINA_FALSE;
if (t1)
{ {
Eina_Bool intersects; if (match->y > r->y)
/* 1. try here: match->y = r->y;
* +----++--+ match->h += r->h;
* |AAAA||??|
* |AAAA|+--+
* |AAAA|
* +----+
*/
eina_rectangle_coords_from(&tmp, rect->x + rect->w, rect->y, w, h);
intersects = _eina_rectangle_pool_collide(head, item, &tmp);
if (!intersects) goto on_intersect; eina_rectangle_free(r);
empty = eina_list_remove_list(empty, l);
return _eina_rectangle_merge_list(empty, match);
} }
if (t2) else if (match->y == r->y && match->h == r->h)
{ {
Eina_Bool intersects; if (match->x > r->x)
/* 2. try here: match->x = r->x;
* +----+ match->w += r->w;
* |AAAA|
* |AAAA|
* |AAAA|
* +----+
* +--+
* |??|
* +--+
*/
eina_rectangle_coords_from(&tmp, rect->x, rect->y + rect->h, w, h);
intersects = _eina_rectangle_pool_collide(head, item, &tmp);
if (!intersects) goto on_intersect; eina_rectangle_free(r);
}
if (t3)
{
Eina_Bool intersects;
/* 3. try here:
* +--++----+
* |??||AAAA|
* +--+|AAAA|
* |AAAA|
* +----+
*/
eina_rectangle_coords_from(&tmp, rect->x - w, rect->y, w, h);
intersects = _eina_rectangle_pool_collide(head, item, &tmp);
if (!intersects) goto on_intersect; empty = eina_list_remove_list(empty, l);
}
if (t4)
{
Eina_Bool intersects;
/* 2. try here:
* +--+
* |??|
* +--+
* +----+
* |AAAA|
* |AAAA|
* |AAAA|
* +----+
*/
eina_rectangle_coords_from(&tmp, rect->x, rect->y - h, w, h);
intersects = _eina_rectangle_pool_collide(head, item, &tmp);
if (!intersects) goto on_intersect; return _eina_rectangle_merge_list(empty, match);
} }
} }
return EINA_FALSE; return eina_list_append(empty, r);
}
on_intersect: static Eina_List *
*x = tmp.x; _eina_rectangle_empty_space_find(Eina_List *empty, int w, int h, int *x, int *y)
*y = tmp.y; {
return EINA_TRUE; Eina_Rectangle *r;
Eina_List *l;
EINA_LIST_FOREACH(empty, l, r)
{
if (r->w >= w && r->h >= h)
{
/* Remove l from empty */
empty = eina_list_remove_list(empty, l);
/* Remember x and y */
*x = r->x;
*y = r->y;
/* Split r in 2 rectangle if needed (only the empty one) and insert them */
if (r->w == w)
{
r->y += h;
r->h -= h;
empty = _eina_rectangle_merge_list(empty, r);
}
else if (r->h == h)
{
r->x += w;
r->w -= w;
empty = _eina_rectangle_merge_list(empty, r);
}
else
{
int x1, y1, w1, h1;
int x2, y2, w2, h2;
x1 = r->x + w;
y1 = r->y;
w1 = r->w - w;
/* h1 could be h or r->h */
x2 = r->x;
y2 = r->y + h;
/* w2 could be w or r->w */
h2 = r->h - h;
if (w1 * r->h > h2 * r->w)
{
h1 = r->h;
w2 = w;
}
else
{
h1 = h;
w2 = r->w;
}
EINA_RECTANGLE_SET(r, x1, y1, w1, h1);
empty = _eina_rectangle_merge_list(empty, r);
r = eina_rectangle_new(x2, y2, w2, h2);
if (r) empty = _eina_rectangle_merge_list(empty, r);
}
/* Return empty */
return empty;
}
}
*x = -1;
*y = -1;
return empty;
} }
/** /**
@ -280,16 +282,24 @@ eina_rectangle_pool_request(Eina_Rectangle_Pool *pool, int w, int h)
{ {
Eina_Rectangle_Alloc *new; Eina_Rectangle_Alloc *new;
Eina_Rectangle *rect; Eina_Rectangle *rect;
Eina_Bool test;
int x; int x;
int y; int y;
EINA_SAFETY_ON_NULL_RETURN_VAL(pool, NULL); EINA_SAFETY_ON_NULL_RETURN_VAL(pool, NULL);
if (w <= 0 || h <= 0) return NULL;
if (w > pool->w || h > pool->h) return NULL; if (w > pool->w || h > pool->h) return NULL;
test = _eina_rectangle_pool_find((Eina_Rectangle_Alloc*) pool->head, pool->w, pool->h, w, h, &x, &y); /* Sort empty if dirty */
if (!test) return NULL; if (pool->sorted)
{
pool->empty = eina_list_sort(pool->empty, 0, EINA_COMPARE_CB(_eina_rectangle_cmp));
pool->sorted = EINA_TRUE;
}
pool->empty = _eina_rectangle_empty_space_find(pool->empty, w, h, &x, &y);
if (x == -1) return NULL;
pool->sorted = EINA_FALSE;
new = eina_mempool_alloc(_eina_rectangle_alloc_mp, new = eina_mempool_alloc(_eina_rectangle_alloc_mp,
sizeof (Eina_Rectangle_Alloc) + sizeof (Eina_Rectangle)); sizeof (Eina_Rectangle_Alloc) + sizeof (Eina_Rectangle));
@ -312,6 +322,7 @@ EAPI void
eina_rectangle_pool_release(Eina_Rectangle *rect) eina_rectangle_pool_release(Eina_Rectangle *rect)
{ {
Eina_Rectangle_Alloc *era = ((Eina_Rectangle_Alloc *) rect) - 1; Eina_Rectangle_Alloc *era = ((Eina_Rectangle_Alloc *) rect) - 1;
Eina_Rectangle *r;
EINA_SAFETY_ON_NULL_RETURN(rect); EINA_SAFETY_ON_NULL_RETURN(rect);
@ -321,6 +332,13 @@ eina_rectangle_pool_release(Eina_Rectangle *rect)
era->pool->references--; era->pool->references--;
era->pool->head = eina_inlist_remove(era->pool->head, EINA_INLIST_GET(era)); era->pool->head = eina_inlist_remove(era->pool->head, EINA_INLIST_GET(era));
r = eina_rectangle_new(rect->x, rect->y, rect->w, rect->h);
if (r)
{
era->pool->empty = _eina_rectangle_merge_list(era->pool->empty, r);
era->pool->sorted = EINA_FALSE;
}
EINA_MAGIC_SET(era, EINA_MAGIC_NONE); EINA_MAGIC_SET(era, EINA_MAGIC_NONE);
eina_mempool_free(_eina_rectangle_alloc_mp, era); eina_mempool_free(_eina_rectangle_alloc_mp, era);
} }
@ -381,7 +399,7 @@ eina_rectangle_init(void)
if (!eina_error_init()) if (!eina_error_init())
{ {
fprintf(stderr, "Could not initialize eina error module.\n"); EINA_ERROR_PERR("Could not initialize eina error module.\n");
return 0; return 0;
} }
if (!eina_mempool_init()) if (!eina_mempool_init())

View File

@ -50,12 +50,13 @@ eina_bench_eina_rectangle_pool(int request)
{ {
rect = eina_list_data_get(list); rect = eina_list_data_get(list);
list = eina_list_remove_list(list, list); list = eina_list_remove_list(list, list);
eina_rectangle_pool_release(rect); if (rect) eina_rectangle_pool_release(rect);
} }
else else
{ {
list = eina_list_append(list, rect); list = eina_list_append(list, rect);
} }
if (!(i & 0xFF)) break;
} }
} }
@ -68,7 +69,7 @@ eina_bench_eina_rectangle_pool(int request)
void eina_bench_rectangle_pool(Eina_Benchmark *bench) void eina_bench_rectangle_pool(Eina_Benchmark *bench)
{ {
eina_benchmark_register(bench, "eina", EINA_BENCHMARK(eina_bench_eina_rectangle_pool), 10, 5000, 100); eina_benchmark_register(bench, "eina", EINA_BENCHMARK(eina_bench_eina_rectangle_pool), 10, 4000, 100);
} }