raster pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=f33161c9ea7e2848491ece52c2439e14bf8a2c21

commit f33161c9ea7e2848491ece52c2439e14bf8a2c21
Author: Carsten Haitzler (Rasterman) <ras...@rasterman.com>
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"

-- 


Reply via email to