evas - region updates - go back to tiler as its faster
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>
Mon, 5 Oct 2015 09:41:00 +0000 (18:41 +0900)
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>
Mon, 5 Oct 2015 09:41:00 +0000 (18:41 +0900)
the overhead didnt show up in y tests. do show up with certain
expedite tests. hmmm. last time i messed with region code it was
actually same speed as tiler. bonus was it was fully accurate.

src/lib/evas/common/evas_tiler.c
src/lib/evas/include/evas_common_private.h

index d645d52..0aff533 100644 (file)
@@ -1,6 +1,8 @@
 #include "evas_common_private.h"
 #include "region.h"
 
+
+#ifdef NEWTILER
 EAPI void
 evas_common_tilebuf_init(void)
 {
@@ -147,3 +149,915 @@ evas_common_tilebuf_free_render_rects(Tilebuf_Rect *rects)
 {
    free(rects);
 }
+
+#else
+
+#define FUZZ 32
+#define MAXREG 24
+#define MAX_NODES 1024
+
+static inline void rect_list_node_pool_flush(void);
+static inline list_node_t *rect_list_node_pool_get(void);
+static inline void rect_list_node_pool_put(list_node_t *node);
+static inline void rect_init(rect_t *r, int x, int y, int w, int h);
+static inline void rect_list_append_node(list_t *rects, list_node_t *node);
+static inline void rect_list_append(list_t *rects, const rect_t r);
+static inline void rect_list_append_xywh(list_t *rects, int x, int y, int w, int h);
+static inline void rect_list_concat(list_t *rects, list_t *other);
+static inline list_node_t *rect_list_unlink_next(list_t *rects, list_node_t *parent_node);
+static inline void rect_list_del_next(list_t *rects, list_node_t *parent_node);
+static inline void rect_list_clear(list_t *rects);
+static inline void rect_list_del_split_strict(list_t *rects, const rect_t del_r);
+static inline list_node_t *rect_list_add_split_fuzzy(list_t *rects, list_node_t *node, int accepted_error);
+static inline void rect_list_merge_rects(list_t *rects, list_t *to_merge, int accepted_error);
+static inline void rect_list_add_split_fuzzy_and_merge(list_t *rects, list_node_t *node, int split_accepted_error, int merge_accepted_error);
+
+static const list_node_t list_node_zeroed = { NULL };
+static const list_t list_zeroed = { NULL, NULL };
+
+typedef struct list_node_pool
+{
+   list_node_t *node;
+   int len;
+   int max;
+} list_node_pool_t;
+
+static list_node_pool_t list_node_pool = { NULL, 0, MAX_NODES };
+
+static inline void
+rect_list_node_pool_flush(void)
+{
+   while (list_node_pool.node)
+     {
+        list_node_t *node = list_node_pool.node;
+        list_node_pool.node = node->next;
+        list_node_pool.len--;
+        free(node);
+     }
+}
+
+static inline list_node_t *
+rect_list_node_pool_get(void)
+{
+   if (list_node_pool.node)
+     {
+        list_node_t *node = list_node_pool.node;
+        list_node_pool.node = node->next;
+        list_node_pool.len--;
+        return node;
+     }
+   else return (list_node_t *)malloc(sizeof(rect_node_t));
+}
+
+static inline void
+rect_list_node_pool_put(list_node_t *node)
+{
+   if (list_node_pool.len < list_node_pool.max)
+     {
+        node->next = list_node_pool.node;
+        list_node_pool.node = node;
+        list_node_pool.len++;
+     }
+   else free(node);
+}
+
+static inline void
+rect_init(rect_t *r, int x, int y, int w, int h)
+{
+   r->area = w * h;
+   r->left = x;
+   r->top = y;
+   r->right = x + w;
+   r->bottom = y + h;
+   r->width = w;
+   r->height = h;
+}
+
+static inline void
+rect_list_append_node(list_t *rects, list_node_t *node)
+{
+   if (rects->tail)
+     {
+       rects->tail->next = node;
+       rects->tail = node;
+     }
+   else
+     {
+       rects->head = node;
+       rects->tail = node;
+     }
+}
+
+static inline void
+rect_list_append(list_t *rects, const rect_t r)
+{
+   rect_node_t *rect_node = (rect_node_t *)rect_list_node_pool_get();
+   rect_node->rect = r;
+   rect_node->_lst = list_node_zeroed;
+   rect_list_append_node(rects, (list_node_t *)rect_node);
+}
+
+static inline void
+rect_list_append_xywh(list_t *rects, int x, int y, int w, int h)
+{
+   rect_t r;
+   rect_init(&r, x, y, w, h);
+   rect_list_append(rects, r);
+}
+
+static inline void
+rect_list_concat(list_t *rects, list_t *other)
+{
+   if (!other->head) return;
+   if (rects->tail)
+     {
+       rects->tail->next = other->head;
+       rects->tail = other->tail;
+     }
+   else
+     {
+       rects->head = other->head;
+       rects->tail = other->tail;
+     }
+   *other = list_zeroed;
+}
+
+static inline list_node_t *
+rect_list_unlink_next(list_t *rects, list_node_t *parent_node)
+{
+   list_node_t *node;
+   
+   if (parent_node)
+     {
+        node = parent_node->next;
+        parent_node->next = node->next;
+     }
+   else
+     {
+        node = rects->head;
+        rects->head = node->next;
+     }
+   if (rects->tail == node) rects->tail = parent_node;
+   *node = list_node_zeroed;
+   return node;
+}
+
+static inline void
+rect_list_del_next(list_t *rects, list_node_t *parent_node)
+{
+    list_node_t *node = rect_list_unlink_next(rects, parent_node);
+    rect_list_node_pool_put(node);
+}
+
+static inline void
+rect_list_clear(list_t *rects)
+{
+   list_node_t *node = rects->head;
+   while (node)
+     {
+        list_node_t *aux;
+        
+        aux = node->next;
+        rect_list_node_pool_put(node);
+        node = aux;
+     }
+   *rects = list_zeroed;
+}
+
+static inline void
+_calc_intra_rect_area(const rect_t a, const rect_t b, int *width, int *height)
+{
+   int max_left, min_right, max_top, min_bottom;
+
+   if (a.left < b.left) max_left = b.left;
+   else max_left = a.left;
+   if (a.right < b.right) min_right = a.right;
+   else min_right = b.right;
+   *width = min_right - max_left;
+
+   if (a.top < b.top) max_top = b.top;
+   else max_top = a.top;
+   if (a.bottom < b.bottom) min_bottom = a.bottom;
+   else min_bottom = b.bottom;
+   *height = min_bottom - max_top;
+}
+
+static inline void
+_split_strict(list_t *dirty, const rect_t current, rect_t r)
+{
+   int h_1, h_2, w_1, w_2;
+
+   h_1 = current.top - r.top;
+   h_2 = r.bottom - current.bottom;
+   w_1 = current.left - r.left;
+   w_2 = r.right - current.right;
+   if (h_1 > 0)
+     {
+       /*    .--.r (b)                .---.r2
+         *    |  |                     |   |
+         *  .-------.cur (a) .---.r    '---'
+         *  | |  |  |     -> |   |   +
+         *  | `--'  |        `---'
+         *  `-------'
+         */
+        rect_list_append_xywh(dirty, r.left, r.top, r.width, h_1);
+        r.height -= h_1;
+        r.top = current.top;
+     }
+   if (h_2 > 0)
+     {
+        /*  .-------.cur (a)
+         *  | .---. |        .---.r
+         *  | |   | |    ->  |   |
+         *  `-------'        `---'   +  .---.r2
+         *    |   |                     |   |
+         *    `---'r (b)                `---'
+         */
+        rect_list_append_xywh(dirty, r.left, current.bottom, r.width, h_2);
+        r.height -= h_2;
+     }
+   if (w_1 > 0)
+     {
+        /* (b) r  .----.cur (a)
+         *     .--|-.  |      .--.r2   .-.r
+         *     |  | |  |  ->  |  |   + | |
+         *     `--|-'  |      `--'     `-'
+         *        `----'
+         */
+        rect_list_append_xywh(dirty, r.left, r.top, w_1, r.height);
+        /* not necessary to keep these, r (b) will be destroyed */
+        /* r.width -= w_1; */
+        /* r.left = current.left; */
+     }
+   if (w_2 > 0)
+     {
+        /*  .----.cur (a)
+         *  |    |
+         *  |  .-|--.r (b)  .-.r   .--.r2
+         *  |  | |  |    -> | |  + |  |
+         *  |  `-|--'       `-'    `--'
+         *  `----'
+         */
+        rect_list_append_xywh(dirty, current.right, r.top, w_2, r.height);
+        /* not necessary to keep this, r (b) will be destroyed */
+        /* r.width -= w_2; */
+     }
+}
+
+static inline void
+rect_list_del_split_strict(list_t *rects, const rect_t del_r)
+{
+   list_t modified = list_zeroed;
+   list_node_t *cur_node, *prev_node;
+   int intra_width, intra_height;
+   rect_t current;
+
+   prev_node = NULL;
+   cur_node = rects->head;
+   while (cur_node)
+     {
+        current = ((rect_node_t*)cur_node)->rect;
+        _calc_intra_rect_area(del_r, current, &intra_width, &intra_height);
+        if ((intra_width <= 0) || (intra_height <= 0))
+          {
+             /*  .---.current      .---.del_r
+              *  |   |             |   |
+              *  `---+---.del_r    `---+---.current
+              *      |   |             |   |
+              *      `---'             `---'
+              * no interception, nothing to do
+              */
+              prev_node = cur_node;
+              cur_node = cur_node->next;
+          }
+        else if ((intra_width == current.width) &&
+                 (intra_height == current.height))
+          {
+             /*  .-------.del_r
+              *  | .---. |
+              *  | |   | |
+              *  | `---'current
+              *  `-------'
+              * current is contained, remove from rects
+              */
+              cur_node = cur_node->next;
+              rect_list_del_next(rects, prev_node);
+          }
+        else
+          {
+              _split_strict(&modified, del_r, current);
+              cur_node = cur_node->next;
+              rect_list_del_next(rects, prev_node);
+          }
+     }
+
+   rect_list_concat(rects, &modified);
+}
+
+static inline void
+_calc_intra_outer_rect_area(const rect_t a, const rect_t b,
+                            rect_t *intra, rect_t *outer)
+{
+   int min_left, max_left, min_right, max_right;
+   int min_top, max_top, min_bottom, max_bottom;
+   
+   if (a.left < b.left)
+     {
+        max_left = b.left;
+        min_left = a.left;
+     }
+   else
+     {
+        max_left = a.left;
+        min_left = b.left;
+     }
+   if (a.right < b.right)
+     {
+        min_right = a.right;
+        max_right = b.right;
+     }
+   else
+     {
+        min_right = b.right;
+        max_right = a.right;
+     }
+   intra->left = max_left;
+   intra->right = min_right;
+   intra->width = min_right - max_left;
+   outer->left = min_left;
+   outer->right = max_right;
+   outer->width = max_right - min_left;
+   if (a.top < b.top)
+     {
+       max_top = b.top;
+        min_top = a.top;
+     }
+   else
+     {
+        max_top = a.top;
+        min_top = b.top;
+     }
+   if (a.bottom < b.bottom)
+     {
+        min_bottom = a.bottom;
+        max_bottom = b.bottom;
+     }
+   else
+     {
+        min_bottom = b.bottom;
+        max_bottom = a.bottom;
+     }
+   intra->top = max_top;
+   intra->bottom = min_bottom;
+   intra->height = min_bottom - max_top;
+   if ((intra->width > 0) && (intra->height > 0))
+     intra->area = intra->width * intra->height;
+   else
+     intra->area = 0;
+   outer->top = min_top;
+   outer->bottom = max_bottom;
+   outer->height = max_bottom - min_top;
+   outer->area = outer->width * outer->height;
+}
+
+enum
+{
+   SPLIT_FUZZY_ACTION_NONE,
+   SPLIT_FUZZY_ACTION_SPLIT,
+   SPLIT_FUZZY_ACTION_MERGE
+};
+
+static inline int
+_split_fuzzy(list_t *dirty, const rect_t a, rect_t *b)
+{
+   int h_1, h_2, w_1, w_2, action;
+
+   h_1 = a.top - b->top;
+   h_2 = b->bottom - a.bottom;
+   w_1 = a.left - b->left;
+   w_2 = b->right - a.right;
+
+   action = SPLIT_FUZZY_ACTION_NONE;
+   if (h_1 > 0)
+     {
+        /*    .--.r (b)                .---.r2
+         *    |  |                     |   |
+         *  .-------.cur (a) .---.r    '---'
+         *  | |  |  |     -> |   |   +
+         *  | `--'  |        `---'
+         *  `-------'
+         */
+        rect_list_append_xywh(dirty, b->left, b->top, b->width, h_1);
+        b->height -= h_1;
+        b->top = a.top;
+        action = SPLIT_FUZZY_ACTION_SPLIT;
+     }
+   if (h_2 > 0)
+     {
+        /*  .-------.cur (a)
+         *  | .---. |        .---.r
+         *  | |   | |    ->  |   |
+         *  `-------'        `---'   +  .---.r2
+         *    |   |                     |   |
+         *    `---'r (b)                `---'
+         */
+        rect_list_append_xywh(dirty, b->left, a.bottom, b->width, h_2);
+        b->height -= h_2;
+        action = SPLIT_FUZZY_ACTION_SPLIT;
+     }
+   if (((w_1 > 0) || (w_2 > 0)) && (a.height == b->height))
+     return SPLIT_FUZZY_ACTION_MERGE;
+   if (w_1 > 0)
+     {
+        /* (b)  r  .----.cur (a)
+         *      .--|-.  |      .--.r2   .-.r
+         *      |  | |  |  ->  |  |   + | |
+         *      `--|-'  |      `--'     `-'
+         *         `----'
+         */
+        rect_list_append_xywh(dirty, b->left, b->top, w_1, b->height);
+        /* not necessary to keep these, r (b) will be destroyed */
+        /* b->width -= w_1; */
+        /* b->left = a.left; */
+        action = SPLIT_FUZZY_ACTION_SPLIT;
+     }
+   if (w_2 > 0)
+     {
+        /* .----.cur (a)
+         * |    |
+         * |  .-|--.r (b)  .-.r   .--.r2
+         * |  | |  |    -> | |  + |  |
+         * |  `-|--'       `-'    `--'
+         * `----'
+         */
+        rect_list_append_xywh(dirty, a.right, b->top, w_2, b->height);
+        /* not necessary to keep these, r (b) will be destroyed */
+        /* b->width -= w_2; */
+        action = SPLIT_FUZZY_ACTION_SPLIT;
+     }
+   return action;
+}
+
+static inline list_node_t *
+rect_list_add_split_fuzzy(list_t *rects, list_node_t *node, int accepted_error)
+{
+   list_t dirty = list_zeroed;
+   list_node_t *old_last = rects->tail;
+
+   if (!rects->head)
+     {
+        rect_list_append_node(rects, node);
+        return old_last;
+     }
+   rect_list_append_node(&dirty, node);
+   while (dirty.head)
+     {
+       list_node_t *d_node, *cur_node, *prev_cur_node;
+        int keep_dirty;
+        rect_t r;
+
+        d_node = rect_list_unlink_next(&dirty, NULL);
+        r = ((rect_node_t *)d_node)->rect;
+        prev_cur_node = NULL;
+        cur_node = rects->head;
+        keep_dirty = 1;
+        while (cur_node)
+         {
+            int area, action;
+            rect_t current, intra, outer;
+
+            current = ((rect_node_t *)cur_node)->rect;
+            _calc_intra_outer_rect_area(r, current, &intra, &outer);
+            area = current.area + r.area - intra.area;
+            if ((intra.width == r.width) && (intra.height == r.height))
+              {
+                 /*  .-------.cur
+                  *  | .---.r|
+                  *  | |   | |
+                  *  | `---' |
+                  *  `-------'
+                  */
+                 keep_dirty = 0;
+                 break;
+              }
+            else if ((intra.width == current.width) &&
+                     (intra.height == current.height))
+              {
+                 /* .-------.r
+                  * | .---.cur
+                  * | |   | |
+                  * | `---' |
+                  * `-------'
+                  */
+                 if (old_last == cur_node)
+                    old_last = prev_cur_node;
+                 cur_node = cur_node->next;
+                 rect_list_del_next(rects, prev_cur_node);
+              }
+            else if ((outer.area - area) <= accepted_error)
+              {
+                 /* .-----------. bounding box (outer)
+                  * |.---. .---.|
+                  * ||cur| |r  ||
+                  * ||   | |   ||
+                  * |`---' `---'|
+                  * `-----------'
+                  * merge them, remove both and add merged
+                  */
+                 rect_node_t *n;
+
+                 if (old_last == cur_node)
+                    old_last = prev_cur_node;
+
+                 n = (rect_node_t *)rect_list_unlink_next(rects, prev_cur_node);
+                 n->rect = outer;
+                 rect_list_append_node(&dirty, (list_node_t *)n);
+
+                 keep_dirty = 0;
+                 break;
+              }
+            else if ((intra.area - area) <= accepted_error)
+              {
+                 /*  .---.cur     .---.r
+                  *  |   |        |   |
+                  *  `---+---.r   `---+---.cur
+                  *      |   |        |   |
+                  *      `---'        `---'
+                  *  no split, no merge
+                  */
+                 prev_cur_node = cur_node;
+                 cur_node = cur_node->next;
+              }
+            else
+              {
+                 /* split is required */
+                 action = _split_fuzzy(&dirty, current, &r);
+                 if (action == SPLIT_FUZZY_ACTION_MERGE)
+                   {
+                      /* horizontal merge is possible: remove both, add merged */
+                      rect_node_t *n;
+
+                      if (old_last == cur_node)
+                        old_last = prev_cur_node;
+
+                      n = (rect_node_t *)
+                        rect_list_unlink_next(rects, prev_cur_node);
+
+                      n->rect.left = outer.left;
+                      n->rect.width = outer.width;
+                      n->rect.right = outer.right;
+                      n->rect.area = outer.width * r.height;
+                      rect_list_append_node(&dirty, (list_node_t *)n);
+                   }
+                 else if (action == SPLIT_FUZZY_ACTION_NONE)
+                   {
+                      /* this rect check was totally useless,
+                       * should never happen */
+                      /* prev_cur_node = cur_node; */
+                      /* cur_node = cur_node->next; */
+                      WRN("Should not get here!");
+                      abort();
+                   }
+                 keep_dirty = 0;
+                 break;
+              }
+         }
+        if (UNLIKELY(keep_dirty)) rect_list_append_node(rects, d_node);
+        else rect_list_node_pool_put(d_node);
+     }
+    return old_last;
+}
+
+static inline void
+_calc_outer_rect_area(const rect_t a, const rect_t b, rect_t *outer)
+{
+   int min_left, max_right;
+   int min_top, max_bottom;
+
+   if (a.left < b.left) min_left = a.left;
+   else min_left = b.left;
+   if (a.right < b.right) max_right = b.right;
+   else max_right = a.right;
+   outer->left = min_left;
+   outer->right = max_right;
+   outer->width = max_right - min_left;
+   if (a.top < b.top) min_top = a.top;
+   else min_top = b.top;
+   if (a.bottom < b.bottom) max_bottom = b.bottom;
+   else max_bottom = a.bottom;
+   outer->top = min_top;
+   outer->bottom = max_bottom;
+   outer->height = max_bottom - min_top;
+   outer->area = outer->width * outer->height;
+}
+
+static inline void
+rect_list_merge_rects(list_t *rects, list_t *to_merge, int accepted_error)
+{
+   while (to_merge->head)
+     {
+        list_node_t *node, *parent_node;
+        rect_t r1;
+        int merged;
+
+        r1 = ((rect_node_t *)to_merge->head)->rect;
+        merged = 0;
+        parent_node = NULL;
+        node = rects->head;
+        while (node)
+         {
+            rect_t r2, outer;
+            int area;
+
+            r2 = ((rect_node_t *)node)->rect;
+            _calc_outer_rect_area(r1, r2, &outer);
+            area = r1.area + r2.area; /* intra area is taken as 0 */
+            if (outer.area - area <= accepted_error)
+              {
+                 /* remove both r1 and r2, create r3
+                  * actually r3 uses r2 instance, saves memory */
+                 rect_node_t *n;
+
+                 n = (rect_node_t *)rect_list_unlink_next(rects, parent_node);
+                 n->rect = outer;
+                 rect_list_append_node(to_merge, (list_node_t *)n);
+                 merged = 1;
+                 break;
+              }
+            parent_node = node;
+            node = node->next;
+         }
+        if (!merged)
+         {
+            list_node_t *n;
+            n = rect_list_unlink_next(to_merge, NULL);
+            rect_list_append_node(rects, n);
+         }
+       else
+         rect_list_del_next(to_merge, NULL);
+    }
+}
+
+static inline void
+rect_list_add_split_fuzzy_and_merge(list_t *rects,
+                                    list_node_t *node,
+                                    int split_accepted_error,
+                                    int merge_accepted_error)
+{
+   list_node_t *n;
+
+   n = rect_list_add_split_fuzzy(rects, node, split_accepted_error);
+   if (n && n->next)
+     {
+        list_t to_merge;
+        /* split list into 2 segments, already merged and to merge */
+        to_merge.head = n->next;
+        to_merge.tail = rects->tail;
+        rects->tail = n;
+        n->next = NULL;
+        rect_list_merge_rects(rects, &to_merge, merge_accepted_error);
+     }
+}
+
+static inline int
+_add_redraw(list_t *rects, int x, int y, int w, int h, int fuzz)
+{
+   rect_node_t *rn;
+   rn = (rect_node_t *)rect_list_node_pool_get();
+   rn->_lst = list_node_zeroed;
+   rect_init(&rn->rect, x, y, w, h);
+   rect_list_add_split_fuzzy_and_merge(rects, (list_node_t *)rn, fuzz, fuzz);
+   return 1;
+}
+
+/////////////////////////////////////////////////////////////////
+
+EAPI void
+evas_common_tilebuf_init(void)
+{
+}
+
+EAPI Tilebuf *
+evas_common_tilebuf_new(int w, int h)
+{
+   Tilebuf *tb;
+
+   tb = calloc(1, sizeof(Tilebuf));
+   if (!tb) return NULL;
+   tb->tile_size.w = 8;
+   tb->tile_size.h = 8;
+   tb->outbuf_w = w;
+   tb->outbuf_h = h;
+   return tb;
+}
+
+EAPI void
+evas_common_tilebuf_free(Tilebuf *tb)
+{
+   rect_list_clear(&tb->rects);
+   rect_list_node_pool_flush();
+   free(tb);
+}
+
+EAPI void
+evas_common_tilebuf_set_tile_size(Tilebuf *tb, int tw, int th)
+{
+   tb->tile_size.w = tw;
+   tb->tile_size.h = th;
+}
+
+EAPI void
+evas_common_tilebuf_get_tile_size(Tilebuf *tb, int *tw, int *th)
+{
+   if (tw) *tw = tb->tile_size.w;
+   if (th) *th = tb->tile_size.h;
+}
+
+EAPI void
+evas_common_tilebuf_tile_strict_set(Tilebuf *tb, Eina_Bool strict)
+{
+   tb->strict_tiles = strict;
+}
+
+EAPI int
+evas_common_tilebuf_add_redraw(Tilebuf *tb, int x, int y, int w, int h)
+{
+   if ((w <= 0) || (h <= 0)) return 0;
+   RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, tb->outbuf_w, tb->outbuf_h);
+   if ((w <= 0) || (h <= 0)) return 0;
+   // optimize a common case -> adding the exact same rect 2x in a row
+   if ((tb->prev_add.x == x) && (tb->prev_add.y == y) && 
+       (tb->prev_add.w == w) && (tb->prev_add.h == h)) return 1;
+   tb->prev_add.x = x; tb->prev_add.y = y;
+   tb->prev_add.w = w; tb->prev_add.h = h;
+   tb->prev_del.w = 0; tb->prev_del.h = 0;
+   return _add_redraw(&tb->rects, x, y, w, h, FUZZ * FUZZ);
+}
+
+EAPI int
+evas_common_tilebuf_del_redraw(Tilebuf *tb, int x, int y, int w, int h)
+{
+   rect_t r;
+
+   if (!tb->rects.head) return 0;
+   if ((w <= 0) || (h <= 0)) return 0;
+   RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, tb->outbuf_w, tb->outbuf_h);
+   if ((w <= 0) || (h <= 0)) return 0;
+   // optimize a common case -> deleting the exact same rect 2x in a row
+   if ((tb->prev_del.x == x) && (tb->prev_del.y == y) && 
+       (tb->prev_del.w == w) && (tb->prev_del.h == h)) return 1;
+   tb->prev_del.x = x; tb->prev_del.y = y;
+   tb->prev_del.w = w; tb->prev_del.h = h;
+   tb->prev_add.w = 0; tb->prev_add.h = 0;
+   rect_init(&r, x, y, w, h);
+   rect_list_del_split_strict(&tb->rects, r);
+   tb->need_merge = 1;
+   return 0;
+}
+
+EAPI int
+evas_common_tilebuf_add_motion_vector(Tilebuf *tb EINA_UNUSED, int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED, int dx EINA_UNUSED, int dy EINA_UNUSED, int alpha EINA_UNUSED)
+{
+   return 0;
+}
+
+EAPI void
+evas_common_tilebuf_clear(Tilebuf *tb)
+{
+   tb->prev_add.x = tb->prev_add.y = tb->prev_add.w = tb->prev_add.h = 0;
+   tb->prev_del.x = tb->prev_del.y = tb->prev_del.w = tb->prev_del.h = 0;
+   rect_list_clear(&tb->rects);
+   tb->need_merge = 0;
+}
+
+EAPI Tilebuf_Rect *
+evas_common_tilebuf_get_render_rects(Tilebuf *tb)
+{
+   list_node_t *n;
+   list_t to_merge;
+   Tilebuf_Rect *rects = NULL, *rbuf, *r;
+   int bx1 = 0, bx2 = 0, by1 = 0, by2 = 0, num = 0, x1, x2, y1, y2, i;
+
+/* don't need this since the below is now always on
+   if (tb->need_merge)
+     {
+        to_merge = tb->rects;
+        tb->rects = list_zeroed;
+        rect_list_merge_rects(&tb->rects, &to_merge, 0);
+        tb->need_merge = 0;
+     }
+ */
+   if (1)
+// always fuzz merge for optimal perf
+//   if (!tb->strict_tiles)
+     {
+        // round up rects to tb->tile_size.w and tb->tile_size.h
+        to_merge = list_zeroed;
+        for (n = tb->rects.head; n; n = n->next)
+          {
+             x1 = ((rect_node_t *)n)->rect.left;
+             x2 = x1 + ((rect_node_t *)n)->rect.width;
+             y1 = ((rect_node_t *)n)->rect.top;
+             y2 = y1 + ((rect_node_t *)n)->rect.height;
+             x1 = tb->tile_size.w * (x1 / tb->tile_size.w);
+             y1 = tb->tile_size.h * (y1 / tb->tile_size.h);
+             x2 = tb->tile_size.w * ((x2 + tb->tile_size.w - 1) / tb->tile_size.w);
+             y2 = tb->tile_size.h * ((y2 + tb->tile_size.h - 1) / tb->tile_size.h);
+             _add_redraw(&to_merge, x1, y1, x2 - x1, y2 - y1, 0);
+          }
+        rect_list_clear(&tb->rects);
+        rect_list_merge_rects(&tb->rects, &to_merge, 0);
+     }
+   n = tb->rects.head;
+   if (n)
+     {
+        RECTS_CLIP_TO_RECT(((rect_node_t *)n)->rect.left,
+                           ((rect_node_t *)n)->rect.top,
+                           ((rect_node_t *)n)->rect.width,
+                           ((rect_node_t *)n)->rect.height,
+                           0, 0, tb->outbuf_w, tb->outbuf_h);
+        num = 1;
+        bx1 = ((rect_node_t *)n)->rect.left;
+        bx2 = bx1 + ((rect_node_t *)n)->rect.width;
+        by1 = ((rect_node_t *)n)->rect.top;
+        by2 = by1 + ((rect_node_t *)n)->rect.height;
+        n = n->next;
+        for (; n; n = n->next)
+          {
+             RECTS_CLIP_TO_RECT(((rect_node_t *)n)->rect.left,
+                                ((rect_node_t *)n)->rect.top,
+                                ((rect_node_t *)n)->rect.width,
+                                ((rect_node_t *)n)->rect.height,
+                                0, 0, tb->outbuf_w, tb->outbuf_h);
+             x1 = ((rect_node_t *)n)->rect.left;
+             if (x1 < bx1) bx1 = x1;
+             x2 = x1 + ((rect_node_t *)n)->rect.width;
+             if (x2 > bx2) bx2 = x2;
+             
+             y1 = ((rect_node_t *)n)->rect.top;
+             if (y1 < by1) by1 = y1;
+             y2 = y1 + ((rect_node_t *)n)->rect.height;
+             if (y2 > by2) by2 = y2;
+             num++;
+          }
+     }
+   else
+     return NULL;
+   
+   /* magic number - if we have > MAXREG regions to update, take bounding */
+   if (num > MAXREG)
+     {
+        r = malloc(sizeof(Tilebuf_Rect));
+        if (r)
+          {
+             EINA_INLIST_GET(r)->next = NULL;
+             EINA_INLIST_GET(r)->prev = NULL;
+             EINA_INLIST_GET(r)->last = NULL;
+             r->x = bx1;
+             r->y = by1;
+             r->w = bx2 - bx1;
+             r->h = by2 - by1;
+             rects = (Tilebuf_Rect *)
+               eina_inlist_append(EINA_INLIST_GET(rects),
+                                  EINA_INLIST_GET(r));
+          }
+        return rects;
+     }
+
+   rbuf = malloc(sizeof(Tilebuf_Rect) * num);
+   if (!rbuf) return NULL;
+
+   for (i = 0, n = tb->rects.head; n; n = n->next)
+     {
+        rect_t cur;
+
+        cur = ((rect_node_t *)n)->rect;
+        if ((cur.width > 0) && (cur.height > 0))
+          {
+             r = &(rbuf[i]);
+             EINA_INLIST_GET(r)->next = NULL;
+             EINA_INLIST_GET(r)->prev = NULL;
+             EINA_INLIST_GET(r)->last = NULL;
+             r->x = cur.left;
+             r->y = cur.top;
+             r->w = cur.width;
+             r->h = cur.height;
+             rects = (Tilebuf_Rect *)
+               eina_inlist_append(EINA_INLIST_GET(rects),
+                                  EINA_INLIST_GET(r));
+             i++;
+          }
+     }
+
+   // It is possible that due to the clipping we do not return any rectangle here.
+   if (!rects) free(rbuf);
+
+   return rects;
+}
+
+EAPI void
+evas_common_tilebuf_free_render_rects(Tilebuf_Rect *rects)
+{
+   free(rects);
+}
+#endif
index 2c42341..632a941 100644 (file)
@@ -244,7 +244,7 @@ extern EAPI int _evas_log_dom_global;
 /*****************************************************************************/
 
 /* use exact rects for updates not tiles */
