evas render - cache object arrays rto avoid processing them in phase1

evas render in phase1 in order to generate update rects, active,
render etc. object arrays has to walk every object in our tree. this
is a waste of time if we already have walked objects in a previous
frame if they havent changed, so cache this data in render cache in
smart objects to avoid re-walking and now just dumbly "memcpy" these
cached arrays into the master array. i have seen cpu usage by e drop
like about 15% in the sencarios i'm looking at "enlightenment
compositor with some window updating animation all the time, but most
other stuff being static).

@optimize
This commit is contained in:
Carsten Haitzler 2016-11-26 10:47:34 +09:00
parent 1bba6d5759
commit 69cb85aaca
7 changed files with 318 additions and 63 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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);
}

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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);