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

Reply via email to