evas: improvement of Eina Rectangle Pool and integration with Evas GL backend.
authorRajeev Ranjan <rajeev.r@samsung.com>
Thu, 19 Jun 2014 12:35:37 +0000 (14:35 +0200)
committerCedric BAIL <c.bail@partner.samsung.com>
Thu, 19 Jun 2014 14:48:45 +0000 (16:48 +0200)
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>
AUTHORS
src/lib/eina/eina_rectangle.c
src/lib/eina/eina_rectangle.h
src/modules/evas/engines/gl_common/evas_gl_common.h
src/modules/evas/engines/gl_common/evas_gl_context.c
src/modules/evas/engines/gl_common/evas_gl_texture.c

diff --git a/AUTHORS b/AUTHORS
index d40a8fd..000723e 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -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
 -----
index 5ae680b..972755f 100644 (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 int
+_eina_rectangle_cmp_asc(const void *data1, const void *data2)
+{
+   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 *r)
+_eina_rectangle_merge_list(Eina_List *empty, Eina_Rectangle_Packing type, Eina_Rectangle *r)
 {
-   Eina_Rectangle *match;
+   Eina_Rectangle *match, *r1;
    Eina_List *l;
    int xw;
    int yh;
+   int x2 ,y2 ,w2 ,h2;
 
    if (r->w == 0 || r->h == 0)
      {
@@ -166,13 +192,41 @@ start_again:
 
            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;
+        }
    }
 
    return eina_list_append(empty, r);
 }
 
 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)
@@ -532,6 +829,29 @@ eina_rectangle_pool_get(Eina_Rectangle *rect)
 }
 
 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)
 {
    EINA_MAGIC_CHECK_RECTANGLE_POOL(pool);
index d3e2443..8f5eead 100644 (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"
 
 /**
index 4e45df0..da30a8e 100644 (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;
index 21d1412..1f4db94 100644 (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);
index 29a5594..87c1346 100644 (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++;