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

Reply via email to