From f8ea554926295213004c4a7917ffb10cac7dfd8f Mon Sep 17 00:00:00 2001 From: Cedric BAIL Date: Sun, 30 Dec 2012 23:39:11 +0000 Subject: [PATCH] efl: limit regression with async rendering. 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 | 84 +++++++++++++++++----- src/lib/evas/canvas/evas_render.c | 2 +- src/lib/evas/common/evas_thread_render.c | 118 ++++++++++++++++--------------- src/lib/evas/include/evas_common.h | 5 +- 4 files changed, 129 insertions(+), 80 deletions(-) diff --git a/src/lib/evas/canvas/evas_async_events.c b/src/lib/evas/canvas/evas_async_events.c index 209ba8e..fe81be0 100644 --- a/src/lib/evas/canvas/evas_async_events.c +++ b/src/lib/evas/canvas/evas_async_events.c @@ -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 { diff --git a/src/lib/evas/canvas/evas_render.c b/src/lib/evas/canvas/evas_render.c index 1e924d7..bed97c5 100644 --- a/src/lib/evas/canvas/evas_render.c +++ b/src/lib/evas/canvas/evas_render.c @@ -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) { diff --git a/src/lib/evas/common/evas_thread_render.c b/src/lib/evas/common/evas_thread_render.c index 750bbc4..34b9dcd 100644 --- a/src/lib/evas/common/evas_thread_render.c +++ b/src/lib/evas/common/evas_thread_render.c @@ -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(); } diff --git a/src/lib/evas/include/evas_common.h b/src/lib/evas/include/evas_common.h index b83b3e8..0102903 100644 --- a/src/lib/evas/include/evas_common.h +++ b/src/lib/evas/include/evas_common.h @@ -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 { -- 2.7.4