evas: improvement of Eina Rectangle Pool and integration with Evas GL backend.

Summary:
This patch introduce various new logic for packing/unpacking of Eina Rectangle in a pool.
It is then used by Evas GL backend texture allocation to improve how efficiently we pack
image in texture atlas. This lead to improved memory usage and reduced power consumption
with usually a more stable higher FPS (as it use less texture to do the same task, their
is less texture switch, so saving memory and speed at the same time).

This patch was developped on Cedric's suggestions to optimize the packing logic using Skyline
algorithm. This patch is based on master and is a new submission for earlier phab link
https://phab.enlightenment.org/D774.

Signed-off-by: Sanjay Nirankari <sanjay.n1@samsung.com>
Signed-off-by: Rajeev Ranjan <rajeev.r@samsung.com>
Signed-off-by: Sreedeep Moulik <sreedeep.m@samsung.com>

Reviewers: cedric, raster

CC: wonsik, jpeg, sreedeep.m, sanjay, govi

Differential Revision: https://phab.enlightenment.org/D1063

Signed-off-by: Cedric BAIL <c.bail@partner.samsung.com>
This commit is contained in:
Rajeev Ranjan 2014-06-19 14:35:37 +02:00 committed by Cedric BAIL
parent 2cebf6785e
commit bd65b5db5d
6 changed files with 442 additions and 112 deletions

View File

@ -130,6 +130,7 @@ Paulo Cavalcanti <paulo.cavalcanti@linux.intel.com>
Jean-Philippe Andre <jp.andre@samsung.com>
Yury Usischev <y.usishchev@samsung.com>
Youngbok Shin <youngb.shin@samsung.com>
Rajeev Ranjan (Rajeev) <rajeev.r@samsung.com> <rajeev.jnnce@gmail.com>
Ecore
-----

View File

