diff options
author | Haegeun Park <haegeun.park@samsung.com> | 2016-02-03 23:02:00 -0800 |
---|---|---|
committer | jutty.lee <jutty.lee@samsung.com> | 2017-01-11 17:22:12 +0900 |
commit | fee2a55b27667680a376b0e5c0e88d4371ff458b (patch) | |
tree | f4435b5fb72c820e1eafd5384eccf1a09a196650 | |
parent | 8ee0c30eb0950b0e142d77f4cb0da745085b2054 (diff) | |
download | efl-fee2a55b27667680a376b0e5c0e88d4371ff458b.tar.gz |
evas: (GL thread) Added GL thread renderer logics based of SW thread renderer
- Modified existing thread logic to manage multiple worker thread
- Added functions for thread enqueue, thread-id query
- Added a new threading mode 'FINISH' for waiting main-thread until command processed
Change-Id: I6cf0228a4adb04ea776e1c41936ab327ec06730e
-rw-r--r-- | src/lib/evas/canvas/evas_main.c | 4 | ||||
-rw-r--r-- | src/lib/evas/common/evas_thread_render.c | 313 | ||||
-rw-r--r-- | src/lib/evas/include/evas_common_private.h | 14 |
3 files changed, 230 insertions, 101 deletions
diff --git a/src/lib/evas/canvas/evas_main.c b/src/lib/evas/canvas/evas_main.c index 912760cc60..d89104ed41 100644 --- a/src/lib/evas/canvas/evas_main.c +++ b/src/lib/evas/canvas/evas_main.c @@ -83,7 +83,7 @@ evas_init(void) _evas_preload_thread_init(); evas_filter_init(); - if (!evas_thread_init()) + if (!evas_threads_init()) goto shutdown_filter; eina_log_timing(_evas_log_dom_global, @@ -160,7 +160,7 @@ evas_shutdown(void) evas_object_filter_cow = NULL; evas_object_mask_cow = NULL; - evas_thread_shutdown(); + evas_threads_shutdown(); _evas_preload_thread_shutdown(); evas_async_events_shutdown(); evas_module_shutdown(); diff --git a/src/lib/evas/common/evas_thread_render.c b/src/lib/evas/common/evas_thread_render.c index 85955669ac..ae7362faa3 100644 --- a/src/lib/evas/common/evas_thread_render.c +++ b/src/lib/evas/common/evas_thread_render.c @@ -2,17 +2,29 @@ #include <assert.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_Inarray evas_thread_queue; -static Evas_Thread_Command *evas_thread_queue_cache = NULL; -static unsigned 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; +typedef struct +{ + char *thread_name; + Eina_Thread worker; + Eina_Condition queue_condition; + Eina_Lock queue_lock; + Eina_Bool queue_ready; + Eina_Inarray queue; + Evas_Thread_Command *queue_cache; + unsigned int queue_cache_max; + + Eina_Condition finish_condition; + Eina_Lock finish_lock; + + volatile int exited; + Eina_Bool exit_thread; +} Evas_Thread; + +static int evas_threads_init_count = 0; + +static Evas_Thread evas_thread_software; +static Evas_Thread evas_thread_gl; +static Evas_Thread evas_thread_evgl; #define SHUTDOWN_TIMEOUT_RESET (0) #define SHUTDOWN_TIMEOUT_CHECK (1) @@ -30,15 +42,14 @@ _shutdown_timeout(double *time, int mode, int timeout_ms) return ((tv.tv_sec + tv.tv_usec / 1000000.0) * 1000.0 - (*time)) > timeout_ms ; } - static void -evas_thread_queue_append(Evas_Thread_Command_Cb cb, void *data, Eina_Bool do_flush) +evas_thread_queue_append(Evas_Thread *ev_thread, Evas_Thread_Command_Cb cb, void *data, Eina_Bool do_flush, Eina_Bool do_finish) { Evas_Thread_Command *cmd; - eina_lock_take(&evas_thread_queue_lock); + eina_lock_take(&ev_thread->queue_lock); - cmd = eina_inarray_grow(&evas_thread_queue, 1); + cmd = eina_inarray_grow(&ev_thread->queue, 1); if (cmd) { cmd->cb = cb; @@ -52,69 +63,129 @@ evas_thread_queue_append(Evas_Thread_Command_Cb cb, void *data, Eina_Bool do_flu if (do_flush) { - evas_thread_queue_ready = EINA_TRUE; - eina_condition_signal(&evas_thread_queue_condition); + ev_thread->queue_ready = EINA_TRUE; + eina_condition_signal(&ev_thread->queue_condition); + } + + if (do_finish) + { + eina_condition_wait(&ev_thread->finish_condition); } out: - eina_lock_release(&evas_thread_queue_lock); + eina_lock_release(&ev_thread->queue_lock); } EAPI void evas_thread_cmd_enqueue(Evas_Thread_Command_Cb cb, void *data) { - evas_thread_queue_append(cb, data, EINA_FALSE); + evas_thread_queue_append(&evas_thread_software, cb, data, EINA_FALSE, EINA_FALSE); } EAPI void evas_thread_queue_flush(Evas_Thread_Command_Cb cb, void *data) { - evas_thread_queue_append(cb, data, EINA_TRUE); + evas_thread_queue_append(&evas_thread_software, cb, data, EINA_TRUE, EINA_FALSE); } +EAPI void +evas_gl_thread_cmd_enqueue(int thread_type, Evas_Thread_Command_Cb cb, void *data, int thread_mode) +{ + Evas_Thread *ev_thread = NULL; + + if (thread_type == EVAS_GL_THREAD_TYPE_GL) + ev_thread = &evas_thread_gl; + else if (thread_type == EVAS_GL_THREAD_TYPE_EVGL) + ev_thread = &evas_thread_evgl; + else + { + ERR("GL thread type is invalid"); + goto out; + } + + if (thread_mode == EVAS_GL_THREAD_MODE_ENQUEUE) + evas_thread_queue_append(ev_thread, cb, data, EINA_FALSE, EINA_FALSE); + else if (thread_mode == EVAS_GL_THREAD_MODE_FLUSH) + evas_thread_queue_append(ev_thread, cb, data, EINA_TRUE, EINA_FALSE); + else if (thread_mode == EVAS_GL_THREAD_MODE_FINISH) + evas_thread_queue_append(ev_thread, cb, data, EINA_TRUE, EINA_TRUE); + else + { + ERR("GL thread mode is invalid"); + goto out; + } + +out: + return; +} + +EAPI Eina_Thread +evas_gl_thread_get(int thread_type) +{ + Evas_Thread *ev_thread = NULL; + + if (thread_type == EVAS_GL_THREAD_TYPE_GL) + ev_thread = &evas_thread_gl; + else if (thread_type == EVAS_GL_THREAD_TYPE_EVGL) + ev_thread = &evas_thread_evgl; + else + { + ERR("GL thread type is invalid"); + goto out; + } + + return ev_thread->worker; + +out: + return (Eina_Thread)NULL; +} + + static void* -evas_thread_worker_func(void *data EINA_UNUSED, Eina_Thread thread EINA_UNUSED) +evas_thread_worker_func(void *data, Eina_Thread thread EINA_UNUSED) { - eina_thread_name_set(eina_thread_self(), "Eevas-thread-wk"); + Evas_Thread *ev_thread = data; + eina_thread_name_set(eina_thread_self(), ev_thread->thread_name); while (1) { Evas_Thread_Command *cmd; unsigned int len, max; - eina_lock_take(&evas_thread_queue_lock); + eina_lock_take(&ev_thread->queue_lock); - while (!evas_thread_queue_ready) + while (!ev_thread->queue_ready) { - if (exit_thread) + if (ev_thread->exit_thread) { - eina_lock_release(&evas_thread_queue_lock); + eina_lock_release(&ev_thread->queue_lock); goto out; } - eina_condition_wait(&evas_thread_queue_condition); + eina_condition_signal(&ev_thread->finish_condition); + eina_condition_wait(&ev_thread->queue_condition); } - if (!eina_inarray_count(&evas_thread_queue)) + if (!eina_inarray_count(&ev_thread->queue)) { ERR("Signaled to find an empty queue. BUG!"); - evas_thread_queue_ready = EINA_FALSE; - eina_lock_release(&evas_thread_queue_lock); + ev_thread->queue_ready = EINA_FALSE; + eina_lock_release(&ev_thread->queue_lock); continue; } - cmd = evas_thread_queue.members; - evas_thread_queue.members = evas_thread_queue_cache; - evas_thread_queue_cache = cmd; + cmd = ev_thread->queue.members; + ev_thread->queue.members = ev_thread->queue_cache; + ev_thread->queue_cache = cmd; - max = evas_thread_queue.max; - evas_thread_queue.max = evas_thread_queue_cache_max; - evas_thread_queue_cache_max = max; + max = ev_thread->queue.max; + ev_thread->queue.max = ev_thread->queue_cache_max; + ev_thread->queue_cache_max = max; - len = evas_thread_queue.len; - evas_thread_queue.len = 0; + len = ev_thread->queue.len; + ev_thread->queue.len = 0; - evas_thread_queue_ready = EINA_FALSE; + ev_thread->queue_ready = EINA_FALSE; - eina_lock_release(&evas_thread_queue_lock); + eina_lock_release(&ev_thread->queue_lock); DBG("Evas render thread command queue length: %u", len); @@ -135,83 +206,82 @@ evas_thread_worker_func(void *data EINA_UNUSED, Eina_Thread thread EINA_UNUSED) out: /* WRN: add a memory barrier or use a lock if we add more code here */ - evas_thread_exited = 1; + ev_thread->exited = 1; return NULL; } -int -evas_thread_init(void) +static Eina_Bool +evas_thread_init(Evas_Thread *ev_thread, char *thread_name) { - if (init_count++) - return init_count; + ev_thread->thread_name = thread_name; + ev_thread->queue_ready = EINA_FALSE; + ev_thread->queue_cache = NULL; + ev_thread->queue_cache_max = 0; - exit_thread = EINA_FALSE; - evas_thread_exited = 0; + ev_thread->exit_thread = EINA_FALSE; + ev_thread->exited = 0; - if(!eina_threads_init()) + eina_inarray_step_set(&ev_thread->queue, sizeof (Eina_Inarray), sizeof (Evas_Thread_Command), 128); + + if (!eina_lock_new(&ev_thread->queue_lock)) { - CRI("Could not init eina threads"); - goto fail_on_eina_thread_init; + CRI("Could not create draw thread queue lock (%m)"); + goto fail_on_queue_lock_creation; } - - eina_inarray_step_set(&evas_thread_queue, sizeof (Eina_Inarray), sizeof (Evas_Thread_Command), 128); - - if (!eina_lock_new(&evas_thread_queue_lock)) + if (!eina_condition_new(&ev_thread->queue_condition, &ev_thread->queue_lock)) { - CRI("Could not create draw thread lock (%m)"); - goto fail_on_lock_creation; + CRI("Could not create draw thread queue condition (%m)"); + goto fail_on_queue_cond_creation; } - if (!eina_condition_new(&evas_thread_queue_condition, &evas_thread_queue_lock)) + if (!eina_lock_new(&ev_thread->finish_lock)) { - CRI("Could not create draw thread condition (%m)"); - goto fail_on_cond_creation; + CRI("Could not create draw thread finish lock (%m)"); + goto fail_on_finish_lock_creation; } - - if (!eina_thread_create(&evas_thread_worker, EINA_THREAD_NORMAL, -1, - evas_thread_worker_func, NULL)) + if (!eina_condition_new(&ev_thread->finish_condition, &ev_thread->queue_lock)) + { + CRI("Could not create draw thread finish condition (%m)"); + goto fail_on_finish_cond_creation; + } + if (!eina_thread_create(&ev_thread->worker, EINA_THREAD_NORMAL, -1, + evas_thread_worker_func, ev_thread)) { CRI("Could not create draw thread (%m)"); goto fail_on_thread_creation; } - - return init_count; + return EINA_TRUE; fail_on_thread_creation: - evas_thread_worker = 0; - eina_condition_free(&evas_thread_queue_condition); -fail_on_cond_creation: - eina_lock_free(&evas_thread_queue_lock); -fail_on_lock_creation: - eina_threads_shutdown(); -fail_on_eina_thread_init: - exit_thread = EINA_TRUE; - evas_thread_exited = 1; - return --init_count; + ev_thread->worker = 0; + eina_condition_free(&ev_thread->finish_condition); +fail_on_finish_cond_creation: + eina_lock_free(&ev_thread->finish_lock); +fail_on_finish_lock_creation: + eina_condition_free(&ev_thread->queue_condition); +fail_on_queue_cond_creation: + eina_lock_free(&ev_thread->queue_lock); +fail_on_queue_lock_creation: + ev_thread->exit_thread = EINA_TRUE; + ev_thread->exited = 1; + return EINA_FALSE; } -int -evas_thread_shutdown(void) +static void +evas_thread_shutdown(Evas_Thread *ev_thread) { - double to = 0 ; - - if (init_count <= 0) - { - ERR("Too many calls to shutdown, ignored."); - return 0; - } + double to = 0; - if (--init_count) - return init_count; + if (!ev_thread) return; - eina_lock_take(&evas_thread_queue_lock); + eina_lock_take(&ev_thread->queue_lock); - exit_thread = EINA_TRUE; - eina_condition_signal(&evas_thread_queue_condition); + ev_thread->exit_thread = EINA_TRUE; + eina_condition_signal(&ev_thread->queue_condition); - eina_lock_release(&evas_thread_queue_lock); + eina_lock_release(&ev_thread->queue_lock); _shutdown_timeout(&to, SHUTDOWN_TIMEOUT_RESET, SHUTDOWN_TIMEOUT); - while (!evas_thread_exited && (evas_async_events_process() != -1)) + while (!ev_thread->exited && (evas_async_events_process() != -1)) { if(_shutdown_timeout(&to, SHUTDOWN_TIMEOUT_CHECK, SHUTDOWN_TIMEOUT)) { @@ -220,16 +290,65 @@ evas_thread_shutdown(void) } } - eina_thread_join(evas_thread_worker); + eina_thread_join(ev_thread->worker); timeout_shutdown: - eina_lock_free(&evas_thread_queue_lock); - eina_condition_free(&evas_thread_queue_condition); + eina_condition_free(&ev_thread->finish_condition); + eina_lock_free(&ev_thread->finish_lock); + eina_condition_free(&ev_thread->queue_condition); + eina_lock_free(&ev_thread->queue_lock); + + ev_thread->worker = 0; + + free(ev_thread->queue_cache); + ev_thread->queue_cache = NULL; + eina_inarray_flush(&ev_thread->queue); +} + +int +evas_threads_init(void) +{ + if (evas_threads_init_count++) + return evas_threads_init_count; + + if (!eina_threads_init()) + { + CRI("Could not init eina threads"); + goto fail_on_eina_thread_init; + } + + if (!evas_thread_init(&evas_thread_software, "Evas-thread-wk-sw")) + goto fail_on_software_thread_init; + if (!evas_thread_init(&evas_thread_gl, "Evas-thread-wk-gl")) + goto fail_on_gl_thread_init; + if (!evas_thread_init(&evas_thread_evgl, "Evas-thread-wk-evgl")) + goto fail_on_evgl_thread_init; + return evas_threads_init_count; + +fail_on_evgl_thread_init: + evas_thread_shutdown(&evas_thread_gl); +fail_on_gl_thread_init: + evas_thread_shutdown(&evas_thread_software); +fail_on_software_thread_init: + eina_threads_shutdown(); +fail_on_eina_thread_init: + return --evas_threads_init_count; + } + +int +evas_threads_shutdown(void) +{ + if (evas_threads_init_count <= 0) + { + ERR("Too many calls to shutdown, ignored."); + return 0; + } - evas_thread_worker = 0; + if (--evas_threads_init_count) + return evas_threads_init_count; - free(evas_thread_queue_cache); - evas_thread_queue_cache = NULL; - eina_inarray_flush(&evas_thread_queue); + evas_thread_shutdown(&evas_thread_evgl); + evas_thread_shutdown(&evas_thread_gl); + evas_thread_shutdown(&evas_thread_software); eina_threads_shutdown(); diff --git a/src/lib/evas/include/evas_common_private.h b/src/lib/evas/include/evas_common_private.h index d52dec5fb3..38a2981e31 100644 --- a/src/lib/evas/include/evas_common_private.h +++ b/src/lib/evas/include/evas_common_private.h @@ -1324,10 +1324,20 @@ EAPI int evas_async_events_process_blocking(void); void evas_render_rendering_wait(Evas_Public_Data *evas); void evas_all_sync(void); -int evas_thread_init(void); -int evas_thread_shutdown(void); + +#define EVAS_GL_THREAD_TYPE_GL 1 +#define EVAS_GL_THREAD_TYPE_EVGL 2 + +#define EVAS_GL_THREAD_MODE_FINISH 0 +#define EVAS_GL_THREAD_MODE_FLUSH 1 +#define EVAS_GL_THREAD_MODE_ENQUEUE 2 + +int evas_threads_init(void); +int evas_threads_shutdown(void); 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); +EAPI void evas_gl_thread_cmd_enqueue(int thread_type, Evas_Thread_Command_Cb cb, void *data, int thread_mode); +EAPI Eina_Thread evas_gl_thread_get(int thread_type); typedef enum _Evas_Render_Mode { |