Hi,
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 :-)
--
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 5fb3edc..9a75ee2 100644
--- a/src/lib/canvas/evas_object_main.c
+++ b/src/lib/canvas/evas_object_main.c
@@ -483,6 +483,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;
@@ -534,6 +535,7 @@ evas_object_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
obj->layer->evas->pointer.x,
obj->layer->evas->pointer.y, 1, 1);
}
+ evas_render_object_recalc(obj);
obj->cur.geometry.x = x;
obj->cur.geometry.y = y;
//// obj->cur.cache.geometry.validity = 0;
@@ -607,6 +609,9 @@ evas_object_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
obj->layer->evas->pointer.x,
obj->layer->evas->pointer.y, 1, 1);
}
+ /* FIXME: This should really call evas_render_object_recalc */
+ if (obj->layer) evas_render_invalidate(obj->layer->evas);
+/* evas_render_object_recalc(obj); */
obj->cur.geometry.w = w;
obj->cur.geometry.h = h;
//// obj->cur.cache.geometry.validity = 0;
@@ -699,6 +704,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);
@@ -746,6 +752,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);
@@ -859,7 +866,10 @@ 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;
+ evas_render_object_recalc(obj);
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..7589869 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,60 @@ _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 (obj->is_active && 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 +326,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 +409,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 +459,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 +542,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 +564,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 +669,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 5927d25..71dc99b 100644
--- a/src/lib/include/evas_private.h
+++ b/src/lib/include/evas_private.h
@@ -100,6 +100,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
@@ -284,6 +285,13 @@ struct _Evas_Callbacks
*/
};
+struct _Evas_Array
+{
+ Evas_Object **obj;
+ unsigned int total;
+ unsigned int count;
+};
+
struct _Evas
{
Evas_Object_List _list_data;
@@ -340,6 +348,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;
@@ -456,6 +470,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;
@@ -799,7 +816,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