efl: limit regression with async rendering.
authorCedric BAIL <cedric.bail@free.fr>
Sun, 30 Dec 2012 23:39:11 +0000 (23:39 +0000)
committerCedric BAIL <cedric.bail@free.fr>
Sun, 30 Dec 2012 23:39:11 +0000 (23:39 +0000)
NOTE: There is still an issue with text rendering, that
is still 4 times slower and impact all text object (text,
textblock and textgrid).

SVN revision: 81912

src/lib/evas/canvas/evas_async_events.c
src/lib/evas/canvas/evas_render.c
src/lib/evas/common/evas_thread_render.c
src/lib/evas/include/evas_common.h

index 209ba8e..fe81be0 100644 (file)
@@ -15,6 +15,9 @@ static int _fd_write = -1;
 static int _fd_read = -1;
 static pid_t _fd_pid = 0;
 
+static Eina_Lock async_lock;
+static Eina_Inarray async_queue;
+
 static int _init_evas_event = 0;
 
 typedef struct _Evas_Event_Async       Evas_Event_Async;
@@ -71,6 +74,9 @@ evas_async_events_init(void)
 
    fcntl(_fd_read, F_SETFL, O_NONBLOCK);
 
+   eina_lock_new(&async_lock);
+   eina_inarray_step_set(&async_queue, sizeof (Eina_Inarray), sizeof (Evas_Event_Async), 16);
+
    return _init_evas_event;
 }
 
@@ -85,6 +91,9 @@ evas_async_events_shutdown(void)
    _fd_read = -1;
    _fd_write = -1;
 
+   eina_lock_free(&async_lock);
+   eina_inarray_flush(&async_queue);
+
    return _init_evas_event;
 }
 
