ecore: Add new way to register animators

Summary:
We have back-ends that can generate their own tick sources, but
ecore_animator_add()/ecore_animator_timeline_add() gives no indication
which backend the animator is running on.  This means that all animators
have to cause all currently in use backends to tick.

For example, if under wayland 4 application windows are open, all 4
windows will create ticks when any animator is present.

These new animator APIs that take an evas object allow us to figure out
out the backend and only cause the appropriate one to tick.

Depends on D7040

Reviewers: devilhorns

Reviewed By: devilhorns

Subscribers: devilhorns, cedric, #reviewers, #committers

Tags: #efl

Differential Revision: https://phab.enlightenment.org/D7041
This commit is contained in:
Derek Foreman 2018-09-18 09:42:38 -05:00
parent 448c7ca2ce
commit 4dc1e8273d
5 changed files with 302 additions and 11 deletions

View File

@ -391,4 +391,9 @@ EAPI void *ecore_job_del(Ecore_Job *obj);
* @}
*/
#ifdef EFL_BETA_API_SUPPORT
EAPI Ecore_Animator *ecore_evas_animator_timeline_add(void *evo, double runtime, Ecore_Timeline_Cb func, const void *data);
EAPI Ecore_Animator *ecore_evas_animator_add(void *evo, Ecore_Task_Cb func, const void *data);
#endif /* EFL_BETA_API_SUPPORT */
#endif

View File

@ -44,6 +44,7 @@
#include "ecore_private.h"
static int _ecore_anim_log_dom = -1;
static Eina_Bool _ee_animators_setup = EINA_FALSE;
#ifdef ERR
# undef ERR
@ -98,6 +99,8 @@ static Eina_Bool tick_skip = EINA_FALSE;
extern volatile int exit_signal_received;
#endif
static Ecore_Evas_Object_Animator_Interface _anim_iface;
static void
_tick_send(signed char val)
{
@ -815,6 +818,8 @@ ecore_animator_del(Ecore_Animator *animator)
if (!animator) return NULL;
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
if (animator->ee) return _anim_iface.del(animator);
if (animator->delete_me)
{
data = animator->data;
@ -855,28 +860,36 @@ EAPI void
ecore_animator_freeze(Ecore_Animator *animator)
{
EINA_MAIN_LOOP_CHECK_RETURN;
if (!animator) return ;
if (animator->delete_me) return ;
if (!animator->suspended)
if (!animator) return;
if (animator->delete_me) return;
if (animator->suspended) return;
if (animator->ee)
{
animator->suspended = EINA_TRUE;
animators_suspended++;
if (!_have_animators()) _end_tick();
_anim_iface.freeze(animator);
return;
}
animator->suspended = EINA_TRUE;
animators_suspended++;
if (!_have_animators()) _end_tick();
}
EAPI void
ecore_animator_thaw(Ecore_Animator *animator)
{
EINA_MAIN_LOOP_CHECK_RETURN;
if (!animator) return ;
if (!animator) return;
if (animator->delete_me) return;
if (animator->suspended)
if (!animator->suspended) return;
if (animator->ee)
{
animator->suspended = EINA_FALSE;
animators_suspended--;
if (_have_animators()) _begin_tick();
_anim_iface.thaw(animator);
return;
}
animator->suspended = EINA_FALSE;
animators_suspended--;
if (_have_animators()) _begin_tick();
}
EAPI void
@ -1030,3 +1043,36 @@ _ecore_animator_init(void)
EINA_LOG_ERR("Ecore was unable to create a log domain.");
}
}
void
ecore_evas_object_animator_init(Ecore_Evas_Object_Animator_Interface *iface)
{
_anim_iface = *iface;
_ee_animators_setup = EINA_TRUE;
}
Ecore_Animator *
ecore_evas_animator_timeline_add(void *evo, double runtime, Ecore_Timeline_Cb func, const void *data)
{
Ecore_Animator *anim = NULL;
if (_ee_animators_setup)
anim = _anim_iface.timeline_add(evo, runtime, func, data);
if (anim) return anim;
return ecore_animator_timeline_add(runtime, func, data);
}
Ecore_Animator *
ecore_evas_animator_add(void *evo, Ecore_Task_Cb func, const void *data)
{
Ecore_Animator *anim = NULL;
if (_ee_animators_setup)
anim = _anim_iface.add(evo, func, data);
if (anim) return anim;
return ecore_animator_add(func, data);
}

View File

@ -220,11 +220,24 @@ struct _Ecore_Animator
Ecore_Timeline_Cb run_func;
void *run_data;
void *ee;
Eina_Bool delete_me : 1;
Eina_Bool suspended : 1;
Eina_Bool just_added : 1;
};
typedef struct _Ecore_Evas_Object_Animator_Interface
{
Ecore_Animator *(*timeline_add)(void *obj, double runtime, Ecore_Timeline_Cb func, const void *data);
Ecore_Animator *(*add)(void *obj, Ecore_Task_Cb func, const void *data);
void (*freeze)(Ecore_Animator *animator);
void (*thaw)(Ecore_Animator *animator);
void *(*del)(Ecore_Animator *animator);
} Ecore_Evas_Object_Animator_Interface;
EAPI void ecore_evas_object_animator_init(Ecore_Evas_Object_Animator_Interface *iface);
#define EVAS_FRAME_QUEUING 1 /* for test */
#define READBUFSIZ 65536