@ -61,9 +61,13 @@ struct _Eina_Rectangle_Pool
Eina_List *empty;
void *data;
Eina_Compare_Cb eina_rectangle_compare_func;
Eina_Trash *bucket;
unsigned int bucket_count;
Eina_Rectangle_Packing type;
unsigned int references;
int w;
int h;
@ -109,18 +113,40 @@ static int _eina_rectangle_log_dom = -1;
#define DBG(...) EINA_LOG_DOM_DBG(_eina_rectangle_log_dom, __VA_ARGS__)
static int
_eina_rectangle_cmp(const Eina_Rectangle *r1, const Eina_Rectangle *r2)
_eina_rectangle_cmp(const void *data1, const void *data2)
{
Eina_Rectangle *r1 = (Eina_Rectangle *) data1;
Eina_Rectangle *r2 = (Eina_Rectangle *) data2;
return (r2->w * r2->h) - (r1->w * r1->h);
}
static Eina_List *
_eina_rectangle_merge_list(Eina_List *empty, Eina_Rectangle *r)
static int
_eina_rectangle_cmp_asc(const void *data1, const void *data2)
{
Eina_Rectangle *match;
Eina_Rectangle *r1 = (Eina_Rectangle *) data1;
Eina_Rectangle *r2 = (Eina_Rectangle *) data2;
return (r1->w * r1->h) - (r2->w * r2->h);
}
static int
_eina_rectangle_cmp_bl(const void *data1, const void *data2)
{
Eina_Rectangle *r1 = (Eina_Rectangle *) data1;
Eina_Rectangle *r2 = (Eina_Rectangle *) data2;
if (r1->y != r2->y)
return (r1->y) - (r2->y);
else
return (r1->x) - (r2->x);
}
static Eina_List *
_eina_rectangle_merge_list(Eina_List *empty, Eina_Rectangle_Packing type, Eina_Rectangle *r)
{
Eina_Rectangle *match, *r1;
Eina_List *l;
int xw;
int yh;
int x2 ,y2 ,w2 ,h2;
if (r->w == 0 || r->h == 0)
{
@ -164,6 +190,34 @@ start_again:
r = match;
goto start_again;
}
else if (match->y > r->y && type == Eina_Packing_Bottom_Left_Skyline
&& (match->y + match->h == r->y + r->h) &&
(match->x + match->w == r->x || r->x + r->w == match->x))
{
if (r->x < match->x)
match->x = r->x;
match->w += r->w;
x2 = r->x;
y2 = r->y;
w2 = r->w;
h2 = match->y - r->y;
eina_rectangle_free(r);
r1 = eina_rectangle_new(x2, y2, w2, h2);
empty = eina_list_remove_list(empty, l);
if (r1)
empty = eina_list_append(empty, r1);
r = match;
goto start_again;
}
}
@ -172,7 +226,7 @@ start_again:
}
static Eina_List *
_eina_rectangle_empty_space_find(Eina_List *empty, int w, int h, int *x, int *y)
_eina_rectangle_empty_space_find(Eina_List *empty, Eina_Rectangle_Packing type, int w, int h, int *x, int *y)
{
Eina_Rectangle *r;
Eina_List *l;
@ -211,7 +265,7 @@ _eina_rectangle_empty_space_find(Eina_List *empty, int w, int h, int *x, int *y)
/* w2 could be w or r->w */
h2 = r->h - h;
if (rw1 * r->h > h2 * r->w)
if ((rw1 * r->h > h2 * r->w) || type == Eina_Packing_Bottom_Left || type == Eina_Packing_Bottom_Left_Skyline)
{
rh1 = r->h;
w2 = w;
@ -221,16 +275,21 @@ _eina_rectangle_empty_space_find(Eina_List *empty, int w, int h, int *x, int *y)
rh1 = h;
w2 = r->w;
}
if (type == Eina_Packing_Bottom_Left_Skyline_Improved)
{
rh1 = r->h;
w2 = r->w;
}
EINA_RECTANGLE_SET(r, rx1, ry1, rw1, rh1);
empty = _eina_rectangle_merge_list(empty, r);
empty = _eina_rectangle_merge_list(empty, type, r);
r = eina_rectangle_new(x2, y2, w2, h2);
}
if (r)
{
empty = _eina_rectangle_merge_list(empty, r); /* Return empty */
empty = _eina_rectangle_merge_list(empty, type, r); /* Return empty */
}
@ -243,6 +302,216 @@ _eina_rectangle_empty_space_find(Eina_List *empty, int w, int h, int *x, int *y)
return empty;
}
static Eina_List *
_eina_rectangle_skyline_merge_list(Eina_List *empty, Eina_Rectangle *r)
{
Eina_Rectangle *match;
Eina_List *l;
EINA_LIST_FOREACH(empty, l, match)
{
if (match->x == r->x + r->w)
{
match->x = r->x;
match->w = r->w + match->w;
}
else if (match->y == r->y + r->h)
{
match->y = r->y;
match->h = r->h + match->h;
}
else if (match->x + match->w == r->x)
{
match->w = r->w + match->w;
}
else if (match->y + match->h == r->y )
{
match->h = r->h + match->h;
}
}
return empty;
}
static Eina_List *
_eina_rectangle_skyline_list_update(Eina_List *empty, Eina_Rectangle *rect)
{
Eina_Rectangle *r, *r1;
Eina_List *l;
int x2, y2, w2, h2;
start_again :
EINA_LIST_FOREACH(empty, l, r)
{
if (eina_rectangles_intersect(rect, r))
{
/* Remove l from empty */
empty = eina_list_remove_list(empty, l);
if (r->y > rect->y)
{
if (r->y + r->h > rect->y + rect->h)
{
w2 = r->w;
h2 = (r->y +r->h) - (rect->y + rect->h);
x2 = r->x;
y2 = (r->y +r->h) - h2;
r1 = eina_rectangle_new(x2, y2, w2, h2);
empty = eina_list_prepend(empty, r1);
}
if ( r->x + r->w > rect->x + rect->w )
{
w2 = (r->x +r->w) - (rect->x + rect->w);
h2 = r->h;
x2 = rect->x + rect->w;
y2 = r->y;
r1 = eina_rectangle_new(x2, y2, w2, h2);
empty = eina_list_prepend(empty, r1);
}
if ( rect->x - r->x)
{
w2 = rect->x - r->x;
h2 = r->h;
x2 = r->x;
y2 = r->y;
r1 = eina_rectangle_new(x2, y2, w2, h2);
empty = eina_list_prepend(empty, r1);
}
}
else if (r->x > rect->x)
{
if (r->x + r->w > rect->x + rect->w)
{
w2 = (r->x + r->w) - (rect->x + rect->w);
h2 = r->h;
x2 = (r->x +r->w) - w2;
y2 = r->y;
r1 = eina_rectangle_new(x2, y2, w2, h2);
empty = eina_list_prepend(empty, r1);
}
if ( r->y + r->h > rect->y + rect->y )
{
w2 = r->w;
h2 = (r->y +r->h) - (rect->y + rect->h);
x2 = r->x;
y2 = rect->y + rect->h;
r1 = eina_rectangle_new(x2, y2, w2, h2);
empty = eina_list_prepend(empty, r1);
}
if ( rect->y > r->y)
{
w2 = r->w;;
h2 = rect->y - r->y;
x2 = r->x;
y2 = r->y;
r1 = eina_rectangle_new(x2, y2, w2, h2);
empty = eina_list_prepend(empty, r1);
}
}
else if (r->x == rect->x && r->y < rect->y)
{
if (rect->y + rect->h < r->y + r->h)
{
w2 = r->w;
h2 = (r->y +r->h) - (rect->y + rect->h);
x2 = r->x;
y2 = rect->y + rect->h;
r1 = eina_rectangle_new(x2, y2, w2, h2);
empty = eina_list_prepend(empty, r1);
}
w2 = r->w;
h2 = rect->y - r->y;
x2 = r->x;
y2 = r->y;
r1 = eina_rectangle_new(x2, y2, w2, h2);
empty = eina_list_prepend(empty, r1);
}
else if (r->y == rect->y && r->x < rect->x)
{
if (rect->w + rect->x < r->w + r->x)
{
w2 = (r->x + r->w) - (rect->x + rect->w);
h2 = r->h;
x2 = rect->x + rect->w;
y2 = r->y;
r1 = eina_rectangle_new(x2, y2, w2, h2);
empty = eina_list_prepend(empty, r1);
}
w2 = rect->x - r->x;
h2 = r->h;;
x2 = r->x;
y2 = r->y;
r1 = eina_rectangle_new(x2, y2, w2, h2);
empty = eina_list_prepend(empty, r1);
}
else if (r->x < rect->x && r->y < rect->y)
{
w2 = rect->x - r->x;
h2 = r->h;
x2 = r->x;
y2 = r->y;
r1 = eina_rectangle_new(x2, y2, w2, h2);
empty = eina_list_prepend(empty, r1);
w2 = r->w;
h2 = rect->y - r->y;
x2 = r->x;
y2 = r->y;
r1 = eina_rectangle_new(x2, y2, w2, h2);
empty = eina_list_prepend(empty, r1);
}
else if (r->x == rect->x && r->y == rect->y)
{
if (r->w > rect->w )
{
w2 = r->w - rect->w;
h2 = r->h;
x2 = rect->x + rect->w;
y2 = r->y;
r1 = eina_rectangle_new(x2, y2, w2, h2);
empty = eina_list_prepend(empty, r1);
}
if (r->h > rect->h )
{
w2 = r->w;
h2 = r->h - rect->h;
x2 = r->x;
y2 = rect->y + rect->h;
r1 = eina_rectangle_new(x2, y2, w2, h2);
empty = eina_list_prepend(empty, r1);
}
}
goto start_again;
}
}
return empty;
}
static Eina_List *
_eina_rectangle_skyline_list_update_duplicate(Eina_List *empty)
{
Eina_Rectangle *r, *r1;
Eina_List *l, *l1, *l2;
start_again:
EINA_LIST_FOREACH(empty, l, r)
{
l1 = eina_list_next(l);
EINA_LIST_FOREACH(l1, l2, r1)
{
if ((r->x <= r1->x) && (r->y <= r1->y) && (r->x + r->w >= r1->x + r1->w) && (r->y + r->h >= r1->y + r1->h))
{
empty = eina_list_remove_list(empty, l2);
goto start_again;
}
else if ((r->x >= r1->x) && (r->y >= r1->y) && (r->x + r->w <= r1->x + r1->w) && (r->y + r->h <= r1->y + r1->h))
{
empty = eina_list_remove_list(empty, l);
goto start_again;
}
}
}
return empty;
}
/**
* @endcond
*/
@ -376,6 +645,8 @@ eina_rectangle_pool_new(int w, int h)
new->h = h;
new->bucket = NULL;
new->bucket_count = 0;
new->eina_rectangle_compare_func = _eina_rectangle_cmp;
new->type = Eina_Packing_Ascending;
EINA_MAGIC_SET(new, EINA_RECTANGLE_POOL_MAGIC);
DBG("pool=%p, size=(%d, %d)", new, w, h);
@ -387,10 +658,17 @@ EAPI void
eina_rectangle_pool_free(Eina_Rectangle_Pool *pool)
{
Eina_Rectangle_Alloc *del;
Eina_List *l;
Eina_Rectangle *r;
EINA_SAFETY_ON_NULL_RETURN(pool);
DBG("pool=%p, size=(%d, %d), references=%u",
pool, pool->w, pool->h, pool->references);
EINA_LIST_FOREACH(pool->empty, l, r)
{
eina_rectangle_free(r);
pool->empty = eina_list_remove_list(pool->empty, l);
}
while (pool->head)
{
del = (Eina_Rectangle_Alloc *)pool->head;
@ -440,11 +718,13 @@ eina_rectangle_pool_request(Eina_Rectangle_Pool *pool, int w, int h)
if (!pool->sorted)
{
pool->empty =
eina_list_sort(pool->empty, 0, EINA_COMPARE_CB(_eina_rectangle_cmp));
eina_list_sort(pool->empty, 0, pool->eina_rectangle_compare_func);
pool->sorted = EINA_TRUE;
}
pool->empty = _eina_rectangle_empty_space_find(pool->empty, w, h, &x, &y);
if (pool->type == Eina_Packing_Bottom_Left_Skyline_Improved)
pool->empty = _eina_rectangle_skyline_list_update_duplicate(pool->empty);
pool->empty = _eina_rectangle_empty_space_find(pool->empty, pool->type, w, h, &x, &y);
if (x == -1)
return NULL;
@ -466,6 +746,9 @@ eina_rectangle_pool_request(Eina_Rectangle_Pool *pool, int w, int h)
rect = (Eina_Rectangle *)(new + 1);
eina_rectangle_coords_from(rect, x, y, w, h);
if (pool->type == Eina_Packing_Bottom_Left_Skyline_Improved)
pool->empty = _eina_rectangle_skyline_list_update(pool->empty, rect);
pool->head = eina_inlist_prepend(pool->head, EINA_INLIST_GET(new));
pool->references++;
@ -482,7 +765,9 @@ EAPI void
eina_rectangle_pool_release(Eina_Rectangle *rect)
{
Eina_Rectangle_Alloc *era = ((Eina_Rectangle_Alloc *)rect) - 1;
Eina_Rectangle_Alloc *new;
Eina_Rectangle *r;
Eina_Rectangle *match;
EINA_SAFETY_ON_NULL_RETURN(rect);
@ -498,8 +783,20 @@ eina_rectangle_pool_release(Eina_Rectangle *rect)
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;
if (era->pool->type == Eina_Packing_Bottom_Left_Skyline_Improved)
{
era->pool->empty = _eina_rectangle_skyline_merge_list(era->pool->empty, r);
era->pool->empty = _eina_rectangle_skyline_list_update_duplicate(era->pool->empty);
EINA_INLIST_FOREACH(era->pool->head, new)
{
match =(Eina_Rectangle *) (new + 1);
if (match)
era->pool->empty = _eina_rectangle_skyline_list_update(era->pool->empty, match);
}
}
else
era->pool->empty = _eina_rectangle_merge_list(era->pool->empty, era->pool->type, r);
era->pool->sorted = EINA_FALSE;
}
if (era->pool->bucket_count < BUCKET_THRESHOLD)
@ -531,6 +828,29 @@ eina_rectangle_pool_get(Eina_Rectangle *rect)
return era->pool;
}
EAPI void
eina_rectangle_pool_packing_set(Eina_Rectangle_Pool *pool, Eina_Rectangle_Packing type)
{
EINA_MAGIC_CHECK_RECTANGLE_POOL(pool);
EINA_SAFETY_ON_NULL_RETURN(pool);
DBG("type=%d pool=%p, size=(%d, %d), references=%u",
type, pool, pool->w, pool->h, pool->references);
pool->type =type;
switch (type)
{
case Eina_Packing_Ascending:
pool->eina_rectangle_compare_func = _eina_rectangle_cmp_asc;
break;
case Eina_Packing_Descending:
pool->eina_rectangle_compare_func = _eina_rectangle_cmp;
break;
default:
pool->eina_rectangle_compare_func = _eina_rectangle_cmp_bl;
}
}
EAPI void
eina_rectangle_pool_data_set(Eina_Rectangle_Pool *pool, const void *data)
{

View File

@ -61,6 +61,19 @@ typedef struct _Eina_Rectangle
*/
typedef struct _Eina_Rectangle_Pool Eina_Rectangle_Pool;
/**
* @typedef Eina_Rectangle_Pool_Type
* Type for an Eina Pool based on packing algorithm.
* @since 1.11
*/
typedef enum {
Eina_Packing_Descending, /**< Current */
Eina_Packing_Ascending, /**< sorting in assending order */
Eina_Packing_Bottom_Left, /**< sorting in bottemleft fasion */
Eina_Packing_Bottom_Left_Skyline, /**< bottemleft skyline */
Eina_Packing_Bottom_Left_Skyline_Improved /**< optimized bottemleft skyline */
} Eina_Rectangle_Packing;
static inline int eina_spans_intersect(int c1, int l1, int c2, int l2) EINA_WARN_UNUSED_RESULT;
static inline Eina_Bool eina_rectangle_is_empty(const Eina_Rectangle *r) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
static inline void eina_rectangle_coords_from(Eina_Rectangle *r, int x, int y, int w, int h) EINA_ARG_NONNULL(1);
@ -238,6 +251,17 @@ EAPI Eina_Rectangle *eina_rectangle_new(int x, int y, int w, int h) EINA_MALLOC
*/
EAPI void eina_rectangle_free(Eina_Rectangle *rect) EINA_ARG_NONNULL(1);
/**
* @brief Sets the type of given rectangle pool.
*
* @param pool The rectangle pool for which type is to be set.
*
* This function sets @p type of @p pool.
* @see Eina_Rectangle_Packing
* @since 1.11
*/
EAPI void eina_rectangle_pool_packing_set(Eina_Rectangle_Pool *pool,Eina_Rectangle_Packing type) EINA_ARG_NONNULL(1);
#include "eina_inline_rectangle.x"
/**

View File

@ -391,11 +391,11 @@ struct _Evas_GL_Shared
#define MIN_ATLAS_ALLOC 16
#define MAX_ATLAS_ALLOC 1024
#define DEF_ATLAS_ALLOC 1024
#define DEF_ATLAS_ALLOC 256
#define MIN_ATLAS_ALLOC_ALPHA 16
#define MAX_ATLAS_ALLOC_ALPHA 4096
#define DEF_ATLAS_ALLOC_ALPHA 4096
#define DEF_ATLAS_ALLOC_ALPHA 512
#define MAX_ATLAS_W 512
#define DEF_ATLAS_W 512
@ -403,10 +403,6 @@ struct _Evas_GL_Shared
#define MAX_ATLAS_H 512
#define DEF_ATLAS_H 512
#define MIN_ATLAS_SLOT 16
#define MAX_ATLAS_SLOT 512
#define DEF_ATLAS_SLOT 16
struct {
struct {
int max;
@ -419,14 +415,13 @@ struct _Evas_GL_Shared
int max_alloc_alpha_size;
int max_w;
int max_h;
int slot_size;
} atlas;
} tune;
} info;
struct {
Eina_List *whole;
Eina_List *atlas[33][6];
Eina_List *atlas[6];
} tex;
Eina_Hash *native_pm_hash;
@ -572,6 +567,7 @@ struct _Evas_GL_Texture_Pool
int checked_out;
} dyn;
Eina_List *allocations;
Eina_Rectangle_Pool *eina_pool;
Eina_Bool whole : 1;
Eina_Bool render : 1;
Eina_Bool native : 1;
@ -590,7 +586,6 @@ struct _Evas_GL_Texture
Evas_Engine_GL_Context *gc;
Evas_GL_Image *im;
Evas_GL_Texture_Pool *pt, *ptu, *ptv, *ptuv, *ptt;
Evas_GL_Texture_Alloca *apt, *aptt;
RGBA_Font_Glyph *fglyph;
int x, y, w, h;
int tx, ty;
@ -604,6 +599,7 @@ struct _Evas_GL_Texture
} double_buffer;
Eina_List *targets;
Eina_Rectangle *apt, *aptt;
Eina_Bool alpha : 1;
Eina_Bool dyn : 1;

View File

@ -674,7 +674,6 @@ evas_gl_common_context_new(void)
shared->info.tune.atlas.max_alloc_alpha_size = DEF_ATLAS_ALLOC_ALPHA;
shared->info.tune.atlas.max_w = DEF_ATLAS_W;
shared->info.tune.atlas.max_h = DEF_ATLAS_H;
shared->info.tune.atlas.slot_size = DEF_ATLAS_SLOT;
// per gpu hacks. based on impirical measurement of some known gpu's
s = (const char *)glGetString(GL_RENDERER);
@ -711,7 +710,6 @@ evas_gl_common_context_new(void)
GETENVOPT("EVAS_GL_ATLAS_ALLOC_ALPHA_SIZE", atlas.max_alloc_alpha_size, MIN_ATLAS_ALLOC_ALPHA, MAX_ATLAS_ALLOC_ALPHA);
GETENVOPT("EVAS_GL_ATLAS_MAX_W", atlas.max_w, 0, MAX_ATLAS_W);
GETENVOPT("EVAS_GL_ATLAS_MAX_H", atlas.max_h, 0, MAX_ATLAS_H);
GETENVOPT("EVAS_GL_ATLAS_SLOT_SIZE", atlas.slot_size, MIN_ATLAS_SLOT, MAX_ATLAS_SLOT);
s = (const char *)getenv("EVAS_GL_GET_PROGRAM_BINARY");
if (s)
{
@ -775,7 +773,6 @@ evas_gl_common_context_new(void)
"EVAS_GL_ATLAS_ALLOC_SIZE: %i\n"
"EVAS_GL_ATLAS_ALLOC_ALPHA_SIZE: %i\n"
"EVAS_GL_ATLAS_MAX_W x EVAS_GL_ATLAS_MAX_H: %i x %i\n"
"EVAS_GL_ATLAS_SLOT_SIZE: %i\n"
,
(int)shared->info.max_texture_size, (int)shared->info.max_texture_size,
(int)shared->info.max_texture_units,
@ -793,8 +790,7 @@ evas_gl_common_context_new(void)
(int)shared->info.tune.pipes.max,
(int)shared->info.tune.atlas.max_alloc_size,
(int)shared->info.tune.atlas.max_alloc_alpha_size,
(int)shared->info.tune.atlas.max_w, (int)shared->info.tune.atlas.max_h,
(int)shared->info.tune.atlas.slot_size
(int)shared->info.tune.atlas.max_w, (int)shared->info.tune.atlas.max_h
);
glDisable(GL_DEPTH_TEST);
@ -939,14 +935,11 @@ evas_gl_common_context_free(Evas_Engine_GL_Context *gc)
evas_gl_common_image_free(gc->shared->images->data);
}
for (i = 0; i < 33; i++)
for (j = 0; j < 6; j++)
{
for (j = 0; j < 3; j++)
{
EINA_LIST_FOREACH(gc->shared->tex.atlas[i][j], l, pt)
evas_gl_texture_pool_empty(pt);
eina_list_free(gc->shared->tex.atlas[i][j]);
}
EINA_LIST_FOREACH(gc->shared->tex.atlas[j], l, pt)
evas_gl_texture_pool_empty(pt);
eina_list_free(gc->shared->tex.atlas[j]);
}
EINA_LIST_FOREACH(gc->shared->tex.whole, l, pt)
evas_gl_texture_pool_empty(pt);

View File

@ -172,14 +172,6 @@ _tex_adjust(Evas_Engine_GL_Context *gc, int *w, int *h)
*h = _nearest_pow2(*h);
}
static int
_tex_round_slot(Evas_Engine_GL_Context *gc, int h)
{
if (!gc->shared->info.tex_npo2)
h = _nearest_pow2(h);
return (h + gc->shared->info.tune.atlas.slot_size - 1) /
gc->shared->info.tune.atlas.slot_size;
}
static int
_tex_format_index(GLuint format)
@ -314,7 +306,6 @@ _pool_tex_new(Evas_Engine_GL_Context *gc, int w, int h, GLenum intformat, GLenum
if (!no_rounding)
{
h = _tex_round_slot(gc, h) * gc->shared->info.tune.atlas.slot_size;
_tex_adjust(gc, &w, &h);
}
pt->gc = gc;
@ -324,6 +315,7 @@ _pool_tex_new(Evas_Engine_GL_Context *gc, int w, int h, GLenum intformat, GLenum
pt->format = format;
pt->dataformat = GL_UNSIGNED_BYTE;
pt->references = 0;
pt->eina_pool = eina_rectangle_pool_new(w, h);
glGenTextures(1, &(pt->texture));
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
@ -343,6 +335,8 @@ _pool_tex_new(Evas_Engine_GL_Context *gc, int w, int h, GLenum intformat, GLenum
if (!ok)
{
glDeleteTextures(1, &(pt->texture));
if (pt->eina_pool)
eina_rectangle_pool_free(pt->eina_pool);
free(pt);
return NULL;
}
@ -366,59 +360,30 @@ _pool_tex_new(Evas_Engine_GL_Context *gc, int w, int h, GLenum intformat, GLenum
return pt;
}
static Evas_GL_Texture_Alloca *
_pool_tex_define(Evas_GL_Texture_Pool *pt, int lastx, int w, int *u, Eina_List *l)
static Eina_Rectangle *
_pool_tex_alloc(Evas_GL_Texture_Pool *pt, int w, int h, int *u, int *v)
{
Evas_GL_Texture_Alloca *napt;
*u = lastx;
napt = malloc(sizeof (Evas_GL_Texture_Alloca));
if (!napt) return NULL;
napt->tex = NULL;
napt->x = lastx;
napt->w = w;
if (l == NULL)
pt->allocations = eina_list_append(pt->allocations, napt);
else
pt->allocations = eina_list_prepend_relative_list(pt->allocations, napt, l);
return napt;
}
static Evas_GL_Texture_Alloca *
_pool_tex_alloc(Evas_GL_Texture_Pool *pt, int w, int h EINA_UNUSED, int *u, int *v)
{
Evas_GL_Texture_Alloca *apt;
Eina_List *l;
int lastx = 0;
*v = 0;
EINA_LIST_FOREACH(pt->allocations, l, apt)
Eina_Rectangle *r;
r = eina_rectangle_pool_request( pt->eina_pool, w, h);
if (r)
{
if (apt->x - lastx >= w)
return _pool_tex_define(pt, lastx, w, u, l);
lastx = apt->x + apt->w;
*v = r->y;
*u = r->x;
pt->allocations = eina_list_prepend(pt->allocations, r);
}
if (pt->w - lastx >= w)
return _pool_tex_define(pt, lastx, w, u, NULL);
return NULL;
return r;
}
static Evas_GL_Texture_Pool *
_pool_tex_find(Evas_Engine_GL_Context *gc, int w, int h,
GLenum intformat, GLenum format, int *u, int *v,
Evas_GL_Texture_Alloca **apt, int atlas_w)
Eina_Rectangle **apt, int atlas_w)
{
Evas_GL_Texture_Pool *pt = NULL;
Eina_List *l;
int th, th2;
int th2;
int pool_h;
if (atlas_w > gc->shared->info.max_texture_size)
atlas_w = gc->shared->info.max_texture_size;
@ -429,32 +394,35 @@ _pool_tex_find(Evas_Engine_GL_Context *gc, int w, int h,
pt = _pool_tex_new(gc, w, h, intformat, format);
if (!pt) return NULL;
gc->shared->tex.whole = eina_list_prepend(gc->shared->tex.whole, pt);
pt->slot = -1;
pt->fslot = -1;
pt->whole = 1;
*apt = _pool_tex_alloc(pt, w, h, u, v);
return pt;
}
th = _tex_round_slot(gc, h);
th2 = _tex_format_index(intformat);
EINA_LIST_FOREACH(gc->shared->tex.atlas[th][th2], l, pt)
EINA_LIST_FOREACH(gc->shared->tex.atlas[th2], l, pt)
{
if ((*apt = _pool_tex_alloc(pt, w, h, u, v)) != NULL)
{
gc->shared->tex.atlas[th][th2] =
eina_list_remove_list(gc->shared->tex.atlas[th][th2], l);
gc->shared->tex.atlas[th][th2] =
eina_list_prepend(gc->shared->tex.atlas[th][th2], pt);
gc->shared->tex.atlas[th2] =
eina_list_remove_list(gc->shared->tex.atlas[th2], l);
gc->shared->tex.atlas[th2] =
eina_list_prepend(gc->shared->tex.atlas[th2], pt);
return pt;
}
}
pool_h = atlas_w;
if ( h > pool_h || w > atlas_w )
{
atlas_w = gc->shared->info.tune.atlas.max_w;
pool_h = gc->shared->info.tune.atlas.max_h;
}
pt = _pool_tex_new(gc, atlas_w, pool_h, intformat, format);
pt = _pool_tex_new(gc, atlas_w, h, intformat, format);
if (!pt) return NULL;
gc->shared->tex.atlas[th][th2] =
eina_list_prepend(gc->shared->tex.atlas[th][th2], pt);
pt->slot = th;
gc->shared->tex.atlas[th2] =
eina_list_prepend(gc->shared->tex.atlas[th2], pt);
pt->fslot = th2;
*apt = _pool_tex_alloc(pt, w, h, u, v);
@ -495,7 +463,7 @@ evas_gl_common_texture_new(Evas_Engine_GL_Context *gc, RGBA_Image *im)
default:
/* This need to be adjusted if we do something else than strip allocation */
w = im->cache_entry.w + TEX_HREP + 2; /* one pixel stop gap and two pixels for the border */
h = im->cache_entry.h + TEX_VREP; /* only one added border for security down */
h = im->cache_entry.h + TEX_VREP + 2; /* only one added border for security down */
}
tex->pt = _pool_tex_find(gc, w, h,
@ -508,7 +476,6 @@ evas_gl_common_texture_new(Evas_Engine_GL_Context *gc, RGBA_Image *im)
evas_gl_common_texture_light_free(tex);
return NULL;
}
tex->apt->tex = tex;
tex->x = u + 1;
tex->y = v + yoffset;
@ -542,6 +509,7 @@ _pool_tex_render_new(Evas_Engine_GL_Context *gc, int w, int h, int intformat, in
pt->dataformat = GL_UNSIGNED_BYTE;
pt->render = 1;
pt->references = 0;
pt->eina_pool = eina_rectangle_pool_new(w, h);
#ifdef GL_GLES
# ifndef GL_FRAMEBUFFER
# define GL_FRAMEBUFFER GL_FRAMEBUFFER_OES
@ -587,6 +555,8 @@ _pool_tex_render_new(Evas_Engine_GL_Context *gc, int w, int h, int intformat, in
if (!ok)
{
glDeleteTextures(1, &(pt->texture));
if (pt->eina_pool)
eina_rectangle_pool_free(pt->eina_pool);
free(pt);
return NULL;
}
@ -630,6 +600,7 @@ _pool_tex_native_new(Evas_Engine_GL_Context *gc, int w, int h, int intformat, in
pt->dataformat = GL_UNSIGNED_BYTE;
pt->references = 0;
pt->native = 1;
pt->eina_pool = eina_rectangle_pool_new(w, h);
glGenTextures(1, &(pt->texture));
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
glBindTexture(im->native.target, pt->texture);
@ -698,7 +669,6 @@ _pool_tex_dynamic_new(Evas_Engine_GL_Context *gc, int w, int h, int intformat, i
pt = calloc(1, sizeof(Evas_GL_Texture_Pool));
if (!pt) return NULL;
h = _tex_round_slot(gc, h) * gc->shared->info.tune.atlas.slot_size;
_tex_adjust(gc, &w, &h);
pt->gc = gc;
pt->w = w;
@ -708,6 +678,7 @@ _pool_tex_dynamic_new(Evas_Engine_GL_Context *gc, int w, int h, int intformat, i
pt->dataformat = GL_UNSIGNED_BYTE;
pt->render = 1;
pt->references = 0;
pt->eina_pool = eina_rectangle_pool_new(w, h);
texinfo.d.num++;
texinfo.d.pix += pt->w * pt->h;
@ -744,6 +715,8 @@ _pool_tex_dynamic_new(Evas_Engine_GL_Context *gc, int w, int h, int intformat, i
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
glDeleteTextures(1, &(pt->texture));
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
if (pt->eina_pool)
eina_rectangle_pool_free(pt->eina_pool);
free(pt);
return NULL;
}
@ -788,6 +761,8 @@ error:
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
glDeleteTextures(1, &(pt->texture));
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
if (pt->eina_pool)
eina_rectangle_pool_free(pt->eina_pool);
free(pt);
return NULL;
#endif
@ -796,7 +771,7 @@ error:
void
evas_gl_texture_pool_empty(Evas_GL_Texture_Pool *pt)
{
Evas_GL_Texture_Alloca *apt;
Eina_Rectangle *apt;
if (!pt->gc) return;
@ -858,9 +833,8 @@ evas_gl_texture_pool_empty(Evas_GL_Texture_Pool *pt)
GLERR(__FUNCTION__, __FILE__, __LINE__, "");
pt->fb = 0;
}
EINA_LIST_FREE(pt->allocations, apt)
free(apt);
EINA_LIST_FREE(pt->allocations, apt)
eina_rectangle_pool_release(apt);
pt->texture = 0;
pt->gc = NULL;
pt->w = 0;
@ -881,10 +855,12 @@ pt_unref(Evas_GL_Texture_Pool *pt)
pt->gc->shared->tex.whole =
eina_list_remove(pt->gc->shared->tex.whole, pt);
else
pt->gc->shared->tex.atlas [pt->slot][pt->fslot] =
eina_list_remove(pt->gc->shared->tex.atlas[pt->slot][pt->fslot], pt);
pt->gc->shared->tex.atlas [pt->fslot] =
eina_list_remove(pt->gc->shared->tex.atlas[pt->fslot], pt);
}
evas_gl_texture_pool_empty(pt);
if (pt->eina_pool)
eina_rectangle_pool_free(pt->eina_pool);
free(pt);
}
@ -892,7 +868,6 @@ static void
pt_link(Evas_Engine_GL_Context *gc, Evas_GL_Texture_Pool *pt)
{
gc->shared->tex.whole = eina_list_prepend(gc->shared->tex.whole, pt);
pt->slot = -1;
pt->fslot = -1;
pt->whole = 1;
pt->references++;
@ -1010,6 +985,28 @@ evas_gl_common_texture_upload(Evas_GL_Texture *tex, RGBA_Image *im, unsigned int
1, 1,
fmt, tex->pt->dataformat,
(unsigned char *) im->image.data + (((im->cache_entry.h - 1) * im->cache_entry.w) + (im->cache_entry.w - 1)) * bytes_count);
//2D packing
// ---
// xxx
// xxx
_tex_sub_2d(tex->gc, tex->x, tex->y - 1,
im->cache_entry.w, 1,
fmt, tex->pt->dataformat,
im->image.data);
// o
// xxx
// xxx
_tex_sub_2d(tex->gc, tex->x - 1, tex->y - 1,
1, 1,
fmt, tex->pt->dataformat,
im->image.data);
// o
// xxx
// xxx
_tex_sub_2d(tex->gc, tex->x + im->cache_entry.w, tex->y - 1,
1, 1,
fmt, tex->pt->dataformat,
im->image.data + (im->cache_entry.w - 1) * bytes_count);
if (tex->gc->shared->info.unpack_row_length)
{
glPixelStorei(GL_UNPACK_ROW_LENGTH, im->cache_entry.w);
@ -1083,8 +1080,8 @@ evas_gl_common_texture_update(Evas_GL_Texture *tex, RGBA_Image *im)
int lformat;
tex->pt->allocations = eina_list_remove(tex->pt->allocations, tex->apt);
pt_unref(tex->pt);
tex->alpha = im->cache_entry.flags.alpha;
if (tex->apt)
eina_rectangle_pool_release(tex->apt);
lformat = _evas_gl_texture_search_format(tex->alpha, tex->gc->shared->info.bgra, im->cache_entry.space);
// FIXME: why a 'render' new here ??? Should already have been allocated, quite a weird path.
@ -1238,7 +1235,6 @@ evas_gl_common_texture_update(Evas_GL_Texture *tex, RGBA_Image *im)
tex->gc->shared->info.tune.atlas.max_alloc_size);
if (!tex->ptt)
goto upload;
tex->aptt->tex = tex;
tex->tx = u + 1;
tex->ty = v;
@ -1327,14 +1323,16 @@ evas_gl_common_texture_free(Evas_GL_Texture *tex, Eina_Bool force EINA_UNUSED)
if (tex->pt)
{
tex->pt->allocations = eina_list_remove(tex->pt->allocations, tex->apt);
free(tex->apt);
if (tex->apt)
eina_rectangle_pool_release(tex->apt);
tex->apt = NULL;
pt_unref(tex->pt);
}
if (tex->ptt)
{
tex->ptt->allocations = eina_list_remove(tex->ptt->allocations, tex->aptt);
free(tex->aptt);
tex->ptt->allocations = eina_list_remove(tex->pt->allocations, tex->aptt);
if (tex->aptt)
eina_rectangle_pool_release(tex->aptt);
tex->aptt = NULL;
pt_unref(tex->ptt);
}
@ -1366,7 +1364,6 @@ evas_gl_common_texture_alpha_new(Evas_Engine_GL_Context *gc, DATA8 *pixels,
evas_gl_common_texture_light_free(tex);
return NULL;
}
tex->apt->tex = tex;
tex->x = u + 1;
tex->y = v;
tex->pt->references++;
@ -1435,7 +1432,6 @@ evas_gl_common_texture_yuv_new(Evas_Engine_GL_Context *gc, DATA8 **rows, unsigne
return NULL;
}
gc->shared->tex.whole = eina_list_prepend(gc->shared->tex.whole, tex->pt);
tex->pt->slot = -1;
tex->pt->fslot = -1;
tex->pt->whole = 1;
tex->pt->references++;