1 #include "evas_common_private.h"
2 #include "evas_private.h"
3 #include <Ecore.h>
4 #include <math.h>
5 #include <assert.h>
6
7 #ifdef EVAS_RENDER_DEBUG_TIMING
8 #include <sys/time.h>
9 #endif
10
11 // FIXME: Ugly!
12 #define EFL_CANVAS_FILTER_INTERNAL_PROTECTED
13 #include "efl_canvas_filter_internal.eo.h"
14
15 /* Enable this for extra verbose rendering debug logs */
16 //#define REND_DBG 1
17 #define STDOUT_DBG
18
19 #ifdef REND_DBG
20 static FILE *dbf = NULL;
21 static int __RD_level = 0;
22 static int __RD_enable = REND_DBG;
23
24 static inline Eina_Slstr *
_efl_object_name(const Evas_Object_Protected_Data * obj)25 _efl_object_name(const Evas_Object_Protected_Data *obj)
26 {
27 const Eo *eo_obj;
28 const char *name;
29 const char *klass;
30
31 if (!obj) return "(nil)";
32 eo_obj = obj->object;
33 name = obj->name ?: efl_name_get(eo_obj);
34 klass = obj->type; //efl_class_name_get(eo_obj);
35 if (name)
36 return eina_slstr_printf("[%p@%p: %s '%s']", eo_obj, obj, klass, name);
37 else
38 return eina_slstr_printf("[%p@%p: %s]", eo_obj, obj, klass);
39 }
40
41 #define RDNAME(_obj) _efl_object_name(_obj)
42
43 static void
rend_dbg(const char * txt)44 rend_dbg(const char *txt)
45 {
46 if (!dbf)
47 {
48 #ifdef STDOUT_DBG
49 dbf = stdout;
50 #else
51 dbf = fopen("EVAS-RENDER-DEBUG.log", "wb");
52 #endif
53 if (!dbf) return;
54 }
55 fputs(txt, dbf);
56 fflush(dbf);
57 }
58 #define RD(xxxx, args...) \
59 do { if (__RD_enable) { \
60 char __tmpbuf[4096]; int __tmpi; \
61 __RD_level = xxxx; \
62 if (xxxx) { \
63 for (__tmpi = 0; __tmpi < xxxx * 2; __tmpi++) \
64 __tmpbuf[__tmpi] = ' '; \
65 __tmpbuf[__tmpi] = 0; \
66 rend_dbg(__tmpbuf); \
67 } \
68 snprintf(__tmpbuf, sizeof(__tmpbuf), ##args); \
69 rend_dbg(__tmpbuf); \
70 } } while (0)
71 #define IFRD(ifcase, xxxx, args...) \
72 if (__RD_enable && (ifcase)) { \
73 char __tmpbuf[4096]; int __tmpi; \
74 __RD_level = xxxx; \
75 if (xxxx) { \
76 for (__tmpi = 0; __tmpi < xxxx * 2; __tmpi++) \
77 __tmpbuf[__tmpi] = ' '; \
78 __tmpbuf[__tmpi] = 0; \
79 rend_dbg(__tmpbuf); \
80 } \
81 snprintf(__tmpbuf, sizeof(__tmpbuf), ##args); \
82 rend_dbg(__tmpbuf); \
83 }
84 #else
85 #define RD(xxx, args...)
86 #define IFRD(ifcase, xxx, args...)
87 #define RDNAME(xxx) ""
88 #endif
89
90 #define OBJ_ARRAY_PUSH(array, obj) eina_array_push(array, obj)
91 #define OBJS_ARRAY_CLEAN(array) eina_array_clean(array)
92 #define OBJS_ARRAY_FLUSH(array) eina_array_flush(array)
93
94 /* save typing */
95 #undef ENFN
96 #undef ENC
97 #define ENFN evas->engine.func
98 #define ENC _evas_engine_context(evas)
99
100 typedef struct _Render_Updates Render_Updates;
101 typedef struct _Cutout_Margin Cutout_Margin;
102
103 struct _Render_Updates
104 {
105 void *surface;
106 Eina_Rectangle *area;
107 };
108
109 struct _Cutout_Margin
110 {
111 int l, r, t, b;
112 };
113
114 static void
115 evas_render_pipe_wakeup(void *data);
116 static Eina_Bool
117 evas_render_updates_internal(Evas *eo_e, unsigned char make_updates, unsigned char do_draw, Eina_Bool do_async);
118 static void
119 evas_render_mask_subrender(Evas_Public_Data *evas,
120 void *output,
121 Evas_Object_Protected_Data *mask,
122 Evas_Object_Protected_Data *prev_mask,
123 int level, Eina_Bool do_async);
124
125 static Eina_List *_rendering_evases = NULL;
126
127 #ifdef EVAS_RENDER_DEBUG_TIMING
128 static double
_time_get()129 _time_get()
130 {
131 struct timeval tv;
132
133 gettimeofday(&tv, NULL);
134
135 return (tv.tv_sec + tv.tv_usec / 1000000.0) * 1000.0;
136 }
137
138 struct accumulator {
139 double total, min, max, draw_start_time;
140 int samples;
141 const char *what;
142 };
143
144 static struct accumulator async_accumulator = {
145 .total = 0,
146 .min = 1000000,
147 .max = 0,
148 .samples = 0,
149 .what = "async render"
150 };
151 static struct accumulator sync_accumulator = {
152 .total = 0,
153 .min = 1000000,
154 .max = 0,
155 .samples = 0,
156 .what = "sync render"
157 };
158
159 static void
_accumulate_time(double before,Eina_Bool async)160 _accumulate_time(double before, Eina_Bool async)
161 {
162 static Eina_Bool async_start = EINA_TRUE;
163 static double cache_before;
164 struct accumulator *acc = &sync_accumulator;
165 if (async)
166 {
167 acc = &async_accumulator;
168 if (async_start)
169 {
170 async_start = EINA_FALSE;
171 cache_before = before;
172 return;
173 }
174 else
175 {
176 async_start = EINA_TRUE;
177 before = cache_before;
178 }
179 }
180
181 double diff = _time_get() - before;
182
183 acc->total += diff;
184 if (diff > acc->max) acc->max = diff;
185 if (diff < acc->min) acc->min = diff;
186
187 acc->samples++;
188 if (acc->samples % 100 == 0)
189 {
190 fprintf(stderr, "*** %s: avg %fms min %fms max %fms\n",
191 acc->what, acc->total / 100.0, acc->min, acc->max);
192 acc->total = 0.0;
193 acc->max = 0.0;
194 acc->min = 1000000;
195 }
196 }
197 #endif
198
199 static int _render_busy = 0;
200
201 static inline Eina_Bool
_is_obj_in_framespace(Evas_Object_Protected_Data * obj,Evas_Public_Data * evas EINA_UNUSED)202 _is_obj_in_framespace(Evas_Object_Protected_Data *obj, Evas_Public_Data *evas EINA_UNUSED)
203 {
204 return obj->is_frame;
205 }
206
207 static inline void
_evas_render_framespace_context_clip_clip(Evas_Public_Data * evas,void * ctx,int ox,int oy)208 _evas_render_framespace_context_clip_clip(Evas_Public_Data *evas, void *ctx,
209 int ox, int oy)
210 {
211 int fx, fy, fw, fh;
212
213 fx = evas->framespace.x;
214 fy = evas->framespace.y;
215 fw = evas->viewport.w - evas->framespace.w;
216 fh = evas->viewport.h - evas->framespace.h;
217
218 ENFN->context_clip_clip(ENC, ctx, fx + ox, fy + oy, fw, fh);
219 }
220
221 static void
_evas_render_cleanup(void)222 _evas_render_cleanup(void)
223 {
224 if (_render_busy != 0) return;
225 evas_common_rgba_pending_unloads_cleanup();
226 }
227
228 static void
_evas_render_busy_begin(void)229 _evas_render_busy_begin(void)
230 {
231 _render_busy++;
232 }
233
234 static void
_evas_render_busy_end(void)235 _evas_render_busy_end(void)
236 {
237 _render_busy--;
238 _evas_render_cleanup();
239 }
240
241 EOLIAN void
_evas_canvas_damage_rectangle_add(Eo * eo_e EINA_UNUSED,Evas_Public_Data * e,int x,int y,int w,int h)242 _evas_canvas_damage_rectangle_add(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e, int x, int y, int w, int h)
243 {
244 Eina_Rectangle *r;
245
246 evas_canvas_async_block(e);
247 NEW_RECT(r, x, y, w, h);
248 if (!r) return;
249 e->damages = eina_list_append(e->damages, r);
250 e->changed = EINA_TRUE;
251 }
252
253 EOLIAN void
_evas_canvas_obscured_rectangle_add(Eo * eo_e EINA_UNUSED,Evas_Public_Data * e,int x,int y,int w,int h)254 _evas_canvas_obscured_rectangle_add(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e, int x, int y, int w, int h)
255 {
256 Eina_Rectangle *r;
257
258 evas_canvas_async_block(e);
259 NEW_RECT(r, x, y, w, h);
260 if (!r) return;
261 e->obscures = eina_list_append(e->obscures, r);
262 }
263
264 EOLIAN void
_evas_canvas_obscured_clear(Eo * eo_e EINA_UNUSED,Evas_Public_Data * e)265 _evas_canvas_obscured_clear(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e)
266 {
267 Eina_Rectangle *r;
268
269 evas_canvas_async_block(e);
270 EINA_LIST_FREE(e->obscures, r)
271 {
272 eina_rectangle_free(r);
273 }
274 }
275
276 static Eina_Bool
_evas_clip_changes_free(const void * container EINA_UNUSED,void * data,void * fdata EINA_UNUSED)277 _evas_clip_changes_free(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
278 {
279 eina_rectangle_free(data);
280 return EINA_TRUE;
281 }
282
283 static inline Eina_Rectangle
_evas_render_smallest_static_clipped_geometry_get(const Evas_Object_Protected_State * state)284 _evas_render_smallest_static_clipped_geometry_get(const Evas_Object_Protected_State *state)
285 {
286 int cx, cy, cw, ch;
287
288 cx = state->geometry.x;
289 cy = state->geometry.y;
290 cw = state->geometry.w;
291 ch = state->geometry.h;
292 while (state->clipper && state->has_fixed_size)
293 {
294 /* walk up the clipper tree as long as the clippers are static */
295 RECTS_CLIP_TO_RECT(cx, cy, cw, ch,
296 state->clipper->cur->geometry.x,
297 state->clipper->cur->geometry.y,
298 state->clipper->cur->geometry.w,
299 state->clipper->cur->geometry.h);
300 if (!state->clipper) break;
301 state = state->clipper->cur;
302 }
303 return (Eina_Rectangle){cx, cy, cw, ch};
304 }
305
306 static Eina_Bool
_evas_render_had_map(Evas_Object_Protected_Data * obj)307 _evas_render_had_map(Evas_Object_Protected_Data *obj)
308 {
309 return ((obj->map->prev.map) && (obj->map->prev.usemap));
310 }
311
312 static Eina_Bool
_evas_render_is_relevant(Evas_Object_Protected_Data * obj)313 _evas_render_is_relevant(Evas_Object_Protected_Data *obj)
314 {
315 return ((evas_object_is_visible(obj) && (!obj->cur->have_clipees)) ||
316 (evas_object_was_visible(obj) && (!obj->prev->have_clipees)));
317 }
318
319 static Eina_Bool
_evas_render_can_render(Evas_Object_Protected_Data * obj)320 _evas_render_can_render(Evas_Object_Protected_Data *obj)
321 {
322 return (evas_object_is_visible(obj) && (!obj->cur->have_clipees) &&
323 !obj->no_render);
324 }
325
326 static void
_evas_render_prev_cur_clip_cache_add(Evas_Public_Data * evas,Evas_Object_Protected_Data * obj)327 _evas_render_prev_cur_clip_cache_add(Evas_Public_Data *evas, Evas_Object_Protected_Data *obj)
328 {
329 // FIXME: Iterate over each output
330 ENFN->output_redraws_rect_add(ENC,
331 obj->prev->cache.clip.x + evas->framespace.x,
332 obj->prev->cache.clip.y + evas->framespace.y,
333 obj->prev->cache.clip.w,
334 obj->prev->cache.clip.h);
335 ENFN->output_redraws_rect_add(ENC,
336 obj->cur->cache.clip.x + evas->framespace.x,
337 obj->cur->cache.clip.y + evas->framespace.y,
338 obj->cur->cache.clip.w,
339 obj->cur->cache.clip.h);
340 }
341
342 static void
_evas_render_cur_clip_cache_del(Evas_Public_Data * e,Evas_Object_Protected_Data * obj)343 _evas_render_cur_clip_cache_del(Evas_Public_Data *e, Evas_Object_Protected_Data *obj)
344 {
345 Evas_Coord x, y, w, h;
346
347 x = obj->cur->cache.clip.x;
348 y = obj->cur->cache.clip.y;
349 w = obj->cur->cache.clip.w;
350 h = obj->cur->cache.clip.h;
351 if (obj->cur->clipper)
352 {
353 RECTS_CLIP_TO_RECT(x, y, w, h,
354 obj->cur->clipper->cur->cache.clip.x,
355 obj->cur->clipper->cur->cache.clip.y,
356 obj->cur->clipper->cur->cache.clip.w,
357 obj->cur->clipper->cur->cache.clip.h);
358 }
359 evas_render_update_del(e, x + e->framespace.x, y + e->framespace.y, w, h);
360 }
361
362 /* sets the redraw flag for all the proxies depending on this obj as a source */
363 static void
_evas_proxy_redraw_set(Evas_Public_Data * e,Evas_Object_Protected_Data * obj,Eina_Bool render)364 _evas_proxy_redraw_set(Evas_Public_Data *e, Evas_Object_Protected_Data *obj,
365 Eina_Bool render)
366 {
367 Evas_Object *eo_proxy;
368 Evas_Object_Protected_Data *proxy;
369 Eina_List *l;
370
371 EINA_LIST_FOREACH(obj->proxy->proxies, l, eo_proxy)
372 {
373 proxy = efl_data_scope_get(eo_proxy, EFL_CANVAS_OBJECT_CLASS);
374
375 /* Flag need redraw on proxy too */
376 EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, proxy->proxy,
377 Evas_Object_Proxy_Data, proxy_write)
378 proxy_write->redraw = EINA_TRUE;
379 EINA_COW_WRITE_END(evas_object_proxy_cow, proxy->proxy, proxy_write);
380
381 if (render)
382 {
383 /* Not good... but make it sure if the proxies have missed at update
384 if its sources are remained changed as pending objects in the prev frame. */
385 evas_object_change(eo_proxy, proxy);
386 proxy->func->render_pre(eo_proxy, proxy, proxy->private_data);
387 _evas_render_prev_cur_clip_cache_add(e, proxy);
388 }
389
390 //Update the proxies recursively.
391 _evas_proxy_redraw_set(e, proxy, render);
392 }
393 }
394
395 /* sets the mask redraw flag for all the objects clipped by this mask */
396 static void
_evas_mask_redraw_set(Evas_Public_Data * e EINA_UNUSED,Evas_Object_Protected_Data * obj)397 _evas_mask_redraw_set(Evas_Public_Data *e EINA_UNUSED,
398 Evas_Object_Protected_Data *obj)
399 {
400 Evas_Object_Protected_Data *clippee;
401 Eina_List *l;
402
403 if (!(obj->mask->redraw))
404 {
405 EINA_COW_WRITE_BEGIN(evas_object_mask_cow, obj->mask,
406 Evas_Object_Mask_Data, mask)
407 mask->redraw = EINA_TRUE;
408 EINA_COW_WRITE_END(evas_object_mask_cow, obj->mask, mask);
409 }
410
411 if (!obj->cur->cache.clip.dirty)
412 {
413 EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
414 state_write->cache.clip.dirty = EINA_TRUE;
415 EINA_COW_STATE_WRITE_END(obj, state_write, cur);
416 }
417
418 EINA_LIST_FOREACH(obj->clip.clipees, l, clippee)
419 {
420 evas_object_clip_recalc(clippee);
421 }
422 }
423
424 static inline Eina_Bool
_evas_render_object_changed_get(Evas_Object_Protected_Data * obj)425 _evas_render_object_changed_get(Evas_Object_Protected_Data *obj)
426 {
427 if (obj->smart.smart)
428 return evas_object_smart_changed_get(obj);
429 else
430 return obj->changed;
431 }
432
433 static inline Eina_Bool
_evas_render_object_is_mask(Evas_Object_Protected_Data * obj)434 _evas_render_object_is_mask(Evas_Object_Protected_Data *obj)
435 {
436 if (!obj) return EINA_FALSE;
437 if (obj->mask->is_mask && obj->clip.clipees)
438 return EINA_TRUE;
439 return EINA_FALSE;
440 }
441
442 static void
_evas_render_phase1_direct(Evas_Public_Data * e,Eina_Inarray * active_objects,Eina_Array * restack_objects EINA_UNUSED,Eina_Array * delete_objects EINA_UNUSED,Eina_Array * render_objects)443 _evas_render_phase1_direct(Evas_Public_Data *e,
444 Eina_Inarray *active_objects,
445 Eina_Array *restack_objects EINA_UNUSED,
446 Eina_Array *delete_objects EINA_UNUSED,
447 Eina_Array *render_objects)
448 {
449 unsigned int i;
450 Evas_Object *eo_obj;
451
452 RD(0, " [--- PHASE 1 DIRECT\n");
453 for (i = 0; i < active_objects->len; i++)
454 {
455 Evas_Active_Entry *ent = eina_inarray_nth(active_objects, i);
456 Evas_Object_Protected_Data *obj = ent->obj;
457
458 EINA_PREFETCH(&(obj->cur->clipper));
459 if (obj->changed) evas_object_clip_recalc(obj);
460
461 if (obj->proxy->proxies)
462 {
463 /* is proxy source */
464 if (_evas_render_object_changed_get(obj))
465 _evas_proxy_redraw_set(e, obj, EINA_FALSE);
466 }
467 if (_evas_render_object_is_mask(obj))
468 {
469 /* is image clipper */
470 if (_evas_render_object_changed_get(obj))
471 _evas_mask_redraw_set(e, obj);
472 }
473 }
474 for (i = 0; i < render_objects->count; i++)
475 {
476 Evas_Object_Protected_Data *obj =
477 eina_array_data_get(render_objects, i);
478 eo_obj = obj->object;
479
480 RD(0, " OBJ %s changed %i\n", RDNAME(obj), obj->changed);
481
482 if (obj->changed)
483 {
484 evas_object_clip_recalc(obj);
485 obj->func->render_pre(eo_obj, obj, obj->private_data);
486
487 if (obj->proxy->redraw || obj->mask->redraw)
488 _evas_render_prev_cur_clip_cache_add(e, obj);
489
490 if (!obj->smart.smart || evas_object_smart_changed_get(obj))
491 {
492 /* proxy sources */
493 if (obj->proxy->proxies)
494 {
495 EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, obj->proxy,
496 Evas_Object_Proxy_Data, proxy_write)
497 proxy_write->redraw = EINA_TRUE;
498 EINA_COW_WRITE_END(evas_object_proxy_cow, obj->proxy,
499 proxy_write);
500 _evas_proxy_redraw_set(e, obj, EINA_TRUE);
501 }
502
503 /* clipper objects (image masks) */
504 if (_evas_render_object_is_mask(obj))
505 _evas_mask_redraw_set(e, obj);
506 }
507
508 _evas_object_gfx_mapping_update(obj);
509
510 Eina_Bool has_map = _evas_render_has_map(obj);
511
512 RD(0, " pre-render-done smart:%p|%p [%p, %i] | [%p, %i] has_map:%i had_map:%i\n",
513 obj->smart.smart,
514 obj->is_smart ? evas_object_smart_members_get_direct(eo_obj) : NULL,
515 obj->map->cur.map, obj->map->cur.usemap,
516 obj->map->prev.map, obj->map->prev.usemap,
517 has_map, _evas_render_had_map(obj));
518
519 if ((obj->is_smart) &&
520 ((has_map && !_evas_render_can_map(obj)) ||
521 obj->changed_src_visible))
522 {
523 RD(0, " has map + smart\n");
524 _evas_render_prev_cur_clip_cache_add(e, obj);
525 }
526 /* This is the only case that map was just turned off,
527 Need to redraw the previous obj region as well. */
528 else if (!has_map && obj->changed_map &&
529 _evas_render_object_changed_get(obj))
530 {
531 _evas_render_prev_cur_clip_cache_add(e, obj);
532 obj->changed_map = EINA_FALSE;
533 }
534 }
535 else
536 {
537 if (obj->is_smart)
538 {
539 }
540 else if (evas_object_is_visible(obj) &&
541 ((obj->rect_del) ||
542 (evas_object_is_opaque(obj))) &&
543 (!evas_object_is_source_invisible(eo_obj, obj)))
544 {
545 RD(0, " rect del\n");
546 _evas_render_cur_clip_cache_del(e, obj);
547 }
548 }
549 }
550 RD(0, " ---]\n");
551 }
552
553 static void
_evas_render_object_map_change_update(Evas_Public_Data * evas,Evas_Object_Protected_Data * obj,Eina_Bool map,Eina_Bool hmap,int * redraw_all)554 _evas_render_object_map_change_update(Evas_Public_Data *evas,
555 Evas_Object_Protected_Data *obj,
556 Eina_Bool map, Eina_Bool hmap,
557 int *redraw_all)
558 {
559 // FIXME: handle multiple output
560 Evas_Coord x = 0, y = 0, w = 0, h = 0;
561 const int fx = evas->framespace.x;
562 const int fy = evas->framespace.y;
563
564 if (map == hmap) return;
565
566 if (!obj->map)
567 {
568 *redraw_all = 1;
569 return;
570 }
571
572 if (map)
573 {
574 x = obj->prev->cache.clip.x;
575 y = obj->prev->cache.clip.y;
576 w = obj->prev->cache.clip.w;
577 h = obj->prev->cache.clip.h;
578 if (obj->prev->clipper)
579 {
580 RECTS_CLIP_TO_RECT(x, y, w, h,
581 obj->prev->clipper->prev->cache.clip.x,
582 obj->prev->clipper->prev->cache.clip.y,
583 obj->prev->clipper->prev->cache.clip.w,
584 obj->prev->clipper->prev->cache.clip.h);
585 }
586 ENFN->output_redraws_rect_add(ENC, x + fx, y + fy, w, h);
587 x = obj->map->cur.map->normal_geometry.x;
588 y = obj->map->cur.map->normal_geometry.y;
589 w = obj->map->cur.map->normal_geometry.w;
590 h = obj->map->cur.map->normal_geometry.h;
591 if (obj->cur->clipper)
592 {
593 RECTS_CLIP_TO_RECT(x, y, w, h,
594 obj->cur->clipper->cur->cache.clip.x,
595 obj->cur->clipper->cur->cache.clip.y,
596 obj->cur->clipper->cur->cache.clip.w,
597 obj->cur->clipper->cur->cache.clip.h);
598 }
599 ENFN->output_redraws_rect_add(ENC, x + fx, y + fy, w, h);
600 }
601 else if (hmap)
602 {
603 x = obj->map->prev.map->normal_geometry.x;
604 y = obj->map->prev.map->normal_geometry.y;
605 w = obj->map->prev.map->normal_geometry.w;
606 h = obj->map->prev.map->normal_geometry.h;
607 if (obj->prev->clipper)
608 {
609 RECTS_CLIP_TO_RECT(x, y, w, h,
610 obj->prev->clipper->prev->cache.clip.x,
611 obj->prev->clipper->prev->cache.clip.y,
612 obj->prev->clipper->prev->cache.clip.w,
613 obj->prev->clipper->prev->cache.clip.h);
614 }
615 ENFN->output_redraws_rect_add(ENC, x + fx, y + fy, w, h);
616 x = obj->cur->cache.clip.x;
617 y = obj->cur->cache.clip.y;
618 w = obj->cur->cache.clip.w;
619 h = obj->cur->cache.clip.h;
620 if (obj->cur->clipper)
621 {
622 RECTS_CLIP_TO_RECT(x, y, w, h,
623 obj->cur->clipper->cur->cache.clip.x,
624 obj->cur->clipper->cur->cache.clip.y,
625 obj->cur->clipper->cur->cache.clip.w,
626 obj->cur->clipper->cur->cache.clip.h);
627 }
628 ENFN->output_redraws_rect_add(ENC, x + fx, y + fy, w, h);
629 }
630 }
631
632
633
634
635 ////////////////////////////////////////////////////////////////////////////
636 //
637 // object render update phase 1 code -> figure out updates and built object
638 // render/active/delete etc. lists/arrays.
639 //
640
641 typedef struct
642 {
643 Eina_Inarray *active_objects;
644 Eina_Array *render_objects;
645 Eina_Array *snapshot_objects;
646
647 Eina_Inarray *update_del;
648 } Render_Cache;
649
650 void
evas_render_update_del(Evas_Public_Data * evas,int x,int y,int w,int h)651 evas_render_update_del(Evas_Public_Data *evas, int x, int y, int w, int h)
652 {
653 // FIXME: handle multiple output
654 if (EINA_LIKELY((evas->update_del_redirect_array == NULL)))
655 {
656 ENFN->output_redraws_rect_del(ENC, x, y, w, h);
657 }
658 else
659 {
660 Eina_Rectangle r;
661
662 r.x = x; r.y = y; r.w = w; r.h = h;
663 eina_inarray_push(evas->update_del_redirect_array, &r);
664 }
665 }
666
667 void
evas_render_object_render_cache_free(Evas_Object * eo_obj EINA_UNUSED,void * data)668 evas_render_object_render_cache_free(Evas_Object *eo_obj EINA_UNUSED,
669 void *data)
670 {
671 Render_Cache *rc;
672
673 if (!data) return;
674 rc = data;
675 eina_inarray_free(rc->active_objects);
676 eina_array_free(rc->render_objects);
677 eina_array_free(rc->snapshot_objects);
678 eina_inarray_free(rc->update_del);
679 free(rc);
680 }
681
682 typedef struct
683 {
684 Evas_Public_Data *e;
685 Eina_Inarray *active_objects;
686 Eina_Array *render_objects;
687 Eina_Array *snapshot_objects;
688 Eina_Array *restack_objects;
689 Eina_Array *delete_objects;
690 int redraw_all;
691 } Phase1_Context;
692
693 #define RENDCACHE 1
694
695 #ifdef RENDCACHE
696 static Render_Cache *
_evas_render_phase1_object_render_cache_new(void)697 _evas_render_phase1_object_render_cache_new(void)
698 {
699 Render_Cache *rc;
700
701 rc = malloc(sizeof(Render_Cache));
702 rc->active_objects = eina_inarray_new(sizeof(Evas_Active_Entry), 32);
703 rc->render_objects = eina_array_new(32);
704 rc->snapshot_objects = eina_array_new(32);
705 rc->update_del = eina_inarray_new(sizeof(Eina_Rectangle), 16);
706 return rc;
707 }
708
709 static void
_evas_render_phase1_object_ctx_render_cache_fill(Phase1_Context * ctx,Render_Cache * rc)710 _evas_render_phase1_object_ctx_render_cache_fill(Phase1_Context *ctx,
711 Render_Cache *rc)
712 {
713 ctx->active_objects = rc->active_objects;
714 ctx->render_objects = rc->render_objects;
715 ctx->snapshot_objects = rc->snapshot_objects;
716 }
717
718 static void
_evas_render_phase1_object_ctx_render_cache_append(Phase1_Context * ctx,Render_Cache * rc)719 _evas_render_phase1_object_ctx_render_cache_append(Phase1_Context *ctx,
720 Render_Cache *rc)
721 {
722 void *obj;
723 unsigned int i, c;
724 Eina_Rectangle *r;
725 Evas_Active_Entry *ent;
726
727 #define ARR_APPEND(x) \
728 if (rc->x != ctx->x) { \
729 do { \
730 c = eina_array_count_get(rc->x); \
731 for (i = 0; i < c; i++) { \
732 obj = eina_array_data_get(rc->x, i); \
733 eina_array_push(ctx->x, obj); \
734 } \
735 } while (0); \
736 }
737 ARR_APPEND(render_objects);
738 ARR_APPEND(snapshot_objects);
739
740 c = eina_inarray_count(rc->active_objects);
741 for (i = 0; i < c; i++)
742 {
743 ent = eina_inarray_nth(rc->active_objects, i);
744 eina_inarray_push(ctx->active_objects, ent);
745 }
746
747 c = eina_inarray_count(rc->update_del);
748 for (i = 0; i < c; i++)
749 {
750 r = eina_inarray_nth(rc->update_del, i);
751 evas_render_update_del(ctx->e, r->x, r->y, r->w, r->h);
752 }
753 }
754 #endif
755
756 static Eina_Bool
757 _evas_render_phase1_object_process(Phase1_Context *p1ctx,
758 Evas_Object_Protected_Data *obj,
759 Eina_Bool restack,
760 Eina_Bool mapped_parent,
761 Eina_Bool src_changed,
762 int level);
763
764 static void
_evas_render_phase1_object_restack_handle(Phase1_Context * p1ctx,Evas_Object_Protected_Data * obj,Eina_Bool obj_changed)765 _evas_render_phase1_object_restack_handle(Phase1_Context *p1ctx,
766 Evas_Object_Protected_Data *obj,
767 Eina_Bool obj_changed)
768 {
769 if (!obj_changed)
770 {
771 OBJ_ARRAY_PUSH(&(p1ctx->e->pending_objects), obj);
772 obj->changed = EINA_TRUE;
773 obj->in_pending_objects = EINA_TRUE;
774 }
775 obj->restack = EINA_TRUE;
776 }
777
778 static void
_evas_render_phase1_object_map_clipper_fix(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj)779 _evas_render_phase1_object_map_clipper_fix(Evas_Object *eo_obj,
780 Evas_Object_Protected_Data *obj)
781 {
782 evas_object_change(obj->cur->clipper->object, obj->cur->clipper);
783 evas_object_clip_dirty(obj->cur->clipper->object, obj->cur->clipper);
784 evas_object_clip_recalc(obj->cur->clipper);
785 evas_object_update_bounding_box(eo_obj, obj, NULL);
786 }
787
788 static void
_evas_render_phase1_object_mapped(Phase1_Context * p1ctx,Evas_Object_Protected_Data * obj,Eina_Bool src_changed,Eina_Bool hmap,Eina_Bool is_active,Eina_Bool obj_changed,int level)789 _evas_render_phase1_object_mapped(Phase1_Context *p1ctx,
790 Evas_Object_Protected_Data *obj,
791 Eina_Bool src_changed,
792 Eina_Bool hmap,
793 Eina_Bool is_active,
794 Eina_Bool obj_changed,
795 int level)
796 {
797 Evas_Object_Protected_Data *obj2;
798 Evas_Object *eo_obj = obj->object;
799
800 RD(level, " obj mapped\n");
801 if (!obj_changed) return;
802
803 if (!hmap && obj->cur->clipper)
804 // Fix some bad clipping issues before an evas map animation starts
805 _evas_render_phase1_object_map_clipper_fix(eo_obj, obj);
806
807 _evas_render_object_map_change_update(p1ctx->e, obj, EINA_TRUE, hmap, &(p1ctx->redraw_all));
808 if (!((is_active) &&
809 (!obj->clip.clipees) &&
810 ((evas_object_is_visible(obj) &&
811 (!obj->cur->have_clipees)) ||
812 (evas_object_was_visible(obj) &&
813 (!obj->prev->have_clipees)))))
814 return;
815 OBJ_ARRAY_PUSH(p1ctx->render_objects, obj);
816 _evas_render_prev_cur_clip_cache_add(p1ctx->e, obj);
817 obj->render_pre = EINA_TRUE;
818 if (!obj->is_smart) return;
819 if (obj_changed) evas_object_smart_render_cache_clear(eo_obj);
820 EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(eo_obj), obj2)
821 {
822 _evas_render_phase1_object_process(p1ctx, obj2, obj->restack,
823 EINA_TRUE, src_changed, level + 1);
824 }
825
826 /* Restacked mapped object should be used as a redraw rect.
827 The "phase 2. force updates for restack" will use restack_objects. */
828 if (EINA_UNLIKELY(obj->restack))
829 OBJ_ARRAY_PUSH(p1ctx->restack_objects, obj);
830 }
831
832 static void
_evas_render_phase1_object_mapped_had_restack(Phase1_Context * p1ctx,Evas_Object_Protected_Data * obj,Eina_Bool map,Eina_Bool obj_changed,int level)833 _evas_render_phase1_object_mapped_had_restack(Phase1_Context *p1ctx,
834 Evas_Object_Protected_Data *obj,
835 Eina_Bool map,
836 Eina_Bool obj_changed,
837 int level)
838 {
839 Evas_Object *eo_obj = obj->object;
840 (void) level;
841
842 RD(level, " had map - restack objs\n");
843 _evas_render_prev_cur_clip_cache_add(p1ctx->e, obj);
844 if (obj_changed)
845 {
846 if (!map)
847 {
848 if ((obj->map->cur.map) && (obj->map->cur.usemap))
849 map = EINA_TRUE;
850 }
851 _evas_render_object_map_change_update(p1ctx->e, obj, map, EINA_TRUE, &(p1ctx->redraw_all));
852 }
853 if (!(!map && obj->cur->clipper)) return;
854 // Fix some bad clipping issues after an evas_map animation finishes
855 evas_object_change(obj->cur->clipper->object, obj->cur->clipper);
856 evas_object_clip_dirty(obj->cur->clipper->object, obj->cur->clipper);
857 evas_object_clip_recalc(obj->cur->clipper);
858 evas_object_update_bounding_box(eo_obj, obj, NULL);
859 }
860
861 static Eina_Bool
_evas_render_phase1_object_changed_smart(Phase1_Context * p1ctx,Evas_Object_Protected_Data * obj,Eina_Bool mapped_parent,Eina_Bool obj_changed,Eina_Bool src_changed,Eina_Bool is_active,int level)862 _evas_render_phase1_object_changed_smart(Phase1_Context *p1ctx,
863 Evas_Object_Protected_Data *obj,
864 Eina_Bool mapped_parent,
865 Eina_Bool obj_changed,
866 Eina_Bool src_changed,
867 Eina_Bool is_active,
868 int level)
869 {
870 Evas_Object_Protected_Data *obj2;
871 Evas_Object *eo_obj = obj->object;
872
873 RD(level, " changed + smart - render ok\n");
874 OBJ_ARRAY_PUSH(p1ctx->render_objects, obj);
875
876 if (!is_active && obj->proxy->proxies) src_changed = EINA_TRUE;
877
878 obj->render_pre = EINA_TRUE;
879 if (obj_changed)
880 {
881 evas_object_smart_render_cache_clear(eo_obj);
882 EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(eo_obj), obj2)
883 {
884 _evas_render_phase1_object_process(p1ctx, obj2, obj->restack,
885 mapped_parent, src_changed,
886 level + 1);
887 }
888 }
889 else
890 {
891 Phase1_Context *ctx = p1ctx;
892
893 #ifdef RENDCACHE
894 Render_Cache *rc = NULL;
895 void *p_del_redir;
896 Phase1_Context tmpctx;
897
898 if (obj->no_change_render > 3)
899 {
900 rc = evas_object_smart_render_cache_get(eo_obj);
901 if (!rc)
902 {
903 rc = _evas_render_phase1_object_render_cache_new();
904 evas_object_smart_render_cache_set(eo_obj, rc);
905 ctx = &tmpctx;
906 *ctx = *p1ctx;
907 p_del_redir = p1ctx->e->update_del_redirect_array;
908 p1ctx->e->update_del_redirect_array = rc->update_del;
909 _evas_render_phase1_object_ctx_render_cache_fill(ctx, rc);
910 EINA_INLIST_FOREACH
911 (evas_object_smart_members_get_direct(eo_obj), obj2)
912 {
913 _evas_render_phase1_object_process(ctx, obj2,
914 obj->restack,
915 mapped_parent,
916 src_changed,
917 level + 1);
918 }
919 p1ctx->redraw_all = ctx->redraw_all;
920 p1ctx->e->update_del_redirect_array = p_del_redir;
921 }
922 _evas_render_phase1_object_ctx_render_cache_append(p1ctx, rc);
923 }
924 else
925 #endif
926 {
927 EINA_INLIST_FOREACH
928 (evas_object_smart_members_get_direct(eo_obj), obj2)
929 {
930 _evas_render_phase1_object_process(ctx, obj2, obj->restack,
931 mapped_parent,
932 src_changed, level + 1);
933 }
934 }
935 }
936 return src_changed;
937 }
938
939 static void
_evas_render_phase1_object_changed_normal(Phase1_Context * p1ctx,Evas_Object_Protected_Data * obj,Eina_Bool is_active,int level EINA_UNUSED)940 _evas_render_phase1_object_changed_normal(Phase1_Context *p1ctx,
941 Evas_Object_Protected_Data *obj,
942 Eina_Bool is_active,
943 int level
944 #ifndef REND_DBG
945 EINA_UNUSED
946 #endif
947 )
948 {
949 if ((!obj->clip.clipees) && _evas_render_is_relevant(obj))
950 {
951 if (EINA_LIKELY(is_active))
952 {
953 RD(level, " relevant + active\n");
954 if (EINA_UNLIKELY(obj->restack))
955 OBJ_ARRAY_PUSH(p1ctx->restack_objects, obj);
956 else
957 {
958 OBJ_ARRAY_PUSH(p1ctx->render_objects, obj);
959 obj->render_pre = EINA_TRUE;
960 }
961 }
962 else
963 {
964 /* It goes to be hidden. Prev caching should be replaced
965 by the current (hidden) state. */
966 if (evas_object_is_visible(obj) !=
967 evas_object_was_visible(obj))
968 evas_object_cur_prev(obj);
969 RD(level, " skip - not smart, not active or clippees or not relevant\n");
970 }
971 }
972 else if (is_active && _evas_render_object_is_mask(obj) &&
973 (obj->cur->visible || obj->prev->visible))
974 {
975 if (EINA_UNLIKELY(obj->restack))
976 OBJ_ARRAY_PUSH(p1ctx->restack_objects, obj);
977 else
978 {
979 OBJ_ARRAY_PUSH(p1ctx->render_objects, obj);
980 obj->render_pre = EINA_TRUE;
981 }
982 RD(level, " relevant + active: clipper image\n");
983 }
984 else
985 {
986 RD(level, " skip - not smart, not active or clippees or not relevant\n");
987 }
988 }
989
990 static void
_evas_render_phase1_object_no_changed_smart(Phase1_Context * p1ctx,Evas_Object_Protected_Data * obj,Eina_Bool restack,Eina_Bool mapped_parent,Eina_Bool src_changed,int level)991 _evas_render_phase1_object_no_changed_smart(Phase1_Context *p1ctx,
992 Evas_Object_Protected_Data *obj,
993 Eina_Bool restack,
994 Eina_Bool mapped_parent,
995 Eina_Bool src_changed,
996 int level)
997 {
998 Evas_Object_Protected_Data *obj2;
999 Phase1_Context *ctx = p1ctx;
1000 Evas_Object *eo_obj = obj->object;
1001
1002 RD(level, " smart + visible/was visible + not clip\n");
1003 OBJ_ARRAY_PUSH(p1ctx->render_objects, obj);
1004 obj->render_pre = EINA_TRUE;
1005 #ifdef RENDCACHE
1006 void *p_del_redir;
1007 Render_Cache *rc = NULL;
1008 Phase1_Context tmpctx;
1009
1010 if (obj->no_change_render > 3)
1011 {
1012 rc = evas_object_smart_render_cache_get(eo_obj);
1013 if (!rc)
1014 {
1015 rc = _evas_render_phase1_object_render_cache_new();
1016 evas_object_smart_render_cache_set(eo_obj, rc);
1017 ctx = &tmpctx;
1018 *ctx = *p1ctx;
1019 p_del_redir = p1ctx->e->update_del_redirect_array;
1020 p1ctx->e->update_del_redirect_array = rc->update_del;
1021 _evas_render_phase1_object_ctx_render_cache_fill(ctx, rc);
1022 EINA_INLIST_FOREACH
1023 (evas_object_smart_members_get_direct(eo_obj), obj2)
1024 {
1025 _evas_render_phase1_object_process(ctx, obj2, restack,
1026 mapped_parent,
1027 src_changed, level + 1);
1028 }
1029 p1ctx->redraw_all = ctx->redraw_all;
1030 p1ctx->e->update_del_redirect_array = p_del_redir;
1031 }
1032 _evas_render_phase1_object_ctx_render_cache_append(p1ctx, rc);
1033 }
1034 else
1035 #endif
1036 {
1037 EINA_INLIST_FOREACH
1038 (evas_object_smart_members_get_direct(eo_obj), obj2)
1039 {
1040 _evas_render_phase1_object_process(ctx, obj2, restack,
1041 mapped_parent,
1042 src_changed, level + 1);
1043 }
1044 }
1045 }
1046
1047 static void
_evas_render_phase1_object_no_changed_normal(Phase1_Context * p1ctx,Evas_Object_Protected_Data * obj,int level EINA_UNUSED)1048 _evas_render_phase1_object_no_changed_normal(Phase1_Context *p1ctx,
1049 Evas_Object_Protected_Data *obj,
1050 int level
1051 #ifndef REND_DBG
1052 EINA_UNUSED
1053 #endif
1054 )
1055 {
1056 if (evas_object_is_opaque(obj) &&
1057 evas_object_is_visible(obj))
1058 {
1059 RD(level, " opaque + visible\n");
1060 OBJ_ARRAY_PUSH(p1ctx->render_objects, obj);
1061 obj->rect_del = EINA_TRUE;
1062 }
1063 else if (evas_object_is_visible(obj))
1064 {
1065 RD(level, " visible\n");
1066 OBJ_ARRAY_PUSH(p1ctx->render_objects, obj);
1067 obj->render_pre = EINA_TRUE;
1068 }
1069 else
1070 {
1071 RD(level, " skip\n");
1072 }
1073 }
1074
1075 static Eina_Bool
_evas_render_phase1_object_process(Phase1_Context * p1ctx,Evas_Object_Protected_Data * obj,Eina_Bool restack,Eina_Bool mapped_parent,Eina_Bool src_changed,int level)1076 _evas_render_phase1_object_process(Phase1_Context *p1ctx,
1077 Evas_Object_Protected_Data *obj,
1078 Eina_Bool restack,
1079 Eina_Bool mapped_parent,
1080 Eina_Bool src_changed,
1081 int level)
1082 {
1083 Eina_Bool clean_them = EINA_FALSE;
1084 Eina_Bool map, hmap, can_map, map_not_can_map, obj_changed, is_active;
1085 Evas_Object *eo_obj = obj->object;
1086
1087 EINA_PREFETCH(&(obj->cur->clipper));
1088
1089 obj->rect_del = EINA_FALSE;
1090 obj->render_pre = EINA_FALSE;
1091
1092 if (obj->delete_me == 2) OBJ_ARRAY_PUSH(p1ctx->delete_objects, obj);
1093 else if (obj->delete_me != 0) obj->delete_me++;
1094
1095 /* If the object will be removed, we should not cache anything during this run. */
1096 if (obj->delete_me != 0) clean_them = EINA_TRUE;
1097
1098 obj_changed = obj->changed;
1099
1100 if (obj->is_static_clip) goto done;
1101
1102 //Need pre render for the children of mapped object.
1103 //But only when they have changed.
1104 if (mapped_parent && (!obj->changed)) goto done;
1105
1106 /* build active object list */
1107 evas_object_clip_recalc(obj);
1108
1109 if (src_changed) is_active = EINA_TRUE;
1110 else
1111 {
1112 is_active = evas_object_is_active(eo_obj, obj);
1113 if (is_active && obj->proxy->proxies) src_changed = is_active;
1114 }
1115 obj->is_active = is_active;
1116
1117 #ifdef REND_DBG
1118 RD(level, "[--- PROCESS %s active = %i, del = %i | %i,%i %ix%i\n",
1119 RDNAME(obj), is_active, obj->delete_me, obj->cur->geometry.x,
1120 obj->cur->geometry.y, obj->cur->geometry.w, obj->cur->geometry.h);
1121 #endif
1122
1123 if ((!mapped_parent) &&
1124 ((is_active) || (obj->delete_me != 0)) &&
1125 (!obj->no_render))
1126 {
1127 Evas_Active_Entry ent;
1128
1129 #ifdef INLINE_ACTIVE_GEOM
1130 if (obj->is_smart)
1131 evas_object_smart_bounding_box_get(obj, &(ent.rect), NULL);
1132 else
1133 {
1134 ent.rect.x = obj->cur->cache.clip.x;
1135 ent.rect.y = obj->cur->cache.clip.y;
1136 ent.rect.w = obj->cur->cache.clip.w;
1137 ent.rect.h = obj->cur->cache.clip.h;
1138 }
1139 #endif
1140 ent.obj = obj;
1141 eina_inarray_push(p1ctx->active_objects, &ent);
1142 }
1143 if (is_active && obj->cur->snapshot && !obj->delete_me &&
1144 evas_object_is_visible(obj))
1145 {
1146 // FIXME: Array should be clean (no need to check if already in there)
1147 int found = 0;
1148 for (unsigned i = 0; !found && (i < p1ctx->snapshot_objects->count); i++)
1149 if (obj == eina_array_data_get(p1ctx->snapshot_objects, i))
1150 found = 1;
1151 if (!found) OBJ_ARRAY_PUSH(p1ctx->snapshot_objects, obj);
1152 }
1153
1154 #ifdef REND_DBG
1155 if (!is_active)
1156 {
1157 RD(level, "%s vis: %i, cache.clip.vis: %i cache.clip.a: %i [func: %p]\n",
1158 RDNAME(obj), obj->cur->visible, obj->cur->cache.clip.visible,
1159 obj->cur->cache.clip.a, obj->func->is_visible);
1160 }
1161 #endif
1162
1163 _evas_object_gfx_mapping_update(obj);
1164 map = _evas_render_has_map(obj);
1165 hmap = _evas_render_had_map(obj);
1166 can_map = _evas_render_can_map(obj);
1167 map_not_can_map = map & !can_map;
1168
1169 if (EINA_UNLIKELY((restack && !map_not_can_map)))
1170 {
1171 _evas_render_phase1_object_restack_handle(p1ctx, obj, obj_changed);
1172 obj_changed = EINA_TRUE;
1173 clean_them = EINA_TRUE;
1174 }
1175
1176 if (EINA_UNLIKELY(map_not_can_map))
1177 {
1178 _evas_render_phase1_object_mapped(p1ctx, obj, src_changed, hmap,
1179 is_active, obj_changed, level);
1180 goto done;
1181 }
1182 else if (EINA_UNLIKELY(hmap && !can_map))
1183 _evas_render_phase1_object_mapped_had_restack(p1ctx, obj, map,
1184 obj_changed, level);
1185
1186 /* handle normal rendering. this object knows how to handle maps */
1187 if (obj_changed)
1188 {
1189 if (obj->is_smart)
1190 src_changed =
1191 _evas_render_phase1_object_changed_smart(p1ctx, obj, mapped_parent,
1192 obj_changed, src_changed,
1193 is_active, level);
1194 else /* non smart object */
1195 _evas_render_phase1_object_changed_normal(p1ctx, obj, is_active,
1196 level);
1197 }
1198 else
1199 {
1200 /* not changed */
1201 RD(level, " not changed... [%i] -> (%i %i %p %i) [%i]\n",
1202 evas_object_is_visible(obj),
1203 obj->cur->visible, obj->cur->cache.clip.visible, obj->smart.smart,
1204 obj->cur->cache.clip.a, evas_object_was_visible(obj));
1205 if ((!obj->clip.clipees) &&
1206 (EINA_LIKELY(obj->delete_me == 0)) &&
1207 (_evas_render_can_render(obj) ||
1208 (evas_object_was_visible(obj) &&
1209 (!obj->prev->have_clipees))))
1210 {
1211 if (obj->is_smart)
1212 _evas_render_phase1_object_no_changed_smart(p1ctx, obj, restack,
1213 mapped_parent,
1214 src_changed, level);
1215 else /* not smart */
1216 _evas_render_phase1_object_no_changed_normal(p1ctx, obj, level);
1217 }
1218 else if (EINA_UNLIKELY(is_active &&
1219 _evas_render_object_is_mask(obj) &&
1220 obj->cur->visible))
1221 {
1222 RD(level, " visible clipper image\n");
1223 OBJ_ARRAY_PUSH(p1ctx->render_objects, obj);
1224 obj->render_pre = EINA_TRUE;
1225 }
1226 }
1227 if (!is_active) obj->restack = EINA_FALSE;
1228 RD(level, "---]\n");
1229 done:
1230 if (obj_changed) obj->no_change_render = 0;
1231 else
1232 {
1233 if (obj->no_change_render < 255) obj->no_change_render++;
1234 }
1235 return clean_them;
1236 }
1237
1238 //
1239 //
1240 //
1241 ////////////////////////////////////////////////////////////////////////////
1242
1243
1244
1245
1246
1247
1248
1249 static Eina_Bool
_evas_render_phase1_process(Phase1_Context * p1ctx)1250 _evas_render_phase1_process(Phase1_Context *p1ctx)
1251 {
1252 Evas_Layer *lay;
1253 Eina_Bool clean_them = EINA_FALSE;
1254
1255 RD(0, " [--- PHASE 1\n");
1256 EINA_INLIST_FOREACH(p1ctx->e->layers, lay)
1257 {
1258 Evas_Object_Protected_Data *obj;
1259
1260 EINA_INLIST_FOREACH(lay->objects, obj)
1261 {
1262 if (evas_object_is_on_plane(obj)) continue;
1263 clean_them |= _evas_render_phase1_object_process
1264 (p1ctx, obj, EINA_FALSE, EINA_FALSE, EINA_FALSE, 2);
1265 }
1266 }
1267 RD(0, " ---]\n");
1268 return clean_them;
1269 }
1270
1271 static void
_evas_render_check_pending_objects(Eina_Array * pending_objects,Evas * eo_e EINA_UNUSED,Evas_Public_Data * e)1272 _evas_render_check_pending_objects(Eina_Array *pending_objects, Evas *eo_e EINA_UNUSED, Evas_Public_Data *e)
1273 {
1274 unsigned int i;
1275
1276 for (i = 0; i < pending_objects->count; ++i)
1277 {
1278 Evas_Object *eo_obj;
1279 int is_active;
1280 Eina_Bool ok = EINA_FALSE;
1281
1282 Evas_Object_Protected_Data *obj = eina_array_data_get(pending_objects, i);
1283 eo_obj = obj->object;
1284
1285 if (!obj->layer) goto clean_stuff;
1286
1287 _evas_object_gfx_mapping_update(obj);
1288 EINA_PREFETCH(&(obj->cur->clipper));
1289 EINA_PREFETCH(&(obj->cur->cache.clip));
1290 //If the children are in active objects, They should be cleaned up.
1291 if (EINA_UNLIKELY((obj->changed_map) &&
1292 (_evas_render_has_map(obj)) &&
1293 (!_evas_render_can_map(obj))))
1294 goto clean_stuff;
1295
1296 evas_object_clip_recalc(obj);
1297 is_active = evas_object_is_active(eo_obj, obj);
1298
1299 if ((!is_active) && (!obj->is_active) && (!obj->render_pre) &&
1300 (!obj->rect_del))
1301 {
1302 ok = EINA_TRUE;
1303 goto clean_stuff;
1304 }
1305
1306 if (obj->is_active == is_active)
1307 {
1308 if (obj->changed)
1309 {
1310 if (obj->is_smart)
1311 {
1312 if (obj->render_pre || obj->rect_del) ok = EINA_TRUE;
1313 }
1314 else
1315 if ((is_active) && (obj->restack) && (!obj->clip.clipees) &&
1316 (_evas_render_can_render(obj) ||
1317 (evas_object_was_visible(obj) && (!obj->prev->have_clipees))))
1318 {
1319 if (!obj->render_pre && !obj->rect_del && !obj->delete_me)
1320 ok = EINA_TRUE;
1321 }
1322 else
1323 if (is_active && (!obj->clip.clipees) &&
1324 (_evas_render_can_render(obj) ||
1325 (evas_object_was_visible(obj) && (!obj->prev->have_clipees))))
1326 {
1327 if (obj->render_pre || obj->rect_del) ok = EINA_TRUE;
1328 }
1329 }
1330 else
1331 {
1332 if ((!obj->clip.clipees) && (obj->delete_me == 0) &&
1333 (!obj->cur->have_clipees || (evas_object_was_visible(obj) && (!obj->prev->have_clipees)))
1334 && evas_object_is_opaque(obj) && evas_object_is_visible(obj))
1335 {
1336 if (obj->rect_del || obj->is_smart) ok = EINA_TRUE;
1337 }
1338 }
1339 }
1340
1341 clean_stuff:
1342 if (!ok)
1343 {
1344 eina_inarray_flush(&e->active_objects);
1345 OBJS_ARRAY_CLEAN(&e->render_objects);
1346 OBJS_ARRAY_CLEAN(&e->restack_objects);
1347 OBJS_ARRAY_CLEAN(&e->delete_objects);
1348 OBJS_ARRAY_CLEAN(&e->snapshot_objects);
1349 e->invalidate = EINA_TRUE;
1350 return;
1351 }
1352 }
1353 }
1354
1355 Eina_Bool
pending_change(void * data,void * gdata EINA_UNUSED)1356 pending_change(void *data, void *gdata EINA_UNUSED)
1357 {
1358 Evas_Object *eo_obj;
1359
1360 Evas_Object_Protected_Data *obj = data;
1361 eo_obj = obj->object;
1362 if (obj->delete_me) return EINA_FALSE;
1363 if (obj->pre_render_done)
1364 {
1365 RD(0, " OBJ %s pending change %i -> 0, pre %i\n", RDNAME(obj), obj->changed, obj->pre_render_done);
1366 evas_object_change_reset(obj);
1367 obj->func->render_post(eo_obj, obj, obj->private_data);
1368 obj->pre_render_done = EINA_FALSE;
1369 }
1370 else if (!_evas_render_can_render(obj) &&
1371 (!obj->is_active) && (!obj->render_pre) &&
1372 (!obj->rect_del))
1373 {
1374 evas_object_change_reset(obj);
1375 }
1376
1377 //FIXME: after evas_object_change_reset(), obj->changed is always false...
1378 Eina_Bool val = obj->changed ? EINA_TRUE : EINA_FALSE;
1379 obj->in_pending_objects = val;
1380 return val;
1381 }
1382
1383 static Eina_Bool
_evas_render_can_use_overlay(Evas_Public_Data * e,Evas_Object * eo_obj,Efl_Canvas_Output * output)1384 _evas_render_can_use_overlay(Evas_Public_Data *e, Evas_Object *eo_obj, Efl_Canvas_Output *output)
1385 {
1386 Eina_Rectangle *r;
1387 Evas_Object *eo_tmp;
1388 Eina_List *alphas = NULL;
1389 Eina_List *opaques = NULL;
1390 Evas_Object *video_parent = NULL;
1391 Eina_Rectangle zone;
1392 Evas_Coord xc1, yc1, xc2, yc2;
1393 int i;
1394 Eina_Bool nooverlay;
1395 Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
1396 Evas_Object_Protected_Data *tmp = NULL;
1397 Evas_Coord imgw, imgh;
1398 unsigned int caps;
1399 Eina_Bool surface_below, stacking_check, object_above = EINA_FALSE;
1400 Eina_Bool ignore_window;
1401
1402 if (!_evas_object_image_can_use_plane(obj, output))
1403 return EINA_FALSE;
1404
1405 video_parent = _evas_object_image_video_parent_get(eo_obj);
1406
1407 /* Check if any one is the stack make this object mapped */
1408 eo_tmp = eo_obj;
1409 tmp = efl_data_scope_get(eo_tmp, EFL_CANVAS_OBJECT_CLASS);
1410 _evas_object_gfx_mapping_update(tmp);
1411 while (tmp && !(_evas_render_has_map(tmp) && !_evas_render_can_map(tmp)))
1412 {
1413 eo_tmp = tmp->smart.parent;
1414 tmp = efl_data_scope_get(eo_tmp, EFL_CANVAS_OBJECT_CLASS);
1415 if (tmp) _evas_object_gfx_mapping_update(tmp);
1416 }
1417
1418 if (tmp && _evas_render_has_map(tmp) && !_evas_render_can_map(tmp))
1419 return EINA_FALSE; /* we are mapped, we can't be an overlay */
1420
1421 if (!evas_object_is_visible(obj))
1422 return EINA_FALSE; /* no need to update the overlay if it's not visible */
1423
1424 /* If any recoloring of the surface is needed, n overlay to */
1425 if ((obj->cur->cache.clip.r != 255) ||
1426 (obj->cur->cache.clip.g != 255) ||
1427 (obj->cur->cache.clip.b != 255) ||
1428 (obj->cur->cache.clip.a != 255))
1429 return EINA_FALSE;
1430
1431 caps = evas_object_image_video_surface_caps_get(eo_obj);
1432
1433 /* check if surface is above the canvas */
1434 surface_below = !!(caps & EVAS_VIDEO_SURFACE_BELOW);
1435 if (!surface_below)
1436 {
1437 /* above canvas, must support resize and clipping */
1438
1439 /* check if video surface supports resize */
1440 evas_object_image_size_get(eo_obj, &imgw, &imgh);
1441 if ((obj->cur->geometry.w != imgw) ||
1442 (obj->cur->geometry.h != imgh))
1443 {
1444 if (!(caps & EVAS_VIDEO_SURFACE_RESIZE))
1445 return EINA_FALSE;
1446 }
1447 /* check if video surface supports clipping */
1448 evas_object_image_size_get(eo_obj, &imgw, &imgh);
1449 if ((obj->cur->cache.clip.x != obj->cur->geometry.x) ||
1450 (obj->cur->cache.clip.y != obj->cur->geometry.y) ||
1451 (obj->cur->cache.clip.w != obj->cur->geometry.w) ||
1452 (obj->cur->cache.clip.h != obj->cur->geometry.h))
1453 {
1454 if (!(caps & EVAS_VIDEO_SURFACE_CLIP))
1455 return EINA_FALSE;
1456 }
1457 }
1458
1459 /* check for window/surface/canvas limits */
1460 ignore_window = !!(caps & EVAS_VIDEO_SURFACE_IGNORE_WINDOW);
1461 if (!ignore_window)
1462 {
1463 Evas_Coord x1, x2, y1, y2;
1464 Evas_Coord fx, fy, fw, fh;
1465
1466 fx = e->framespace.x;
1467 fy = e->framespace.y;
1468 fw = e->framespace.w;
1469 fh = e->framespace.h;
1470
1471 x1 = obj->cur->geometry.x + fx;
1472 y1 = obj->cur->geometry.y + fy;
1473 x2 = obj->cur->geometry.x + obj->cur->geometry.w + fx;
1474 y2 = obj->cur->geometry.y + obj->cur->geometry.h + fy;
1475
1476 if ((x1 < fx) || (y1 < fy) ||
1477 (x2 > e->output.w - (fw - fx)) ||
1478 (y2 > e->output.h - (fh - fy)))
1479 return EINA_FALSE;
1480 }
1481
1482 /* check if there are other objects above the video object? */
1483 stacking_check = !!(caps & EVAS_VIDEO_SURFACE_STACKING_CHECK);
1484 if (!stacking_check)
1485 return EINA_TRUE;
1486
1487 /* Check presence of transparent object on top of the video object */
1488 EINA_RECTANGLE_SET(&zone,
1489 obj->cur->cache.clip.x,
1490 obj->cur->cache.clip.y,
1491 obj->cur->cache.clip.w,
1492 obj->cur->cache.clip.h);
1493
1494 for (i = e->active_objects.len - 1; i > 0; i--)
1495 {
1496 Eina_Rectangle self;
1497 Eina_Rectangle *match;
1498 Evas_Object *eo_current;
1499 Eina_List *l;
1500 int xm1, ym1, xm2, ym2;
1501 Evas_Active_Entry *ent = eina_inarray_nth(&e->active_objects, i);
1502 Evas_Object_Protected_Data *current = ent->obj;
1503
1504 eo_current = current->object;
1505 /* Did we find the video object in the stack ? */
1506 if (eo_current == video_parent || eo_current == eo_obj)
1507 break;
1508
1509 EINA_RECTANGLE_SET(&self,
1510 current->cur->cache.clip.x,
1511 current->cur->cache.clip.y,
1512 current->cur->cache.clip.w,
1513 current->cur->cache.clip.h);
1514
1515 /* This doesn't cover the area of the video object, so don't bother with that object */
1516 if (!eina_rectangles_intersect(&zone, &self))
1517 continue;
1518
1519 xc1 = current->cur->cache.clip.x;
1520 yc1 = current->cur->cache.clip.y;
1521 xc2 = current->cur->cache.clip.x + current->cur->cache.clip.w;
1522 yc2 = current->cur->cache.clip.y + current->cur->cache.clip.h;
1523
1524 if (evas_object_is_visible(current) &&
1525 (!current->clip.clipees) &&
1526 (current->cur->visible) &&
1527 (!current->delete_me) &&
1528 (current->cur->cache.clip.visible) &&
1529 (!efl_isa(eo_current, EFL_CANVAS_GROUP_CLASS)))
1530 {
1531 Eina_Bool included = EINA_FALSE;
1532
1533 if (!surface_below)
1534 {
1535 object_above = EINA_TRUE;
1536 break;
1537 }
1538
1539 if (evas_object_is_opaque(current) ||
1540 ((current->func->has_opaque_rect) &&
1541 (current->func->has_opaque_rect(eo_current, current, current->private_data))))
1542 {
1543 /* The object is opaque */
1544
1545 /* Check if the opaque object is inside another opaque object */
1546 EINA_LIST_FOREACH(opaques, l, match)
1547 {
1548 xm1 = match->x;
1549 ym1 = match->y;
1550 xm2 = match->x + match->w;
1551 ym2 = match->y + match->h;
1552
1553 /* Both object are included */
1554 if (xc1 >= xm1 && yc1 >= ym1 && xc2 <= xm2 && yc2 <= ym2)
1555 {
1556 included = EINA_TRUE;
1557 break;
1558 }
1559 }
1560
1561 /* Not included yet */
1562 if (!included)
1563 {
1564 Eina_List *ln;
1565 Evas_Coord xn2, yn2;
1566
1567 r = eina_rectangle_new(current->cur->cache.clip.x, current->cur->cache.clip.y,
1568 current->cur->cache.clip.w, current->cur->cache.clip.h);
1569
1570 opaques = eina_list_append(opaques, r);
1571
1572 xn2 = r->x + r->w;
1573 yn2 = r->y + r->h;
1574
1575 /* Remove all the transparent object that are covered by the new opaque object */
1576 EINA_LIST_FOREACH_SAFE(alphas, l, ln, match)
1577 {
1578 xm1 = match->x;
1579 ym1 = match->y;
1580 xm2 = match->x + match->w;
1581 ym2 = match->y + match->h;
1582
1583 if (xm1 >= r->x && ym1 >= r->y && xm2 <= xn2 && ym2 <= yn2)
1584 {
1585 /* The new rectangle is over some transparent object,
1586 so remove the transparent object */
1587 alphas = eina_list_remove_list(alphas, l);
1588 }
1589 }
1590 }
1591 }
1592 else
1593 {
1594 /* The object has some transparency */
1595
1596 /* Check if the transparent object is inside any other transparent object */
1597 EINA_LIST_FOREACH(alphas, l, match)
1598 {
1599 xm1 = match->x;
1600 ym1 = match->y;
1601 xm2 = match->x + match->w;
1602 ym2 = match->y + match->h;
1603
1604 /* Both object are included */
1605 if (xc1 >= xm1 && yc1 >= ym1 && xc2 <= xm2 && yc2 <= ym2)
1606 {
1607 included = EINA_TRUE;
1608 break;
1609 }
1610 }
1611
1612 /* If not check if it is inside any opaque one */
1613 if (!included)
1614 {
1615 EINA_LIST_FOREACH(opaques, l, match)
1616 {
1617 xm1 = match->x;
1618 ym1 = match->y;
1619 xm2 = match->x + match->w;
1620 ym2 = match->y + match->h;
1621
1622 /* Both object are included */
1623 if (xc1 >= xm1 && yc1 >= ym1 && xc2 <= xm2 && yc2 <= ym2)
1624 {
1625 included = EINA_TRUE;
1626 break;
1627 }
1628 }
1629 }
1630
1631 /* No inclusion at all, so add it */
1632 if (!included)
1633 {
1634 r = eina_rectangle_new(current->cur->cache.clip.x, current->cur->cache.clip.y,
1635 current->cur->cache.clip.w, current->cur->cache.clip.h);
1636
1637 alphas = eina_list_append(alphas, r);
1638 }
1639 }
1640 }
1641 }
1642
1643 /* If there is any pending transparent object, then no overlay */
1644 nooverlay = !!eina_list_count(alphas);
1645
1646 EINA_LIST_FREE(alphas, r)
1647 eina_rectangle_free(r);
1648 EINA_LIST_FREE(opaques, r)
1649 eina_rectangle_free(r);
1650
1651 if (nooverlay || object_above)
1652 return EINA_FALSE;
1653
1654 return EINA_TRUE;
1655 }
1656
1657 static Eina_Bool
_proxy_context_clip(Evas_Public_Data * evas,void * ctx,Evas_Proxy_Render_Data * proxy_render_data,Evas_Object_Protected_Data * obj,int off_x,int off_y)1658 _proxy_context_clip(Evas_Public_Data *evas, void *ctx, Evas_Proxy_Render_Data *proxy_render_data, Evas_Object_Protected_Data *obj, int off_x, int off_y)
1659 {
1660 const Eina_Rectangle *clip;
1661 Evas_Object_Protected_Data *clipper;
1662 int cw, ch;
1663
1664 /* cache.clip can not be relied on, since the evas is frozen, but we need
1665 * to set the clip. so we recurse from clipper to clipper until we reach
1666 * the source object's clipper */
1667
1668 if (!proxy_render_data) return EINA_TRUE;
1669 if (proxy_render_data->source_clip)
1670 {
1671 Evas_Object_Protected_Data *src_obj = proxy_render_data->src_obj;
1672 /* trust cache.clip since we clip like the source */
1673 ENFN->context_clip_clip(ENC, ctx,
1674 src_obj->cur->cache.clip.x + off_x,
1675 src_obj->cur->cache.clip.y + off_y,
1676 src_obj->cur->cache.clip.w, src_obj->cur->cache.clip.h);
1677 ENFN->context_clip_get(ENC, ctx, NULL, NULL, &cw, &ch);
1678 return ((cw > 0) && (ch > 0));
1679 }
1680
1681 if (!obj->cur->clipper) return EINA_TRUE;
1682
1683 clipper = obj->cur->clipper;
1684 if (!clipper->cur->visible) return EINA_FALSE;
1685 clip = &clipper->cur->geometry;
1686 ENFN->context_clip_clip(ENC, ctx, clip->x + off_x, clip->y + off_y, clip->w, clip->h);
1687 ENFN->context_clip_get(ENC, ctx, NULL, NULL, &cw, &ch);
1688 if ((cw <= 0) || (ch <= 0)) return EINA_FALSE;
1689
1690 /* stop if we found the source object's clipper */
1691 if (clipper == proxy_render_data->src_obj->cur->clipper) return EINA_TRUE;
1692
1693 /* recurse to the clipper itself.
1694 * origin of clipper's clipper won't be transformed to derivative space. */
1695 return _proxy_context_clip(evas, ctx, proxy_render_data, clipper,
1696 -proxy_render_data->src_obj->cur->geometry.x,
1697 -proxy_render_data->src_obj->cur->geometry.y);
1698 }
1699
1700 static Eina_Bool
_mask_apply_inside_proxy(Evas_Proxy_Render_Data * proxy_render_data,Evas_Object_Protected_Data * mask)1701 _mask_apply_inside_proxy(Evas_Proxy_Render_Data *proxy_render_data,
1702 Evas_Object_Protected_Data *mask)
1703 {
1704 // Trying to find out if the mask should be applied inside the proxy or not.
1705 if (!proxy_render_data || proxy_render_data->source_clip) return EINA_TRUE;
1706 if (!proxy_render_data->src_obj->cur->clipper) return EINA_FALSE;
1707 if (!mask) return EINA_FALSE;
1708
1709 // FIXME: Need to implement a logic similar to _proxy_context_clip
1710 return EINA_FALSE;
1711 }
1712
1713 static void
_evas_render_mapped_context_clip_set(Evas_Public_Data * evas,Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,void * ctx,Evas_Proxy_Render_Data * proxy_render_data,int off_x,int off_y)1714 _evas_render_mapped_context_clip_set(Evas_Public_Data *evas, Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, void *ctx, Evas_Proxy_Render_Data *proxy_render_data, int off_x, int off_y)
1715 {
1716 int x, y, w, h;
1717 Eina_Bool proxy_src_clip = EINA_TRUE;
1718
1719 if (proxy_render_data) proxy_src_clip = proxy_render_data->source_clip;
1720
1721 if (proxy_src_clip)
1722 {
1723 x = obj->cur->cache.clip.x;
1724 y = obj->cur->cache.clip.y;
1725 w = obj->cur->cache.clip.w;
1726 h = obj->cur->cache.clip.h;
1727
1728 RECTS_CLIP_TO_RECT(x, y, w, h,
1729 obj->cur->clipper->cur->cache.clip.x,
1730 obj->cur->clipper->cur->cache.clip.y,
1731 obj->cur->clipper->cur->cache.clip.w,
1732 obj->cur->clipper->cur->cache.clip.h);
1733
1734 ENFN->context_clip_set(ENC, ctx, x + off_x, y + off_y, w, h);
1735 }
1736 else if (evas->is_frozen)
1737 {
1738 /* can't trust cache.clip here - clip should be in ctx already */
1739 }
1740 else
1741 {
1742 //FIXME: Consider to clip by the proxy clipper.
1743 if (proxy_render_data->eo_src != eo_obj)
1744 {
1745 x = obj->cur->clipper->cur->geometry.x + off_x;
1746 y = obj->cur->clipper->cur->geometry.y + off_y;
1747 w = obj->cur->clipper->cur->geometry.w;
1748 h = obj->cur->clipper->cur->geometry.h;
1749 ENFN->context_clip_clip(ENC, ctx, x, y, w, h);
1750 }
1751 }
1752 }
1753
1754 static void
_evas_render_mapped_mask(Evas_Public_Data * evas,Evas_Object_Protected_Data * obj,Evas_Object_Protected_Data * mask,Evas_Proxy_Render_Data * proxy_render_data,void * output,void * ctx,int off_x,int off_y,int level,Eina_Bool do_async)1755 _evas_render_mapped_mask(Evas_Public_Data *evas, Evas_Object_Protected_Data *obj, Evas_Object_Protected_Data *mask,
1756 Evas_Proxy_Render_Data *proxy_render_data, void *output, void *ctx, int off_x, int off_y, int level, Eina_Bool do_async)
1757 {
1758 if (!mask) return;
1759 if (proxy_render_data &&
1760 !proxy_render_data->source_clip &&
1761 proxy_render_data->src_obj->clip.mask == mask) return;
1762
1763 // This path can be hit when we're multiplying masks on top of each other...
1764 Evas_Object_Protected_Data *prev_mask = obj->clip.prev_mask;
1765 Eina_Bool redraw = mask->mask->redraw || !mask->mask->surface;
1766
1767 RD(level, " has mask: %s redraw:%d sfc:%p prev_mask:%p\n",
1768 RDNAME(mask), mask->mask->redraw, mask->mask->surface, prev_mask);
1769 if (prev_mask && !_mask_apply_inside_proxy(proxy_render_data, prev_mask))
1770 {
1771 RD(level, " discard prev mask and redraw (guessed outside proxy)\n");
1772 prev_mask = NULL;
1773 redraw = EINA_TRUE;
1774 }
1775 if (redraw)
1776 evas_render_mask_subrender(evas, output, mask, prev_mask, level + 1, do_async);
1777
1778 if (mask->mask->surface)
1779 {
1780 Eina_Rectangle clip = _evas_render_smallest_static_clipped_geometry_get(mask->cur);
1781 ENFN->context_clip_image_set(ENC, ctx, mask->mask->surface,
1782 clip.x + off_x,
1783 clip.y + off_y,
1784 evas, do_async);
1785 }
1786 }
1787
1788 Eina_Bool
evas_render_mapped(Evas_Public_Data * evas,Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,void * context,void * output,void * surface,int off_x,int off_y,int mapped,int ecx,int ecy,int ecw,int ech,Evas_Proxy_Render_Data * proxy_render_data,int level,Eina_Bool do_async)1789 evas_render_mapped(Evas_Public_Data *evas, Evas_Object *eo_obj,
1790 Evas_Object_Protected_Data *obj, void *context,
1791 void *output, void *surface,
1792 int off_x, int off_y, int mapped, int ecx,
1793 int ecy, int ecw, int ech,
1794 Evas_Proxy_Render_Data *proxy_render_data, int level,
1795 Eina_Bool do_async)
1796 {
1797 Evas_Object_Protected_Data *obj2;
1798 Eina_Bool clean_them = EINA_FALSE;
1799 Eina_Bool proxy_src_clip = EINA_TRUE;
1800 Eina_Bool was_pre_render_done = obj->pre_render_done;
1801 void *ctx;
1802
1803 if (!proxy_render_data)
1804 {
1805 /* don't render if the source is invisible */
1806 if ((evas_object_is_source_invisible(eo_obj, obj)))
1807 return EINA_FALSE;
1808 }
1809 else
1810 proxy_src_clip = proxy_render_data->source_clip;
1811
1812 evas_object_clip_recalc(obj);
1813 _evas_object_gfx_mapping_update(obj);
1814
1815 /* leave early if clipper is not visible */
1816 if ((obj->cur->clipper) && (!obj->cur->clipper->cur->visible))
1817 return EINA_FALSE;
1818
1819 eina_evlog("+render_object", eo_obj, 0.0, NULL);
1820 #ifdef REND_DBG
1821 RD(level, "{\n");
1822 RD(level, " evas_render_mapped(evas:%p, obj:%s, ctx:%p, sfc:%p, offset:%i,%i, %s, %s)\n",
1823 evas->evas, RDNAME(obj), context, surface, off_x, off_y,
1824 mapped ? "mapped" : "normal", do_async ? "async" : "sync");
1825 IFRD(obj->is_smart, level, " is_smart");
1826 IFRD(obj->is_frame, level, " in framespace%s", obj->is_frame_top ? " (top object)" : "");
1827 if (obj->cur->clipper)
1828 {
1829 RD(level, " clipper: %s (mask: %s) %d,%d %dx%d ; color: {%d,%d,%d,%d} ; cached: {%d,%d,%d,%d}\n",
1830 RDNAME(obj->cur->clipper), RDNAME(obj->clip.mask),
1831 obj->cur->clipper->cur->geometry.x, obj->cur->clipper->cur->geometry.y,
1832 obj->cur->clipper->cur->geometry.w, obj->cur->clipper->cur->geometry.h,
1833 obj->cur->clipper->cur->color.r, obj->cur->clipper->cur->color.g,
1834 obj->cur->clipper->cur->color.b, obj->cur->clipper->cur->color.a,
1835 obj->cur->clipper->cur->cache.clip.r, obj->cur->clipper->cur->cache.clip.g,
1836 obj->cur->clipper->cur->cache.clip.b, obj->cur->clipper->cur->cache.clip.a);
1837 }
1838
1839 RD(level, " geom: %d,%d %dx%d, cache.clip: (vis: %d) %d,%d %dx%d ; color: {%d,%d,%d,%d} ; cached: {%d,%d,%d,%d}\n",
1840 obj->cur->geometry.x, obj->cur->geometry.y, obj->cur->geometry.w, obj->cur->geometry.h, obj->cur->cache.clip.visible,
1841 obj->cur->cache.clip.x, obj->cur->cache.clip.y, obj->cur->cache.clip.w, obj->cur->cache.clip.h,
1842 obj->cur->color.r, obj->cur->color.g, obj->cur->color.b, obj->cur->color.a,
1843 obj->cur->cache.clip.r, obj->cur->cache.clip.g, obj->cur->cache.clip.b, obj->cur->cache.clip.a);
1844 {
1845 int _cu, _cc, _cm, _cx, _cy, _cw, _ch, _cr, _cg, _cb, _ca, _cmr, _cmg, _cmb, _cma;
1846 _cu = ENFN->context_clip_get(ENC, context, &_cx, &_cy, &_cw, &_ch);
1847 _cc = ENFN->context_color_get(ENC, context, &_cr, &_cg, &_cb, &_ca);
1848 _cm = ENFN->context_multiplier_get(ENC, context, &_cmr, &_cmg, &_cmb, &_cma);
1849 RD(level, " context clip: [%d] %d,%d %dx%d ; color: [%d] {%d,%d,%d,%d} ; mult: [%d] {%d,%d,%d,%d}\n",
1850 _cu, _cx, _cy, _cw, _ch, _cc, _cr, _cg, _cb, _ca, _cm, _cmr, _cmg, _cmb, _cma);
1851 }
1852 #endif
1853
1854 if (mapped)
1855 {
1856 if (_evas_render_object_is_mask(obj))
1857 {
1858 RD(level, " is mask: redraw:%d sfc:%p\n", obj->mask->redraw, obj->mask->surface);
1859 if (surface != obj->mask->surface)
1860 {
1861 RD(level, " not rendering mask surface\n");
1862 RD(level, "}\n");
1863 eina_evlog("-render_object", eo_obj, 0.0, NULL);
1864 return EINA_FALSE;
1865 }
1866 // else don't return: draw mask in its surface
1867 }
1868 else if (proxy_src_clip)
1869 {
1870 if (!evas->is_frozen) /* same as "if (proxy_render_data)" */
1871 {
1872 if ((!evas_object_is_visible(obj)) || (obj->clip.clipees)
1873 || (obj->cur->have_clipees) || (obj->no_render))
1874 {
1875 IFRD(obj->no_render, level, " no_render\n");
1876 IFRD(obj->clip.clipees || obj->cur->have_clipees, level, " has clippees\n");
1877 IFRD(!evas_object_is_visible(obj), level, " not visible\n");
1878 RD(level, "}\n");
1879 eina_evlog("-render_object", eo_obj, 0.0, NULL);
1880 return EINA_FALSE;
1881 }
1882 }
1883 else
1884 {
1885 /* can not trust cache.clip - evas is frozen */
1886 if (!obj->cur->visible || obj->clip.clipees || (obj->no_render && !proxy_render_data) ||
1887 (!obj->cur->color.a && (obj->cur->render_op == EVAS_RENDER_BLEND)))
1888 {
1889 IFRD(obj->no_render, level, " proxy_src_clip + no_render\n");
1890 IFRD(obj->clip.clipees || obj->cur->have_clipees, level, " proxy_src_clip + has clippees\n");
1891 IFRD(!obj->cur->visible, level, " proxy_src_clip + not visible\n");
1892 IFRD(!obj->cur->color.a && (obj->cur->render_op == EVAS_RENDER_BLEND), level, " proxy_src_clip + 0 alpha\n");
1893 RD(level, "}\n");
1894 eina_evlog("-render_object", eo_obj, 0.0, NULL);
1895 return EINA_FALSE;
1896 }
1897 else if (proxy_render_data && (surface != obj->proxy->surface) &&
1898 obj->proxy->src_invisible)
1899 {
1900 RD(level, " src_invisible + not proxy surface (recursive proxies)\n");
1901 RD(level, "}\n");
1902 eina_evlog("-render_object", eo_obj, 0.0, NULL);
1903 return EINA_FALSE;
1904 }
1905 }
1906 }
1907 else if (!evas_object_is_proxy_visible(obj) ||
1908 (obj->clip.clipees) || (obj->cur->have_clipees))
1909 {
1910 IFRD(!evas_object_is_proxy_visible(obj), level, " proxy not visible\n");
1911 IFRD(obj->clip.clipees || obj->cur->have_clipees, level, " has clippees\n");
1912 RD(level, "}\n");
1913 eina_evlog("-render_object", eo_obj, 0.0, NULL);
1914 return EINA_FALSE;
1915 }
1916 else if (obj->no_render && (surface != obj->proxy->surface))
1917 {
1918 RD(level, " no_render\n");
1919 RD(level, "}\n");
1920 eina_evlog("-render_object", eo_obj, 0.0, NULL);
1921 return EINA_FALSE;
1922 }
1923 }
1924 else if (!(((evas_object_is_active(eo_obj, obj) && (!obj->clip.clipees) &&
1925 (_evas_render_can_render(obj))))
1926 ))
1927 {
1928 IFRD(!evas_object_is_active(eo_obj, obj), level, " not active\n");
1929 IFRD(!_evas_render_can_render(obj), level, " can't render\n");
1930 IFRD(obj->clip.clipees, level, " has clippees\n");
1931 RD(level, "}\n");
1932 eina_evlog("-render_object", eo_obj, 0.0, NULL);
1933 return EINA_FALSE;
1934 }
1935
1936 // set render_pre - for child objs that may not have gotten it.
1937 obj->pre_render_done = EINA_TRUE;
1938 RD(level, " hasmap: %s [can_map: %d] cur.map:%p cur.usemap:%d\n",
1939 _evas_render_has_map(obj) ? "yes" : "no",
1940 obj->func->can_map ? obj->func->can_map(eo_obj): -1,
1941 obj->map->cur.map, obj->map->cur.usemap);
1942 if (_evas_render_has_map(obj) && !_evas_render_can_map(obj))
1943 {
1944 int sw, sh;
1945 Eina_Bool changed = EINA_FALSE, rendered = EINA_FALSE, pchanged = EINA_FALSE;
1946
1947 clean_them = EINA_TRUE;
1948
1949 sw = obj->cur->geometry.w;
1950 sh = obj->cur->geometry.h;
1951 RD(level, " surf size: %ix%i\n", sw, sh);
1952 if ((sw <= 0) || (sh <= 0)) goto end;
1953
1954 pchanged = evas_object_map_update(eo_obj, off_x, off_y, sw, sh, sw, sh);
1955
1956 if (obj->map->surface)
1957 {
1958 if ((obj->map->surface_w != sw) ||
1959 (obj->map->surface_h != sh))
1960 {
1961 RD(level, " new surf: %ix%i\n", sw, sh);
1962 EINA_COW_WRITE_BEGIN(evas_object_map_cow, obj->map, Evas_Object_Map_Data, map_write)
1963 {
1964 ENFN->image_free(ENC, map_write->surface);
1965 map_write->surface = NULL;
1966 }
1967 EINA_COW_WRITE_END(evas_object_map_cow, obj->map, map_write);
1968 }
1969 }
1970 if (!obj->map->surface)
1971 {
1972 EINA_COW_WRITE_BEGIN(evas_object_map_cow, obj->map, Evas_Object_Map_Data, map_write)
1973 {
1974 map_write->surface_w = sw;
1975 map_write->surface_h = sh;
1976
1977 map_write->surface = ENFN->image_map_surface_new
1978 (ENC, map_write->surface_w,
1979 map_write->surface_h,
1980 map_write->cur.map->alpha);
1981 }
1982 EINA_COW_WRITE_END(evas_object_map_cow, obj->map, map_write);
1983
1984 RD(level, " first surf: %ix%i\n", sw, sh);
1985 changed = EINA_TRUE;
1986 }
1987
1988 if (!changed) changed = evas_object_smart_changed_get(obj);
1989
1990 /* mark the old map as invalid, so later we don't reuse it as a
1991 * cache. */
1992 if (pchanged && obj->map->prev.map)
1993 {
1994 EINA_COW_WRITE_BEGIN(evas_object_map_cow, obj->map, Evas_Object_Map_Data, map_write)
1995 map_write->prev.valid_map = EINA_FALSE;
1996 EINA_COW_WRITE_END(evas_object_map_cow, obj->map, map_write);
1997 }
1998
1999 // clear surface before re-render
2000 if ((changed) && (obj->map->surface))
2001 {
2002 int off_x2, off_y2;
2003
2004 RD(level, " children redraw\n");
2005 // FIXME: calculate "changes" within map surface and only clear
2006 // and re-render those
2007 if (obj->map->cur.map->alpha)
2008 {
2009 ctx = ENFN->context_new(ENC);
2010 ENFN->context_color_set(ENC, ctx, 0, 0, 0, 0);
2011 ENFN->context_render_op_set(ENC, ctx, EVAS_RENDER_COPY);
2012 ENFN->rectangle_draw(ENC, output, ctx, obj->map->surface,
2013 0, 0, obj->map->surface_w, obj->map->surface_h,
2014 EINA_FALSE);
2015 ENFN->context_free(ENC, ctx);
2016 }
2017 ctx = ENFN->context_new(ENC);
2018 off_x2 = -obj->cur->geometry.x;
2019 off_y2 = -obj->cur->geometry.y;
2020 if (obj->is_smart)
2021 {
2022 EINA_INLIST_FOREACH
2023 (evas_object_smart_members_get_direct(eo_obj), obj2)
2024 {
2025 clean_them |= evas_render_mapped(evas, obj2->object,
2026 obj2, ctx,
2027 output, obj->map->surface,
2028 off_x2, off_y2, 1,
2029 ecx, ecy, ecw, ech,
2030 proxy_render_data,
2031 level + 1, do_async);
2032 /* We aren't sure this object will be rendered by
2033 normal(not proxy) drawing after, we reset this
2034 only in case of normal drawing. For optmizing,
2035 push this object in an array then reset them
2036 in the end of the rendering.*/
2037 if (!proxy_render_data)
2038 evas_object_change_reset(obj2);
2039 }
2040 }
2041 else
2042 {
2043 int x = 0, y = 0, w = 0, h = 0;
2044
2045 w = obj->map->surface_w;
2046 h = obj->map->surface_h;
2047 RECTS_CLIP_TO_RECT(x, y, w, h,
2048 obj->cur->geometry.x + off_x2,
2049 obj->cur->geometry.y + off_y2,
2050 obj->cur->geometry.w,
2051 obj->cur->geometry.h);
2052
2053 ENFN->context_clip_set(ENC, ctx, x, y, w, h);
2054 #ifdef REND_DBG
2055 int _c, _cx, _cy, _cw, _ch;
2056 _c = ENFN->context_clip_get(ENC, ctx, &_cx, &_cy, &_cw, &_ch);
2057 RD(level, " draw mapped obj: render(clip: [%d] %d,%d %dx%d)\n", _c, _cx, _cy, _cw, _ch);
2058 #endif
2059 // FIXME: Should this really be sync render?
2060 obj->func->render(eo_obj, obj, obj->private_data,
2061 ENC, output, ctx,
2062 obj->map->surface, off_x2, off_y2,
2063 EINA_FALSE);
2064 }
2065 ENFN->context_free(ENC, ctx);
2066 rendered = EINA_TRUE;
2067 }
2068
2069 if (rendered)
2070 {
2071 EINA_COW_WRITE_BEGIN(evas_object_map_cow, obj->map, Evas_Object_Map_Data, map_write)
2072 {
2073 map_write->surface = ENFN->image_dirty_region
2074 (ENC, map_write->surface,
2075 0, 0, map_write->surface_w, map_write->surface_h);
2076
2077 map_write->cur.valid_map = EINA_TRUE;
2078 }
2079 EINA_COW_WRITE_END(evas_object_map_cow, obj->map, map_write);
2080 }
2081
2082 /* duplicate context and reset clip */
2083 // FIXME: Shouldn't we use a new, clean context?
2084 ctx = ENFN->context_dup(ENC, context);
2085 ENFN->context_clip_unset(ENC, ctx);
2086 //ENFN->context_multiplier_unset(ENC, ctx); // this probably should be here, too
2087
2088 if (obj->map->surface)
2089 {
2090 Evas_Object_Protected_Data *mask = obj->clip.mask;
2091
2092 if (obj->cur->clipper)
2093 {
2094 evas_object_clip_recalc(obj);
2095
2096 if (obj->is_smart)
2097 {
2098 EINA_COW_STATE_WRITE_BEGIN(obj, state_write, cur)
2099 {
2100 state_write->cache.clip.dirty = EINA_TRUE;
2101 }
2102 EINA_COW_STATE_WRITE_END(obj, state_write, cur);
2103 }
2104 _evas_render_mapped_context_clip_set(evas, eo_obj, obj, ctx,
2105 proxy_render_data, off_x,
2106 off_y);
2107
2108 /* Clipper masks */
2109 _evas_render_mapped_mask(evas, obj, mask, proxy_render_data, output, ctx, off_x, off_y, level, do_async);
2110 }
2111
2112 if (obj->cur->cache.clip.visible || !proxy_src_clip)
2113 {
2114 if (!mapped)
2115 {
2116 ENFN->context_clip_clip(ENC, ctx, ecx, ecy, ecw, ech);
2117 if (!_is_obj_in_framespace(obj, evas))
2118 {
2119 _evas_render_framespace_context_clip_clip
2120 (evas, ctx, off_x - evas->framespace.x, off_y - evas->framespace.y);
2121 }
2122 }
2123 ENFN->context_multiplier_unset(ENC, ctx);
2124 ENFN->context_render_op_set(ENC, ctx, obj->cur->render_op);
2125 #ifdef REND_DBG
2126 int _c, _cx, _cy, _cw, _ch;
2127 _c = ENFN->context_clip_get(ENC, ctx, &_cx, &_cy, &_cw, &_ch);
2128 RD(level, " draw image map(clip: [%d] %d,%d %dx%d)\n", _c, _cx, _cy, _cw, _ch);
2129 #endif
2130 evas_draw_image_map_async_check
2131 (obj, ENC, output, ctx, surface,
2132 obj->map->surface, obj->map->spans,
2133 obj->map->cur.map->smooth, 0, do_async);
2134 }
2135 }
2136
2137 ENFN->context_free(ENC, ctx);
2138
2139 // FIXME: needs to cache these maps and
2140 // keep them only rendering updates
2141 }
2142 else // not "has map"
2143 {
2144 ctx = ENFN->context_dup(ENC, context);
2145 if (mapped)
2146 {
2147 RD(level, " child of mapped obj\n");
2148
2149 if (obj->is_smart)
2150 {
2151 /* Clipper masks */
2152 if (obj->cur->clipper && (mapped > 1) &&
2153 _evas_render_object_is_mask(obj->cur->clipper))
2154 _evas_render_mapped_mask(evas, obj, obj->cur->clipper, proxy_render_data, output, ctx, off_x, off_y, level, do_async);
2155 else if (!proxy_src_clip && proxy_render_data)
2156 {
2157 if (!_proxy_context_clip(evas, ctx, proxy_render_data, obj, off_x, off_y))
2158 goto on_empty_clip;
2159 }
2160
2161 #ifdef REND_DBG
2162 int _c, _cx, _cy, _cw, _ch;
2163 _c = ENFN->context_clip_get(ENC, ctx, &_cx, &_cy, &_cw, &_ch);
2164 RD(level, " draw smart children(clip: [%d] %d,%d %dx%d)\n",
2165 _c, _cx, _cy, _cw, _ch);
2166 #endif
2167
2168 EINA_INLIST_FOREACH
2169 (evas_object_smart_members_get_direct(eo_obj), obj2)
2170 {
2171 /* skip proxy object if its source is its smart parent.
2172 who makes this relation? a proxy object working for
2173 a smart object to set a filter program. the proxy
2174 object should be a member of smart object to sync
2175 stacking changes. */
2176 if (obj2->is_filter_object) continue;
2177
2178 clean_them |= evas_render_mapped(evas, obj2->object,
2179 obj2, ctx,
2180 output, surface,
2181 off_x, off_y, mapped + 1,
2182 ecx, ecy, ecw, ech,
2183 proxy_render_data,
2184 level + 1, do_async);
2185 /* We aren't sure this object will be rendered by
2186 normal(not proxy) drawing after, we reset this
2187 only in case of normal drawing. For optmizing,
2188 push this object in an array then reset them
2189 in the end of the rendering.*/
2190 if (!proxy_render_data)
2191 evas_object_change_reset(obj2);
2192 }
2193 }
2194 else
2195 {
2196 const Eina_Rectangle *clip = &obj->cur->geometry;
2197 ENFN->context_clip_clip(ENC, ctx, clip->x + off_x, clip->y + off_y, clip->w, clip->h);
2198
2199 if (obj->cur->clipper && (mapped > 1))
2200 {
2201 Evas_Object_Protected_Data *mask = obj->clip.mask;
2202
2203 if (obj->mask->surface != surface)
2204 {
2205 if (proxy_src_clip)
2206 {
2207 if ((_evas_render_has_map(obj) && !_evas_render_can_map(obj)) ||
2208 _evas_render_object_is_mask(obj->cur->clipper))
2209 evas_object_clip_recalc(obj);
2210 _evas_render_mapped_context_clip_set(evas, eo_obj, obj, ctx,
2211 proxy_render_data,
2212 off_x, off_y);
2213 }
2214 else if (proxy_render_data)
2215 {
2216 if (!_proxy_context_clip(evas, ctx, proxy_render_data, obj, off_x, off_y))
2217 goto on_empty_clip;
2218 }
2219 }
2220 else
2221 {
2222 // rendering a mask in its own surface:
2223 // we want to render it fully and clip only at
2224 // clippee (maskee) render time
2225 RD(level, " draw mask\n");
2226 }
2227
2228 /* Clipper masks */
2229 _evas_render_mapped_mask(evas, obj, mask, proxy_render_data, output, ctx, off_x, off_y, level, do_async);
2230 }
2231
2232 #ifdef REND_DBG
2233 int _c, _cx, _cy, _cw, _ch;
2234 _c = ENFN->context_clip_get(ENC, ctx, &_cx, &_cy, &_cw, &_ch);
2235 RD(level, " render(clip: [%d] %d,%d %dx%d)\n", _c, _cx, _cy, _cw, _ch);
2236 #endif
2237
2238 obj->func->render(eo_obj, obj, obj->private_data,
2239 ENC, output, ctx, surface, off_x, off_y, do_async);
2240 }
2241 }
2242 else if (!obj->is_smart)
2243 {
2244 if (obj->cur->clipper)
2245 {
2246 Evas_Object_Protected_Data *clipper = obj->cur->clipper;
2247 int x, y, w, h;
2248
2249 if (proxy_src_clip)
2250 {
2251 if ((_evas_render_has_map(obj) && !_evas_render_can_map(obj)) ||
2252 _evas_render_object_is_mask(obj->cur->clipper))
2253 evas_object_clip_recalc(obj);
2254 x = obj->cur->cache.clip.x;
2255 y = obj->cur->cache.clip.y;
2256 w = obj->cur->cache.clip.w;
2257 h = obj->cur->cache.clip.h;
2258 RECTS_CLIP_TO_RECT(x, y, w, h,
2259 clipper->cur->cache.clip.x,
2260 clipper->cur->cache.clip.y,
2261 clipper->cur->cache.clip.w,
2262 clipper->cur->cache.clip.h);
2263 ENFN->context_clip_set(ENC, ctx, x + off_x, y + off_y, w, h);
2264 if (!_is_obj_in_framespace(obj, evas))
2265 {
2266 _evas_render_framespace_context_clip_clip
2267 (evas, ctx, off_x - evas->framespace.x, off_y - evas->framespace.y);
2268 }
2269
2270 ENFN->context_clip_clip(ENC, ctx, ecx, ecy, ecw, ech);
2271 }
2272 else if (proxy_render_data)
2273 {
2274 if (!_proxy_context_clip(evas, ctx, proxy_render_data, obj, off_x, off_y))
2275 goto on_empty_clip;
2276 }
2277 }
2278 else if (!_is_obj_in_framespace(obj, evas))
2279 {
2280 _evas_render_framespace_context_clip_clip
2281 (evas, ctx, off_x - evas->framespace.x, off_y - evas->framespace.y);
2282 }
2283
2284 #ifdef REND_DBG
2285 int _c, _cx, _cy, _cw, _ch;
2286 _c = ENFN->context_clip_get(ENC, context, &_cx, &_cy, &_cw, &_ch);
2287 RD(level, " draw normal obj: render(clip: [%d] %d,%d %dx%d)\n", _c, _cx, _cy, _cw, _ch);
2288 #endif
2289
2290 obj->func->render(eo_obj, obj, obj->private_data,
2291 ENC, output, ctx, surface,
2292 off_x, off_y, do_async);
2293 }
2294 if (obj->changed_map) clean_them = EINA_TRUE;
2295
2296 on_empty_clip:
2297 ENFN->context_free(ENC, ctx);
2298 }
2299
2300 end:
2301 RD(level, "}\n");
2302 obj->pre_render_done = was_pre_render_done;
2303 eina_evlog("-render_object", eo_obj, 0.0, NULL);
2304 return clean_them;
2305 }
2306
2307 /*
2308 * Render the source object when a proxy is set.
2309 * Used to force a draw if necessary, else just makes sure it's available.
2310 * Called from: image objects and text with filters.
2311 */
2312 void
evas_render_proxy_subrender(Evas * eo_e,void * output,Evas_Object * eo_source,Evas_Object * eo_proxy,Evas_Object_Protected_Data * proxy_obj,Eina_Bool source_clip,Eina_Bool do_async)2313 evas_render_proxy_subrender(Evas *eo_e, void *output, Evas_Object *eo_source, Evas_Object *eo_proxy,
2314 Evas_Object_Protected_Data *proxy_obj,
2315 Eina_Bool source_clip, Eina_Bool do_async)
2316 {
2317 Evas_Public_Data *evas = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
2318 Evas_Object_Protected_Data *source, *proxy;
2319 int level = 1;
2320 void *ctx;
2321 int w, h, off_x = 0, off_y = 0;
2322 Eina_Rectangle lr = {0, 0, 0, 0};
2323
2324 #ifdef REND_DBG
2325 level = __RD_level;
2326 #endif
2327
2328 if (!eo_source) return;
2329 eina_evlog("+proxy_subrender", eo_proxy, 0.0, NULL);
2330 source = efl_data_scope_get(eo_source, EFL_CANVAS_OBJECT_CLASS);
2331 proxy = efl_data_scope_get(eo_proxy, EFL_CANVAS_OBJECT_CLASS);
2332
2333 evas_object_image_load_region_get(eo_proxy, &lr.x, &lr.y, &lr.w, &lr.h);
2334
2335 if (lr.w > 0 && lr.h > 0)
2336 {
2337 w = lr.w;
2338 h = lr.h;
2339 off_x = -lr.x;
2340 off_y = -lr.y;
2341 }
2342 else if (proxy->proxy->proxies || (!proxy->cur->clipper) || (!proxy->cur->has_fixed_size))
2343 {
2344 /* make full surface available if this proxy is being sampled from */
2345 w = source->cur->geometry.w;
2346 h = source->cur->geometry.h;
2347 }
2348 else
2349 {
2350 Eina_Rectangle clip = _evas_render_smallest_static_clipped_geometry_get(proxy->cur);
2351 /* nothing is using this proxy, so the proxy render surface can be sized
2352 * to fit exactly the proxy object's render size, and the proxy render will
2353 * naturally be clipped to this geometry
2354 */
2355 w = clip.w;
2356 h = clip.h;
2357 /* set the render offset for the proxy offset based on the geometry which will
2358 * be visible on the proxy surface after clipping
2359 */
2360 off_x = proxy->cur->geometry.x - clip.x;
2361 off_y = proxy->cur->geometry.y - clip.y;
2362 }
2363
2364 RD(level, " proxy_subrender(source: %s, proxy: %s, %dx%d)\n",
2365 RDNAME(source), RDNAME(proxy_obj), w, h);
2366
2367 EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, source->proxy,
2368 Evas_Object_Proxy_Data, proxy_write)
2369 {
2370 proxy_write->redraw = EINA_FALSE;
2371
2372 /* We need to redraw surface then */
2373 if ((proxy_write->surface) &&
2374 ((proxy_write->w != w) || (proxy_write->h != h)))
2375 {
2376 RD(level, " free surface: %p\n", proxy_write->surface);
2377 ENFN->image_free(ENC, proxy_write->surface);
2378 proxy_write->surface = NULL;
2379 }
2380
2381 /* FIXME: Hardcoded alpha 'on' */
2382 /* FIXME (cont): Should see if the object has alpha */
2383 if (!proxy_write->surface)
2384 {
2385 if ((w < 1) || (h < 1)) goto end;
2386 proxy_write->surface = ENFN->image_map_surface_new(ENC, w, h, 1);
2387 RD(level, " created surface: %p %dx%d\n", proxy_write->surface, w, h);
2388 if (!proxy_write->surface) goto end;
2389 proxy_write->w = w;
2390 proxy_write->h = h;
2391 }
2392
2393 eina_evlog("+proxy_fill", eo_proxy, 0.0, NULL);
2394 ctx = ENFN->context_new(ENC);
2395 ENFN->context_color_set(ENC, ctx, 0, 0,0, 0);
2396 ENFN->context_render_op_set(ENC, ctx, EVAS_RENDER_COPY);
2397 ENFN->rectangle_draw(ENC, output, ctx, proxy_write->surface, 0, 0, w, h, do_async);
2398 ENFN->context_free(ENC, ctx);
2399 eina_evlog("-proxy_fill", eo_proxy, 0.0, NULL);
2400
2401 Evas_Proxy_Render_Data proxy_render_data = {
2402 .eo_proxy = eo_proxy,
2403 .proxy_obj = proxy_obj,
2404 .eo_src = eo_source,
2405 .src_obj = source,
2406 .source_clip = source_clip
2407 };
2408
2409 /* protect changes to the objects' cache.clip */
2410 evas_event_freeze(evas->evas);
2411
2412 ctx = ENFN->context_new(ENC);
2413 evas_render_mapped(evas, eo_source, source, ctx,
2414 output, proxy_write->surface,
2415 -source->cur->geometry.x + off_x,
2416 -source->cur->geometry.y + off_y,
2417 level + 1, 0, 0, evas->output.w, evas->output.h,
2418 &proxy_render_data, level + 1, do_async);
2419 ENFN->context_free(ENC, ctx);
2420
2421 proxy_write->surface = ENFN->image_dirty_region(ENC, proxy_write->surface, 0, 0, w, h);
2422
2423 /* restore previous state */
2424 evas_event_thaw(evas->evas);
2425 }
2426 end:
2427 EINA_COW_WRITE_END(evas_object_proxy_cow, source->proxy, proxy_write);
2428 eina_evlog("-proxy_subrender", eo_proxy, 0.0, NULL);
2429 }
2430
2431 /* @internal
2432 * Synchronously render a mask image (or smart object) into a surface.
2433 * In SW the target surface will be ALPHA only (GRY8), after conversion.
2434 * In GL the target surface will be RGBA for now. TODO: Find out how to
2435 * render GL to alpha, if that's possible.
2436 */
2437 static void
evas_render_mask_subrender(Evas_Public_Data * evas,void * output,Evas_Object_Protected_Data * mask,Evas_Object_Protected_Data * prev_mask,int level,Eina_Bool do_async)2438 evas_render_mask_subrender(Evas_Public_Data *evas,
2439 void *output,
2440 Evas_Object_Protected_Data *mask,
2441 Evas_Object_Protected_Data *prev_mask,
2442 int level, Eina_Bool do_async)
2443 {
2444 int x, y, w, h, r, g, b, a, cr, cg, cb, ca;
2445 Eina_Bool is_image, done = EINA_FALSE, restore_state = EINA_FALSE;
2446 void *ctx;
2447
2448 if (!mask) return;
2449
2450 eina_evlog("+mask_subrender", mask->object, 0.0, NULL);
2451 RD(level, "evas_render_mask_subrender(mask: %s, prev: %s, %s)\n",
2452 RDNAME(mask), RDNAME(prev_mask), do_async ? "async" : "sync");
2453
2454 is_image = efl_isa(mask->object, EFL_CANVAS_IMAGE_INTERNAL_CLASS);
2455
2456 x = mask->cur->geometry.x;
2457 y = mask->cur->geometry.y;
2458 w = mask->cur->geometry.w;
2459 h = mask->cur->geometry.h;
2460 if (mask->cur->clipper && mask->cur->has_fixed_size)
2461 {
2462 Eina_Rectangle clip = _evas_render_smallest_static_clipped_geometry_get(mask->cur);
2463 x = clip.x;
2464 y = clip.y;
2465 w = clip.w;
2466 h = clip.h;
2467 }
2468
2469 r = mask->cur->color.r;
2470 g = mask->cur->color.g;
2471 b = mask->cur->color.b;
2472 a = mask->cur->color.a;
2473 cr = mask->cur->cache.clip.r;
2474 cg = mask->cur->cache.clip.g;
2475 cb = mask->cur->cache.clip.b;
2476 ca = mask->cur->cache.clip.a;
2477 if ((r != 255) || (g != 255) || (b != 255) || (a != 255) ||
2478 (cr != 255) || (cg != 255) || (cb != 255) || (ca != 255))
2479 {
2480 restore_state = EINA_TRUE;
2481 EINA_COW_STATE_WRITE_BEGIN(mask, state_write, cur)
2482 {
2483 state_write->color.r = 255;
2484 state_write->color.g = 255;
2485 state_write->color.b = 255;
2486 state_write->color.a = 255;
2487 state_write->cache.clip.r = 255;
2488 state_write->cache.clip.g = 255;
2489 state_write->cache.clip.b = 255;
2490 state_write->cache.clip.a = 255;
2491 }
2492 EINA_COW_STATE_WRITE_END(mask, state_write, cur);
2493 }
2494
2495 // For SW engine, we want sync render of masks to be able to convert the
2496 // surface from RGBA to Alpha. See below. (this logic could be improved)
2497 if (!ENFN->gl_surface_read_pixels)
2498 do_async = EINA_FALSE;
2499
2500 if (prev_mask == mask)
2501 prev_mask = NULL;
2502
2503 if (prev_mask)
2504 {
2505 if (!prev_mask->mask->is_mask)
2506 {
2507 ERR("Passed invalid mask that is not a mask");
2508 prev_mask = NULL;
2509 }
2510 else if (!prev_mask->mask->surface)
2511 {
2512 // Note: This is preventive code. Never seen it happen.
2513 WRN("Mask render order may be invalid");
2514 evas_render_mask_subrender(evas, output, prev_mask, prev_mask->clip.prev_mask, level + 1, do_async);
2515 }
2516 }
2517
2518 EINA_COW_WRITE_BEGIN(evas_object_mask_cow, mask->mask, Evas_Object_Mask_Data, mdata)
2519 mdata->redraw = EINA_FALSE;
2520
2521 if (is_image && ENFN->image_scaled_update)
2522 {
2523 Eina_Bool filled = EINA_FALSE, border = EINA_FALSE;
2524 int bl = 0, br = 0, bt = 0, bb = 0;
2525
2526 if (evas_object_image_filled_get(mask->object))
2527 filled = EINA_TRUE;
2528 else
2529 {
2530 int fx, fy, fw, fh;
2531 evas_object_image_fill_get(mask->object, &fx, &fy, &fw, &fh);
2532 if ((fx == 0) && (fy == 0) && (fw == mask->cur->geometry.w) && (fh == mask->cur->geometry.h))
2533 filled = EINA_TRUE;
2534 }
2535
2536 evas_object_image_border_get(mask->object, &bl, &br, &bt, &bb);
2537 if (bl || br || bt || bb)
2538 border = EINA_TRUE;
2539
2540 if (!border && filled && !prev_mask && mask->func->engine_data_get)
2541 {
2542 eina_evlog("+mask_scaled_update", mask->object, 0.0, NULL);
2543 /* Fast path (for GL) that avoids creating a map surface, render the
2544 * scaled image in it, when the shaders can just scale on the fly. */
2545 Eina_Bool smooth = evas_object_image_smooth_scale_get(mask->object);
2546 void *original = mask->func->engine_data_get(mask->object);
2547 void *scaled = ENFN->image_scaled_update
2548 (ENC, mdata->surface, original, w, h, smooth, EVAS_COLORSPACE_GRY8);
2549 if (scaled)
2550 {
2551 done = EINA_TRUE;
2552 mdata->surface = scaled;
2553 mdata->w = w;
2554 mdata->h = h;
2555 mdata->is_alpha = (ENFN->image_colorspace_get(ENC, scaled) == EVAS_COLORSPACE_GRY8);
2556 mdata->is_scaled = EINA_TRUE;
2557 }
2558 eina_evlog("-mask_scaled_update", mask->object, 0.0, NULL);
2559 }
2560 }
2561
2562 if (!done)
2563 {
2564 /* delete render surface if changed or if already alpha
2565 * (we don't know how to render objects to alpha) */
2566 if (mdata->surface && ((w != mdata->w) || (h != mdata->h) || mdata->is_alpha || mdata->is_scaled))
2567 {
2568 ENFN->image_free(ENC, mdata->surface);
2569 mdata->surface = NULL;
2570 }
2571
2572 /* create new RGBA render surface if needed */
2573 if (!mdata->surface)
2574 {
2575 eina_evlog("+mask_surface_new", mask->object, 0.0, NULL);
2576 mdata->surface = ENFN->image_map_surface_new(ENC, w, h, EINA_TRUE);
2577 eina_evlog("-mask_surface_new", mask->object, 0.0, NULL);
2578 if (!mdata->surface) goto end;
2579 mdata->is_alpha = EINA_FALSE;
2580 mdata->is_scaled = EINA_FALSE;
2581 mdata->w = w;
2582 mdata->h = h;
2583 }
2584
2585 /* Clear surface with transparency */
2586 eina_evlog("+mask_rect_clear", mask->object, 0.0, NULL);
2587 ctx = ENFN->context_new(ENC);
2588 ENFN->context_color_set(ENC, ctx, 0, 0, 0, 0);
2589 ENFN->context_render_op_set(ENC, ctx, EVAS_RENDER_COPY);
2590 ENFN->rectangle_draw(ENC, output, ctx, mdata->surface, 0, 0, w, h, do_async);
2591 ENFN->context_free(ENC, ctx);
2592 eina_evlog("-mask_rect_clear", mask->object, 0.0, NULL);
2593
2594 /* Render mask to RGBA surface */
2595 ctx = ENFN->context_new(ENC);
2596 if (prev_mask)
2597 {
2598 Eina_Rectangle pclip = _evas_render_smallest_static_clipped_geometry_get(prev_mask->cur);
2599 ENFN->context_clip_image_set(ENC, ctx,
2600 prev_mask->mask->surface,
2601 pclip.x - x,
2602 pclip.y - y,
2603 evas, do_async);
2604 ENFN->context_clip_set(ENC, ctx,
2605 pclip.x - x,
2606 pclip.y - y,
2607 pclip.w,
2608 pclip.h);
2609 }
2610
2611 if (EINA_LIKELY(!mask->is_smart))
2612 {
2613 mask->func->render(mask->object, mask, mask->private_data,
2614 ENC, output, ctx, mdata->surface, -x, -y, do_async);
2615 }
2616 else
2617 {
2618 // Unreachable code until we implement support for smart masks
2619 evas_render_mapped(evas, mask->object, mask, ctx,
2620 output, mdata->surface,
2621 -x, -y, 2, 0, 0, evas->output.w, evas->output.h,
2622 NULL, level, do_async);
2623 }
2624 ENFN->context_free(ENC, ctx);
2625
2626 /* BEGIN HACK */
2627
2628 /* Now we want to convert this RGBA surface to Alpha.
2629 * NOTE: So, this is not going to work with the GL engine but only with
2630 * the SW engine. Here's the detection hack:
2631 * FIXME: If you know of a way to support rendering to GL_ALPHA in GL,
2632 * then we should render directly to an ALPHA surface. A priori,
2633 * GLES FBO does not support this.
2634 */
2635 if (!ENFN->gl_surface_read_pixels)
2636 {
2637 RGBA_Image *alpha_surface;
2638 DATA32 *rgba;
2639 DATA8* alpha;
2640
2641 eina_evlog("+mask_new_cpy_data", mask->object, 0.0, NULL);
2642 alpha_surface = ENFN->image_new_from_copied_data
2643 (ENC, w, h, NULL, EINA_TRUE, EVAS_COLORSPACE_GRY8);
2644 eina_evlog("-mask_new_cpy_data", mask->object, 0.0, NULL);
2645 if (!alpha_surface) goto end;
2646
2647 eina_evlog("+mask_cpy_data", mask->object, 0.0, NULL);
2648 /* Copy alpha channel */
2649 rgba = ((RGBA_Image *) mdata->surface)->image.data;
2650 alpha = alpha_surface->image.data8;
2651 for (y = h; y; --y)
2652 for (x = w; x; --x, alpha++, rgba++)
2653 *alpha = (DATA8) A_VAL(rgba);
2654 eina_evlog("-mask_cpy_data", mask->object, 0.0, NULL);
2655
2656 /* Now we can drop the original surface */
2657 ENFN->image_free(ENC, mdata->surface);
2658 mdata->surface = alpha_surface;
2659 mdata->is_alpha = EINA_TRUE;
2660 }
2661 /* END OF HACK */
2662 }
2663
2664 mdata->surface = ENFN->image_dirty_region(ENC, mdata->surface, 0, 0, w, h);
2665
2666 end:
2667 EINA_COW_WRITE_END(evas_object_mask_cow, mask->mask, mdata);
2668
2669 if (restore_state)
2670 {
2671 EINA_COW_STATE_WRITE_BEGIN(mask, state_write, cur)
2672 {
2673 state_write->color.r = r;
2674 state_write->color.g = g;
2675 state_write->color.b = b;
2676 state_write->color.a = a;
2677 state_write->cache.clip.r = cr;
2678 state_write->cache.clip.g = cg;
2679 state_write->cache.clip.b = cb;
2680 state_write->cache.clip.a = ca;
2681 }
2682 EINA_COW_STATE_WRITE_END(mask, state_write, cur);
2683 }
2684 eina_evlog("-mask_subrender", mask->object, 0.0, NULL);
2685 }
2686
2687 static void
_evas_render_cutout_add(Evas_Public_Data * evas,void * context,Evas_Object_Protected_Data * obj,int off_x,int off_y,Cutout_Margin * cutout_margin)2688 _evas_render_cutout_add(Evas_Public_Data *evas, void *context,
2689 Evas_Object_Protected_Data *obj, int off_x, int off_y,
2690 Cutout_Margin *cutout_margin)
2691 {
2692 Evas_Coord cox = 0, coy = 0, cow = 0, coh = 0;
2693
2694 if (evas_object_is_source_invisible(obj->object, obj)) return;
2695 if (evas_object_is_opaque(obj))
2696 {
2697 cox = obj->cur->cache.clip.x;
2698 coy = obj->cur->cache.clip.y;
2699 cow = obj->cur->cache.clip.w;
2700 coh = obj->cur->cache.clip.h;
2701 if ((obj->map->cur.map) && (obj->map->cur.usemap))
2702 {
2703 Evas_Object_Protected_Data *oo;
2704
2705 for (oo = obj; oo->cur->clipper; oo = oo->cur->clipper)
2706 {
2707 if ((oo->cur->clipper->map->cur.map_parent
2708 != oo->map->cur.map_parent) &&
2709 (!((oo->map->cur.map) && (oo->map->cur.usemap))))
2710 break;
2711 RECTS_CLIP_TO_RECT(cox, coy, cow, coh,
2712 oo->cur->geometry.x,
2713 oo->cur->geometry.y,
2714 oo->cur->geometry.w,
2715 oo->cur->geometry.h);
2716 if ((cow <= 0) || (coh <= 0)) return;
2717 }
2718 }
2719 }
2720 else if (obj->func->get_opaque_rect)
2721 {
2722 obj->func->get_opaque_rect(obj->object, obj, obj->private_data, &cox, &coy, &cow, &coh);
2723 if ((cow <= 0) || (coh <= 0)) return;
2724 RECTS_CLIP_TO_RECT(cox, coy, cow, coh,
2725 obj->cur->cache.clip.x, obj->cur->cache.clip.y,
2726 obj->cur->cache.clip.w, obj->cur->cache.clip.h);
2727 }
2728 else return;
2729 if (!_is_obj_in_framespace(obj, evas))
2730 {
2731 int fw, fh;
2732
2733 fw = evas->viewport.w - evas->framespace.w;
2734 fh = evas->viewport.h - evas->framespace.h;
2735 RECTS_CLIP_TO_RECT(cox, coy, cow, coh,
2736 0, 0, fw, fh);
2737 }
2738 if (cutout_margin)
2739 {
2740 cox += cutout_margin->l;
2741 coy += cutout_margin->t;
2742 cow -= cutout_margin->l + cutout_margin->r;
2743 coh -= cutout_margin->t + cutout_margin->b;
2744 }
2745 if ((cow <= 0) || (coh <= 0)) return;
2746 ENFN->context_cutout_add(ENC, context, cox + off_x, coy + off_y, cow, coh);
2747 }
2748
2749 void
evas_render_rendering_wait(Evas_Public_Data * evas)2750 evas_render_rendering_wait(Evas_Public_Data *evas)
2751 {
2752 double t0 = ecore_time_get();
2753 while (evas->rendering)
2754 {
2755 evas_async_events_process_blocking();
2756 if ((ecore_time_get() - t0) > 0.2)
2757 {
2758 ERR("timeout waiting for async rendering");
2759 break;
2760 }
2761 }
2762 }
2763
2764 /*
2765 * Syncs ALL async rendering canvases. Must be called in the main thread.
2766 */
2767 void
evas_all_sync(void)2768 evas_all_sync(void)
2769 {
2770 Evas_Public_Data *evas;
2771
2772 if (!_rendering_evases) return;
2773
2774 evas = eina_list_data_get(eina_list_last(_rendering_evases));
2775 evas_render_rendering_wait(evas);
2776
2777 assert(_rendering_evases == NULL);
2778 }
2779
2780 static Eina_Bool
_drop_scie_ref(const void * container EINA_UNUSED,void * data,void * fdata EINA_UNUSED)2781 _drop_scie_ref(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
2782 {
2783 evas_common_rgba_image_scalecache_item_unref(data);
2784 return EINA_TRUE;
2785 }
2786
2787 static Eina_Bool
_drop_image_cache_ref(const void * container EINA_UNUSED,void * data,void * fdata EINA_UNUSED)2788 _drop_image_cache_ref(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
2789 {
2790 evas_cache_image_drop((Image_Entry *)data);
2791
2792 return EINA_TRUE;
2793 }
2794
2795 static void
_cb_always_call(Evas * eo_e,Evas_Public_Data * e,Evas_Callback_Type type,void * event_info)2796 _cb_always_call(Evas *eo_e, Evas_Public_Data *e, Evas_Callback_Type type, void *event_info)
2797 {
2798 int freeze_num = 0, i;
2799
2800 switch (type)
2801 {
2802 case EVAS_CALLBACK_RENDER_PRE:
2803 if (!e->cb_render_pre) return;
2804 break;
2805 case EVAS_CALLBACK_RENDER_POST:
2806 if (!e->cb_render_post) return;
2807 break;
2808 case EVAS_CALLBACK_RENDER_FLUSH_PRE:
2809 if (!e->cb_render_flush_pre) return;
2810 break;
2811 case EVAS_CALLBACK_RENDER_FLUSH_POST:
2812 if (!e->cb_render_flush_post) return;
2813 break;
2814 default: break;
2815 }
2816 freeze_num = efl_event_freeze_count_get(eo_e);
2817 for (i = 0; i < freeze_num; i++) efl_event_thaw(eo_e);
2818 evas_event_callback_call(eo_e, type, event_info);
2819 for (i = 0; i < freeze_num; i++) efl_event_freeze(eo_e);
2820 }
2821
2822 #ifndef INLINE_ACTIVE_GEOM
2823 static inline Eina_Bool
_is_obj_in_rect(Evas_Object * eo_obj,Evas_Object_Protected_Data * obj,int x,int y,int w,int h)2824 _is_obj_in_rect(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj,
2825 int x, int y, int w, int h)
2826 {
2827 if (obj->is_smart && !_evas_render_has_map(obj))
2828 {
2829 Eina_Rectangle rect;
2830
2831 evas_object_smart_bounding_box_get(obj, &rect, NULL);
2832 if (RECTS_INTERSECT(x, y, w, h, rect.x, rect.y, rect.w, rect.h))
2833 return EINA_TRUE;
2834 }
2835 else
2836 {
2837 // FIXME: handle multiple output
2838 if (evas_object_is_in_output_rect(eo_obj, obj, x, y, w, h))
2839 return EINA_TRUE;
2840 }
2841 return EINA_FALSE;
2842 }
2843 #endif
2844
2845 static void
_snapshot_redraw_update(Evas_Public_Data * evas,Evas_Object_Protected_Data * snap)2846 _snapshot_redraw_update(Evas_Public_Data *evas, Evas_Object_Protected_Data *snap)
2847 {
2848 Eina_Bool above = EINA_FALSE, add_rect = EINA_FALSE, need_redraw = EINA_FALSE;
2849 const int x = snap->cur->geometry.x;
2850 const int y = snap->cur->geometry.y;
2851 const int w = snap->cur->geometry.w;
2852 const int h = snap->cur->geometry.h;
2853 Evas_Object_Protected_Data *obj;
2854 Evas_Active_Entry *ent;
2855 Eina_Rectangle snap_clip;
2856 Eina_Tiler *tiler = NULL;
2857 void *surface;
2858
2859 // FIXME: Tiler should be inside snapshot data
2860 // TODO: Also list redraw regions (partial updates)
2861
2862 if (!evas_object_is_visible(snap)) return;
2863
2864 evas_object_clip_recalc(snap);
2865 snap_clip.x = snap->cur->cache.clip.x - x;
2866 snap_clip.y = snap->cur->cache.clip.y - y;
2867 snap_clip.w = snap->cur->cache.clip.w;
2868 snap_clip.h = snap->cur->cache.clip.h;
2869
2870 surface = _evas_object_image_surface_get(snap, EINA_FALSE);
2871 if (!surface) need_redraw = EINA_TRUE;
2872 if (snap->changed) add_rect = EINA_TRUE;
2873
2874 if (!add_rect && !need_redraw)
2875 {
2876 // Objects below snapshot
2877 EINA_INARRAY_FOREACH(&evas->active_objects, ent)
2878 {
2879 obj = ent->obj;
2880 if (obj == snap) break;
2881
2882 if (!obj->is_smart && obj->changed &&
2883 evas_object_is_in_output_rect(obj->object, obj, x, y, w, h))
2884 need_redraw = EINA_TRUE;
2885 }
2886 }
2887
2888 if (snap->snapshot_no_obscure || _evas_render_has_map(snap))
2889 goto skip_obscures;
2890
2891 tiler = eina_tiler_new(w, h);
2892 eina_tiler_tile_size_set(tiler, 1, 1);
2893 eina_tiler_strict_set(tiler, EINA_TRUE);
2894
2895 // Opaque objects above snapshot
2896 for (unsigned i = 0; i < evas->obscuring_objects.count; i++)
2897 {
2898 obj = eina_array_data_get(&evas->obscuring_objects, i);
2899 if (!above)
2900 {
2901 if (obj == snap) above = EINA_TRUE;
2902 continue;
2903 }
2904 if (!obj->cur->snapshot || evas_object_is_opaque(obj))
2905 {
2906 const Eina_Rectangle cur = {
2907 obj->cur->cache.clip.x - x, obj->cur->cache.clip.y - y,
2908 obj->cur->cache.clip.w, obj->cur->cache.clip.h
2909 };
2910
2911 if (_evas_eina_rectangle_inside(&cur, &snap_clip))
2912 goto end; // Totally hidden
2913
2914 eina_tiler_rect_add(tiler, &cur);
2915 }
2916 }
2917
2918 skip_obscures:
2919 need_redraw |= _evas_filter_obscured_regions_set(snap, tiler);
2920 if (memcmp(&snap->cur->geometry, &snap->prev->geometry, sizeof(snap->cur->geometry)))
2921 need_redraw = EINA_TRUE;
2922 snap->snapshot_needs_redraw |= need_redraw;
2923
2924 if (add_rect || need_redraw)
2925 {
2926 // FIXME: Only add necessary rects (if object itself hasn't changed)
2927 // FIXME: handle multiple output
2928 ENFN->output_redraws_rect_add(ENC, x, y, w, h);
2929 }
2930
2931 end:
2932 eina_tiler_free(tiler);
2933 }
2934
2935 static void
evas_render_pre(Evas * eo_e,Evas_Public_Data * evas)2936 evas_render_pre(Evas *eo_e, Evas_Public_Data *evas)
2937 {
2938 Eo *eo_obj;
2939
2940 if (!evas->finalize_objects) return; // avoid evlog
2941
2942 // Finalize EO objects now
2943 eina_evlog("+render_pre_objects_finalize", eo_e, 0.0, NULL);
2944
2945 EINA_LIST_FREE(evas->finalize_objects, eo_obj)
2946 {
2947 Evas_Object_Protected_Data *obj;
2948
2949 obj = efl_data_scope_safe_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
2950 if (!EVAS_OBJECT_DATA_ALIVE(obj)) continue;
2951 obj->legacy.finalized = EINA_TRUE;
2952
2953 if (!obj->legacy.visible_set)
2954 efl_gfx_entity_visible_set(eo_obj, EINA_TRUE);
2955
2956 // weight should be set during finalize()
2957 if (EINA_UNLIKELY(!obj->legacy.weight_set))
2958 efl_gfx_hint_weight_set(eo_obj, 1.0, 1.0);
2959 }
2960
2961 eina_evlog("-render_pre_objects_finalize", eo_e, 0.0, NULL);
2962 }
2963
2964 EAPI void
evas_render_pending_objects_flush(Evas * eo_e)2965 evas_render_pending_objects_flush(Evas *eo_e)
2966 {
2967 Evas_Public_Data *evas = efl_data_scope_safe_get(eo_e, EVAS_CANVAS_CLASS);
2968 EINA_SAFETY_ON_NULL_RETURN(evas);
2969 evas_render_pre(eo_e, evas);
2970 }
2971
2972 static Eina_Bool
evas_render_updates_internal_loop(Evas * eo_e,Evas_Public_Data * evas,void * output,void * surface,void * context,Evas_Object_Protected_Data * top,int ux,int uy,int uw,int uh,int cx,int cy,int cw,int ch,int fx,int fy,Eina_Bool skip_cutouts,Cutout_Margin * cutout_margin,Eina_Bool alpha,Eina_Bool do_async,unsigned int * offset,int level)2973 evas_render_updates_internal_loop(Evas *eo_e, Evas_Public_Data *evas,
2974 void *output, void *surface, void *context,
2975 Evas_Object_Protected_Data *top,
2976 int ux, int uy, int uw, int uh,
2977 int cx, int cy, int cw, int ch,
2978 int fx, int fy,
2979 Eina_Bool skip_cutouts, Cutout_Margin *cutout_margin,
2980 Eina_Bool alpha, Eina_Bool do_async,
2981 unsigned int *offset, int level)
2982 {
2983 Evas_Object *eo_obj;
2984 Evas_Object_Protected_Data *obj;
2985 int off_x, off_y;
2986 unsigned int i, j;
2987 Eina_Bool clean_them = EINA_FALSE;
2988 Eina_Bool above_top = EINA_FALSE;
2989
2990 eina_evlog("+render_setup", eo_e, 0.0, NULL);
2991 RD(level, " [--- UPDATE %i %i %ix%i\n", ux, uy, uw, uh);
2992
2993 off_x = cx - ux;
2994 off_y = cy - uy;
2995 /* build obscuring objects list (in order from bottom to top) */
2996 if (alpha)
2997 {
2998 ENFN->context_clip_set(ENC, context, ux + off_x, uy + off_y, uw, uh);
2999 }
3000 for (i = 0; i < evas->obscuring_objects.count; ++i)
3001 {
3002 obj = eina_array_data_get(&evas->obscuring_objects, i);
3003 if (obj == top) above_top = EINA_TRUE;
3004
3005 if (evas_object_is_in_output_rect(obj->object, obj, ux - fx, uy - fy, uw, uh))
3006 {
3007 OBJ_ARRAY_PUSH(&evas->temporary_objects, obj);
3008
3009 if (above_top) continue;
3010 if (obj->cur->snapshot && !evas_object_is_opaque(obj))
3011 continue;
3012
3013 /* reset the background of the area if needed (using cutout and engine alpha flag to help) */
3014 if (alpha && !skip_cutouts)
3015 _evas_render_cutout_add(evas, context, obj, off_x + fx, off_y + fy, cutout_margin);
3016 }
3017 }
3018 if (alpha)
3019 {
3020 ENFN->context_color_set(ENC, context, 0, 0, 0, 0);
3021 ENFN->context_multiplier_unset(ENC, context);
3022 ENFN->context_render_op_set(ENC, context, EVAS_RENDER_COPY);
3023 ENFN->rectangle_draw(ENC, output, context, surface, cx, cy, cw, ch, do_async);
3024 ENFN->context_cutout_clear(ENC, context);
3025 ENFN->context_clip_unset(ENC, context);
3026 }
3027 eina_evlog("-render_setup", eo_e, 0.0, NULL);
3028
3029 eina_evlog("+render_objects", eo_e, 0.0, NULL);
3030 /* render all object that intersect with rect */
3031 for (i = 0; i < evas->active_objects.len; i++)
3032 {
3033 Evas_Active_Entry *ent = eina_inarray_nth(&evas->active_objects, i);
3034
3035 obj = ent->obj;
3036 eo_obj = obj->object;
3037
3038 if (obj == top) break;
3039
3040 /* if it's in our outpout rect and it doesn't clip anything */
3041 RD(level, " OBJ: %s %i %i %ix%i\n", RDNAME(obj), obj->cur->geometry.x, obj->cur->geometry.y, obj->cur->geometry.w, obj->cur->geometry.h);
3042 if (
3043 (!obj->clip.clipees) &&
3044 (obj->cur->visible) &&
3045 (obj->cur->cache.clip.visible) &&
3046 #ifdef INLINE_ACTIVE_GEOM
3047 RECTS_INTERSECT(ux - fx, uy - fy, uw, uh,
3048 ent->rect.x, ent->rect.y,
3049 ent->rect.w, ent->rect.h) &&
3050 #else
3051 (_is_obj_in_rect(eo_obj, obj, ux - fx, uy - fy, uw, uh)) &&
3052 #endif
3053 (!obj->delete_me) &&
3054 ((obj->cur->color.a > 0 || obj->cur->render_op != EVAS_RENDER_BLEND)))
3055 {
3056 int x, y, w, h;
3057
3058 RD(level, " DRAW (vis: %i, a: %i, clipees: %p)\n", obj->cur->visible, obj->cur->color.a, obj->clip.clipees);
3059 if ((evas->temporary_objects.count > *offset) &&
3060 (eina_array_data_get(&evas->temporary_objects, *offset) == obj))
3061 (*offset)++;
3062 x = cx; y = cy; w = cw; h = ch;
3063 if (((w > 0) && (h > 0)) || (obj->is_smart))
3064 {
3065 Evas_Object_Protected_Data *mask;
3066
3067 if (!obj->is_smart)
3068 {
3069 int cfx, cfy;
3070 if (!obj->is_frame)
3071 {
3072 cfx = obj->cur->cache.clip.x + off_x + fx;
3073 cfy = obj->cur->cache.clip.y + off_y + fy;
3074 }
3075 else
3076 {
3077 cfx = obj->cur->cache.clip.x + off_x;
3078 cfy = obj->cur->cache.clip.y + off_y;
3079 }
3080 RECTS_CLIP_TO_RECT(x, y, w, h, cfx, cfy,
3081 obj->cur->cache.clip.w,
3082 obj->cur->cache.clip.h);
3083 }
3084
3085 ENFN->context_clip_set(ENC, context, x, y, w, h);
3086
3087 mask = obj->clip.mask;
3088 if (mask)
3089 {
3090 Evas_Object_Protected_Data *prev_mask = obj->clip.prev_mask;
3091
3092 if (mask->mask->redraw || !mask->mask->surface)
3093 evas_render_mask_subrender(obj->layer->evas, output, mask, prev_mask, 4, do_async);
3094
3095 if (mask->mask->surface)
3096 {
3097 Eina_Rectangle clip = _evas_render_smallest_static_clipped_geometry_get(mask->cur);
3098 ENFN->context_clip_image_set(ENC, context,
3099 mask->mask->surface,
3100 clip.x + off_x,
3101 clip.y + off_y,
3102 evas, do_async);
3103 }
3104 }
3105
3106 eina_evlog("+cutouts_add", obj->object, 0.0, NULL);
3107 above_top = EINA_FALSE;
3108 #if 1 /* FIXME: this can slow things down... figure out optimum... coverage */
3109 if (!skip_cutouts)
3110 {
3111 for (j = *offset; j < evas->temporary_objects.count; ++j)
3112 {
3113 Evas_Object_Protected_Data *obj2;
3114
3115 obj2 = eina_array_data_get(&evas->temporary_objects, j);
3116 if (obj2 == top) above_top = EINA_TRUE;
3117 if (obj2->cur->snapshot)
3118 {
3119 if (above_top) continue;
3120 if (!evas_object_is_opaque(obj2)) continue;
3121 }
3122 #if 1
3123 if (
3124 RECTS_INTERSECT
3125 (obj->cur->cache.clip.x, obj->cur->cache.clip.y,
3126 obj->cur->cache.clip.w, obj->cur->cache.clip.h,
3127 obj2->cur->cache.clip.x, obj2->cur->cache.clip.y,
3128 obj2->cur->cache.clip.w, obj2->cur->cache.clip.h) &&
3129 RECTS_INTERSECT
3130 (obj2->cur->cache.clip.x, obj2->cur->cache.clip.y,
3131 obj2->cur->cache.clip.w, obj2->cur->cache.clip.h,
3132 ux, uy, uw, uh)
3133 )
3134 #endif
3135 _evas_render_cutout_add(evas, context, obj2, off_x + fx, off_y + fy, cutout_margin);
3136 }
3137 }
3138 #endif
3139 ENFN->context_cutout_target(ENC, context,
3140 off_x + obj->cur->cache.clip.x,
3141 off_y + obj->cur->cache.clip.y,
3142 obj->cur->cache.clip.w,
3143 obj->cur->cache.clip.h);
3144 eina_evlog("-cutouts_add", obj->object, 0.0, NULL);
3145 clean_them |= evas_render_mapped(evas, eo_obj, obj, context,
3146 output, surface,
3147 off_x + fx, off_y + fy, 0,
3148 cx, cy, cw, ch,
3149 NULL, level + 3, do_async);
3150 ENFN->context_cutout_clear(ENC, context);
3151
3152 if (mask) ENFN->context_clip_image_unset(ENC, context);
3153 }
3154 }
3155 }
3156
3157 eina_evlog("-render_objects", eo_e, 0.0, NULL);
3158 /* free obscuring objects list */
3159 OBJS_ARRAY_CLEAN(&evas->temporary_objects);
3160
3161 #ifdef REND_DBG
3162 if (top) RD(level, " ---] SNAPSHOT [obj:%s sfc:%p]\n", RDNAME(top), surface);
3163 else RD(level, " ---]\n");
3164 #endif
3165
3166 return clean_them;
3167 }
3168
3169 typedef enum _Evas_3State
3170 {
3171 EVAS_3STATE_OUTSIDE,
3172 EVAS_3STATE_INSIDE,
3173 EVAS_3STATE_OVER
3174 } Evas_3State;
3175
3176 static Evas_3State
_evas_overlay_output_find(Efl_Canvas_Output * output,Evas_Object_Protected_Data * obj)3177 _evas_overlay_output_find(Efl_Canvas_Output *output,
3178 Evas_Object_Protected_Data *obj)
3179 {
3180 const Eina_Rectangle geometry = {
3181 obj->cur->geometry.x,
3182 obj->cur->geometry.y,
3183 obj->cur->geometry.w,
3184 obj->cur->geometry.h
3185 };
3186 Eina_Rectangle copy = geometry;
3187
3188 /* A video object can only be in one output at a time, check that first */
3189 if (!eina_rectangle_intersection(©, &output->geometry))
3190 return EVAS_3STATE_OUTSIDE;
3191
3192 if (memcmp(©, &geometry, sizeof (Eina_Rectangle)) != 0)
3193 /* This means that it does intersect this output and another */
3194 return EVAS_3STATE_OVER;
3195
3196 return EVAS_3STATE_INSIDE;
3197 }
3198
3199 static void
_evas_planes(Evas_Public_Data * evas)3200 _evas_planes(Evas_Public_Data *evas)
3201 {
3202 Evas_Active_Entry *ao;
3203
3204 /* check if individual image objects can be dropped into hardware planes */
3205 if (ENFN->image_plane_assign)
3206 EINA_INARRAY_FOREACH(&evas->active_objects, ao)
3207 {
3208 Evas_Object_Protected_Data *obj2;
3209 Evas_Object *eo_obj2;
3210 Efl_Canvas_Output *output;
3211 Evas_3State state;
3212 Eina_List *lo;
3213
3214 obj2 = ao->obj;
3215 eo_obj2 = obj2->object;
3216
3217 if (!efl_isa(eo_obj2, EFL_CANVAS_IMAGE_INTERNAL_CLASS)) continue;
3218
3219 /* Find the output the object was in */
3220 EINA_LIST_FOREACH(evas->outputs, lo, output)
3221 {
3222 if (!output->output) continue ;
3223 if (!eina_list_data_find(output->planes, obj2)) continue;
3224 _evas_object_image_plane_release(eo_obj2, obj2, output);
3225 break;
3226 }
3227
3228 if (evas_object_is_visible(obj2))
3229 EINA_LIST_FOREACH(evas->outputs, lo, output)
3230 {
3231 /* A video object can only be in one output at a time, check that first */
3232 state = _evas_overlay_output_find(output, obj2);
3233 if (state == EVAS_3STATE_OUTSIDE) continue;
3234
3235 if (!_evas_render_can_use_overlay(evas, eo_obj2, output))
3236 {
3237 /* This may free up things temporarily allocated by
3238 * _can_use_overlay() testing in the engine */
3239 _evas_object_image_plane_release(eo_obj2, obj2, output);
3240 } else break;
3241 }
3242 if (evas_object_plane_changed(obj2))
3243 {
3244 /* Since we're lifting this object out of the scene graph
3245 * (or putting it back), we need to force redraw of the space
3246 * under it.
3247 */
3248 _evas_canvas_damage_rectangle_add(NULL, evas,
3249 obj2->cur->geometry.x,
3250 obj2->cur->geometry.y,
3251 obj2->cur->geometry.w,
3252 obj2->cur->geometry.h);
3253
3254 /* We also need to clean its previously drawn position
3255 * but only if we're removing it */
3256 if (evas_object_is_on_plane(obj2))
3257 _evas_canvas_damage_rectangle_add(NULL, evas,
3258 obj2->prev->geometry.x,
3259 obj2->prev->geometry.y,
3260 obj2->prev->geometry.w,
3261 obj2->prev->geometry.h);
3262
3263 }
3264 }
3265 }
3266
3267 static Eina_Bool
evas_render_updates_internal(Evas * eo_e,unsigned char make_updates,unsigned char do_draw,Eina_Bool do_async)3268 evas_render_updates_internal(Evas *eo_e,
3269 unsigned char make_updates,
3270 unsigned char do_draw,
3271 Eina_Bool do_async)
3272 {
3273 // FIXME: handle multiple output
3274 Evas_Object *eo_obj;
3275 Evas_Object_Protected_Data *obj;
3276 Evas_Public_Data *evas, *e;
3277 Efl_Canvas_Output *out;
3278 Eina_List *ll, *l;
3279 Eina_Bool clean_them = EINA_FALSE;
3280 Eina_Bool rendering = EINA_FALSE;
3281 Eina_Bool alpha;
3282 Eina_Rectangle *r;
3283 unsigned int i;
3284 Phase1_Context p1ctx;
3285 int redraw_all = 0;
3286 Evas_Render_Mode render_mode = !do_async ?
3287 EVAS_RENDER_MODE_SYNC :
3288 EVAS_RENDER_MODE_ASYNC_INIT;
3289 Eina_Bool haveup = EINA_FALSE;
3290 static int show_update_boxes = -1;
3291
3292 MAGIC_CHECK(eo_e, Evas, MAGIC_EVAS);
3293 return EINA_FALSE;
3294 MAGIC_CHECK_END();
3295
3296 e = evas = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
3297 if (e->inside_post_render) return EINA_FALSE;
3298 if (!e->changed) return EINA_FALSE;
3299
3300 if (e->rendering)
3301 {
3302 if (do_async)
3303 return EINA_FALSE;
3304 else
3305 {
3306 WRN("Mixing render sync as already doing async "
3307 "render! Syncing! e=%p [%s]", e,
3308 e->engine.module->definition->name);
3309 eina_evlog("+render_wait", eo_e, 0.0, NULL);
3310 evas_render_rendering_wait(e);
3311 eina_evlog("-render_wait", eo_e, 0.0, NULL);
3312 }
3313 }
3314 #ifdef EVAS_RENDER_DEBUG_TIMING
3315 double start_time = _time_get();
3316 #endif
3317
3318 if (show_update_boxes == -1)
3319 {
3320 if (getenv("EVAS_RENDER_DEBUG_UPDATE_BOXES")) show_update_boxes = 1;
3321 else show_update_boxes = 0;
3322 }
3323 evas_render_pre(eo_e, evas);
3324
3325 _evas_planes(e);
3326
3327 eina_evlog("+render_calc", eo_e, 0.0, NULL);
3328 evas_call_smarts_calculate(eo_e);
3329 eina_evlog("-render_calc", eo_e, 0.0, NULL);
3330
3331 RD(0, "[--- RENDER EVAS (size: %ix%i): %p (eo %p)\n", e->viewport.w, e->viewport.h, e, eo_e);
3332
3333 _cb_always_call(eo_e, e, EVAS_CALLBACK_RENDER_PRE, NULL);
3334
3335 /* Check if the modified object mean recalculating every thing */
3336 if (!e->invalidate)
3337 {
3338 eina_evlog("+render_pending", eo_e, 0.0, NULL);
3339 _evas_render_check_pending_objects(&e->pending_objects, eo_e, e);
3340 eina_evlog("-render_pending", eo_e, 0.0, NULL);
3341 }
3342
3343 /* phase 1. add extra updates for changed objects */
3344 if (e->invalidate || e->render_objects.count <= 0)
3345 {
3346 eina_evlog("+render_phase1", eo_e, 0.0, NULL);
3347
3348 p1ctx.e = e;
3349 p1ctx.active_objects = &e->active_objects;
3350 p1ctx.restack_objects = &e->restack_objects;
3351 p1ctx.delete_objects = &e->delete_objects;
3352 p1ctx.render_objects = &e->render_objects;
3353 p1ctx.snapshot_objects = &e->snapshot_objects;
3354 p1ctx.redraw_all = redraw_all;
3355 clean_them = _evas_render_phase1_process(&p1ctx);
3356 redraw_all = p1ctx.redraw_all;
3357 eina_evlog("-render_phase1", eo_e, 0.0, NULL);
3358 }
3359
3360 eina_evlog("+render_phase1_direct", eo_e, 0.0, NULL);
3361 /* phase 1.8. pre render for proxy */
3362 _evas_render_phase1_direct(e, &e->active_objects, &e->restack_objects,
3363 &e->delete_objects, &e->render_objects);
3364 eina_evlog("-render_phase1_direct", eo_e, 0.0, NULL);
3365
3366 /* phase 2. force updates for restacks */
3367 eina_evlog("+render_phase2", eo_e, 0.0, NULL);
3368 for (i = 0; i < e->restack_objects.count; ++i)
3369 {
3370 obj = eina_array_data_get(&e->restack_objects, i);
3371 if (!obj->private_data) continue;
3372 if (_evas_render_object_is_mask(obj))
3373 _evas_mask_redraw_set(e, obj);
3374 obj->func->render_pre(obj->object, obj, obj->private_data);
3375 _evas_render_prev_cur_clip_cache_add(e, obj);
3376 }
3377 OBJS_ARRAY_CLEAN(&e->restack_objects);
3378 eina_evlog("-render_phase2", eo_e, 0.0, NULL);
3379
3380 /* phase 3. add exposes */
3381 eina_evlog("+render_phase3", eo_e, 0.0, NULL);
3382 EINA_LIST_FREE(e->damages, r)
3383 {
3384 ENFN->output_redraws_rect_add(ENC, r->x, r->y, r->w, r->h);
3385 eina_rectangle_free(r);
3386 }
3387 eina_evlog("-render_phase3", eo_e, 0.0, NULL);
3388
3389 /* phase 4. framespace, output & viewport changes */
3390 eina_evlog("+render_phase4", eo_e, 0.0, NULL);
3391 if (e->viewport.changed)
3392 {
3393 ENFN->output_redraws_rect_add(ENC, 0, 0, e->output.w, e->output.h);
3394 }
3395 if ((e->output.w != e->viewport.w) || (e->output.h != e->viewport.h))
3396 {
3397 ERR("viewport size != output size!");
3398 }
3399
3400 if (e->framespace.changed)
3401 {
3402 /* NB: If the framespace changes, we need to add a redraw rectangle
3403 * which covers the Whole viewport. This is because 'framespace' is
3404 * defined as "the space IN the viewport which is Occupied by the
3405 * window frame" */
3406 ENFN->output_redraws_rect_add(ENC,
3407 e->viewport.x, e->viewport.y,
3408 e->viewport.w, e->viewport.h);
3409 }
3410
3411 if (redraw_all)
3412 {
3413 ENFN->output_redraws_rect_add(ENC, 0, 0, e->output.w, e->output.h);
3414 }
3415 eina_evlog("-render_phase4", eo_e, 0.0, NULL);
3416
3417 /* phase 5. add obscures */
3418 eina_evlog("+render_phase5", eo_e, 0.0, NULL);
3419 EINA_LIST_FOREACH(e->obscures, ll, r)
3420 evas_render_update_del(e, r->x, r->y, r->w, r->h);
3421
3422 static int prepare = -1;
3423 if (prepare == -1)
3424 {
3425 if (getenv("EVAS_PREPARE")) prepare = !!atoi(getenv("EVAS_PREPARE"));
3426 else prepare = 1;
3427 }
3428 /* build obscure objects list of active objects that obscure as well
3429 * as objects that may need data (image data loads, texture updates,
3430 * pre-render buffers/fbo's etc.) that are not up to date yet */
3431 for (i = 0; i < e->active_objects.len; i++)
3432 {
3433 Evas_Active_Entry *ent = eina_inarray_nth(&e->active_objects, i);
3434
3435 obj = ent->obj;
3436 eo_obj = obj->object;
3437 if (!obj->private_data) continue;
3438 if (UNLIKELY(
3439 (!obj->is_smart) &&
3440 (!obj->clip.clipees) &&
3441 (evas_object_is_opaque(obj) || obj->cur->snapshot ||
3442 ((obj->func->has_opaque_rect) &&
3443 (obj->func->has_opaque_rect(eo_obj, obj, obj->private_data)))) &&
3444 evas_object_is_visible(obj) &&
3445 (!obj->mask->is_mask) && (!obj->clip.mask) &&
3446 (!obj->delete_me)))
3447 OBJ_ARRAY_PUSH(&e->obscuring_objects, obj);
3448 if (prepare)
3449 {
3450 if (obj->func->render_prepare)
3451 obj->func->render_prepare(eo_obj, obj, do_async);
3452 }
3453 }
3454 if (!redraw_all)
3455 {
3456 for (i = 0; i < e->snapshot_objects.count; i++)
3457 {
3458 obj = eina_array_data_get(&e->snapshot_objects, i);
3459 _snapshot_redraw_update(evas, obj);
3460 }
3461 }
3462 eina_evlog("-render_phase5", eo_e, 0.0, NULL);
3463
3464 EINA_LIST_FOREACH(e->outputs, l, out)
3465 {
3466 // Avoid processing not ready output until they are
3467 if (!out->output) continue;
3468 // Locked output are output that should not yet be rendered
3469 // because the tick/vsync for it doesn't allow it yet.
3470 if (out->lock > 0) continue;
3471
3472 /* phase 6. Initialize output */
3473 if (out->changed)
3474 {
3475 ENFN->output_resize(ENC, out->output,
3476 out->geometry.w, out->geometry.h);
3477 ENFN->output_redraws_rect_add(ENC,
3478 out->geometry.x, out->geometry.y,
3479 out->geometry.w, out->geometry.h);
3480 out->changed = EINA_FALSE;
3481 }
3482
3483 /* Define the output for Evas_GL operation */
3484 if (ENFN->gl_output_set)
3485 ENFN->gl_output_set(ENC, out->output);
3486
3487 /* phase 7. check if video surface should be inlined or stay in their hardware plane */
3488 eina_evlog("+render_phase7", eo_e, 0.0, NULL);
3489 alpha = ENFN->canvas_alpha_get(out->output);
3490
3491 EINA_LIST_FOREACH(e->video_objects, ll, eo_obj)
3492 {
3493 Evas_Object_Protected_Data *obj2;
3494 Evas_3State state;
3495
3496 obj2 = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
3497 state = _evas_overlay_output_find(out, obj2);
3498 if (state == EVAS_3STATE_OUTSIDE) continue;
3499
3500 /* we need the surface to be transparent to display the underlying overlay */
3501 if (state == EVAS_3STATE_INSIDE &&
3502 alpha &&
3503 _evas_render_can_use_overlay(e, eo_obj, out))
3504 _evas_object_image_video_overlay_show(eo_obj);
3505 else
3506 _evas_object_image_video_overlay_hide(eo_obj);
3507 }
3508 eina_evlog("-render_phase7", eo_e, 0.0, NULL);
3509
3510 /* phase 8. go thru each update rect and render objects in it*/
3511 eina_evlog("+render_phase8", eo_e, 0.0, NULL);
3512 if (do_draw)
3513 {
3514 Render_Updates *ru;
3515 void *surface;
3516 int ux, uy, uw, uh;
3517 int cx, cy, cw, ch;
3518 unsigned int offset = 0;
3519 int fx = e->framespace.x;
3520 int fy = e->framespace.y;
3521 int j;
3522
3523 DBG("Rendering output %p [%i, %i, %i, %i]\n", out,
3524 out->geometry.x, out->geometry.y,
3525 out->geometry.w, out->geometry.h);
3526
3527 if (do_async) _evas_render_busy_begin();
3528 eina_evlog("+render_surface", eo_e, 0.0, NULL);
3529 while ((surface =
3530 ENFN->output_redraws_next_update_get
3531 (ENC, out->output,
3532 &ux, &uy, &uw, &uh,
3533 &cx, &cy, &cw, &ch)))
3534 {
3535 void *ctx;
3536
3537 haveup = EINA_TRUE;
3538
3539 /* adjust the rendering rectangle to the output offset */
3540 ux += out->geometry.x;
3541 uy += out->geometry.y;
3542
3543 DBG("Surface %p offset: [%i, %i, %i, %i]\n", surface,
3544 ux, uy, uw, uh);
3545
3546 /* phase 7.1 render every snapshot that needs to be updated
3547 for this part of the screen */
3548 eina_evlog("+render_snapshots", eo_e, 0.0, NULL);
3549 for (j = e->snapshot_objects.count - 1; j >= 0; j--)
3550 {
3551 Evas_Object_Protected_Data *snap;
3552 Eina_Rectangle output, cr, ur;
3553
3554 snap = eina_array_data_get(&e->snapshot_objects, j);
3555
3556 EINA_RECTANGLE_SET(&output,
3557 snap->cur->geometry.x,
3558 snap->cur->geometry.y,
3559 snap->cur->geometry.w,
3560 snap->cur->geometry.h);
3561 EINA_RECTANGLE_SET(&ur, ux, uy, uw, uh);
3562
3563 // FIXME: We should render snapshots only once per frame,
3564 // not once per update region per output !
3565 if (snap->snapshot_needs_redraw &&
3566 eina_rectangle_intersection(&ur, &output))
3567 {
3568 Cutout_Margin cm = {};
3569 unsigned int restore_offset = offset;
3570 Eina_Bool skip_cutouts = EINA_FALSE;
3571 void *pseudo_canvas;
3572
3573 EINA_RECTANGLE_SET(&cr,
3574 ur.x - output.x, ur.y - output.y,
3575 ur.w, ur.h);
3576
3577 pseudo_canvas = _evas_object_image_surface_get(snap, EINA_TRUE);
3578
3579 // Get required margin for filters (eg. blur radius)
3580 _evas_filter_radius_get(snap, &cm.l, &cm.r, &cm.t, &cm.b);
3581
3582 if (snap->map->cur.usemap || snap->proxy->proxies ||
3583 snap->snapshot_no_obscure ||
3584 ((cm.l + cm.r) >= output.w) ||
3585 ((cm.t + cm.b) >= output.h))
3586 skip_cutouts = EINA_TRUE;
3587
3588 RD(0, " SNAPSHOT %s [sfc:%p ur:%d,%d %dx%d]\n", RDNAME(snap), pseudo_canvas, ur.x, ur.y, ur.w, ur.h);
3589 ctx = ENFN->context_new(ENC);
3590 clean_them |= evas_render_updates_internal_loop(eo_e, e, out->output, pseudo_canvas, ctx,
3591 snap,
3592 ur.x, ur.y, ur.w, ur.h,
3593 cr.x, cr.y, cr.w, cr.h,
3594 fx, fy, skip_cutouts, &cm,
3595 alpha, do_async,
3596 &offset, 1);
3597 ENFN->context_free(ENC, ctx);
3598
3599 offset = restore_offset;
3600 }
3601 }
3602 eina_evlog("-render_snapshots", eo_e, 0.0, NULL);
3603
3604 eina_evlog("+render_update", eo_e, 0.0, NULL);
3605 /* phase 7.2 render all the object on the target surface */
3606 if ((do_async) || (make_updates))
3607 {
3608 ru = malloc(sizeof(*ru));
3609 ru->surface = surface;
3610 //XXX: need a way of reffing output surfaces
3611 NEW_RECT(ru->area, ux, uy, uw, uh);
3612 eina_spinlock_take(&(e->render.lock));
3613 out->updates = eina_list_append(out->updates, ru);
3614 eina_spinlock_release(&(e->render.lock));
3615 }
3616
3617 ctx = ENFN->context_new(ENC);
3618 clean_them |= evas_render_updates_internal_loop(eo_e, e, out->output, surface,
3619 ctx, NULL,
3620 ux, uy, uw, uh,
3621 cx, cy, cw, ch,
3622 fx, fy,
3623 EINA_FALSE, NULL,
3624 alpha, do_async,
3625 &offset, 0);
3626 ENFN->context_free(ENC, ctx);
3627
3628 eina_evlog("-render_update", eo_e, 0.0, NULL);
3629 if (!do_async)
3630 {
3631 if (show_update_boxes == 1)
3632 {
3633 static int fn = 0;
3634 void *ctx;
3635
3636 fn++;
3637 ctx = ENFN->context_new(ENC);
3638 ENFN->context_color_set
3639 (ENC, ctx, fn & 0xff, 0x40, 0x20, 0xff);
3640 ENFN->rectangle_draw(ENC, out->output,
3641 ctx, surface,
3642 ux - out->geometry.x, uy - out->geometry.y, uw, 1, do_async);
3643 ENFN->rectangle_draw(ENC, out->output,
3644 ctx, surface,
3645 ux - out->geometry.x, uy - out->geometry.y + uh - 1, uw, 1, do_async);
3646 ENFN->rectangle_draw(ENC, out->output,
3647 ctx, surface,
3648 ux - out->geometry.x, uy - out->geometry.y, 1, uh, do_async);
3649 ENFN->rectangle_draw(ENC, out->output,
3650 ctx, surface,
3651 ux - out->geometry.x + uw - 1, uy - out->geometry.y, 1, uh, do_async);
3652 ENFN->context_free(ENC, ctx);
3653 }
3654 eina_evlog("+render_push", eo_e, 0.0, NULL);
3655 ENFN->output_redraws_next_update_push(ENC, out->output, surface,
3656 ux - out->geometry.x, uy - out->geometry.y, uw, uh,
3657 render_mode);
3658 eina_evlog("-render_push", eo_e, 0.0, NULL);
3659 }
3660 }
3661
3662 eina_evlog("-render_surface", eo_e, 0.0, NULL);
3663 }
3664 else if (make_updates)
3665 {
3666 Render_Updates *ru;
3667 void *surface;
3668 int ux, uy, uw, uh;
3669 int cx, cy, cw, ch;
3670 while ((surface =
3671 ENFN->output_redraws_next_update_get
3672 (ENC, out->output,
3673 &ux, &uy, &uw, &uh,
3674 &cx, &cy, &cw, &ch)))
3675 {
3676 haveup = EINA_TRUE;
3677
3678 /* adjust the rendering rectangle to the output offset */
3679 ux += out->geometry.x;
3680 uy += out->geometry.y;
3681 ru = malloc(sizeof(*ru));
3682 ru->surface = surface;
3683 //XXX: need a way of reffing output surfaces
3684 NEW_RECT(ru->area, ux, uy, uw, uh);
3685 eina_spinlock_take(&(e->render.lock));
3686 out->updates = eina_list_append(out->updates, ru);
3687 eina_spinlock_release(&(e->render.lock));
3688 }
3689
3690 }
3691 }
3692
3693 /* First process all output, then flush */
3694 if (do_draw)
3695 {
3696 if (haveup)
3697 {
3698 if (do_async)
3699 {
3700 eina_evlog("+render_output_async_flush", eo_e, 0.0, NULL);
3701 efl_ref(eo_e);
3702 _rendering_evases = eina_list_prepend(_rendering_evases, e);
3703 e->rendering = _rendering_evases;
3704 _cb_always_call(eo_e, e, EVAS_CALLBACK_RENDER_FLUSH_PRE, NULL);
3705 evas_thread_queue_flush((Evas_Thread_Command_Cb)evas_render_pipe_wakeup, e);
3706 eina_evlog("-render_output_async_flush", eo_e, 0.0, NULL);
3707 }
3708 else
3709 {
3710 eina_evlog("+render_output_flush", eo_e, 0.0, NULL);
3711 EINA_LIST_FOREACH(e->video_objects, ll, eo_obj)
3712 {
3713 _evas_object_image_video_overlay_do(eo_obj);
3714 }
3715 _cb_always_call(eo_e, e, EVAS_CALLBACK_RENDER_FLUSH_PRE, NULL);
3716 EINA_LIST_FOREACH(e->outputs, l, out)
3717 if (out->output)
3718 ENFN->output_flush(ENC, out->output, EVAS_RENDER_MODE_SYNC);
3719 _cb_always_call(eo_e, e, EVAS_CALLBACK_RENDER_FLUSH_POST, NULL);
3720 _deferred_callbacks_process(eo_e, evas);
3721 eina_evlog("-render_output_flush", eo_e, 0.0, NULL);
3722 }
3723 }
3724 rendering = haveup;
3725 }
3726 eina_evlog("-render_phase8", eo_e, 0.0, NULL);
3727
3728 if (evas_font_data_cache_get(EVAS_FONT_DATA_CACHE_TEXTURE) == 0)
3729 ENFN->font_glyphs_gc_collect(ENC, 1.0f, NULL, NULL, EINA_TRUE);
3730 else
3731 ENFN->font_glyphs_gc_collect(ENC, 0.33f, NULL, NULL, EINA_TRUE);
3732
3733 eina_evlog("+render_clear", eo_e, 0.0, NULL);
3734 if (!do_async && rendering)
3735 {
3736 /* clear redraws */
3737 EINA_LIST_FOREACH(e->outputs, l, out)
3738 if (out->output)
3739 ENFN->output_redraws_clear(ENC, out->output);
3740 }
3741 eina_evlog("-render_clear", eo_e, 0.0, NULL);
3742
3743 /* and do a post render pass */
3744 eina_evlog("+render_post", eo_e, 0.0, NULL);
3745 IFRD(e->active_objects.len, 0, " [--- POST RENDER\n");
3746 for (i = 0; i < e->active_objects.len; i++)
3747 {
3748 Evas_Active_Entry *ent = eina_inarray_nth(&e->active_objects, i);
3749
3750 obj = ent->obj;
3751 eo_obj = obj->object;
3752 if (!obj->private_data) continue;
3753 obj->pre_render_done = EINA_FALSE;
3754 RD(0, " OBJ %s changed:%i do_draw:%i\n", RDNAME(obj), obj->changed, do_draw);
3755 if ((clean_them) || (obj->changed && do_draw))
3756 {
3757 RD(0, " OBJ %s render_post()\n", RDNAME(obj));
3758 obj->restack = EINA_FALSE;
3759 evas_object_change_reset(obj);
3760 obj->func->render_post(eo_obj, obj, obj->private_data);
3761 }
3762 }
3763
3764 for (i = 0; i < e->snapshot_objects.count; i++)
3765 {
3766 Evas_Object_Protected_Data *snap;
3767
3768 snap = eina_array_data_get(&e->snapshot_objects, i);
3769 snap->snapshot_needs_redraw = EINA_FALSE;
3770 snap->snapshot_no_obscure = EINA_FALSE;
3771 }
3772 eina_evlog("-render_post", eo_e, 0.0, NULL);
3773 IFRD(e->active_objects.len, 0, " ---]\n");
3774
3775 /* Set back Evas_GL output to NULL */
3776 /* if (ENFN->gl_output_set) */
3777 /* ENFN->gl_output_set(ENC, NULL); */
3778
3779 /* free our obscuring object list */
3780 OBJS_ARRAY_CLEAN(&e->obscuring_objects);
3781
3782 /* If some object are still marked as changed, do not remove
3783 them from the pending list. */
3784 eina_array_remove(&e->pending_objects, pending_change, NULL);
3785
3786 /* Reinsert parent of changed object in the pending changed state */
3787 eina_evlog("+render_post_change", eo_e, 0.0, NULL);
3788 for (i = 0; i < e->pending_objects.count; ++i)
3789 {
3790 obj = eina_array_data_get(&e->pending_objects, i);
3791 if (obj->smart.parent)
3792 {
3793 /* these are all objects which could not be rendered because they were
3794 * added to their smart parent in this cycle and the parent was not changed
3795 */
3796 Evas_Object_Protected_Data *smart_parent;
3797
3798 smart_parent = efl_data_scope_get(obj->smart.parent,
3799 EFL_CANVAS_OBJECT_CLASS);
3800 evas_object_change(obj->smart.parent, smart_parent);
3801 /* render cache must be invalidated to correctly render subobj on next pass */
3802 evas_object_smart_render_cache_clear(obj->smart.parent);
3803 }
3804 obj->changed = EINA_TRUE;
3805 }
3806 eina_evlog("-render_post_change", eo_e, 0.0, NULL);
3807
3808 eina_evlog("+render_post_reset", eo_e, 0.0, NULL);
3809 for (i = 0; i < e->render_objects.count; ++i)
3810 {
3811 obj = eina_array_data_get(&e->render_objects, i);
3812 eo_obj = obj->object;
3813 if (!obj->private_data) continue;
3814 obj->pre_render_done = EINA_FALSE;
3815 if ((obj->changed) && (do_draw))
3816 {
3817 obj->restack = EINA_FALSE;
3818 evas_object_change_reset(obj);
3819 obj->func->render_post(eo_obj, obj, obj->private_data);
3820 }
3821 }
3822 eina_evlog("-render_post_reset", eo_e, 0.0, NULL);
3823
3824 for (i = 0; i < e->render_post_change_objects.count; ++i)
3825 {
3826 obj = eina_array_data_get(&e->render_post_change_objects, i);
3827 eo_obj = obj->object;
3828 evas_object_change(eo_obj, obj);
3829 }
3830 OBJS_ARRAY_CLEAN(&e->render_post_change_objects);
3831
3832 eina_evlog("+render_end", eo_e, 0.0, NULL);
3833 e->changed = EINA_FALSE;
3834 e->viewport.changed = EINA_FALSE;
3835 e->framespace.changed = EINA_FALSE;
3836 e->invalidate = EINA_FALSE;
3837
3838 // always clean... lots of mem waste!
3839 /* If their are some object to restack or some object to delete,
3840 * it's useless to keep the render object list around. */
3841 if (clean_them)
3842 {
3843 eina_inarray_flush(&e->active_objects);
3844 OBJS_ARRAY_CLEAN(&e->render_objects);
3845 OBJS_ARRAY_CLEAN(&e->restack_objects);
3846 OBJS_ARRAY_CLEAN(&e->temporary_objects);
3847 OBJS_ARRAY_CLEAN(&e->snapshot_objects);
3848 eina_array_foreach(&e->clip_changes, _evas_clip_changes_free, NULL);
3849 eina_array_clean(&e->clip_changes);
3850 e->invalidate = EINA_TRUE;
3851 }
3852
3853 /* delete all objects flagged for deletion now */
3854 for (i = 0; i < e->delete_objects.count; ++i)
3855 {
3856 obj = eina_array_data_get(&e->delete_objects, i);
3857 evas_object_free(obj, EINA_TRUE);
3858 }
3859 eina_array_clean(&e->delete_objects);
3860 /* if we deleted no objects this frame or we deleted a lot (> 1024) then
3861 * try and reset the deleted objects array to empty (no mem used) for
3862 * efficiency */
3863 if ((e->delete_objects.count == 0) || (e->delete_objects.count > 1024))
3864 eina_array_flush(&e->delete_objects);
3865
3866 evas_module_clean();
3867
3868 /* Send a RENDER_POST when we are rendering synchronously or,
3869 when do_async but no drawing. This gurantees pre-post pair. */
3870 if (!do_async || !rendering)
3871 {
3872 Evas_Event_Render_Post post;
3873 Eina_List *l1, *l2;
3874 Render_Updates *ru;
3875
3876 post.updated_area = NULL;
3877 if (haveup)
3878 {
3879 EINA_LIST_FOREACH(e->outputs, l1, out)
3880 {
3881 if (!out->output) continue ;
3882 EINA_LIST_FOREACH(out->updates, l2, ru)
3883 {
3884 post.updated_area = eina_list_append(post.updated_area, ru->area);
3885 //XXX: need a way of unreffing output surfaces
3886 ru->surface = NULL;
3887 }
3888 }
3889 }
3890 eina_spinlock_take(&(e->render.lock));
3891 e->inside_post_render = EINA_TRUE;
3892 _cb_always_call(eo_e, e, EVAS_CALLBACK_RENDER_POST, &post);
3893 e->inside_post_render = EINA_FALSE;
3894 eina_spinlock_release(&(e->render.lock));
3895 if (post.updated_area) eina_list_free(post.updated_area);
3896 }
3897
3898 RD(0, "---]\n");
3899
3900 #ifdef EVAS_RENDER_DEBUG_TIMING
3901 _accumulate_time(start_time, do_async);
3902 #endif
3903
3904 if (!do_async) _evas_render_cleanup();
3905 eina_evlog("-render_end", eo_e, 0.0, NULL);
3906 return rendering;
3907 }
3908
3909 static Eina_Bool
_drop_glyph_ref(const void * container EINA_UNUSED,void * data,void * fdata EINA_UNUSED)3910 _drop_glyph_ref(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
3911 {
3912 evas_common_font_glyphs_unref(data);
3913 return EINA_TRUE;
3914 }
3915
3916 static Eina_Bool
_drop_texts_ref(const void * container EINA_UNUSED,void * data,void * fdata EINA_UNUSED)3917 _drop_texts_ref(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
3918 {
3919 evas_common_font_fonts_unref(data);
3920
3921 return EINA_TRUE;
3922 }
3923
3924 static void
evas_render_wakeup(Evas * eo_e)3925 evas_render_wakeup(Evas *eo_e)
3926 {
3927 Evas_Event_Render_Post post;
3928 Render_Updates *ru;
3929 Eina_Bool haveup = EINA_FALSE;
3930 Eina_List *ret_updates = NULL, *l;
3931 Evas_Post_Render_Job *job;
3932 Evas_Public_Data *evas;
3933 Efl_Canvas_Output *out;
3934 Eina_Inlist *jobs_il;
3935
3936 evas = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
3937
3938 eina_evlog("+render_wakeup", eo_e, 0.0, NULL);
3939 eina_spinlock_take(&(evas->render.lock));
3940 EINA_LIST_FOREACH(evas->outputs, l, out)
3941 {
3942 if (!out->output) continue ;
3943 EINA_LIST_FREE(out->updates, ru)
3944 {
3945 ret_updates = eina_list_append(ret_updates, ru->area);
3946 free(ru);
3947 haveup = EINA_TRUE;
3948 }
3949 }
3950 eina_spinlock_release(&(evas->render.lock));
3951
3952 /* post rendering */
3953 _rendering_evases = eina_list_remove_list(_rendering_evases, evas->rendering);
3954 evas->rendering = NULL;
3955
3956 /* flush redraws */
3957 if (haveup)
3958 {
3959 Eina_List *ll;
3960 Evas_Object *eo_obj;
3961 EINA_LIST_FOREACH(evas->video_objects, ll, eo_obj)
3962 {
3963 _evas_object_image_video_overlay_do(eo_obj);
3964 }
3965 _cb_always_call(eo_e, evas, EVAS_CALLBACK_RENDER_FLUSH_POST, NULL);
3966 }
3967
3968 /* clear redraws */
3969 EINA_LIST_FOREACH(evas->outputs, l, out)
3970 {
3971 if (!out->output) continue ;
3972 ENFN->output_redraws_clear(ENC, out->output);
3973 }
3974
3975 /* unref queues */
3976 eina_array_foreach(&evas->scie_unref_queue, _drop_scie_ref, NULL);
3977 eina_array_flush(&evas->scie_unref_queue);
3978 evas_common_rgba_image_scalecache_prune();
3979
3980 eina_array_foreach(&evas->image_unref_queue, _drop_image_cache_ref, NULL);
3981 eina_array_flush(&evas->image_unref_queue);
3982
3983 eina_array_foreach(&evas->glyph_unref_queue, _drop_glyph_ref, NULL);
3984 eina_array_flush(&evas->glyph_unref_queue);
3985
3986 eina_array_foreach(&evas->texts_unref_queue, _drop_texts_ref, NULL);
3987 eina_array_flush(&evas->texts_unref_queue);
3988
3989 SLKL(evas->post_render.lock);
3990 jobs_il = EINA_INLIST_GET(evas->post_render.jobs);
3991 evas->post_render.jobs = NULL;
3992 SLKU(evas->post_render.lock);
3993
3994 evas->inside_post_render = EINA_TRUE;
3995 EINA_INLIST_FREE(jobs_il, job)
3996 {
3997 jobs_il = eina_inlist_remove(jobs_il, EINA_INLIST_GET(job));
3998 if (job->func)
3999 job->func(job->data);
4000 free(job);
4001 }
4002
4003 post.updated_area = ret_updates;
4004 _cb_always_call(eo_e, evas, EVAS_CALLBACK_RENDER_POST, &post);
4005 evas->inside_post_render = EINA_FALSE;
4006 _deferred_callbacks_process(eo_e, evas);
4007
4008 evas_render_updates_free(ret_updates);
4009
4010 eina_evlog("-render_wakeup", eo_e, 0.0, NULL);
4011 efl_unref(eo_e);
4012
4013 #ifdef EVAS_RENDER_DEBUG_TIMING
4014 _accumulate_time(0, EINA_TRUE);
4015 #endif
4016 }
4017
4018 static void
evas_render_async_wakeup(void * target,Evas_Callback_Type type EINA_UNUSED,void * event_info EINA_UNUSED)4019 evas_render_async_wakeup(void *target, Evas_Callback_Type type EINA_UNUSED, void *event_info EINA_UNUSED)
4020 {
4021 Evas_Public_Data *e = target;
4022 evas_render_wakeup(e->evas);
4023 _evas_render_busy_end();
4024 }
4025
4026 // FIXME: This event should be per output... maybe ? maybe not ?
4027 static void
evas_render_pipe_wakeup(void * data)4028 evas_render_pipe_wakeup(void *data)
4029 {
4030 Eina_List *l, *ll;
4031 Render_Updates *ru;
4032 Evas_Public_Data *evas = data;
4033 Efl_Canvas_Output *out;
4034 Evas *e;
4035
4036 eina_evlog("+render_pipe_wakeup", evas->evas, 0.0, NULL);
4037 eina_spinlock_take(&(evas->render.lock));
4038 e = evas->evas;
4039 EINA_LIST_FOREACH(evas->outputs, ll, out)
4040 {
4041 if (!out->output) continue ;
4042 EINA_LIST_FOREACH(out->updates, l, ru)
4043 {
4044 eina_evlog("+render_push", evas->evas, 0.0, NULL);
4045 ENFN->output_redraws_next_update_push
4046 (ENC, out->output, ru->surface,
4047 ru->area->x - out->geometry.x, ru->area->y - out->geometry.y,
4048 ru->area->w, ru->area->h,
4049 EVAS_RENDER_MODE_ASYNC_END);
4050 eina_evlog("-render_push", evas->evas, 0.0, NULL);
4051 //XXX: need a way to unref render output surfaces
4052 ru->surface = NULL;
4053 }
4054 eina_evlog("+render_output_flush", evas->evas, 0.0, NULL);
4055 ENFN->output_flush(ENC, out->output, EVAS_RENDER_MODE_ASYNC_END);
4056 eina_evlog("-render_output_flush", evas->evas, 0.0, NULL);
4057 }
4058 eina_spinlock_release(&(evas->render.lock));
4059 evas_async_events_put(data, 0, NULL, evas_render_async_wakeup);
4060 /* use local pointer to avoid data race with 'evas' deref after releasing lock */
4061 eina_evlog("-render_pipe_wakeup", e, 0.0, NULL);
4062 }
4063
4064 EAPI void
evas_render_updates_free(Eina_List * updates)4065 evas_render_updates_free(Eina_List *updates)
4066 {
4067 Eina_Rectangle *r;
4068
4069 EINA_LIST_FREE(updates, r)
4070 eina_rectangle_free(r);
4071 }
4072
4073 EOLIAN Eina_Bool
_evas_canvas_render_async(Eo * eo_e,Evas_Public_Data * e)4074 _evas_canvas_render_async(Eo *eo_e, Evas_Public_Data *e)
4075 {
4076 Eina_Bool ret;
4077 eina_evlog("+render_block", eo_e, 0.0, NULL);
4078 evas_canvas_async_block(e);
4079 eina_evlog("-render_block", eo_e, 0.0, NULL);
4080 eina_evlog("+render", eo_e, 0.0, NULL);
4081 ret = evas_render_updates_internal(eo_e, 1, 1, EINA_TRUE);
4082 eina_evlog("-render", eo_e, 0.0, NULL);
4083 return ret;
4084 }
4085
4086 static Eina_List *
evas_render_updates_internal_wait(Evas * eo_e,unsigned char make_updates,unsigned char do_draw)4087 evas_render_updates_internal_wait(Evas *eo_e,
4088 unsigned char make_updates,
4089 unsigned char do_draw)
4090 {
4091 Eina_List *ret = NULL, *l;
4092 Efl_Canvas_Output *out;
4093 Evas_Public_Data *e;
4094
4095 e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
4096 if (!evas_render_updates_internal(eo_e, make_updates, do_draw, EINA_FALSE))
4097 return NULL;
4098
4099 eina_spinlock_take(&(e->render.lock));
4100 EINA_LIST_FOREACH(e->outputs, l, out)
4101 {
4102 if (!out->output) continue ;
4103 ret = eina_list_merge(ret, out->updates);
4104 out->updates = NULL;
4105 }
4106 eina_spinlock_release(&(e->render.lock));
4107
4108 return ret;
4109 }
4110
4111 EOLIAN Eina_List*
_evas_canvas_render_updates(Eo * eo_e,Evas_Public_Data * e)4112 _evas_canvas_render_updates(Eo *eo_e, Evas_Public_Data *e)
4113 {
4114 Eina_List *ret, *updates = NULL;
4115 Render_Updates *ru;
4116 eina_evlog("+render_block", eo_e, 0.0, NULL);
4117 evas_canvas_async_block(e);
4118 eina_evlog("-render_block", eo_e, 0.0, NULL);
4119 eina_evlog("+render", eo_e, 0.0, NULL);
4120 ret = evas_render_updates_internal_wait(eo_e, 1, 1);
4121 eina_evlog("-render", eo_e, 0.0, NULL);
4122 EINA_LIST_FREE(ret, ru)
4123 {
4124 updates = eina_list_append(updates, ru->area);
4125 free(ru);
4126 }
4127 return updates;
4128 }
4129
4130 EOLIAN void
_evas_canvas_render(Eo * eo_e,Evas_Public_Data * e)4131 _evas_canvas_render(Eo *eo_e, Evas_Public_Data *e)
4132 {
4133 Eina_List *ret;
4134 Render_Updates *ru;
4135 if (!e->changed) return;
4136 eina_evlog("+render_block", eo_e, 0.0, NULL);
4137 evas_canvas_async_block(e);
4138 eina_evlog("-render_block", eo_e, 0.0, NULL);
4139 eina_evlog("+render", eo_e, 0.0, NULL);
4140 ret = evas_render_updates_internal_wait(eo_e, 0, 1);
4141 eina_evlog("-render", eo_e, 0.0, NULL);
4142 EINA_LIST_FREE(ret, ru)
4143 {
4144 eina_rectangle_free(ru->area);
4145 free(ru);
4146 }
4147 }
4148
4149 EOLIAN void
_evas_canvas_norender(Eo * eo_e,Evas_Public_Data * e)4150 _evas_canvas_norender(Eo *eo_e, Evas_Public_Data *e)
4151 {
4152 evas_canvas_async_block(e);
4153 evas_render_updates_internal_wait(eo_e, 0, 0);
4154 }
4155
4156 EAPI void
evas_norender_with_updates(Eo * eo_e)4157 evas_norender_with_updates(Eo *eo_e)
4158 {
4159 Evas_Public_Data *e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
4160 Eina_List *ret;
4161 Render_Updates *ru;
4162
4163 evas_canvas_async_block(e);
4164 ret = evas_render_updates_internal_wait(eo_e, 1, 0);
4165 EINA_LIST_FREE(ret, ru)
4166 {
4167 eina_rectangle_free(ru->area);
4168 free(ru);
4169 }
4170 }
4171
4172 EOLIAN void
_evas_canvas_render_idle_flush(Eo * eo_e,Evas_Public_Data * evas)4173 _evas_canvas_render_idle_flush(Eo *eo_e, Evas_Public_Data *evas)
4174 {
4175 eina_evlog("+idle_flush", eo_e, 0.0, NULL);
4176 evas_canvas_async_block(evas);
4177
4178 evas_render_rendering_wait(evas);
4179
4180 evas_fonts_zero_pressure();
4181
4182 if (ENFN && ENFN->output_idle_flush)
4183 {
4184 Efl_Canvas_Output *output;
4185 Eina_List *l;
4186
4187 EINA_LIST_FOREACH(evas->outputs, l, output)
4188 if (output->output)
4189 ENFN->output_idle_flush(ENC, output->output);
4190 }
4191
4192 eina_inarray_flush(&evas->active_objects);
4193 OBJS_ARRAY_FLUSH(&evas->render_objects);
4194 OBJS_ARRAY_FLUSH(&evas->restack_objects);
4195 OBJS_ARRAY_FLUSH(&evas->delete_objects);
4196 OBJS_ARRAY_FLUSH(&evas->obscuring_objects);
4197 OBJS_ARRAY_FLUSH(&evas->temporary_objects);
4198 OBJS_ARRAY_FLUSH(&evas->map_clip_objects);
4199 eina_array_foreach(&evas->clip_changes, _evas_clip_changes_free, NULL);
4200 eina_array_clean(&evas->clip_changes);
4201
4202 evas->invalidate = EINA_TRUE;
4203 eina_evlog("-idle_flush", eo_e, 0.0, NULL);
4204 }
4205
4206 EOLIAN void
_evas_canvas_sync(Eo * eo_e,Evas_Public_Data * e)4207 _evas_canvas_sync(Eo *eo_e, Evas_Public_Data *e)
4208 {
4209 eina_evlog("+render_sync", eo_e, 0.0, NULL);
4210 evas_canvas_async_block(e);
4211 evas_render_rendering_wait(e);
4212 eina_evlog("-render_sync", eo_e, 0.0, NULL);
4213 }
4214
4215 void
_evas_render_dump_map_surfaces(Evas_Object * eo_obj)4216 _evas_render_dump_map_surfaces(Evas_Object *eo_obj)
4217 {
4218 Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
4219 if ((obj->map->cur.map) && obj->map->surface)
4220 {
4221 Evas_Public_Data *evas = obj->layer->evas;
4222 ENFN->image_free(ENC, obj->map->surface);
4223 EINA_COW_WRITE_BEGIN(evas_object_map_cow, obj->map, Evas_Object_Map_Data, map_write)
4224 map_write->surface = NULL;
4225 EINA_COW_WRITE_END(evas_object_map_cow, obj->map, map_write);
4226 }
4227
4228 if (obj->is_smart)
4229 {
4230 Evas_Object_Protected_Data *obj2;
4231
4232 EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(eo_obj), obj2)
4233 _evas_render_dump_map_surfaces(obj2->object);
4234 }
4235 }
4236
4237 EOLIAN void
_evas_canvas_render_dump(Eo * eo_e EINA_UNUSED,Evas_Public_Data * evas)4238 _evas_canvas_render_dump(Eo *eo_e EINA_UNUSED, Evas_Public_Data *evas)
4239 {
4240 Evas_Layer *lay;
4241
4242 evas_canvas_async_block(evas);
4243
4244 evas_all_sync();
4245 evas_cache_async_freeze();
4246
4247 EINA_INLIST_FOREACH(evas->layers, lay)
4248 {
4249 Evas_Object_Protected_Data *obj;
4250
4251 lay->walking_objects++;
4252 EINA_INLIST_FOREACH(lay->objects, obj)
4253 {
4254 if (obj->proxy->surface)
4255 {
4256 EINA_COW_WRITE_BEGIN(evas_object_proxy_cow, obj->proxy, Evas_Object_Proxy_Data, proxy_write)
4257 {
4258 ENFN->image_free(ENC, proxy_write->surface);
4259 proxy_write->surface = NULL;
4260 }
4261 EINA_COW_WRITE_END(evas_object_proxy_cow, obj->proxy, proxy_write);
4262 }
4263 if (obj->mask->surface)
4264 {
4265 EINA_COW_WRITE_BEGIN(evas_object_mask_cow, obj->mask, Evas_Object_Mask_Data, mdata)
4266 {
4267 ENFN->image_free(ENC, mdata->surface);
4268 mdata->surface = NULL;
4269 }
4270 EINA_COW_WRITE_END(evas_object_mask_cow, obj->mask, mdata);
4271 }
4272 if ((obj->type) && (!strcmp(obj->type, "image")))
4273 evas_object_inform_call_image_unloaded(obj->object);
4274 _evas_render_dump_map_surfaces(obj->object);
4275 }
4276 lay->walking_objects--;
4277 _evas_layer_flush_removes(lay);
4278 }
4279 if (ENFN && ENFN->output_dump)
4280 {
4281 Efl_Canvas_Output *output;
4282 Eina_List *l;
4283
4284 EINA_LIST_FOREACH(evas->outputs, l, output)
4285 if (output->output)
4286 ENFN->output_dump(ENC, output->output);
4287 }
4288
4289 #define GC_ALL(Cow) \
4290 if (Cow) while (eina_cow_gc(Cow))
4291 GC_ALL(evas_object_proxy_cow);
4292 GC_ALL(evas_object_map_cow);
4293 GC_ALL(evas_object_image_pixels_cow);
4294 GC_ALL(evas_object_image_load_opts_cow);
4295 GC_ALL(evas_object_image_state_cow);
4296
4297 evas_fonts_zero_pressure();
4298
4299 if (ENFN && ENFN->output_idle_flush)
4300 {
4301 Efl_Canvas_Output *output;
4302 Eina_List *l;
4303
4304 EINA_LIST_FOREACH(evas->outputs, l, output)
4305 if (output->output)
4306 ENFN->output_idle_flush(ENC, output->output);
4307 }
4308
4309 eina_inarray_flush(&evas->active_objects);
4310 OBJS_ARRAY_FLUSH(&evas->render_objects);
4311 OBJS_ARRAY_FLUSH(&evas->restack_objects);
4312 OBJS_ARRAY_FLUSH(&evas->delete_objects);
4313 OBJS_ARRAY_FLUSH(&evas->obscuring_objects);
4314 OBJS_ARRAY_FLUSH(&evas->temporary_objects);
4315 OBJS_ARRAY_FLUSH(&evas->map_clip_objects);
4316 eina_array_foreach(&evas->clip_changes, _evas_clip_changes_free, NULL);
4317 eina_array_clean(&evas->clip_changes);
4318
4319 evas->invalidate = EINA_TRUE;
4320
4321 evas_cache_async_thaw();
4322 }
4323
4324 void
evas_render_invalidate(Evas * eo_e)4325 evas_render_invalidate(Evas *eo_e)
4326 {
4327 Evas_Public_Data *e;
4328
4329 MAGIC_CHECK(eo_e, Evas, MAGIC_EVAS);
4330 return;
4331 MAGIC_CHECK_END();
4332 e = efl_data_scope_get(eo_e, EVAS_CANVAS_CLASS);
4333
4334 eina_inarray_flush(&e->active_objects);
4335 OBJS_ARRAY_CLEAN(&e->render_objects);
4336
4337 OBJS_ARRAY_FLUSH(&e->restack_objects);
4338 OBJS_ARRAY_FLUSH(&e->delete_objects);
4339
4340 OBJS_ARRAY_FLUSH(&e->snapshot_objects);
4341 OBJS_ARRAY_FLUSH(&e->map_clip_objects);
4342
4343 e->invalidate = EINA_TRUE;
4344 }
4345
4346 void
evas_render_object_recalc(Evas_Object_Protected_Data * obj)4347 evas_render_object_recalc(Evas_Object_Protected_Data *obj)
4348 {
4349 if ((!obj->changed) && (obj->delete_me < 2))
4350 {
4351 Evas_Public_Data *e;
4352
4353 e = obj->layer->evas;
4354 if ((!e) || (e->cleanup)) return;
4355 if (!obj->in_pending_objects)
4356 OBJ_ARRAY_PUSH(&e->pending_objects, obj);
4357 obj->in_pending_objects = obj->changed = EINA_TRUE;
4358 }
4359 }
4360
4361 void
evas_unref_queue_image_put(Evas_Public_Data * pd,void * image)4362 evas_unref_queue_image_put(Evas_Public_Data *pd, void *image)
4363 {
4364 eina_array_push(&pd->image_unref_queue, image);
4365 evas_common_rgba_image_scalecache_items_ref(image, &pd->scie_unref_queue);
4366 }
4367
4368 void
evas_unref_queue_glyph_put(Evas_Public_Data * pd,void * glyph)4369 evas_unref_queue_glyph_put(Evas_Public_Data *pd, void *glyph)
4370 {
4371 eina_array_push(&pd->glyph_unref_queue, glyph);
4372 }
4373
4374 void
evas_unref_queue_texts_put(Evas_Public_Data * pd,void * texts)4375 evas_unref_queue_texts_put(Evas_Public_Data *pd, void *texts)
4376 {
4377 eina_array_push(&pd->texts_unref_queue, texts);
4378 }
4379
4380 void
evas_post_render_job_add(Evas_Public_Data * pd,void (* func)(void *),void * data)4381 evas_post_render_job_add(Evas_Public_Data *pd, void (*func)(void *), void *data)
4382 {
4383 Evas_Post_Render_Job *job;
4384
4385 if (!pd || pd->delete_me) return;
4386 if (!func) return;
4387
4388 job = malloc(sizeof(*job));
4389 job->func = func;
4390 job->data = data;
4391
4392 SLKL(pd->post_render.lock);
4393 pd->post_render.jobs = (Evas_Post_Render_Job *)
4394 eina_inlist_append(EINA_INLIST_GET(pd->post_render.jobs), EINA_INLIST_GET(job));
4395 SLKU(pd->post_render.lock);
4396 }
4397
4398 void
evas_render_post_change_object_push(Evas_Object_Protected_Data * obj)4399 evas_render_post_change_object_push(Evas_Object_Protected_Data *obj)
4400 {
4401 Evas_Public_Data *e;
4402
4403 if (!obj || !obj->layer || !obj->layer->evas) return;
4404
4405 e = obj->layer->evas;
4406 OBJ_ARRAY_PUSH(&e->render_post_change_objects, obj);
4407 }
4408
4409 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/
4410
4411