-/* #define RECTUPDATE */
+//#define NEWTILER
 #define TILESIZE 8
 #define IMG_MAX_SIZE 65000
 
@@ -433,7 +433,11 @@ typedef struct _Cutout_Rects            Cutout_Rects;
 typedef struct _Convert_Pal             Convert_Pal;
 
 typedef struct _Tilebuf                 Tilebuf;
-typedef struct _Tilebuf_Rect           Tilebuf_Rect;
+typedef struct _Tilebuf_Rect            Tilebuf_Rect;
+
+#ifndef NEWTILER
+typedef struct _Tilebuf_Tile            Tilebuf_Tile;
+#endif
 
 typedef struct _Evas_Common_Transform        Evas_Common_Transform;
 
@@ -1075,11 +1079,65 @@ struct _RGBA_Gfx_Compositor
    RGBA_Gfx_Pt_Func  (*composite_pixel_mask_pt_get)(Eina_Bool src_alpha, Eina_Bool dst_alpha);
 };
 
+#ifndef NEWTILER
+typedef struct list_node list_node_t;
+typedef struct list list_t;
+typedef struct rect rect_t;
+typedef struct rect_node rect_node_t;
+
+struct list_node
+{
+    struct list_node *next;
+};
+
+struct list
+{
+    struct list_node *head;
+    struct list_node *tail;
+};
+
+struct rect
+{
+    int left;
+    int top;
+    int right;
+    int bottom;
+    int width;
+    int height;
+    int area;
+};
+
+struct rect_node
+{
+    struct list_node _lst;
+    struct rect rect;
+};
+#endif
+
 struct _Tilebuf
 {
    int outbuf_w, outbuf_h;
+#ifdef NEWTILER
    void *region;
+#else
+   struct {
+      short w, h;
+   } tile_size;
+   int need_merge;
+   list_t rects;
+   struct {
+      int x, y, w, h;
+   } prev_add, prev_del;
+   Eina_Bool strict_tiles : 1;
+#endif
+};
+
+#ifndef NEWTILER
+struct _Tilebuf_Tile
+{
+   Eina_Bool redraw : 1;
 };
+#endif
 
 struct _Tilebuf_Rect
 {