summaryrefslogtreecommitdiff
path: root/src/lib/evas/common
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2015-09-23 22:22:27 +0900
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2015-09-24 14:09:09 +0900
commit49adf8aa47f37c41ee1fed288c828737104f1c5f (patch)
tree9d453bc773e9586417c9d801a221ba9a58b7aa82 /src/lib/evas/common
parent5df38e9d53bd8caf9b6dcd8b4321934ecd9dba75 (diff)
evas tiler update handler - move to region code to be accurate and fast
this move evas tiler that does update handling to use fully correct regions using region.[xh]. this also removed old unused regionbuf code and a bunch of commented out code no longer needed. much simpler now and easier to maintain.
Diffstat (limited to 'src/lib/evas/common')
-rw-r--r--src/lib/evas/common/evas_regionbuf.c357
-rw-r--r--src/lib/evas/common/evas_tiler.c878
2 files changed, 38 insertions, 1197 deletions
diff --git a/src/lib/evas/common/evas_regionbuf.c b/src/lib/evas/common/evas_regionbuf.c
deleted file mode 100644
index 3b14af8..0000000
--- a/src/lib/evas/common/evas_regionbuf.c
+++ /dev/null
@@ -1,357 +0,0 @@
1#include "evas_common_private.h"
2
3#if 0
4Regionbuf *
5evas_common_regionbuf_new(int w, int h)
6{
7 Regionbuf *rb;
8
9 rb = calloc(1, sizeof(Regionbuf) + (h * sizeof(Regionspan)));
10 if (!rb) return NULL;
11 rb->spans = (Regionspan **)(rb + sizeof(Regionbuf));
12 rb->w = w;
13 rb->h = h;
14 return rb;
15}
16
17void
18evas_common_regionbuf_free(Regionbuf *rb)
19{
20 evas_common_regionbuf_clear(rb);
21 free(rb);
22}
23
24void
25evas_common_regionbuf_clear(Regionbuf *rb)
26{
27 int y;
28
29 for (y = 0; y < rb->h; y++)
30 {
31 while (rb->spans[y])
32 {
33 Regionspan *span;
34
35 span = rb->spans[y];
36 rb->spans[y] = eina_inlist_remove(rb->spans[y], rb->spans[y]);
37 free(span);
38 }
39 }
40}
41
42void
43evas_common_regionbuf_span_add(Regionbuf *rb, int x1, int x2, int y)
44{
45 Regionspan *span, *span2, *nspan, *sp_start, *sp_stop;
46
47 /* abort if outside */
48 if ((y < 0) ||
49 (y >= rb->h) ||
50 (x2 < 0) ||
51 (x1 >= rb->w)) return;
52 /* clip to horiz bounds */
53 if (x1 < 0) x1 = 0;
54 if (x2 < (rb->w - 1)) x2 = rb->w - 1;
55 sp_start = NULL;
56 sp_stop = NULL;
57 EINA_INLIST_FOREACH(rb->spans[y], span)
58 {
59 nspan = (Regionspan *)(EINA_INLIST_GET(span))->next;
60 /* we dont know what t do with the span yet */
61 if (!sp_start)
62 {
63 /* if new span starts before or on this span or just after
64 * with no gap */
65 if (x1 <= (span->x2 + 1))
66 sp_start = span;
67 /* if there is no next span */
68 if (!nspan)
69 {
70 sp_stop = span;
71 break;
72 }
73 /* if new span ends before the next span starts with a gap of
74 * 1 pixel (or more) */
75 else if (x2 < (nspan->x1 - 1))
76 {
77 sp_stop = span;
78 break;
79 }
80 }
81 /* we already know it already starts before or in sp_start */
82 else
83 {
84 /* there is no span after this one, so this has to be the stop */
85 if (!nspan)
86 {
87 sp_stop = span;
88 break;
89 }
90 /* if new span ends before the next span starts with a gap of
91 * 1 pixel (or more) */
92 else if (x2 < (nspan->x1 - 1))
93 {
94 sp_stop = span;
95 break;
96 }
97 }
98 }
99 /* sp_start is where the new span starts in or before */
100 /* sp_stop is where the new span stops in or after */
101 if ((sp_start) && (sp_stop))
102 {
103 /* same start and stop */
104 if (sp_start == sp_stop)
105 {
106 if (x2 < (sp_start->x1 - 1))
107 {
108 span2 = calloc(1, sizeof(Regionspan));
109 span2->x1 = x1;
110 span2->x2 = x2;
111 rb->spans[y] = eina_inlist_prepend_relative(rb->spans[y], span2, sp_start);
112 return;
113 }
114 if (x1 < sp_start->x1)
115 sp_start->x1 = x1;
116 if (x2 > sp_start->x2)
117 sp_start->x2 = x2;
118 return;
119 }
120 else
121 {
122 Eina_Inlist *l;
123
124 /* remove all nodes after sp_start and before_sp_stop because
125 * the new */
126 for (l = (EINA_INLIST_GET(sp_start))->next; l != EINA_INLIST_GET(sp_stop);)
127 {
128 span = (Regionspan *)l;
129 l = l->next;
130 rb->spans[y] = eina_inlist_remove(rb->spans[y], span);
131 free(span);
132 }
133 /* remove the end span */
134 rb->spans[y] = eina_inlist_remove(rb->spans[y], sp_stop);
135 /* if the new span is before the start span - extend */
136 if (x1 < sp_start->x1)
137 sp_start->x1 = x1;
138 /* if it goes beyond the stop span - extend stop span */
139 if (x2 > sp_stop->x2)
140 sp_stop->x2 = x2;
141 /* extend start span to stop span */
142 sp_start->x2 = sp_stop->x2;
143 /* don't need stop span anymore */
144 free(sp_stop);
145 return;
146 }
147 }
148 /* no start AND stop... just append */
149 span2 = calloc(1, sizeof(Regionspan));
150 span2->x1 = x1;
151 span2->x2 = x2;
152 rb->spans[y] = eina_inlist_append(rb->spans[y], span2);
153}
154
155void
156evas_common_regionbuf_span_del(Regionbuf *rb, int x1, int x2, int y)
157{
158 /* FIXME: del span */
159 Regionspan *span, *span2, *nspan, *sp_start, *sp_stop;
160
161 /* abort if outside */
162 if ((y < 0) ||
163 (y >= rb->h) ||
164 (x2 < 0) ||
165 (x1 >= rb->w)) return;
166 /* clip to horiz bounds */
167 if (x1 < 0) x1 = 0;
168 if (x2 < (rb->w - 1)) x2 = rb->w - 1;
169 sp_start = NULL;
170 sp_stop = NULL;
171 EINA_INLIST_FOREACH(rb->spans[y], span)
172 {
173 nspan = (Regionspan *)(EINA_INLIST_GET(l))->next;
174 /* we dont know what t do with the span yet */
175 if (!sp_start)
176 {
177 /* if new span starts before or on this span or just after
178 * with no gap */
179 if (x1 <= (span->x2))
180 sp_start = span;
181 /* if there is no next span */
182 if (!nspan)
183 {
184 sp_stop = span;
185 break;
186 }
187 /* if new span ends before the next span starts with a gap of
188 * 1 pixel (or more) */
189 else if (x2 < nspan->x1)
190 {
191 sp_stop = span;
192 break;
193 }
194 }
195 /* we already know it already starts before or in sp_start */
196 else
197 {
198 /* there is no span after this one, so this has to be the stop */
199 if (!nspan)
200 {
201 sp_stop = span;
202 break;
203 }
204 /* if new span ends before the next span starts with a gap of
205 * 1 pixel (or more) */
206 else if (x2 < nspan->x1)
207 {
208 sp_stop = span;
209 break;
210 }
211 }
212 }
213 /* sp_start is where the new span starts in or before */
214 /* sp_stop is where the new span stops in or after */
215 if ((sp_start) && (sp_stop))
216 {
217 /* same start and stop */
218 if (sp_start == sp_stop)
219 {
220 /* if it ends before this the span start starts... return */
221 if (x2 < sp_start->x1)
222 return;
223 /* it starts on or before this span */
224 else if (x1 <= sp_start->x1)
225 {
226 /* right edge is within the span */
227 if (x2 < sp_start->x2)
228 {
229 sp_start->x2 = x2;
230 return;
231 }
232 else
233 {
234 rb->spans[y] = eina_inlist_remove(rb->spans[y], sp_start);
235 return;
236 }
237 }
238 /* it ends on or after the end of this span */
239 else if (x2 >= sp_start->x2)
240 {
241 /* it starts after the start */
242 if (x1 > sp_start->x1)
243 {
244 sp_start->x1 = x1;
245 return;
246 }
247 /* remove it all */
248 else
249 {
250 rb->spans[y] = eina_inlist_remove(rb->spans[y], sp_start);
251 return;
252 }
253 return;
254 }
255 /* this breaks the span into 2 */
256 else
257 {
258 span2 = calloc(1, sizeof(Regionspan));
259 span2->x1 = sp_start->x1;
260 span2->x2 = x1 - 1;
261 rb->spans[y] = eina_inlist_prepend_relative(rb->spans[y], span2, sp_start);
262 sp_start->x1 = x2 + 1;
263 return;
264 }
265 }
266 else
267 {
268 Eina_Inlist *l;
269
270 /* remove all nodes after sp_start and before_sp_stop because
271 * the new */
272 for (l = (EINA_INLIST_GET(sp_start))->next; l != EINA_INLIST_GET(sp_stop);)
273 {
274 span = (Regionspan *)l;
275 l = l->next;
276 rb->spans[y] = eina_inlist_remove(rb->spans[y], span);
277 free(span);
278 }
279 /* all of the start span is cut out */
280 if (x1 <= sp_start->x1)
281 {
282 rb->spans[y] = eina_inlist_remove(rb->spans[y], sp_start);
283 free(sp_start);
284 }
285 /* chup it off at the new span start */
286 else
287 sp_start->x2 = x1 - 1;
288 /* all of the end span is cut out */
289 if (x2 >= sp_stop->x2)
290 {
291 rb->spans[y] = eina_inlist_remove(rb->spans[y], sp_stop);
292 free(sp_stop);
293 }
294 /* chop it up at the end */
295 else
296 sp_stop->x1 = x2 + 1;
297 return;
298 }
299 }
300}
301
302Tilebuf_Rect *
303evas_common_regionbuf_rects_get(Regionbuf *rb)
304{
305 Tilebuf_Rect *rects = NULL, *r;
306 int y;
307
308 /* FIXME: take spans, make rects */
309 for (y = 0; y < rb->h; y++)
310 {
311 Regionspan *sp_start;
312 Eina_Inlist *l, *ll;
313
314 for (l = EINA_INLIST_GET(rb->spans[y]); l;)
315 {
316 Regionspan *span;
317 int yy;
318
319 sp_start = (Regionspan *)l;
320 l = l->next;
321 rb->spans[y] = eina_inlist_remove(rb->spans[y], sp_start);
322 for (yy = y + 1; yy < rb->h; yy++)
323 {
324 int match = 0;
325
326 for (ll = EINA_INLIST_GET(rb->spans[yy]); ll;)
327 {
328 span = (Regionspan *)ll;
329 ll = ll->next;
330 if (span->x1 == sp_start->x1)
331 {
332 if ((span->x1 != sp_start->x1) ||
333 (span->x2 != sp_start->x2))
334 {
335 goto coallate;
336 }
337 match = 1;
338 rb->spans[yy] = eina_inlist_remove(rb->spans[yy], span);
339 free(span);
340 }
341 }
342 if (!match) goto coallate;
343 }
344 coallate:
345 r = calloc(1, sizeof(Tilebuf_Rect));
346 r->x = sp_start->x1;
347 r->y = y;
348 r->w = sp_start->x2 - sp_start->x1 + 1;
349 r->h = yy - y;
350 rects = eina_inlist_append(rects, r);
351 free(sp_start);
352 }
353 }
354 evas_common_regionbuf_clear(rb);
355 return rects;
356}
357#endif
diff --git a/src/lib/evas/common/evas_tiler.c b/src/lib/evas/common/evas_tiler.c
index 2dbe9fd..74f5d18 100644
--- a/src/lib/evas/common/evas_tiler.c
+++ b/src/lib/evas/common/evas_tiler.c
@@ -1,684 +1,5 @@
1#include "evas_common_private.h" 1#include "evas_common_private.h"
2 2#include "region.h"
3#define FUZZ 32
4#define MAXREG 24
5#define MAX_NODES 1024
6
7static inline void rect_list_node_pool_flush(void);
8static inline list_node_t *rect_list_node_pool_get(void);
9static inline void rect_list_node_pool_put(list_node_t *node);
10static inline void rect_init(rect_t *r, int x, int y, int w, int h);
11static inline void rect_list_append_node(list_t *rects, list_node_t *node);
12static inline void rect_list_append(list_t *rects, const rect_t r);
13static inline void rect_list_append_xywh(list_t *rects, int x, int y, int w, int h);
14static inline void rect_list_concat(list_t *rects, list_t *other);
15static inline list_node_t *rect_list_unlink_next(list_t *rects, list_node_t *parent_node);
16static inline void rect_list_del_next(list_t *rects, list_node_t *parent_node);
17static inline void rect_list_clear(list_t *rects);
18static inline void rect_list_del_split_strict(list_t *rects, const rect_t del_r);
19static inline list_node_t *rect_list_add_split_fuzzy(list_t *rects, list_node_t *node, int accepted_error);
20static inline void rect_list_merge_rects(list_t *rects, list_t *to_merge, int accepted_error);
21static inline void rect_list_add_split_fuzzy_and_merge(list_t *rects, list_node_t *node, int split_accepted_error, int merge_accepted_error);
22
23static const list_node_t list_node_zeroed = { NULL };
24static const list_t list_zeroed = { NULL, NULL };
25
26typedef struct list_node_pool
27{
28 list_node_t *node;
29 int len;
30 int max;
31} list_node_pool_t;
32
33static list_node_pool_t list_node_pool = { NULL, 0, MAX_NODES };
34
35static inline void
36rect_list_node_pool_flush(void)
37{
38 while (list_node_pool.node)
39 {
40 list_node_t *node = list_node_pool.node;
41 list_node_pool.node = node->next;
42 list_node_pool.len--;
43 free(node);
44 }
45}
46
47static inline list_node_t *
48rect_list_node_pool_get(void)
49{
50 if (list_node_pool.node)
51 {
52 list_node_t *node = list_node_pool.node;
53 list_node_pool.node = node->next;
54 list_node_pool.len--;
55 return node;
56 }
57 else return (list_node_t *)malloc(sizeof(rect_node_t));
58}
59
60static inline void
61rect_list_node_pool_put(list_node_t *node)
62{
63 if (list_node_pool.len < list_node_pool.max)
64 {
65 node->next = list_node_pool.node;
66 list_node_pool.node = node;
67 list_node_pool.len++;
68 }
69 else free(node);
70}
71
72static inline void
73rect_init(rect_t *r, int x, int y, int w, int h)
74{
75 r->area = w * h;
76 r->left = x;
77 r->top = y;
78 r->right = x + w;
79 r->bottom = y + h;
80 r->width = w;
81 r->height = h;
82}
83
84static inline void
85rect_list_append_node(list_t *rects, list_node_t *node)
86{
87 if (rects->tail)
88 {
89 rects->tail->next = node;
90 rects->tail = node;
91 }
92 else
93 {
94 rects->head = node;
95 rects->tail = node;
96 }
97}
98
99static inline void
100rect_list_append(list_t *rects, const rect_t r)
101{
102 rect_node_t *rect_node = (rect_node_t *)rect_list_node_pool_get();
103 rect_node->rect = r;
104 rect_node->_lst = list_node_zeroed;
105 rect_list_append_node(rects, (list_node_t *)rect_node);
106}
107
108static inline void
109rect_list_append_xywh(list_t *rects, int x, int y, int w, int h)
110{
111 rect_t r;
112 rect_init(&r, x, y, w, h);
113 rect_list_append(rects, r);
114}
115
116static inline void
117rect_list_concat(list_t *rects, list_t *other)
118{
119 if (!other->head) return;
120 if (rects->tail)
121 {
122 rects->tail->next = other->head;
123 rects->tail = other->tail;
124 }
125 else
126 {
127 rects->head = other->head;
128 rects->tail = other->tail;
129 }
130 *other = list_zeroed;
131}
132
133static inline list_node_t *
134rect_list_unlink_next(list_t *rects, list_node_t *parent_node)
135{
136 list_node_t *node;
137
138 if (parent_node)
139 {
140 node = parent_node->next;
141 parent_node->next = node->next;
142 }
143 else
144 {
145 node = rects->head;
146 rects->head = node->next;
147 }
148 if (rects->tail == node) rects->tail = parent_node;
149 *node = list_node_zeroed;
150 return node;
151}
152
153static inline void
154rect_list_del_next(list_t *rects, list_node_t *parent_node)
155{
156 list_node_t *node = rect_list_unlink_next(rects, parent_node);
157 rect_list_node_pool_put(node);
158}
159
160static inline void
161rect_list_clear(list_t *rects)
162{
163 list_node_t *node = rects->head;
164 while (node)
165 {
166 list_node_t *aux;
167
168 aux = node->next;
169 rect_list_node_pool_put(node);
170 node = aux;
171 }
172 *rects = list_zeroed;
173}
174
175static inline void
176_calc_intra_rect_area(const rect_t a, const rect_t b, int *width, int *height)
177{
178 int max_left, min_right, max_top, min_bottom;
179
180 if (a.left < b.left) max_left = b.left;
181 else max_left = a.left;
182 if (a.right < b.right) min_right = a.right;
183 else min_right = b.right;
184 *width = min_right - max_left;
185
186 if (a.top < b.top) max_top = b.top;
187 else max_top = a.top;
188 if (a.bottom < b.bottom) min_bottom = a.bottom;
189 else min_bottom = b.bottom;
190 *height = min_bottom - max_top;
191}
192
193static inline void
194_split_strict(list_t *dirty, const rect_t current, rect_t r)
195{
196 int h_1, h_2, w_1, w_2;
197
198 h_1 = current.top - r.top;
199 h_2 = r.bottom - current.bottom;
200 w_1 = current.left - r.left;
201 w_2 = r.right - current.right;
202 if (h_1 > 0)
203 {
204 /* .--.r (b) .---.r2
205 * | | | |
206 * .-------.cur (a) .---.r '---'
207 * | | | | -> | | +
208 * | `--' | `---'
209 * `-------'
210 */
211 rect_list_append_xywh(dirty, r.left, r.top, r.width, h_1);
212 r.height -= h_1;
213 r.top = current.top;
214 }
215 if (h_2 > 0)
216 {
217 /* .-------.cur (a)
218 * | .---. | .---.r
219 * | | | | -> | |
220 * `-------' `---' + .---.r2
221 * | | | |
222 * `---'r (b) `---'
223 */
224 rect_list_append_xywh(dirty, r.left, current.bottom, r.width, h_2);
225 r.height -= h_2;
226 }
227 if (w_1 > 0)
228 {
229 /* (b) r .----.cur (a)
230 * .--|-. | .--.r2 .-.r
231 * | | | | -> | | + | |
232 * `--|-' | `--' `-'
233 * `----'
234 */
235 rect_list_append_xywh(dirty, r.left, r.top, w_1, r.height);
236 /* not necessary to keep these, r (b) will be destroyed */
237 /* r.width -= w_1; */
238 /* r.left = current.left; */
239 }
240 if (w_2 > 0)
241 {
242 /* .----.cur (a)
243 * | |
244 * | .-|--.r (b) .-.r .--.r2
245 * | | | | -> | | + | |
246 * | `-|--' `-' `--'
247 * `----'
248 */
249 rect_list_append_xywh(dirty, current.right, r.top, w_2, r.height);
250 /* not necessary to keep this, r (b) will be destroyed */
251 /* r.width -= w_2; */
252 }
253}
254
255static inline void
256rect_list_del_split_strict(list_t *rects, const rect_t del_r)
257{
258 list_t modified = list_zeroed;
259 list_node_t *cur_node, *prev_node;
260 int intra_width, intra_height;
261 rect_t current;
262
263 prev_node = NULL;
264 cur_node = rects->head;
265 while (cur_node)
266 {
267 current = ((rect_node_t*)cur_node)->rect;
268 _calc_intra_rect_area(del_r, current, &intra_width, &intra_height);
269 if ((intra_width <= 0) || (intra_height <= 0))
270 {
271 /* .---.current .---.del_r
272 * | | | |
273 * `---+---.del_r `---+---.current
274 * | | | |
275 * `---' `---'
276 * no interception, nothing to do
277 */
278 prev_node = cur_node;
279 cur_node = cur_node->next;
280 }
281 else if ((intra_width == current.width) &&
282 (intra_height == current.height))
283 {
284 /* .-------.del_r
285 * | .---. |
286 * | | | |
287 * | `---'current
288 * `-------'
289 * current is contained, remove from rects
290 */
291 cur_node = cur_node->next;
292 rect_list_del_next(rects, prev_node);
293 }
294 else
295 {
296 _split_strict(&modified, del_r, current);
297 cur_node = cur_node->next;
298 rect_list_del_next(rects, prev_node);
299 }
300 }
301
302 rect_list_concat(rects, &modified);
303}
304
305static inline void
306_calc_intra_outer_rect_area(const rect_t a, const rect_t b,
307 rect_t *intra, rect_t *outer)
308{
309 int min_left, max_left, min_right, max_right;
310 int min_top, max_top, min_bottom, max_bottom;
311
312 if (a.left < b.left)
313 {
314 max_left = b.left;
315 min_left = a.left;
316 }
317 else
318 {
319 max_left = a.left;
320 min_left = b.left;
321 }
322 if (a.right < b.right)
323 {
324 min_right = a.right;
325 max_right = b.right;
326 }
327 else
328 {
329 min_right = b.right;
330 max_right = a.right;
331 }
332 intra->left = max_left;
333 intra->right = min_right;
334 intra->width = min_right - max_left;
335 outer->left = min_left;
336 outer->right = max_right;
337 outer->width = max_right - min_left;
338 if (a.top < b.top)
339 {
340 max_top = b.top;
341 min_top = a.top;
342 }
343 else
344 {
345 max_top = a.top;
346 min_top = b.top;
347 }
348 if (a.bottom < b.bottom)
349 {
350 min_bottom = a.bottom;
351 max_bottom = b.bottom;
352 }
353 else
354 {
355 min_bottom = b.bottom;
356 max_bottom = a.bottom;
357 }
358 intra->top = max_top;
359 intra->bottom = min_bottom;
360 intra->height = min_bottom - max_top;
361 if ((intra->width > 0) && (intra->height > 0))
362 intra->area = intra->width * intra->height;
363 else
364 intra->area = 0;
365 outer->top = min_top;
366 outer->bottom = max_bottom;
367 outer->height = max_bottom - min_top;
368 outer->area = outer->width * outer->height;
369}
370
371enum
372{
373 SPLIT_FUZZY_ACTION_NONE,
374 SPLIT_FUZZY_ACTION_SPLIT,
375 SPLIT_FUZZY_ACTION_MERGE
376};
377
378static inline int
379_split_fuzzy(list_t *dirty, const rect_t a, rect_t *b)
380{
381 int h_1, h_2, w_1, w_2, action;
382
383 h_1 = a.top - b->top;
384 h_2 = b->bottom - a.bottom;
385 w_1 = a.left - b->left;
386 w_2 = b->right - a.right;
387
388 action = SPLIT_FUZZY_ACTION_NONE;
389 if (h_1 > 0)
390 {
391 /* .--.r (b) .---.r2
392 * | | | |
393 * .-------.cur (a) .---.r '---'
394 * | | | | -> | | +
395 * | `--' | `---'
396 * `-------'
397 */
398 rect_list_append_xywh(dirty, b->left, b->top, b->width, h_1);
399 b->height -= h_1;
400 b->top = a.top;
401 action = SPLIT_FUZZY_ACTION_SPLIT;
402 }
403 if (h_2 > 0)
404 {
405 /* .-------.cur (a)
406 * | .---. | .---.r
407 * | | | | -> | |
408 * `-------' `---' + .---.r2
409 * | | | |
410 * `---'r (b) `---'
411 */
412 rect_list_append_xywh(dirty, b->left, a.bottom, b->width, h_2);
413 b->height -= h_2;
414 action = SPLIT_FUZZY_ACTION_SPLIT;
415 }
416 if (((w_1 > 0) || (w_2 > 0)) && (a.height == b->height))
417 return SPLIT_FUZZY_ACTION_MERGE;
418 if (w_1 > 0)
419 {
420 /* (b) r .----.cur (a)
421 * .--|-. | .--.r2 .-.r
422 * | | | | -> | | + | |
423 * `--|-' | `--' `-'
424 * `----'
425 */
426 rect_list_append_xywh(dirty, b->left, b->top, w_1, b->height);
427 /* not necessary to keep these, r (b) will be destroyed */
428 /* b->width -= w_1; */
429 /* b->left = a.left; */
430 action = SPLIT_FUZZY_ACTION_SPLIT;
431 }
432 if (w_2 > 0)
433 {
434 /* .----.cur (a)
435 * | |
436 * | .-|--.r (b) .-.r .--.r2
437 * | | | | -> | | + | |
438 * | `-|--' `-' `--'
439 * `----'
440 */
441 rect_list_append_xywh(dirty, a.right, b->top, w_2, b->height);
442 /* not necessary to keep these, r (b) will be destroyed */
443 /* b->width -= w_2; */
444 action = SPLIT_FUZZY_ACTION_SPLIT;
445 }
446 return action;
447}
448
449static inline list_node_t *
450rect_list_add_split_fuzzy(list_t *rects, list_node_t *node, int accepted_error)
451{
452 list_t dirty = list_zeroed;
453 list_node_t *old_last = rects->tail;
454
455 if (!rects->head)
456 {
457 rect_list_append_node(rects, node);
458 return old_last;
459 }
460 rect_list_append_node(&dirty, node);
461 while (dirty.head)
462 {
463 list_node_t *d_node, *cur_node, *prev_cur_node;
464 int keep_dirty;
465 rect_t r;
466
467 d_node = rect_list_unlink_next(&dirty, NULL);
468 r = ((rect_node_t *)d_node)->rect;
469 prev_cur_node = NULL;
470 cur_node = rects->head;
471 keep_dirty = 1;
472 while (cur_node)
473 {
474 int area, action;
475 rect_t current, intra, outer;
476
477 current = ((rect_node_t *)cur_node)->rect;
478 _calc_intra_outer_rect_area(r, current, &intra, &outer);
479 area = current.area + r.area - intra.area;
480 if ((intra.width == r.width) && (intra.height == r.height))
481 {
482 /* .-------.cur
483 * | .---.r|
484 * | | | |
485 * | `---' |
486 * `-------'
487 */
488 keep_dirty = 0;
489 break;
490 }
491 else if ((intra.width == current.width) &&
492 (intra.height == current.height))
493 {
494 /* .-------.r
495 * | .---.cur
496 * | | | |
497 * | `---' |
498 * `-------'
499 */
500 if (old_last == cur_node)
501 old_last = prev_cur_node;
502 cur_node = cur_node->next;
503 rect_list_del_next(rects, prev_cur_node);
504 }
505 else if ((outer.area - area) <= accepted_error)
506 {
507 /* .-----------. bounding box (outer)
508 * |.---. .---.|
509 * ||cur| |r ||
510 * || | | ||
511 * |`---' `---'|
512 * `-----------'
513 * merge them, remove both and add merged
514 */
515 rect_node_t *n;
516
517 if (old_last == cur_node)
518 old_last = prev_cur_node;
519
520 n = (rect_node_t *)rect_list_unlink_next(rects, prev_cur_node);
521 n->rect = outer;
522 rect_list_append_node(&dirty, (list_node_t *)n);
523
524 keep_dirty = 0;
525 break;
526 }
527 else if ((intra.area - area) <= accepted_error)
528 {
529 /* .---.cur .---.r
530 * | | | |
531 * `---+---.r `---+---.cur
532 * | | | |
533 * `---' `---'
534 * no split, no merge
535 */
536 prev_cur_node = cur_node;
537 cur_node = cur_node->next;
538 }
539 else
540 {
541 /* split is required */
542 action = _split_fuzzy(&dirty, current, &r);
543 if (action == SPLIT_FUZZY_ACTION_MERGE)
544 {
545 /* horizontal merge is possible: remove both, add merged */
546 rect_node_t *n;
547
548 if (old_last == cur_node)
549 old_last = prev_cur_node;
550
551 n = (rect_node_t *)
552 rect_list_unlink_next(rects, prev_cur_node);
553
554 n->rect.left = outer.left;
555 n->rect.width = outer.width;
556 n->rect.right = outer.right;
557 n->rect.area = outer.width * r.height;
558 rect_list_append_node(&dirty, (list_node_t *)n);
559 }
560 else if (action == SPLIT_FUZZY_ACTION_NONE)
561 {
562 /* this rect check was totally useless,
563 * should never happen */
564 /* prev_cur_node = cur_node; */
565 /* cur_node = cur_node->next; */
566 WRN("Should not get here!");
567 abort();
568 }
569 keep_dirty = 0;
570 break;
571 }
572 }
573 if (UNLIKELY(keep_dirty)) rect_list_append_node(rects, d_node);
574 else rect_list_node_pool_put(d_node);
575 }
576 return old_last;
577}
578
579static inline void
580_calc_outer_rect_area(const rect_t a, const rect_t b, rect_t *outer)
581{
582 int min_left, max_right;
583 int min_top, max_bottom;
584
585 if (a.left < b.left) min_left = a.left;
586 else min_left = b.left;
587 if (a.right < b.right) max_right = b.right;
588 else max_right = a.right;
589 outer->left = min_left;
590 outer->right = max_right;
591 outer->width = max_right - min_left;
592 if (a.top < b.top) min_top = a.top;
593 else min_top = b.top;
594 if (a.bottom < b.bottom) max_bottom = b.bottom;
595 else max_bottom = a.bottom;
596 outer->top = min_top;
597 outer->bottom = max_bottom;
598 outer->height = max_bottom - min_top;
599 outer->area = outer->width * outer->height;
600}
601
602static inline void
603rect_list_merge_rects(list_t *rects, list_t *to_merge, int accepted_error)
604{
605 while (to_merge->head)
606 {
607 list_node_t *node, *parent_node;
608 rect_t r1;
609 int merged;
610
611 r1 = ((rect_node_t *)to_merge->head)->rect;
612 merged = 0;
613 parent_node = NULL;
614 node = rects->head;
615 while (node)
616 {
617 rect_t r2, outer;
618 int area;
619
620 r2 = ((rect_node_t *)node)->rect;
621 _calc_outer_rect_area(r1, r2, &outer);
622 area = r1.area + r2.area; /* intra area is taken as 0 */
623 if (outer.area - area <= accepted_error)
624 {
625 /* remove both r1 and r2, create r3
626 * actually r3 uses r2 instance, saves memory */
627 rect_node_t *n;
628
629 n = (rect_node_t *)rect_list_unlink_next(rects, parent_node);
630 n->rect = outer;
631 rect_list_append_node(to_merge, (list_node_t *)n);
632 merged = 1;
633 break;
634 }
635 parent_node = node;
636 node = node->next;
637 }
638 if (!merged)
639 {
640 list_node_t *n;
641 n = rect_list_unlink_next(to_merge, NULL);
642 rect_list_append_node(rects, n);
643 }
644 else
645 rect_list_del_next(to_merge, NULL);
646 }
647}
648
649static inline void
650rect_list_add_split_fuzzy_and_merge(list_t *rects,
651 list_node_t *node,
652 int split_accepted_error,
653 int merge_accepted_error)
654{
655 list_node_t *n;
656
657 n = rect_list_add_split_fuzzy(rects, node, split_accepted_error);
658 if (n && n->next)
659 {
660 list_t to_merge;
661 /* split list into 2 segments, already merged and to merge */
662 to_merge.head = n->next;
663 to_merge.tail = rects->tail;
664 rects->tail = n;
665 n->next = NULL;
666 rect_list_merge_rects(rects, &to_merge, merge_accepted_error);
667 }
668}
669
670static inline int
671_add_redraw(list_t *rects, int x, int y, int w, int h, int fuzz)
672{
673 rect_node_t *rn;
674 rn = (rect_node_t *)rect_list_node_pool_get();
675 rn->_lst = list_node_zeroed;
676 rect_init(&rn->rect, x, y, w, h);
677 rect_list_add_split_fuzzy_and_merge(rects, (list_node_t *)rn, fuzz, fuzz);
678 return 1;
679}
680
681/////////////////////////////////////////////////////////////////
682 3
683EAPI void 4EAPI void
684evas_common_tilebuf_init(void) 5evas_common_tilebuf_init(void)
@@ -688,79 +9,49 @@ evas_common_tilebuf_init(void)
688EAPI Tilebuf * 9EAPI Tilebuf *
689evas_common_tilebuf_new(int w, int h) 10evas_common_tilebuf_new(int w, int h)
690{ 11{
691 Tilebuf *tb; 12 Tilebuf *tb = malloc(sizeof(Tilebuf));
692
693 tb = calloc(1, sizeof(Tilebuf));
694 if (!tb) return NULL;
695 tb->tile_size.w = 8;
696 tb->tile_size.h = 8;
697 tb->outbuf_w = w; 13 tb->outbuf_w = w;
698 tb->outbuf_h = h; 14 tb->outbuf_h = h;
15 tb->region = region_new(tb->outbuf_w, tb->outbuf_h);
699 return tb; 16 return tb;
700} 17}
701 18
702EAPI void 19EAPI void
703evas_common_tilebuf_free(Tilebuf *tb) 20evas_common_tilebuf_free(Tilebuf *tb)
704{ 21{
705 rect_list_clear(&tb->rects); 22 region_free(tb->region);
706 rect_list_node_pool_flush();
707 free(tb); 23 free(tb);
708} 24}
709 25
710EAPI void 26EAPI void
711evas_common_tilebuf_set_tile_size(Tilebuf *tb, int tw, int th) 27evas_common_tilebuf_set_tile_size(Tilebuf *tb EINA_UNUSED, int tw EINA_UNUSED, int th EINA_UNUSED)
712{ 28{
713 tb->tile_size.w = tw;
714 tb->tile_size.h = th;
715} 29}
716 30
717EAPI void 31EAPI void
718evas_common_tilebuf_get_tile_size(Tilebuf *tb, int *tw, int *th) 32evas_common_tilebuf_get_tile_size(Tilebuf *tb EINA_UNUSED, int *tw, int *th)
719{ 33{
720 if (tw) *tw = tb->tile_size.w; 34 if (tw) *tw = 1;
721 if (th) *th = tb->tile_size.h; 35 if (th) *th = 1;
722} 36}
723 37
724EAPI void 38EAPI void
725evas_common_tilebuf_tile_strict_set(Tilebuf *tb, Eina_Bool strict) 39evas_common_tilebuf_tile_strict_set(Tilebuf *tb EINA_UNUSED, Eina_Bool strict EINA_UNUSED)
726{ 40{
727 tb->strict_tiles = strict;
728} 41}
729 42
730EAPI int 43EAPI int
731evas_common_tilebuf_add_redraw(Tilebuf *tb, int x, int y, int w, int h) 44evas_common_tilebuf_add_redraw(Tilebuf *tb, int x, int y, int w, int h)
732{ 45{
733 if ((w <= 0) || (h <= 0)) return 0; 46 region_rect_add(tb->region, x, y, w, h);
734 RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, tb->outbuf_w, tb->outbuf_h); 47 return 1;
735 if ((w <= 0) || (h <= 0)) return 0;
736 // optimize a common case -> adding the exact same rect 2x in a row
737 if ((tb->prev_add.x == x) && (tb->prev_add.y == y) &&
738 (tb->prev_add.w == w) && (tb->prev_add.h == h)) return 1;
739 tb->prev_add.x = x; tb->prev_add.y = y;
740 tb->prev_add.w = w; tb->prev_add.h = h;
741 tb->prev_del.w = 0; tb->prev_del.h = 0;
742 return _add_redraw(&tb->rects, x, y, w, h, FUZZ * FUZZ);
743} 48}
744 49
745EAPI int 50EAPI int
746evas_common_tilebuf_del_redraw(Tilebuf *tb, int x, int y, int w, int h) 51evas_common_tilebuf_del_redraw(Tilebuf *tb, int x, int y, int w, int h)
747{ 52{
748 rect_t r; 53 region_rect_del(tb->region, x, y, w, h);
749 54 return 1;
750 if (!tb->rects.head) return 0;
751 if ((w <= 0) || (h <= 0)) return 0;
752 RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, tb->outbuf_w, tb->outbuf_h);
753 if ((w <= 0) || (h <= 0)) return 0;
754 // optimize a common case -> deleting the exact same rect 2x in a row
755 if ((tb->prev_del.x == x) && (tb->prev_del.y == y) &&
756 (tb->prev_del.w == w) && (tb->prev_del.h == h)) return 1;
757 tb->prev_del.x = x; tb->prev_del.y = y;
758 tb->prev_del.w = w; tb->prev_del.h = h;
759 tb->prev_add.w = 0; tb->prev_add.h = 0;
760 rect_init(&r, x, y, w, h);
761 rect_list_del_split_strict(&tb->rects, r);
762 tb->need_merge = 1;
763 return 0;
764} 55}
765 56
766EAPI int 57EAPI int
@@ -772,134 +63,41 @@ evas_common_tilebuf_add_motion_vector(Tilebuf *tb EINA_UNUSED, int x EINA_UNUSED
772EAPI void 63EAPI void
773evas_common_tilebuf_clear(Tilebuf *tb) 64evas_common_tilebuf_clear(Tilebuf *tb)
774{ 65{
775 tb->prev_add.x = tb->prev_add.y = tb->prev_add.w = tb->prev_add.h = 0; 66 region_free(tb->region);
776 tb->prev_del.x = tb->prev_del.y = tb->prev_del.w = tb->prev_del.h = 0; 67 tb->region = region_new(tb->outbuf_w, tb->outbuf_h);
777 rect_list_clear(&tb->rects);
778 tb->need_merge = 0;
779} 68}
780 69
781EAPI Tilebuf_Rect * 70EAPI Tilebuf_Rect *
782evas_common_tilebuf_get_render_rects(Tilebuf *tb) 71evas_common_tilebuf_get_render_rects(Tilebuf *tb)
783{ 72{
784 list_node_t *n; 73 Tilebuf_Rect *rects = NULL, *r, *rend, *rbuf;
785 list_t to_merge; 74 Box *rects2, *rs;
786 Tilebuf_Rect *rects = NULL, *rbuf, *r; 75 int n;
787 int bx1 = 0, bx2 = 0, by1 = 0, by2 = 0, num = 0, x1, x2, y1, y2, i;
788 76
789/* don't need this since the below is now always on 77 rects2 = region_rects(tb->region);
790 if (tb->need_merge) 78 if (!rects2) return NULL;
791 { 79 n = region_rects_num(tb->region);
792 to_merge = tb->rects; 80 if (n <= 0) return NULL;
793 tb->rects = list_zeroed;
794 rect_list_merge_rects(&tb->rects, &to_merge, 0);
795 tb->need_merge = 0;
796 }
797 */
798 if (1)
799// always fuzz merge for optimal perf
800// if (!tb->strict_tiles)
801 {
802 // round up rects to tb->tile_size.w and tb->tile_size.h
803 to_merge = list_zeroed;
804 for (n = tb->rects.head; n; n = n->next)
805 {
806 x1 = ((rect_node_t *)n)->rect.left;
807 x2 = x1 + ((rect_node_t *)n)->rect.width;
808 y1 = ((rect_node_t *)n)->rect.top;
809 y2 = y1 + ((rect_node_t *)n)->rect.height;
810 x1 = tb->tile_size.w * (x1 / tb->tile_size.w);
811 y1 = tb->tile_size.h * (y1 / tb->tile_size.h);
812 x2 = tb->tile_size.w * ((x2 + tb->tile_size.w - 1) / tb->tile_size.w);
813 y2 = tb->tile_size.h * ((y2 + tb->tile_size.h - 1) / tb->tile_size.h);
814 _add_redraw(&to_merge, x1, y1, x2 - x1, y2 - y1, 0);
815 }
816 rect_list_clear(&tb->rects);
817 rect_list_merge_rects(&tb->rects, &to_merge, 0);
818 }
819 n = tb->rects.head;
820 if (n)
821 {
822 RECTS_CLIP_TO_RECT(((rect_node_t *)n)->rect.left,
823 ((rect_node_t *)n)->rect.top,
824 ((rect_node_t *)n)->rect.width,
825 ((rect_node_t *)n)->rect.height,
826 0, 0, tb->outbuf_w, tb->outbuf_h);
827 num = 1;
828 bx1 = ((rect_node_t *)n)->rect.left;
829 bx2 = bx1 + ((rect_node_t *)n)->rect.width;
830 by1 = ((rect_node_t *)n)->rect.top;
831 by2 = by1 + ((rect_node_t *)n)->rect.height;
832 n = n->next;
833 for (; n; n = n->next)
834 {
835 RECTS_CLIP_TO_RECT(((rect_node_t *)n)->rect.left,
836 ((rect_node_t *)n)->rect.top,
837 ((rect_node_t *)n)->rect.width,
838 ((rect_node_t *)n)->rect.height,
839 0, 0, tb->outbuf_w, tb->outbuf_h);
840 x1 = ((rect_node_t *)n)->rect.left;
841 if (x1 < bx1) bx1 = x1;
842 x2 = x1 + ((rect_node_t *)n)->rect.width;
843 if (x2 > bx2) bx2 = x2;
844
845 y1 = ((rect_node_t *)n)->rect.top;
846 if (y1 < by1) by1 = y1;
847 y2 = y1 + ((rect_node_t *)n)->rect.height;
848 if (y2 > by2) by2 = y2;
849 num++;
850 }
851 }
852 else
853 return NULL;
854
855 /* magic number - if we have > MAXREG regions to update, take bounding */
856 if (num > MAXREG)
857 {
858 r = malloc(sizeof(Tilebuf_Rect));
859 if (r)
860 {
861 EINA_INLIST_GET(r)->next = NULL;
862 EINA_INLIST_GET(r)->prev = NULL;
863 EINA_INLIST_GET(r)->last = NULL;
864 r->x = bx1;
865 r->y = by1;
866 r->w = bx2 - bx1;
867 r->h = by2 - by1;
868 rects = (Tilebuf_Rect *)
869 eina_inlist_append(EINA_INLIST_GET(rects),
870 EINA_INLIST_GET(r));
871 }
872 return rects;
873 }
874 81
875 rbuf = malloc(sizeof(Tilebuf_Rect) * num); 82 rbuf = malloc(n * sizeof(Tilebuf_Rect));
876 if (!rbuf) return NULL; 83 if (!rbuf) return NULL;
877 84
878 for (i = 0, n = tb->rects.head; n; n = n->next) 85 rend = rbuf + n;
879 { 86 rs = rects2;
880 rect_t cur; 87 for (r = rbuf; r < rend; r++)
881 88 {
882 cur = ((rect_node_t *)n)->rect; 89 EINA_INLIST_GET(r)->next = NULL;
883 if ((cur.width > 0) && (cur.height > 0)) 90 EINA_INLIST_GET(r)->prev = NULL;
884 { 91 EINA_INLIST_GET(r)->last = NULL;
885 r = &(rbuf[i]); 92 r->x = rs->x1;
886 EINA_INLIST_GET(r)->next = NULL; 93 r->y = rs->y1;
887 EINA_INLIST_GET(r)->prev = NULL; 94 r->w = rs->x2 - rs->x1;
888 EINA_INLIST_GET(r)->last = NULL; 95 r->h = rs->y2 - rs->y1;
889 r->x = cur.left; 96 rs++;
890 r->y = cur.top; 97 rects = (Tilebuf_Rect *)
891 r->w = cur.width; 98 eina_inlist_append(EINA_INLIST_GET(rects),
892 r->h = cur.height; 99 EINA_INLIST_GET(r));
893 rects = (Tilebuf_Rect *)
894 eina_inlist_append(EINA_INLIST_GET(rects),
895 EINA_INLIST_GET(r));
896 i++;
897 }
898 } 100 }
899
900 // It is possible that due to the clipping we do not return any rectangle here.
901 if (!rects) free(rbuf);
902
903 return rects; 101 return rects;
904} 102}
905 103