raster pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=f33161c9ea7e2848491ece52c2439e14bf8a2c21
commit f33161c9ea7e2848491ece52c2439e14bf8a2c21 Author: Carsten Haitzler (Rasterman) <[email protected]> Date: Thu Jul 2 18:24:18 2015 +0900 ecore animators - improve accuracy by having a thread do animator timing this will cause animators to be more accurate now with timing coming from a dedicated thread whose only reason in life is to trigger timed wakeups. the wakeup time is even adjusted with fmod to the exact frametime slot that is expected --- src/lib/ecore/ecore_anim.c | 173 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 138 insertions(+), 35 deletions(-) diff --git a/src/lib/ecore/ecore_anim.c b/src/lib/ecore/ecore_anim.c index b02d905..fd41235 100644 --- a/src/lib/ecore/ecore_anim.c +++ b/src/lib/ecore/ecore_anim.c @@ -4,6 +4,7 @@ #include <stdlib.h> #include <math.h> +#include <unistd.h> #include <Eo.h> @@ -37,8 +38,8 @@ struct _Ecore_Animator_Data typedef struct _Ecore_Animator_Data Ecore_Animator_Data; +static Eina_Bool _do_tick(void); static Eina_Bool _ecore_animator_run(void *data); -static Eina_Bool _ecore_animator(void *data); static int animators_delete_me = 0; static Ecore_Animator_Data *animators = NULL; @@ -46,7 +47,6 @@ static double animators_frametime = 1.0 / 30.0; static unsigned int animators_suspended = 0; static Ecore_Animator_Source src = ECORE_ANIMATOR_SOURCE_TIMER; -static Ecore_Timer *timer = NULL; static int ticking = 0; static Ecore_Cb begin_tick_cb = NULL; static const void *begin_tick_data = NULL; @@ -54,6 +54,139 @@ static Ecore_Cb end_tick_cb = NULL; static const void *end_tick_data = NULL; static Eina_Bool animator_ran = EINA_FALSE; + +static Eina_Thread_Queue *timer_thq = NULL; +static Ecore_Thread *timer_thread = NULL; +static volatile int timer_event_is_busy = 0; + +typedef struct +{ + Eina_Thread_Queue_Msg head; + char val; +} Msg; + +static void +_tick_send(char val) +{ + Msg *msg; + void *ref; + DBG("_tick_send(%i)", val); + msg = eina_thread_queue_send(timer_thq, sizeof(Msg), &ref); + msg->val = val; + eina_thread_queue_send_done(timer_thq, ref); +} + +static void +_timer_send_time(double t) +{ + double *tim = malloc(sizeof(*tim)); + if (tim) + { + *tim = t; + DBG(" ... send %1.8f", t); + ecore_thread_feedback(timer_thread, tim); + } +} + +static void +_timer_tick_core(void *data EINA_UNUSED, Ecore_Thread *thread) +{ + Msg *msg; + void *ref; + int tick = 0; + + while (!ecore_thread_check(thread)) + { + DBG("------- timer_event_is_busy=%i", timer_event_is_busy); + if (!timer_event_is_busy) + { + DBG("wait..."); + msg = eina_thread_queue_wait(timer_thq, &ref); + if (msg) + { + tick = msg->val; + eina_thread_queue_wait_done(timer_thq, ref); + } + } + else + { + do + { + DBG("poll..."); + msg = eina_thread_queue_poll(timer_thq, &ref); + if (msg) + { + tick = msg->val; + eina_thread_queue_wait_done(timer_thq, ref); + } + } + while (msg); + } + DBG("tick = %i", tick); + if (tick == -1) + { + timer_thread = NULL; + eina_thread_queue_free(timer_thq); + timer_thq = NULL; + return; + } + else if (tick) + { + double t0 = ecore_time_get(); + double d = fmod(t0, animators_frametime); + + usleep((animators_frametime - d) * 1000000); + _timer_send_time(t0 - d + animators_frametime); + } + } +} + +static void +_timer_tick_notify(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED, void *msg) +{ + DBG("notify.... %3.3f %i", *((double *)msg), timer_event_is_busy); + if (timer_event_is_busy) + { + double *t = msg; + static double pt = 0.0; + + DBG("VSYNC %1.8f = delt %1.8f", *t, *t - pt); + ecore_loop_time_set(*t); + _do_tick(); + pt = *t; + } + free(msg); +} + +static void +_timer_tick_begin(void) +{ + if (!timer_thq) + { + timer_thq = eina_thread_queue_new(); + timer_thread = ecore_thread_feedback_run(_timer_tick_core, + _timer_tick_notify, + NULL, NULL, NULL, EINA_TRUE); + } + timer_event_is_busy = 1; + _tick_send(1); +} + +static void +_timer_tick_end(void) +{ + if (!timer_thq) return; + timer_event_is_busy = 0; + _tick_send(0); +} + +static void +_timer_tick_quit(void) +{ + if (!timer_thq) return; + _tick_send(-1); +} + static Eina_Bool _have_animators(void) { @@ -72,16 +205,7 @@ _begin_tick(void) switch (src) { case ECORE_ANIMATOR_SOURCE_TIMER: - if (!timer) - { - double t_loop = ecore_loop_time_get(); - double sync_0 = 0.0; - double d = -fmod(t_loop - sync_0, animators_frametime); - - timer = _ecore_timer_loop_add(animators_frametime, - _ecore_animator, NULL); - _ecore_timer_util_delay(timer, d); - } + _timer_tick_begin(); break; case ECORE_ANIMATOR_SOURCE_CUSTOM: @@ -99,11 +223,7 @@ _end_tick(void) if (!ticking) return; ticking = 0; - if (timer) - { - _ecore_timer_del(timer); - timer = NULL; - } + _timer_tick_end(); if ((src == ECORE_ANIMATOR_SOURCE_CUSTOM) && end_tick_cb) end_tick_cb((void *)end_tick_data); @@ -659,6 +779,7 @@ ecore_animator_custom_tick(void) void _ecore_animator_shutdown(void) { + _timer_tick_quit(); _end_tick(); while (animators) { @@ -710,22 +831,4 @@ _ecore_animator_run(void *data) return run_ret; } -static Eina_Bool -_ecore_animator(void *data EINA_UNUSED) -{ - double t; - - Eina_Bool r; - _ecore_lock(); - // set _ecore_time_loop_time to the EXACT time that the timer - // should have ticked off (even if it didn't) - // if you have a custom animator tick, you may need to adjust inside - // it before calling ecore_animator_custom_tick() - t = fmod(_ecore_time_loop_time, animators_frametime); - _ecore_time_loop_time -= t; - r = _do_tick(); - _ecore_unlock(); - return r; -} - #include "ecore_animator.eo.c" --
