diff --git a/src/lib/evas/canvas/evas_object_image.c b/src/lib/evas/canvas/evas_object_image.c index 727c68f354..110b9da089 100644 --- a/src/lib/evas/canvas/evas_object_image.c +++ b/src/lib/evas/canvas/evas_object_image.c @@ -2412,10 +2412,10 @@ evas_object_image_render_pre(Evas_Object *eo_obj, } } if ((w > 0) && (h > 0)) - e->engine.func->output_redraws_rect_del(e->engine.data.output, - x + e->framespace.x, - y + e->framespace.y, - w, h); + evas_render_update_del(e, + x + e->framespace.x, + y + e->framespace.y, + w, h); } EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write) { @@ -2504,10 +2504,10 @@ evas_object_image_render_pre(Evas_Object *eo_obj, } } if ((w > 0) && (h > 0)) - e->engine.func->output_redraws_rect_del(e->engine.data.output, - x + e->framespace.x, - y + e->framespace.y, - w, h); + evas_render_update_del(e, + x + e->framespace.x, + y + e->framespace.y, + w, h); } else if ((o->cur->border.fill == EVAS_BORDER_FILL_SOLID) && (obj->cur->color.a == 255)) @@ -2532,10 +2532,10 @@ evas_object_image_render_pre(Evas_Object *eo_obj, } } if ((w > 0) && (h > 0)) - e->engine.func->output_redraws_rect_del(e->engine.data.output, - x + e->framespace.x, - y + e->framespace.y, - w, h); + evas_render_update_del(e, + x + e->framespace.x, + y + e->framespace.y, + w, h); } EINA_COW_PIXEL_WRITE_BEGIN(o, pixi_write) { @@ -2597,10 +2597,10 @@ evas_object_image_render_pre(Evas_Object *eo_obj, obj->cur->clipper->cur->cache.clip.w, obj->cur->clipper->cur->cache.clip.h); } - e->engine.func->output_redraws_rect_del(e->engine.data.output, - x + e->framespace.x, - y + e->framespace.y, - w, h); + evas_render_update_del(e, + x + e->framespace.x, + y + e->framespace.y, + w, h); changed_prep = EINA_FALSE; } else diff --git a/src/lib/evas/canvas/evas_object_rectangle.c b/src/lib/evas/canvas/evas_object_rectangle.c index 6c0fe9e3f5..be88ec7c37 100644 --- a/src/lib/evas/canvas/evas_object_rectangle.c +++ b/src/lib/evas/canvas/evas_object_rectangle.c @@ -299,11 +299,10 @@ evas_object_rectangle_render_pre(Evas_Object *eo_obj, obj->cur->clipper->cur->cache.clip.w, obj->cur->clipper->cur->cache.clip.h); } - obj->layer->evas->engine.func->output_redraws_rect_del - (obj->layer->evas->engine.data.output, - x + obj->layer->evas->framespace.x, - y + obj->layer->evas->framespace.y, - w, h); + evas_render_update_del(obj->layer->evas, + x + obj->layer->evas->framespace.x, + y + obj->layer->evas->framespace.y, + w, h); } /* if it changed geometry - and obviously not visibility or color */ /* calculate differences since we have a constant color fill */ diff --git a/src/lib/evas/canvas/evas_object_smart.c b/src/lib/evas/canvas/evas_object_smart.c index 51338c5ab6..3715625c3a 100644 --- a/src/lib/evas/canvas/evas_object_smart.c +++ b/src/lib/evas/canvas/evas_object_smart.c @@ -29,6 +29,7 @@ struct _Evas_Smart_Data Eina_Inlist *callbacks; Eina_Inlist *contained; /** list of smart member objects */ + void *render_cache; /* ptr array + data blob holding all interfaces private data for * this object */ void **interface_privates; @@ -481,6 +482,32 @@ evas_object_smart_members_get(const Evas_Object *eo_obj) return members; } +void +evas_object_smart_render_cache_clear(Evas_Object *eo_obj) +{ + Evas_Smart_Data *o = efl_data_scope_get(eo_obj, MY_CLASS); + if (!o) return; + if (!o->render_cache) return; + evas_render_object_render_cache_free(eo_obj, o->render_cache); + o->render_cache = NULL; +} + +void * +evas_object_smart_render_cache_get(const Evas_Object *eo_obj) +{ + Evas_Smart_Data *o = efl_data_scope_get(eo_obj, MY_CLASS); + if (!o) return NULL; + return o->render_cache; +} + +void +evas_object_smart_render_cache_set(Evas_Object *eo_obj, void *data) +{ + Evas_Smart_Data *o = efl_data_scope_get(eo_obj, MY_CLASS); + if (!o) return; + o->render_cache = data; +} + const Eina_Inlist * evas_object_smart_members_get_direct(const Evas_Object *eo_obj) { @@ -489,6 +516,7 @@ evas_object_smart_members_get_direct(const Evas_Object *eo_obj) MAGIC_CHECK_END(); if (!efl_isa(eo_obj, MY_CLASS)) return NULL; Evas_Smart_Data *o = efl_data_scope_get(eo_obj, MY_CLASS); + if (!o) return NULL; return o->contained; } @@ -1273,6 +1301,12 @@ evas_object_smart_cleanup(Evas_Object *eo_obj) free(info); } + if (o->render_cache) + { + evas_render_object_render_cache_free(eo_obj, o->render_cache); + o->render_cache = NULL; + } + evas_smart_cb_descriptions_resize(&o->callbacks_descriptions, 0); evas_object_smart_data_set(eo_obj, NULL); } diff --git a/src/lib/evas/canvas/evas_object_vg.c b/src/lib/evas/canvas/evas_object_vg.c index ae89f1ac16..453646828a 100644 --- a/src/lib/evas/canvas/evas_object_vg.c +++ b/src/lib/evas/canvas/evas_object_vg.c @@ -346,11 +346,10 @@ evas_object_vg_render_pre(Evas_Object *eo_obj, obj->cur->clipper->cur->cache.clip.w, obj->cur->clipper->cur->cache.clip.h); } - obj->layer->evas->engine.func->output_redraws_rect_del - (obj->layer->evas->engine.data.output, - x + obj->layer->evas->framespace.x, - y + obj->layer->evas->framespace.y, - w, h); + evas_render_update_del(obj->layer->evas, + x + obj->layer->evas->framespace.x, + y + obj->layer->evas->framespace.y, + w, h); } done: evas_object_render_pre_effect_updates(&obj->layer->evas->clip_changes, eo_obj, is_v, was_v); diff --git a/src/lib/evas/canvas/evas_render.c b/src/lib/evas/canvas/evas_render.c index bc136c3566..3047a36fd5 100644 --- a/src/lib/evas/canvas/evas_render.c +++ b/src/lib/evas/canvas/evas_render.c @@ -71,26 +71,26 @@ rend_dbg(const char *txt) do \ { \ eina_array_push(array, obj); \ - efl_data_ref(obj->object, NULL); \ + /*efl_data_ref(obj->object, NULL);*/ \ } while (0) #define OBJS_ARRAY_CLEAN(array) \ { \ - Evas_Object_Protected_Data *item; \ - Eina_Array_Iterator iterator; \ - unsigned int idx; \ - EINA_ARRAY_ITER_NEXT(array, idx, item, iterator) \ - efl_data_unref(item->object, item); \ + /*Evas_Object_Protected_Data *item;*/ \ + /*Eina_Array_Iterator iterator;*/ \ + /*unsigned int idx;*/ \ + /*EINA_ARRAY_ITER_NEXT(array, idx, item, iterator)*/ \ + /*efl_data_unref(item->object, item);*/ \ eina_array_clean(array); \ } #define OBJS_ARRAY_FLUSH(array) \ { \ - Evas_Object_Protected_Data *item; \ - Eina_Array_Iterator iterator; \ - unsigned int idx; \ - EINA_ARRAY_ITER_NEXT(array, idx, item, iterator) \ - efl_data_unref(item->object, item); \ + /*Evas_Object_Protected_Data *item;*/ \ + /*Eina_Array_Iterator iterator;*/ \ + /*unsigned int idx;*/ \ + /*EINA_ARRAY_ITER_NEXT(array, idx, item, iterator)*/ \ + /*efl_data_unref(item->object, item);*/ \ eina_array_flush(array); \ } @@ -320,9 +320,7 @@ _evas_render_cur_clip_cache_del(Evas_Public_Data *e, Evas_Object_Protected_Data obj->cur->clipper->cur->cache.clip.w, obj->cur->clipper->cur->cache.clip.h); } - e->engine.func->output_redraws_rect_del(e->engine.data.output, - x + e->framespace.x, - y + e->framespace.y, w, h); + evas_render_update_del(e, x + e->framespace.x, y + e->framespace.y, w, h); } /* sets the redraw flag for all the proxies depending on this obj as a source */ @@ -599,17 +597,122 @@ _evas_render_object_map_change_update(Evas_Public_Data *e, Evas_Object *eo_obj E *redraw_all = 1; } + + + +//////////////////////////////////////////////////////////////////////////// +// +// object render update phase 1 code -> figure out updates and built object +// render/active/delete etc. lists/arrays. +// + +typedef struct +{ + Eina_Array *active_objects; + Eina_Array *render_objects; + Eina_Array *snapshot_objects; + + Eina_Inarray *update_del; +} Render_Cache; + +void +evas_render_update_del(Evas_Public_Data *e, int x, int y, int w, int h) +{ + if (EINA_LIKELY((e->update_del_redirect_array == NULL))) + { + e->engine.func->output_redraws_rect_del(e->engine.data.output, + x, y, w, h); + } + else + { + Eina_Rectangle r; + + r.x = x; r.y = y; r.w = w; r.h = h; + eina_inarray_push(e->update_del_redirect_array, &r); + } +} + +void +evas_render_object_render_cache_free(Evas_Object *eo_obj EINA_UNUSED, + void *data) +{ + Render_Cache *rc; + + if (!data) return; + rc = data; + OBJS_ARRAY_CLEAN(rc->active_objects); + OBJS_ARRAY_CLEAN(rc->render_objects); + OBJS_ARRAY_CLEAN(rc->snapshot_objects); + eina_array_free(rc->active_objects); + eina_array_free(rc->render_objects); + eina_array_free(rc->snapshot_objects); + free(rc); +} + +static Render_Cache * +_evas_render_phase1_object_render_cache_new(void) +{ + Render_Cache *rc; + + rc = malloc(sizeof(Render_Cache)); + rc->active_objects = eina_array_new(32); + rc->render_objects = eina_array_new(32); + rc->snapshot_objects = eina_array_new(32); + rc->update_del = eina_inarray_new(sizeof(Eina_Rectangle), 16); + return rc; +} + typedef struct { Evas_Public_Data *e; Eina_Array *active_objects; - Eina_Array *restack_objects; - Eina_Array *delete_objects; Eina_Array *render_objects; Eina_Array *snapshot_objects; + Eina_Array *restack_objects; + Eina_Array *delete_objects; int redraw_all; } Phase1_Context; +static void +_evas_render_phase1_object_ctx_render_cache_fill(Phase1_Context *ctx, + Render_Cache *rc) +{ + ctx->active_objects = rc->active_objects; + ctx->render_objects = rc->render_objects; + ctx->snapshot_objects = rc->snapshot_objects; +} + +static void +_evas_render_phase1_object_ctx_render_cache_append(Phase1_Context *ctx, + Render_Cache *rc) +{ + void *obj; + unsigned int i, c; + Eina_Rectangle *r; + +#define ARR_APPEND(x) \ + if (rc->x != ctx->x) { \ + do { \ + c = eina_array_count_get(rc->x); \ + for (i = 0; i < c; i++) { \ + obj = eina_array_data_get(rc->x, i); \ + eina_array_push(ctx->x, obj); \ + /*efl_data_ref(obj, NULL);*/ \ + } \ + } while (0); \ + } + ARR_APPEND(active_objects); + ARR_APPEND(render_objects); + ARR_APPEND(snapshot_objects); + + c = eina_inarray_count(rc->update_del); + for (i = 0; i < c; i++) + { + r = eina_inarray_nth(rc->update_del, i); + evas_render_update_del(ctx->e, r->x, r->y, r->w, r->h); + } +} + static Eina_Bool _evas_render_phase1_object_process(Phase1_Context *p1ctx, Evas_Object *eo_obj, @@ -673,6 +776,7 @@ _evas_render_phase1_object_mapped(Phase1_Context *p1ctx, _evas_render_prev_cur_clip_cache_add(p1ctx->e, obj); obj->render_pre = EINA_TRUE; if (!obj->is_smart) return; + if (obj_changed) evas_object_smart_render_cache_clear(eo_obj); EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(eo_obj), obj2) { _evas_render_phase1_object_process(p1ctx, obj2->object, obj->restack, @@ -708,16 +812,21 @@ _evas_render_phase1_object_mapped_had_restack(Phase1_Context *p1ctx, evas_object_update_bounding_box(eo_obj, obj, NULL); } +#define RENDCACHE 1 + static Eina_Bool _evas_render_phase1_object_changed_smart(Phase1_Context *p1ctx, Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, Eina_Bool mapped_parent, + Eina_Bool obj_changed, Eina_Bool src_changed, Eina_Bool is_active, int level) { Evas_Object_Protected_Data *obj2; + Render_Cache *rc = NULL; + void *p_del_redir; RD(level, " changed + smart - render ok\n"); OBJ_ARRAY_PUSH(p1ctx->render_objects, obj); @@ -725,11 +834,62 @@ _evas_render_phase1_object_changed_smart(Phase1_Context *p1ctx, if (!is_active && obj->proxy->proxies) src_changed = EINA_TRUE; obj->render_pre = EINA_TRUE; - EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(eo_obj), obj2) + if (obj_changed) { - _evas_render_phase1_object_process(p1ctx, obj2->object, obj->restack, - mapped_parent, src_changed, - level + 1); + evas_object_smart_render_cache_clear(eo_obj); + EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(eo_obj), obj2) + { + _evas_render_phase1_object_process(p1ctx, obj2->object, + obj->restack, + mapped_parent, src_changed, + level + 1); + } + } + else + { + Phase1_Context *ctx = p1ctx; + Phase1_Context tmpctx; + +#ifdef RENDCACHE + if (obj->no_change_render > 3) + { + rc = evas_object_smart_render_cache_get(eo_obj); + if (!rc) + { + rc = _evas_render_phase1_object_render_cache_new(); + evas_object_smart_render_cache_set(eo_obj, rc); + ctx = &tmpctx; + *ctx = *p1ctx; + p_del_redir = p1ctx->e->update_del_redirect_array; + p1ctx->e->update_del_redirect_array = rc->update_del; + _evas_render_phase1_object_ctx_render_cache_fill(ctx, rc); + EINA_INLIST_FOREACH + (evas_object_smart_members_get_direct(eo_obj), obj2) + { + _evas_render_phase1_object_process(ctx, obj2->object, + obj->restack, + mapped_parent, + src_changed, + level + 1); + } + p1ctx->redraw_all = ctx->redraw_all; + p1ctx->e->update_del_redirect_array = p_del_redir; + } + _evas_render_phase1_object_ctx_render_cache_append(p1ctx, rc); + } + else +#endif + { + EINA_INLIST_FOREACH + (evas_object_smart_members_get_direct(eo_obj), obj2) + { + _evas_render_phase1_object_process(ctx, obj2->object, + obj->restack, + mapped_parent, + src_changed, + level + 1); + } + } } return src_changed; } @@ -798,18 +958,55 @@ _evas_render_phase1_object_no_changed_smart(Phase1_Context *p1ctx, int level) { Evas_Object_Protected_Data *obj2; + Phase1_Context *ctx = p1ctx; + Phase1_Context tmpctx; + Render_Cache *rc = NULL; + void *p_del_redir; RD(level, " smart + visible/was visible + not clip\n"); OBJ_ARRAY_PUSH(p1ctx->render_objects, obj); obj->render_pre = EINA_TRUE; - EINA_INLIST_FOREACH(evas_object_smart_members_get_direct(eo_obj), obj2) +#ifdef RENDCACHE + if (obj->no_change_render > 3) { - _evas_render_phase1_object_process(p1ctx, - obj2->object, - restack, - mapped_parent, - src_changed, - level + 1); + rc = evas_object_smart_render_cache_get(eo_obj); + if (!rc) + { + rc = _evas_render_phase1_object_render_cache_new(); + evas_object_smart_render_cache_set(eo_obj, rc); + ctx = &tmpctx; + *ctx = *p1ctx; + p_del_redir = p1ctx->e->update_del_redirect_array; + p1ctx->e->update_del_redirect_array = rc->update_del; + _evas_render_phase1_object_ctx_render_cache_fill(ctx, rc); + EINA_INLIST_FOREACH + (evas_object_smart_members_get_direct(eo_obj), obj2) + { + _evas_render_phase1_object_process(ctx, + obj2->object, + restack, + mapped_parent, + src_changed, + level + 1); + } + p1ctx->redraw_all = ctx->redraw_all; + p1ctx->e->update_del_redirect_array = p_del_redir; + } + _evas_render_phase1_object_ctx_render_cache_append(p1ctx, rc); + } + else +#endif + { + EINA_INLIST_FOREACH + (evas_object_smart_members_get_direct(eo_obj), obj2) + { + _evas_render_phase1_object_process(ctx, + obj2->object, + restack, + mapped_parent, + src_changed, + level + 1); + } } } @@ -860,14 +1057,17 @@ _evas_render_phase1_object_process(Phase1_Context *p1ctx, if (obj->delete_me == 2) OBJ_ARRAY_PUSH(p1ctx->delete_objects, obj); else if (obj->delete_me != 0) obj->delete_me++; + /* If the object will be removed, we should not cache anything during this run. */ if (obj->delete_me != 0) clean_them = EINA_TRUE; - if (obj->is_static_clip) return clean_them; + obj_changed = obj->changed; + + if (obj->is_static_clip) goto done; //Need pre render for the children of mapped object. //But only when they have changed. - if (mapped_parent && (!obj->changed)) return clean_them; + if (mapped_parent && (!obj->changed)) goto done; /* build active object list */ evas_object_clip_recalc(obj); @@ -906,7 +1106,6 @@ _evas_render_phase1_object_process(Phase1_Context *p1ctx, map = _evas_render_has_map(obj); hmap = _evas_render_had_map(obj); can_map = _evas_render_can_map(obj); - obj_changed = obj->changed; map_not_can_map = map & !can_map; if (EINA_UNLIKELY((restack && !map_not_can_map))) @@ -921,7 +1120,7 @@ _evas_render_phase1_object_process(Phase1_Context *p1ctx, _evas_render_phase1_object_mapped(p1ctx, eo_obj, obj, src_changed, hmap, is_active, obj_changed, level); - return clean_them; + goto done; } else if (EINA_UNLIKELY(hmap && !can_map)) _evas_render_phase1_object_mapped_had_restack(p1ctx, eo_obj, obj, @@ -934,6 +1133,7 @@ _evas_render_phase1_object_process(Phase1_Context *p1ctx, src_changed = _evas_render_phase1_object_changed_smart(p1ctx, eo_obj, obj, mapped_parent, + obj_changed, src_changed, is_active, level); else /* non smart object */ @@ -974,9 +1174,26 @@ _evas_render_phase1_object_process(Phase1_Context *p1ctx, } if (!is_active) obj->restack = EINA_FALSE; RD(level, "---]\n"); +done: + if (obj_changed) obj->no_change_render = 0; + else + { + if (obj->no_change_render < 255) obj->no_change_render++; + } return clean_them; } +// +// +// +//////////////////////////////////////////////////////////////////////////// + + + + + + + static Eina_Bool _evas_render_phase1_process(Phase1_Context *p1ctx) { @@ -2871,10 +3088,7 @@ evas_render_updates_internal(Evas *eo_e, /* phase 5. add obscures */ eina_evlog("+render_phase5", eo_e, 0.0, NULL); EINA_LIST_FOREACH(e->obscures, ll, r) - { - e->engine.func->output_redraws_rect_del(e->engine.data.output, - r->x, r->y, r->w, r->h); - } + evas_render_update_del(e, r->x, r->y, r->w, r->h); static int prepare = -1; if (prepare == -1) diff --git a/src/lib/evas/canvas/render2/evas_render2_old.c b/src/lib/evas/canvas/render2/evas_render2_old.c index f1699f3665..d57d31d7f7 100644 --- a/src/lib/evas/canvas/render2/evas_render2_old.c +++ b/src/lib/evas/canvas/render2/evas_render2_old.c @@ -211,8 +211,7 @@ _evas_render2_stage_explicit_updates(Evas_Public_Data *e) } // remove obscures from rendering - we keep them around EINA_LIST_FOREACH(e->obscures, l, r) - e->engine.func->output_redraws_rect_del(e->engine.data.output, - r->x, r->y, r->w, r->h); + evas_render_update_del(e, r->x, r->y, r->w, r->h); } static void diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index f955e1d3b3..ce4fc76bad 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -886,6 +886,8 @@ struct _Evas_Public_Data Eina_List *font_path; + Eina_Inarray *update_del_redirect_array; + int in_smart_calc; int smart_calc_count; @@ -1134,6 +1136,7 @@ struct _Evas_Object_Protected_Data unsigned int animator_ref; uint64_t callback_mask; + unsigned char no_change_render; unsigned char delete_me; Eina_Bool render_pre : 1; @@ -1593,6 +1596,9 @@ void evas_debug_magic_null(void); void evas_debug_magic_wrong(DATA32 expected, DATA32 supplied); void evas_debug_generic(const char *str); const char *evas_debug_magic_string_get(DATA32 magic); +void evas_render_update_del(Evas_Public_Data *e, int x, int y, int w, int h); +void evas_render_object_render_cache_free(Evas_Object *eo_obj, void *data); + void evas_object_smart_use(Evas_Smart *s); void evas_object_smart_unuse(Evas_Smart *s); void evas_smart_cb_descriptions_fix(Evas_Smart_Cb_Description_Array *a) EINA_ARG_NONNULL(1); @@ -1617,6 +1623,10 @@ void evas_object_smart_member_raise(Evas_Object *member); void evas_object_smart_member_lower(Evas_Object *member); void evas_object_smart_member_stack_above(Evas_Object *member, Evas_Object *other); void evas_object_smart_member_stack_below(Evas_Object *member, Evas_Object *other); +void evas_object_smart_render_cache_clear(Evas_Object *eo_obj); +void *evas_object_smart_render_cache_get(const Evas_Object *eo_obj); +void evas_object_smart_render_cache_set(Evas_Object *eo_obj, void *data); + const Eina_Inlist *evas_object_smart_members_get_direct(const Evas_Object *obj); void _efl_canvas_group_group_members_all_del(Evas_Object *obj); void _evas_object_smart_xy_update(Eo *eo_obj, Evas_Coord *px, Evas_Coord *py, Evas_Coord x, Evas_Coord y);