On Fri, Apr 11, 2008 at 8:56 PM, Cedric BAIL <[EMAIL PROTECTED]> wrote:
> Some of you already know, I am working on improving the speed of
> evas_render_phase1_object_process. The idea is that the list of
> active_object, and object to render will change much between to call
> to evas_render.
>
> I started by removing the use of evas_list and use a growing array
> of evas_object that is only freed on idle. This does bring only a
> small speed improvement. Then I started to cache the result
> evas_render_phase1_object_process and keep it alive except on layer
> change, show, hide and some color set case. On move and resize I
> wanted to just check if the state of stack of call to render_pre is
> still valid and call them accordingly. It's almost working. Just the
> resize is not. I don't understand why yet, but I can't make it work
> the same way as the move. Perhaps someone can help me on understanding
> this.
>
> So the code is attached for your fun, but don't commit it or it
> will break for sure :-)
After some sleep I found where was the problem and here is an updated
patch that finally work. It improve speed when you don't call
evas_object_show/hide and don't use layer. Each time you call them,
the cache will be droped in other case it will work.
This improvement will complexify the task when we will one day enable
render_pre for smart object as it make the assumption that no
evas_object are modified during call to evas_render_updates_internal.
Please review this patch and test it with your application.
--
Cedric BAIL
diff --git a/src/lib/canvas/evas_main.c b/src/lib/canvas/evas_main.c
index 7313a33..573e386 100644
--- a/src/lib/canvas/evas_main.c
+++ b/src/lib/canvas/evas_main.c
@@ -85,6 +85,8 @@ evas_free(Evas *e)
return;
MAGIC_CHECK_END();
+ if (e->walking_list == 0) evas_render_idle_flush(e);
+
if (e->walking_list > 0) return;
del = 1;
e->walking_list++;
diff --git a/src/lib/canvas/evas_object_main.c b/src/lib/canvas/evas_object_main.c
index e5e5fde..1d31f25 100644
--- a/src/lib/canvas/evas_object_main.c
+++ b/src/lib/canvas/evas_object_main.c
@@ -77,6 +77,7 @@ evas_object_change(Evas_Object *obj)
obj->layer->evas->changed = 1;
if (obj->changed) return;
+ evas_render_object_recalc(obj);
obj->changed = 1;
/* set changed flag on all objects this one clips too */
for (l = obj->clip.clipees; l; l = l->next)
@@ -483,6 +484,7 @@ evas_object_del(Evas_Object *obj)
while (obj->clip.clipees) evas_object_clip_unset(obj->clip.clipees->data);
if (obj->cur.clipper) evas_object_clip_unset(obj);
if (obj->smart.smart) evas_object_smart_del(obj);
+ if (obj->layer) evas_render_invalidate(obj->layer->evas);
evas_object_event_callback_call(obj, EVAS_CALLBACK_FREE, NULL);
evas_object_smart_cleanup(obj);
obj->delete_me = 1;
@@ -936,6 +938,7 @@ evas_object_show(Evas_Object *obj)
evas_object_inform_call_show(obj);
return;
}
+ if (obj->layer) evas_render_invalidate(obj->layer->evas);
obj->cur.visible = 1;
evas_object_change(obj);
evas_object_clip_dirty(obj);
@@ -983,6 +986,7 @@ evas_object_hide(Evas_Object *obj)
evas_object_inform_call_hide(obj);
return;
}
+ if (obj->layer) evas_render_invalidate(obj->layer->evas);
obj->cur.visible = 0;
evas_object_change(obj);
evas_object_clip_dirty(obj);
@@ -1096,6 +1100,8 @@ evas_object_color_set(Evas_Object *obj, int r, int g, int b, int a)
obj->cur.color.r = r;
obj->cur.color.g = g;
obj->cur.color.b = b;
+ if ((obj->cur.color.a == 0) || (a == 0))
+ if (obj->layer) evas_render_invalidate(obj->layer->evas);
if ((obj->cur.color.a == 0) && (a == 0)) return;
obj->cur.color.a = a;
evas_object_change(obj);
diff --git a/src/lib/canvas/evas_render.c b/src/lib/canvas/evas_render.c
index ccc5c52..2eb7026 100644
--- a/src/lib/canvas/evas_render.c
+++ b/src/lib/canvas/evas_render.c
@@ -4,6 +4,42 @@
static Evas_List *
evas_render_updates_internal(Evas *e, unsigned char make_updates, unsigned char do_draw);
+static inline void
+_evas_object_array_push(Evas_Array *array, Evas_Object *obj)
+{
+ if (!array) return ;
+ if (array->count + 1 > array->total)
+ {
+ Evas_Object **tmp;
+ unsigned int total;
+
+ total = array->total + 16;
+ tmp = realloc(array->obj, sizeof (Evas_Object*) * total);
+ if (!tmp) return ;
+
+ array->total = total;
+ array->obj = tmp;
+ }
+
+ array->obj[array->count++] = obj;
+}
+
+static void
+_evas_object_array_clean(Evas_Array *array)
+{
+ array->count = 0;
+}
+
+static void
+_evas_object_array_free(Evas_Array *array)
+{
+ array->count = 0;
+ array->total = 0;
+
+ if (array->obj) free(array->obj);
+ array->obj = NULL;
+}
+
/**
* To be documented.
*
@@ -68,24 +104,62 @@ evas_obscured_clear(Evas *e)
}
static void
-_evas_render_phase1_object_process(Evas *e, Evas_Object *obj, Evas_List **active_objects, Evas_List **restack_objects, Evas_List **delete_objects, int restack)
+_evas_render_phase1_direct(Evas *e, Evas_Array *render_objects)
{
- int is_active;
-
+ int i;
+
+ for (i = 0; i < render_objects->count; ++i)
+ {
+ Evas_Object *obj;
+
+ obj = render_objects->obj[i];
+ if (obj->changed) obj->func->render_pre(obj);
+ else
+ {
+ if (obj->smart.smart)
+ obj->func->render_pre(obj);
+ else
+ if (obj->rect_del)
+ {
+ e->engine.func->output_redraws_rect_del(e->engine.data.output,
+ obj->cur.cache.clip.x,
+ obj->cur.cache.clip.y,
+ obj->cur.cache.clip.w,
+ obj->cur.cache.clip.h);
+ }
+ }
+ }
+}
+
+static Evas_Bool
+_evas_render_phase1_object_process(Evas *e, Evas_Object *obj, Evas_Array *active_objects, Evas_Array *restack_objects, Evas_Array *delete_objects, Evas_Array *render_objects, int restack)
+{
+ int clean_them = 0;
+ int is_active;
+
+ obj->rect_del = 0;
+ obj->render_pre = 0;
+
/* if (obj->cur.cache.clip.dirty) */
evas_object_clip_recalc(obj);
/* because of clip objects - delete 2 cycles later */
if (obj->delete_me == 2)
- *delete_objects = evas_list_append(*delete_objects, obj);
+ _evas_object_array_push(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 = 1;
+
/* build active object list */
is_active = evas_object_is_active(obj);
- if ((is_active) || (obj->delete_me != 0))
- *active_objects = evas_list_append(*active_objects, obj);
+ obj->is_active = is_active;
+ if ((is_active) || (obj->delete_me != 0))
+ _evas_object_array_push(active_objects, obj);
if (restack)
{
obj->restack = 1;
obj->changed = 1;
+ clean_them = 1;
}
if (obj->changed)
{
@@ -93,6 +167,8 @@ _evas_render_phase1_object_process(Evas *e, Evas_Object *obj, Evas_List **active
{
Evas_Object_List *l;
+ if (clean_them == 0) _evas_object_array_push(render_objects, obj);
+ obj->render_pre = 1;
obj->func->render_pre(obj);
for (l = obj->smart.contained; l; l = l->next)
{
@@ -103,6 +179,7 @@ _evas_render_phase1_object_process(Evas *e, Evas_Object *obj, Evas_List **active
active_objects,
restack_objects,
delete_objects,
+ render_objects,
obj->restack);
}
}
@@ -111,11 +188,15 @@ _evas_render_phase1_object_process(Evas *e, Evas_Object *obj, Evas_List **active
if ((is_active) && (obj->restack) && (!obj->clip.clipees) &&
((evas_object_is_visible(obj) && (!obj->cur.have_clipees)) ||
(evas_object_was_visible(obj) && (!obj->prev.have_clipees))))
- *restack_objects = evas_list_append(*restack_objects, obj);
+ _evas_object_array_push(restack_objects, obj);
else if ((is_active) && (!obj->clip.clipees) &&
((evas_object_is_visible(obj) && (!obj->cur.have_clipees)) ||
(evas_object_was_visible(obj) && (!obj->prev.have_clipees))))
- obj->func->render_pre(obj);
+ {
+ if (clean_them == 0) _evas_object_array_push(render_objects, obj);
+ obj->func->render_pre(obj);
+ obj->render_pre = 1;
+ }
}
}
else
@@ -128,7 +209,9 @@ _evas_render_phase1_object_process(Evas *e, Evas_Object *obj, Evas_List **active
{
Evas_Object_List *l;
+ if (clean_them == 0) _evas_object_array_push(render_objects, obj);
obj->func->render_pre(obj);
+ obj->render_pre = 1;
for (l = obj->smart.contained; l; l = l->next)
{
Evas_Object *obj2;
@@ -138,6 +221,7 @@ _evas_render_phase1_object_process(Evas *e, Evas_Object *obj, Evas_List **active
active_objects,
restack_objects,
delete_objects,
+ render_objects,
restack);
}
}
@@ -145,21 +229,27 @@ _evas_render_phase1_object_process(Evas *e, Evas_Object *obj, Evas_List **active
{
if (evas_object_is_opaque(obj) &&
evas_object_is_visible(obj))
- e->engine.func->output_redraws_rect_del(e->engine.data.output,
- obj->cur.cache.clip.x,
- obj->cur.cache.clip.y,
- obj->cur.cache.clip.w,
- obj->cur.cache.clip.h);
+ {
+ if (clean_them == 0) _evas_object_array_push(render_objects, obj);
+ obj->rect_del = 1;
+ e->engine.func->output_redraws_rect_del(e->engine.data.output,
+ obj->cur.cache.clip.x,
+ obj->cur.cache.clip.y,
+ obj->cur.cache.clip.w,
+ obj->cur.cache.clip.h);
+ }
}
}
}
- if (!is_active) obj->restack = 0;
+ if (!is_active) obj->restack = 0;
+ return clean_them;
}
-static void
-_evas_render_phase1_process(Evas *e, Evas_List **active_objects, Evas_List **restack_objects, Evas_List **delete_objects)
+static Evas_Bool
+_evas_render_phase1_process(Evas *e, Evas_Array *active_objects, Evas_Array *restack_objects, Evas_Array *delete_objects, Evas_Array *render_objects)
{
- Evas_Object_List *l;
+ Evas_Object_List *l;
+ int clean_them = 0;
for (l = (Evas_Object_List *)e->layers; l; l = l->next)
{
@@ -172,9 +262,59 @@ _evas_render_phase1_process(Evas *e, Evas_List **active_objects, Evas_List **res
Evas_Object *obj;
obj = (Evas_Object *)l2;
- _evas_render_phase1_object_process(e, obj, active_objects,
- restack_objects,
- delete_objects, 0);
+ clean_them |= _evas_render_phase1_object_process(e, obj,
+ active_objects, restack_objects,
+ delete_objects, render_objects,
+ 0);
+ }
+ }
+
+ return clean_them;
+}
+
+static void
+_evas_render_check_pending_objects(Evas_Array *pending_objects, Evas *e)
+{
+ int i;
+
+ for (i = 0; i < pending_objects->count; ++i)
+ {
+ Evas_Object *obj;
+ int ok = 0;
+ int is_active;
+
+ obj = pending_objects->obj[i];
+
+ if (obj->render_pre
+ || obj->rect_del)
+ {
+ evas_object_clip_recalc(obj);
+ is_active = evas_object_is_active(obj);
+
+ if (obj->is_active == is_active)
+ {
+ if (obj->changed)
+ {
+ if (is_active && (!obj->clip.clipees) &&
+ ((evas_object_is_visible(obj) && (!obj->cur.have_clipees)) ||
+ (evas_object_was_visible(obj) && (!obj->prev.have_clipees))))
+ ok = 1;
+ }
+ else
+ {
+ if ((!obj->clip.clipees) && (obj->delete_me == 0) &&
+ (!obj->cur.have_clipees || (evas_object_was_visible(obj) && (!obj->prev.have_clipees)))
+ && evas_object_is_opaque(obj) && evas_object_is_visible(obj))
+ if (obj->rect_del)
+ ok = 1;
+ }
+ }
+ }
+
+ if (!ok)
+ {
+ evas_render_invalidate(e);
+ return ;
}
}
}
@@ -185,28 +325,37 @@ evas_render_updates_internal(Evas *e, unsigned char make_updates, unsigned char
Evas_List *updates = NULL;
Evas_List *obscuring_objects = NULL;
Evas_List *obscuring_objects_orig = NULL;
- Evas_List *active_objects = NULL;
- Evas_List *delete_objects = NULL;
- Evas_List *restack_objects = NULL;
Evas_List *ll;
- void *surface;
+ void *surface;
+ Evas_Bool clean_them = 0;
int ux, uy, uw, uh;
int cx, cy, cw, ch;
+ int i;
MAGIC_CHECK(e, Evas, MAGIC_EVAS);
return NULL;
MAGIC_CHECK_END();
if (!e->changed) return NULL;
+ /* Check if the modified object mean recalculating every thing */
+ if (&e->pending_objects.count > 0)
+ {
+ _evas_render_check_pending_objects(&e->pending_objects, e);
+ _evas_object_array_clean(&e->pending_objects);
+ }
+
/* phase 1. add extra updates for changed objects */
- _evas_render_phase1_process(e, &active_objects, &restack_objects, &delete_objects);
+ if (e->render_objects.count > 0)
+ _evas_render_phase1_direct(e, &e->render_objects);
+ else
+ clean_them = _evas_render_phase1_process(e, &e->active_objects, &e->restack_objects, &e->delete_objects, &e->render_objects);
+
/* phase 2. force updates for restacks */
- while (restack_objects)
+ for (i = 0; i < e->restack_objects.count; ++i)
{
Evas_Object *obj;
- obj = restack_objects->data;
- restack_objects = evas_list_remove(restack_objects, obj);
+ obj = e->restack_objects.obj[i];
obj->func->render_pre(obj);
e->engine.func->output_redraws_rect_add(e->engine.data.output,
obj->prev.cache.clip.x,
@@ -259,11 +408,11 @@ evas_render_updates_internal(Evas *e, unsigned char make_updates, unsigned char
r->x, r->y, r->w, r->h);
}
/* build obscure objects list of active objects that obscure */
- for (ll = active_objects; ll; ll = ll->next)
+ for (i = 0; i < e->active_objects.count; ++i)
{
Evas_Object *obj;
- obj = (Evas_Object *)(ll->data);
+ obj = e->active_objects.obj[i];
if (UNLIKELY(evas_object_is_opaque(obj) &&
evas_object_is_visible(obj) &&
(!obj->clip.clipees) &&
@@ -309,11 +458,11 @@ evas_render_updates_internal(Evas *e, unsigned char make_updates, unsigned char
obscuring_objects = evas_list_append(obscuring_objects, obj);
}
/* render all object that intersect with rect */
- for (ll = active_objects; ll; ll = ll->next)
+ for (i = 0; i < e->active_objects.count; ++i)
{
Evas_Object *obj;
Evas_List *l3;
- obj = (Evas_Object *)(ll->data);
+ obj = e->active_objects.obj[i];
/* if it's in our outpout rect and it doesn't clip anything */
if (evas_object_is_in_output_rect(obj, ux, uy, uw, uh) &&
@@ -392,11 +541,11 @@ evas_render_updates_internal(Evas *e, unsigned char make_updates, unsigned char
/* clear redraws */
e->engine.func->output_redraws_clear(e->engine.data.output);
/* and do a post render pass */
- for (ll = active_objects; ll; ll = ll->next)
+ for (i = 0; i < e->active_objects.count; ++i)
{
Evas_Object *obj;
- obj = (Evas_Object *)(ll->data);
+ obj = e->active_objects.obj[i];
obj->pre_render_done = 0;
if ((obj->changed) && (do_draw))
{
@@ -414,17 +563,19 @@ evas_render_updates_internal(Evas *e, unsigned char make_updates, unsigned char
}
/* free our obscuring object list */
evas_list_free(obscuring_objects_orig);
- /* free our active object list */
- evas_list_free(active_objects);
/* delete all objects flagged for deletion now */
- while (delete_objects)
+ for (i = 0; i < e->delete_objects.count; ++i)
{
Evas_Object *obj;
- obj = (Evas_Object *)(delete_objects->data);
- delete_objects = evas_list_remove_list(delete_objects, delete_objects);
+ obj = e->delete_objects.obj[i];
evas_object_free(obj, 1);
}
+
+ /* If their are some object to restack or some object to delete, it's useless to keep the render object list around. */
+ if (clean_them)
+ evas_render_invalidate(e);
+
e->changed = 0;
e->viewport.changed = 0;
e->output.changed = 0;
@@ -517,4 +668,45 @@ evas_render_idle_flush(Evas *e)
if ((e->engine.func) && (e->engine.func->output_idle_flush) &&
(e->engine.data.output))
e->engine.func->output_idle_flush(e->engine.data.output);
+
+ _evas_object_array_free(&e->delete_objects);
+ _evas_object_array_free(&e->active_objects);
+ _evas_object_array_free(&e->restack_objects);
+ _evas_object_array_free(&e->render_objects);
+ _evas_object_array_free(&e->pending_objects);
}
+
+void
+evas_render_invalidate(Evas *e)
+{
+ MAGIC_CHECK(e, Evas, MAGIC_EVAS);
+ return;
+ MAGIC_CHECK_END();
+
+ _evas_object_array_clean(&e->active_objects);
+ _evas_object_array_clean(&e->render_objects);
+ _evas_object_array_clean(&e->pending_objects);
+
+ _evas_object_array_free(&e->restack_objects);
+ _evas_object_array_free(&e->delete_objects);
+}
+
+void
+evas_render_object_recalc(Evas_Object *obj)
+{
+ MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
+ return;
+ MAGIC_CHECK_END();
+
+ if (!obj->changed && obj->layer)
+ {
+ Evas *e;
+
+ e = obj->layer->evas;
+
+ if (e->active_objects.count > 0
+ && e->render_objects.count > 0)
+ _evas_object_array_push(&e->pending_objects, obj);
+ }
+}
+
diff --git a/src/lib/canvas/evas_stack.c b/src/lib/canvas/evas_stack.c
index 3a01eda..b4299e3 100644
--- a/src/lib/canvas/evas_stack.c
+++ b/src/lib/canvas/evas_stack.c
@@ -73,6 +73,7 @@ evas_object_raise(Evas_Object *obj)
evas_object_inform_call_restack(obj);
return;
}
+ if (obj->layer) evas_render_invalidate(obj->layer->evas);
obj->restack = 1;
evas_object_change(obj);
evas_object_inform_call_restack(obj);
@@ -132,6 +133,7 @@ evas_object_lower(Evas_Object *obj)
evas_object_inform_call_restack(obj);
return;
}
+ if (obj->layer) evas_render_invalidate(obj->layer->evas);
obj->restack = 1;
evas_object_change(obj);
evas_object_inform_call_restack(obj);
@@ -216,6 +218,7 @@ evas_object_stack_above(Evas_Object *obj, Evas_Object *above)
evas_object_inform_call_restack(obj);
return;
}
+ if (obj->layer) evas_render_invalidate(obj->layer->evas);
obj->restack = 1;
evas_object_change(obj);
evas_object_inform_call_restack(obj);
@@ -300,6 +303,7 @@ evas_object_stack_below(Evas_Object *obj, Evas_Object *below)
evas_object_inform_call_restack(obj);
return;
}
+ if (obj->layer) evas_render_invalidate(obj->layer->evas);
obj->restack = 1;
evas_object_change(obj);
evas_object_inform_call_restack(obj);
diff --git a/src/lib/include/evas_private.h b/src/lib/include/evas_private.h
index 317e985..483dd4e 100644
--- a/src/lib/include/evas_private.h
+++ b/src/lib/include/evas_private.h
@@ -104,6 +104,7 @@ typedef struct _Evas_Intercept_Func_Color Evas_Intercept_Func_Color;
typedef struct _Evas_Key_Grab Evas_Key_Grab;
typedef struct _Evas_Callbacks Evas_Callbacks;
typedef struct _Evas_Format Evas_Format;
+typedef struct _Evas_Array Evas_Array;
#define MAGIC_EVAS 0x70777770
#define MAGIC_OBJ 0x71777770
@@ -288,6 +289,13 @@ struct _Evas_Callbacks
*/
};
+struct _Evas_Array
+{
+ Evas_Object **obj;
+ unsigned int total;
+ unsigned int count;
+};
+
struct _Evas
{
Evas_Object_List _list_data;
@@ -344,6 +352,12 @@ struct _Evas
int info_magic;
} engine;
+ Evas_Array delete_objects;
+ Evas_Array active_objects;
+ Evas_Array restack_objects;
+ Evas_Array render_objects;
+ Evas_Array pending_objects;
+
int delete_grabs;
int walking_grabs;
Evas_List *grabs;
@@ -488,6 +502,9 @@ struct _Evas_Object
unsigned short repeat_events : 1;
unsigned short restack : 1;
unsigned short changed : 1;
+ unsigned short is_active : 1;
+ unsigned short render_pre : 1;
+ unsigned short rect_del : 1;
unsigned short mouse_in : 1;
unsigned short pre_render_done : 1;
unsigned short intercepted : 1;
@@ -832,7 +849,10 @@ void _evas_walk(Evas *e);
void _evas_unwalk(Evas *e);
EAPI int _evas_module_engine_inherit(Evas_Func *funcs, char *name);
-
+
+void evas_render_invalidate(Evas *e);
+void evas_render_object_recalc(Evas_Object *obj);
+
#define EVAS_API_OVERRIDE(func, api, prefix) \
(api)->func = prefix##func
#ifdef __cplusplus
-------------------------------------------------------------------------
This SF.net email is sponsored by the 2008 JavaOne(SM) Conference
Don't miss this year's exciting event. There's still time to save $100.
Use priority code J8TL2D2.
http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone
_______________________________________________
enlightenment-devel mailing list
enlightenment-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/enlightenment-devel