@@ -108,15 +117,40 @@ evas_async_events_fd_get(void)
 static int
 _evas_async_events_process_single(void)
 {
-   Evas_Event_Async *ev;
+   int wakeup;
    int ret;
 
-   ret = read(_fd_read, &ev, sizeof(Evas_Event_Async *));
-   if (ret == sizeof(Evas_Event_Async *))
+   ret = read(_fd_read, &wakeup, sizeof(int));
+   if (ret == sizeof(int))
      {
-        if (ev->func) ev->func((void *)ev->target, ev->type, ev->event_info);
-        free(ev);
-        return 1;
+        static Evas_Event_Async *memory = NULL;
+        static unsigned int memory_max = 0;
+        Evas_Event_Async *ev;
+        unsigned int len;
+        unsigned int max;
+
+        eina_lock_take(&async_lock);
+
+        ev = async_queue.members;
+        async_queue.members = memory;
+        memory = ev;
+
+        max = async_queue.max;
+        async_queue.max = memory_max;
+        memory_max = max;
+
+        len = async_queue.len;
+        async_queue.len = 0;
+
+        eina_lock_release(&async_lock);
+        
+        while (len > 0)
+          {
+             if (ev->func) ev->func((void *)ev->target, ev->type, ev->event_info);
+             ev++;
+             len--;
+          }
+        ret = 1;
      }
    else if (ret < 0)
      {
@@ -179,32 +213,44 @@ EAPI Eina_Bool
 evas_async_events_put(const void *target, Evas_Callback_Type type, void *event_info, Evas_Async_Events_Put_Cb func)
 {
    Evas_Event_Async *ev;
-   ssize_t check;
+   ssize_t check = sizeof (int);
    Eina_Bool result = EINA_FALSE;
+   int count;
 
    if (!func) return 0;
    if (_fd_write == -1) return 0;
 
    _evas_async_events_fork_handle();
-   
-   ev = calloc(1, sizeof (Evas_Event_Async));
-   if (!ev) return 0;
 
-   ev->func = func;
-   ev->target = target;
-   ev->type = type;
-   ev->event_info = event_info;
+   eina_lock_take(&async_lock);
+
+   count = async_queue.len;
+   ev = eina_inarray_add(&async_queue);
+   if (ev)
+     {
+        ev->func = func;
+        ev->target = target;
+        ev->type = type;
+        ev->event_info = event_info;
+     }
+
+   eina_lock_release(&async_lock);
 
-   do
+   if (count == 0 && ev)
      {
-        check = write(_fd_write, &ev, sizeof (Evas_Event_Async*));
+       int wakeup = 1;
+
+       do
+        {
+          check = write(_fd_write, &wakeup, sizeof (int));
+        }
+       while ((check != sizeof (int)) &&
+             ((errno == EINTR) || (errno == EAGAIN)));
      }
-   while ((check != sizeof (Evas_Event_Async*)) &&
-          ((errno == EINTR) || (errno == EAGAIN)));
 
    evas_cache_image_wakeup();
 
-   if (check == sizeof (Evas_Event_Async*))
+   if (check == sizeof (int))
      result = EINA_TRUE;
    else
      {
index 1e924d7..bed97c5 100644 (file)
@@ -1705,7 +1705,7 @@ evas_render_updates_internal(Evas *eo_e,
              e->render.data = updates_data;
              e->render.updates_cb = updates_func;
 
-             evas_thread_queue_flush((Evas_Thread_Command_Cb)done_func, done_data, 0);
+             evas_thread_queue_flush((Evas_Thread_Command_Cb)done_func, done_data);
           }
         else if (haveup)
           {
index 750bbc4..34b9dcd 100644 (file)
@@ -6,67 +6,61 @@ static Eina_Thread evas_thread_worker;
 static Eina_Condition evas_thread_queue_condition;
 static Eina_Lock evas_thread_queue_lock;
 static Eina_Bool evas_thread_queue_ready = EINA_FALSE;
-static Eina_Inlist *evas_thread_queue = NULL;
+static Eina_Inarray evas_thread_queue;
+
+static Evas_Thread_Command *evas_thread_queue_cache = NULL;
+static int evas_thread_queue_cache_max = 0;
+
 static volatile int evas_thread_exited = 0;
 static Eina_Bool exit_thread = EINA_FALSE;
 static int init_count = 0;
 
-static Evas_Thread_Command *
-evas_thread_cmd_new(Evas_Thread_Command_Cb cb, void *data, size_t size)
-{
-    Evas_Thread_Command *cmd = malloc(sizeof(*cmd) + size);
-    if (!cmd)
-      {
-         ERR("Out of memory allocating thread command.");
-         return NULL;
-      }
-
-    cmd->cb = cb;
-    if (size)
-      {
-         cmd->data = cmd + 1;
-         memcpy(cmd->data, data, size);
-      }
-    else
-      cmd->data = data;
-
-    return cmd;
-}
-
 static void
-evas_thread_queue_append(Evas_Thread_Command *cmd, Eina_Bool do_flush)
+evas_thread_queue_append(Evas_Thread_Command_Cb cb, void *data, Eina_Bool do_flush)
 {
-    eina_lock_take(&evas_thread_queue_lock);
-
-    evas_thread_queue = eina_inlist_append(evas_thread_queue, EINA_INLIST_GET(cmd));
-
-    if (do_flush)
-      {
-         evas_thread_queue_ready = EINA_TRUE;
-         eina_condition_signal(&evas_thread_queue_condition);
-      }
-
-    eina_lock_release(&evas_thread_queue_lock);
+   Evas_Thread_Command *cmd;
+
+   eina_lock_take(&evas_thread_queue_lock);
+
+   if (evas_thread_queue.members == NULL)
+     {
+        evas_thread_queue.members = evas_thread_queue_cache;
+        evas_thread_queue.len = 0;
+        evas_thread_queue.max = evas_thread_queue_cache_max;
+        evas_thread_queue_cache = NULL;
+        evas_thread_queue_cache_max = 0;
+     }
+
+   cmd = eina_inarray_add(&evas_thread_queue);
+   if (cmd)
+     {
+        cmd->cb = cb;
+        cmd->data = data;
+     }
+   else
+     {
+        ERR("Out of memory allocating thread command.");
+     }
+
+   if (do_flush)
+     {
+        evas_thread_queue_ready = EINA_TRUE;
+        eina_condition_signal(&evas_thread_queue_condition);
+     }
+
+   eina_lock_release(&evas_thread_queue_lock);
 }
 
 EAPI void
-evas_thread_cmd_enqueue(Evas_Thread_Command_Cb cb, void *data, size_t size)
+evas_thread_cmd_enqueue(Evas_Thread_Command_Cb cb, void *data)
 {
-    Evas_Thread_Command *cmd = evas_thread_cmd_new(cb, data, size);
-    if (!cmd)
-      return;
-
-    evas_thread_queue_append(cmd, EINA_FALSE);
+    evas_thread_queue_append(cb, data, EINA_FALSE);
 }
 
 EAPI void
-evas_thread_queue_flush(Evas_Thread_Command_Cb cb, void *data, size_t size)
+evas_thread_queue_flush(Evas_Thread_Command_Cb cb, void *data)
 {
-    Evas_Thread_Command *cmd = evas_thread_cmd_new(cb, data, size);
-    if (!cmd)
-      return;
-
-    evas_thread_queue_append(cmd, EINA_TRUE);
+    evas_thread_queue_append(cb, data, EINA_TRUE);
 }
 
 static void*
@@ -74,8 +68,10 @@ evas_thread_worker_func(void *data EINA_UNUSED, Eina_Thread thread EINA_UNUSED)
 {
     while (1)
       {
+         Evas_Thread_Command *head;
          Evas_Thread_Command *cmd;
-         Eina_Inlist *queue;
+         int len;
+         int max;
 
          eina_lock_take(&evas_thread_queue_lock);
 
@@ -89,31 +85,35 @@ evas_thread_worker_func(void *data EINA_UNUSED, Eina_Thread thread EINA_UNUSED)
               eina_condition_wait(&evas_thread_queue_condition);
            }
 
-         if (!evas_thread_queue)
+         if (!eina_inarray_count(&evas_thread_queue))
            {
               ERR("Signaled to find an empty queue. BUG!");
               eina_lock_release(&evas_thread_queue_lock);
               continue;
            }
 
-         queue = evas_thread_queue;
-         evas_thread_queue = NULL;
+         head = evas_thread_queue.members;
+         evas_thread_queue.members = NULL;
+         max = evas_thread_queue.max; evas_thread_queue.max = 0;
+         len = evas_thread_queue.len; evas_thread_queue.len = 0;
+         
          evas_thread_queue_ready = EINA_FALSE;
 
          eina_lock_release(&evas_thread_queue_lock);
 
-         while (queue)
+         cmd = head;
+         while (len)
            {
-              cmd = EINA_INLIST_CONTAINER_GET(queue, Evas_Thread_Command);
-
-              assert(cmd);
               assert(cmd->cb);
 
               cmd->cb(cmd->data);
 
-              queue = eina_inlist_remove(queue, queue);
-              free(cmd);
+              cmd++;
+              len--;
            }
+
+         evas_thread_queue_cache = head;
+         evas_thread_queue_cache_max = max;
       }
 
 out:
@@ -129,6 +129,8 @@ evas_thread_init(void)
 
     eina_threads_init();
 
+    eina_inarray_step_set(&evas_thread_queue, sizeof (Eina_Inarray), sizeof (Evas_Thread_Command), 128);
+
     if (!eina_lock_new(&evas_thread_queue_lock))
       CRIT("Could not create draw thread lock");
     if (!eina_condition_new(&evas_thread_queue_condition, &evas_thread_queue_lock))
@@ -160,5 +162,7 @@ evas_thread_shutdown(void)
     eina_lock_free(&evas_thread_queue_lock);
     eina_condition_free(&evas_thread_queue_condition);
 
+    eina_inarray_flush(&evas_thread_queue);
+
     eina_threads_shutdown();
 }
index b83b3e8..0102903 100644 (file)
@@ -443,7 +443,6 @@ typedef struct _Evas_Thread_Command Evas_Thread_Command;
 
 struct _Evas_Thread_Command
 {
-   EINA_INLIST;
    Evas_Thread_Command_Cb cb;
    void *data;
 };
@@ -1272,8 +1271,8 @@ void                 evas_render_rendering_wait(Evas_Public_Data *evas);
 
 void              evas_thread_init(void);
 void              evas_thread_shutdown(void);
-EAPI void         evas_thread_cmd_enqueue(Evas_Thread_Command_Cb cb, void *data, size_t size);
-EAPI void         evas_thread_queue_flush(Evas_Thread_Command_Cb cb, void *data, size_t size);
+EAPI void         evas_thread_cmd_enqueue(Evas_Thread_Command_Cb cb, void *data);
+EAPI void         evas_thread_queue_flush(Evas_Thread_Command_Cb cb, void *data);
 
 typedef enum _Evas_Render_Mode
 {