From 9b2b121e6f27d50da357a2bd055f375953249c29 Mon Sep 17 00:00:00 2001 From: Leandro Pereira Date: Tue, 18 Dec 2012 16:21:03 +0000 Subject: [PATCH] evas: Add thread threaded render queue SVN revision: 81280 --- src/Makefile_Evas.am | 1 + src/lib/evas/canvas/evas_main.c | 3 + src/lib/evas/common/evas_thread_render.c | 164 +++++++++++++++++++++++ src/lib/evas/include/evas_common.h | 16 +++ 4 files changed, 184 insertions(+) create mode 100644 src/lib/evas/common/evas_thread_render.c diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am index 8774ae1203..e7e17bb425 100644 --- a/src/Makefile_Evas.am +++ b/src/Makefile_Evas.am @@ -147,6 +147,7 @@ lib/evas/common/evas_scale_main.c \ lib/evas/common/evas_scale_sample.c \ lib/evas/common/evas_scale_smooth.c \ lib/evas/common/evas_scale_span.c \ +lib/evas/common/evas_thread_render.c \ lib/evas/common/evas_tiler.c \ lib/evas/common/evas_regionbuf.c \ lib/evas/common/evas_pipe.c \ diff --git a/src/lib/evas/canvas/evas_main.c b/src/lib/evas/canvas/evas_main.c index 9fc8aab0a3..8251ed0e3f 100644 --- a/src/lib/evas/canvas/evas_main.c +++ b/src/lib/evas/canvas/evas_main.c @@ -58,6 +58,8 @@ evas_init(void) #endif _evas_preload_thread_init(); + evas_thread_init(); + return _evas_init_count; shutdown_module: @@ -84,6 +86,7 @@ evas_shutdown(void) if (--_evas_init_count != 0) return _evas_init_count; + evas_thread_shutdown(); _evas_preload_thread_shutdown(); evas_async_events_shutdown(); evas_font_dir_cache_free(); diff --git a/src/lib/evas/common/evas_thread_render.c b/src/lib/evas/common/evas_thread_render.c new file mode 100644 index 0000000000..750bbc4c85 --- /dev/null +++ b/src/lib/evas/common/evas_thread_render.c @@ -0,0 +1,164 @@ +#include + +#include "evas_common.h" + +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 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) +{ + 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); +} + +EAPI void +evas_thread_cmd_enqueue(Evas_Thread_Command_Cb cb, void *data, size_t size) +{ + Evas_Thread_Command *cmd = evas_thread_cmd_new(cb, data, size); + if (!cmd) + return; + + evas_thread_queue_append(cmd, EINA_FALSE); +} + +EAPI void +evas_thread_queue_flush(Evas_Thread_Command_Cb cb, void *data, size_t size) +{ + Evas_Thread_Command *cmd = evas_thread_cmd_new(cb, data, size); + if (!cmd) + return; + + evas_thread_queue_append(cmd, EINA_TRUE); +} + +static void* +evas_thread_worker_func(void *data EINA_UNUSED, Eina_Thread thread EINA_UNUSED) +{ + while (1) + { + Evas_Thread_Command *cmd; + Eina_Inlist *queue; + + eina_lock_take(&evas_thread_queue_lock); + + while (!evas_thread_queue_ready) + { + if (exit_thread) + { + eina_lock_release(&evas_thread_queue_lock); + goto out; + } + eina_condition_wait(&evas_thread_queue_condition); + } + + if (!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; + evas_thread_queue_ready = EINA_FALSE; + + eina_lock_release(&evas_thread_queue_lock); + + while (queue) + { + 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); + } + } + +out: + /* WRN: add a memory barrier or use a lock if we add more code here */ + evas_thread_exited = 1; + return NULL; +} + +void +evas_thread_init(void) +{ + if (init_count++) return; + + eina_threads_init(); + + 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)) + CRIT("Could not create draw thread condition"); + if (!eina_thread_create(&evas_thread_worker, EINA_THREAD_NORMAL, 0, + evas_thread_worker_func, NULL)) + CRIT("Could not create draw thread"); +} + +void +evas_thread_shutdown(void) +{ + assert(init_count); + + if (--init_count) + return; + + eina_lock_take(&evas_thread_queue_lock); + + exit_thread = EINA_TRUE; + eina_condition_signal(&evas_thread_queue_condition); + + eina_lock_release(&evas_thread_queue_lock); + + while (!evas_thread_exited) + evas_async_events_process(); + + eina_thread_join(evas_thread_worker); + eina_lock_free(&evas_thread_queue_lock); + eina_condition_free(&evas_thread_queue_condition); + + eina_threads_shutdown(); +} diff --git a/src/lib/evas/include/evas_common.h b/src/lib/evas/include/evas_common.h index 4ba578a0d1..62df43c722 100644 --- a/src/lib/evas/include/evas_common.h +++ b/src/lib/evas/include/evas_common.h @@ -435,6 +435,18 @@ typedef void (*Gfx_Func_Convert) (DATA32 *src, DATA8 *dst, int src_jump, int dst /*****************************************************************************/ +typedef void (*Evas_Thread_Command_Cb)(void *data); +typedef struct _Evas_Thread_Command Evas_Thread_Command; + +struct _Evas_Thread_Command +{ + EINA_INLIST; + Evas_Thread_Command_Cb cb; + void *data; +}; + +/*****************************************************************************/ + typedef enum _RGBA_Image_Flags { RGBA_IMAGE_NOTHING = (0), @@ -1252,6 +1264,10 @@ Tilebuf_Rect *evas_common_regionbuf_rects_get (Regionbuf *rb); void evas_font_dir_cache_free(void); +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); /****/ /*****************************************************************************/