View File

@ -39,6 +39,8 @@
#define EFL_INTERNAL_UNSTABLE
#include "interfaces/efl_common_internal.h"
#include "ecore_private.h"
#ifndef O_BINARY
# define O_BINARY 0
#endif
@ -71,6 +73,14 @@ static const Efl_Event_Description *_event_description_get(Efl_Pointer_Action ac
//RENDER_SYNC
static int _ecore_evas_render_sync = 1;
static void _ecore_evas_animator_flush(Ecore_Evas *ee);
static Ecore_Animator *_ecore_evas_animator_timeline_add(void *evo, double runtime, Ecore_Timeline_Cb func, const void *data);
static Ecore_Animator *_ecore_evas_animator_add(void *evo, Ecore_Task_Cb func, const void *data);
static void _ecore_evas_animator_freeze(Ecore_Animator *animator);
static void _ecore_evas_animator_thaw(Ecore_Animator *animator);
static void *_ecore_evas_animator_del(Ecore_Animator *animator);
static void
_ecore_evas_focus_out_dispatch(Ecore_Evas *ee, Efl_Input_Device *seat)
{
@ -215,6 +225,9 @@ _ecore_evas_idle_enter(void *data EINA_UNUSED)
}
EINA_INLIST_FOREACH(ecore_evases, ee)
{
if (ee->ee_anim.deleted)
_ecore_evas_animator_flush(ee);
if (ee->draw_block) continue;
if (ee->manual_render)
@ -588,6 +601,8 @@ ecore_evas_engine_type_supported_get(Ecore_Evas_Engine_Type engine)
EAPI int
ecore_evas_init(void)
{
Ecore_Evas_Object_Animator_Interface iface;
if (++_ecore_evas_init_count != 1)
return _ecore_evas_init_count;
@ -629,6 +644,14 @@ ecore_evas_init(void)
_ecore_evas_app_comp_sync = EINA_FALSE;
else if (getenv("ECORE_EVAS_COMP_SYNC"))
_ecore_evas_app_comp_sync = EINA_TRUE;
iface.add = _ecore_evas_animator_add;
iface.timeline_add = _ecore_evas_animator_timeline_add;
iface.freeze = _ecore_evas_animator_freeze;
iface.thaw = _ecore_evas_animator_thaw;
iface.del = _ecore_evas_animator_del;
ecore_evas_object_animator_init(&iface);
return _ecore_evas_init_count;
shutdown_ecore:
@ -3041,6 +3064,54 @@ _ecore_evas_fps_debug_rendertime_add(double t)
}
}
static void
_ecore_evas_animator_detach(Ecore_Animator *a)
{
Ecore_Evas *ee;
Eina_Inlist *tmp;
if (a->delete_me) return;
tmp = EINA_INLIST_GET(a);
ee = a->ee;
if (a->suspended)
ee->ee_anim.suspended = eina_inlist_remove(ee->ee_anim.suspended, EINA_INLIST_GET(a));
else if ((!tmp->next) && (!tmp->prev) && (EINA_INLIST_GET(a) != ee->ee_anim.active))
return;
else
ee->ee_anim.active = eina_inlist_remove(ee->ee_anim.active, EINA_INLIST_GET(a));
a->suspended = EINA_FALSE;
}
static void
_ecore_evas_animators_do(Ecore_Evas *ee)
{
ee->ee_anim.run_list = ee->ee_anim.active;
ee->ee_anim.active = NULL;
while (ee->ee_anim.run_list)
{
Ecore_Animator *animator;
animator = EINA_INLIST_CONTAINER_GET(ee->ee_anim.run_list, Ecore_Animator);
ee->ee_anim.run_list = eina_inlist_remove(ee->ee_anim.run_list, EINA_INLIST_GET(animator));
if (!_ecore_call_task_cb(animator->func, animator->data) || animator->delete_me)
{
if (animator->delete_me) continue;
animator->delete_me = EINA_TRUE;
ee->ee_anim.deleted = eina_inlist_append(ee->ee_anim.deleted, EINA_INLIST_GET(animator));
}
else
{
ee->ee_anim.active = eina_inlist_append(ee->ee_anim.active, EINA_INLIST_GET(animator));
}
}
}
EAPI void
ecore_evas_animator_tick(Ecore_Evas *ee, Eina_Rectangle *viewport, double loop_time)
{
@ -3062,6 +3133,8 @@ ecore_evas_animator_tick(Ecore_Evas *ee, Eina_Rectangle *viewport, double loop_t
ee->animator_ran = EINA_TRUE;
efl_event_callback_call(ee->evas, EFL_EVENT_ANIMATOR_TICK, &a);
if (ee->ee_anim.active)
_ecore_evas_animators_do(ee);
// FIXME: We do not support partial animator in the subcanvas
EINA_LIST_FOREACH(ee->sub_ecore_evas, l, subee)
{
@ -5193,3 +5266,150 @@ ecore_evas_done(Ecore_Evas *ee, Eina_Bool single_window)
if (single_window)
evas_event_feed_mouse_in(ee->evas, (unsigned int)((unsigned long long)(ecore_time_get() * 1000.0) & 0xffffffff), NULL);
}
static Ecore_Animator *
_ecore_evas_animator_add(void *evo, Ecore_Task_Cb func, const void *data)
{
Ecore_Evas *ee;
Ecore_Animator *animator;
if (EINA_UNLIKELY(!eina_main_loop_is()))
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
if (!func)
{
ERR("callback function must be set up for an Ecore_Animator object.");
return NULL;
}
ee = ecore_evas_ecore_evas_get(evas_object_evas_get(evo));
if (!ee) return NULL;
/* If we don't have back-end specific ticks, fallback to old animators */
if (!ee->engine.func->fn_animator_register) return NULL;
animator = calloc(1, sizeof(Ecore_Animator));
if (!animator) return NULL;
animator->func = func;
animator->data = (void *)data;
animator->ee = ee;
ee->ee_anim.active = eina_inlist_append(ee->ee_anim.active, EINA_INLIST_GET(animator));
_ticking_start(ee);
return animator;
}
static Eina_Bool
_ecore_evas_animator_run(void *data)
{
Ecore_Animator *animator = data;
double pos = 0.0, t;
Eina_Bool run_ret;
t = ecore_loop_time_get();
if (animator->run > 0.0)
{
pos = (t - animator->start) / animator->run;
if (pos > 1.0) pos = 1.0;
else if (pos < 0.0)
pos = 0.0;
}
run_ret = animator->run_func(animator->run_data, pos);
if (eina_dbl_exact(pos, 1.0)) run_ret = EINA_FALSE;
return run_ret;
}
static Ecore_Animator *
_ecore_evas_animator_timeline_add(void *evo,
double runtime,
Ecore_Timeline_Cb func,
const void *data)
{
Ecore_Animator *animator;
if (runtime <= 0.0) runtime = 0.0;
animator = _ecore_evas_animator_add(evo, _ecore_evas_animator_run, NULL);
if (!animator) return NULL;
animator->data = animator;
animator->run_func = func;
animator->run_data = (void *)data;
animator->start = ecore_loop_time_get();
animator->run = runtime;
return animator;
}
static void *
_ecore_evas_animator_del(Ecore_Animator *in)
{
Ecore_Animator *animator = in;
Ecore_Evas *ee;
void *data = NULL;
if (animator->delete_me)
return animator->data;
ee = animator->ee;
_ecore_evas_animator_detach(animator);
ee->ee_anim.deleted = eina_inlist_append(ee->ee_anim.deleted, EINA_INLIST_GET(animator));
animator->delete_me = EINA_TRUE;
if (animator->run_func)
data = animator->run_data;
else
data = animator->data;
_ticking_stop(ee);
return data;
}
static void
_ecore_evas_animator_flush(Ecore_Evas *ee)
{
Ecore_Animator *l;
EINA_INLIST_FREE(ee->ee_anim.deleted, l)
{
ee->ee_anim.deleted = eina_inlist_remove(ee->ee_anim.deleted, EINA_INLIST_GET(l));
free(l);
}
}
void
_ecore_evas_animator_freeze(Ecore_Animator *in)
{
Ecore_Animator *animator = in;
Ecore_Evas *ee;
ee = animator->ee;
_ecore_evas_animator_detach(animator);
ee->ee_anim.suspended = eina_inlist_append(ee->ee_anim.suspended, EINA_INLIST_GET(animator));
animator->suspended = EINA_TRUE;
_ticking_stop(ee);
}
void
_ecore_evas_animator_thaw(Ecore_Animator *in)
{
Ecore_Animator *animator = in;
Ecore_Evas *ee;
EINA_MAIN_LOOP_CHECK_RETURN;
if (!animator) return;
if (animator->delete_me) return;
if (!animator->suspended) return;
ee = animator->ee;
ee->ee_anim.suspended = eina_inlist_remove(ee->ee_anim.suspended,
EINA_INLIST_GET(animator));
animator->suspended = EINA_FALSE;
ee->ee_anim.active = eina_inlist_append(ee->ee_anim.active,
EINA_INLIST_GET(animator));
_ticking_start(ee);
}

View File

@ -332,6 +332,13 @@ struct _Ecore_Evas
Ecore_Animator *anim;
unsigned int animator_count;
struct {
Eina_Inlist *active;
Eina_Inlist *deleted;
Eina_Inlist *suspended;
Eina_Inlist *run_list;
} ee_anim;
struct {
unsigned char avoid_damage;
unsigned char resize_shape : 1;