From: jiin.moon Date: Fri, 13 Jan 2017 04:05:54 +0000 (+0900) Subject: ecore_wayland: To use vsync as custom source of animator X-Git-Tag: submit/tizen/20170406.055746~25 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F78%2F123078%2F2;p=platform%2Fupstream%2Fefl.git ecore_wayland: To use vsync as custom source of animator If user does not call "ecore_animator_source_set(ECORE_ANIMATOR_SOURCE_CUSTOM)", animator would be working by timer. it means this patch does not effect without setting by user. I will check more regarding resource leak Change-Id: I679dc43c6657d80ac5bdc424945c44fd0c050e6a --- diff --git a/configure.ac b/configure.ac index 7621fdb..2bf07d2 100755 --- a/configure.ac +++ b/configure.ac @@ -3139,7 +3139,7 @@ EFL_INTERNAL_DEPEND_PKG([ECORE_WAYLAND], [eo]) EFL_INTERNAL_DEPEND_PKG([ECORE_WAYLAND], [eina]) EFL_DEPEND_PKG([ECORE_WAYLAND], [WAYLAND], - [wayland-client >= 1.3.0 wayland-cursor >= 1.3.0 xkbcommon >= 0.3.0 xdg-shell-client text-client tizen-extension-client wayland-tbm-client]) + [wayland-client >= 1.3.0 wayland-cursor >= 1.3.0 xkbcommon >= 0.3.0 xdg-shell-client text-client tizen-extension-client wayland-tbm-client libtdm-client]) EFL_EVAL_PKGS([ECORE_WAYLAND]) diff --git a/packaging/efl.spec b/packaging/efl.spec index 3b2072a..7f93e57 100644 --- a/packaging/efl.spec +++ b/packaging/efl.spec @@ -106,6 +106,7 @@ BuildRequires: pkgconfig(xcb-dri3) BuildRequires: pkgconfig(gbm) BuildRequires: pkgconfig(libtbm) BuildRequires: pkgconfig(libtdm) +BuildRequires: pkgconfig(libtdm-client) BuildRequires: pkgconfig(libdrm) BuildRequires: pkgconfig(wayland-client) BuildRequires: pkgconfig(wayland-server) diff --git a/src/Makefile_Ecore_Wayland.am b/src/Makefile_Ecore_Wayland.am index 614c698..c68eaed 100644 --- a/src/Makefile_Ecore_Wayland.am +++ b/src/Makefile_Ecore_Wayland.am @@ -15,6 +15,7 @@ lib/ecore_wayland/ecore_wl_input.c \ lib/ecore_wayland/ecore_wl_output.c \ lib/ecore_wayland/ecore_wl_window.c \ lib/ecore_wayland/ecore_wl_subsurf.c \ +lib/ecore_wayland/ecore_wl_anim_vsync.c \ lib/ecore_wayland/ecore_wl_private.h \ lib/ecore_wayland/ivi-application-protocol.c \ lib/ecore_wayland/ivi-application-client-protocol.h \ diff --git a/src/lib/ecore/Ecore_Common.h b/src/lib/ecore/Ecore_Common.h index 2e4e012..0d6556b 100644 --- a/src/lib/ecore/Ecore_Common.h +++ b/src/lib/ecore/Ecore_Common.h @@ -3470,6 +3470,23 @@ EAPI void ecore_animator_custom_source_tick_begin_callback_set(Ecore_Cb func, co */ EAPI void ecore_animator_custom_source_tick_end_callback_set(Ecore_Cb func, const void *data); + +/* TIZEN_ONLY : To use vsync as a custom source of animator */ +/** + * @internal + * @brief Set the function that quit a custom animator tick source + * + * @param func The function to call when ticking is to quit + * @param data The data passed to the tick quit function as its parameter + * + * @warning Do not use this function unless you know what you are doing. + * + */ + +EAPI void ecore_animator_custom_source_tick_quit_callback_set(Ecore_Cb func, const void *data); +/* TIZEN_ONLY : To use vsync as a custom source of animator */ + + /** * @brief Triggers a custom animator tick. * diff --git a/src/lib/ecore/ecore_anim.c b/src/lib/ecore/ecore_anim.c index a1d1c46..78dd14d 100644 --- a/src/lib/ecore/ecore_anim.c +++ b/src/lib/ecore/ecore_anim.c @@ -76,6 +76,12 @@ static Ecore_Cb begin_tick_cb = NULL; static const void *begin_tick_data = NULL; static Ecore_Cb end_tick_cb = NULL; static const void *end_tick_data = NULL; + +/* TIZEN_ONLY : To use vsync as a custom source of animator */ +static Ecore_Cb quit_tick_cb = NULL; +static const void *quit_tick_data = NULL; +/* TIZEN_ONLY : To use vsync as a custom source of animator */ + static Eina_Bool animator_ran = EINA_FALSE; static int timer_fd_read = -1; @@ -848,10 +854,29 @@ ecore_animator_custom_tick(void) _ecore_unlock(); } +/* TIZEN_ONLY : To use vsync as a custom source of animator */ +EAPI void +ecore_animator_custom_source_tick_quit_callback_set(Ecore_Cb func, + EINA_UNUSED const void *data) +{ + EINA_MAIN_LOOP_CHECK_RETURN; + _ecore_lock(); + _end_tick(); + quit_tick_cb = func; + quit_tick_data = data; + if (_have_animators()) _begin_tick(); + _ecore_unlock(); +} +/* TIZEN_ONLY : To use vsync as a custom source of animator */ + void _ecore_animator_shutdown(void) { _timer_tick_quit(); + +/* TIZEN_ONLY : To use vsync as a custom source of animator */ + if (src == ECORE_ANIMATOR_SOURCE_CUSTOM && quit_tick_cb) quit_tick_cb((void *)quit_tick_data); + _end_tick(); while (animators) { diff --git a/src/lib/ecore_wayland/ecore_wl.c b/src/lib/ecore_wayland/ecore_wl.c index 537395e..ab9efcc 100644 --- a/src/lib/ecore_wayland/ecore_wl.c +++ b/src/lib/ecore_wayland/ecore_wl.c @@ -610,16 +610,16 @@ ecore_wl_animator_source_set(Ecore_Animator_Source source) if (_ecore_wl_server_mode) return EINA_FALSE; - /* FIXME: check existing source. If custom, disable anim_callbacks */ - - /* based on the animator source we are using, setup or destroy callbacks */ + /* TIZEN_ONLY : To use vsync as custom source of animator */ switch (source) { case ECORE_ANIMATOR_SOURCE_CUSTOM: ecore_animator_custom_source_tick_begin_callback_set - (_ecore_wl_animator_tick_cb_begin, NULL); + (_ecore_wl_animator_vsync_tick_begin, NULL); ecore_animator_custom_source_tick_end_callback_set - (_ecore_wl_animator_tick_cb_end, NULL); + (_ecore_wl_animator_vsync_tick_end, NULL); + ecore_animator_custom_source_tick_quit_callback_set + (_ecore_wl_animator_vsync_tick_quit, NULL); break; case ECORE_ANIMATOR_SOURCE_TIMER: ecore_animator_custom_source_tick_begin_callback_set(NULL, NULL); diff --git a/src/lib/ecore_wayland/ecore_wl_anim_vsync.c b/src/lib/ecore_wayland/ecore_wl_anim_vsync.c new file mode 100644 index 0000000..7a964ce --- /dev/null +++ b/src/lib/ecore_wayland/ecore_wl_anim_vsync.c @@ -0,0 +1,398 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include "Ecore.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static tdm_client *client = NULL; +static tdm_client_output *output = NULL; +static tdm_client_vblank *vblank = NULL; +static Eina_Bool vblank_wait= 0; +static int _vsync_log_dom = -1; +static int tdm_fd = -1; +static unsigned int _tdm_req_fps = (1.0 / 60.0) * 1000; +static Eina_Thread_Queue *thq = NULL; +static Ecore_Thread *tdm_thread = NULL; +static Eina_Bool tdm_event_is_busy = EINA_FALSE; +static Eina_Bool tick_skip = EINA_FALSE; +static Eina_Spinlock tick_queue_lock; +static int tick_queue_count = 0; +typedef struct +{ + Eina_Thread_Queue_Msg head; + char val; +} Msg; + +#define DELTA_COUNT 10 +#undef ERR +#define ERR(...) EINA_LOG_DOM_ERR(_vsync_log_dom, __VA_ARGS__) + +#undef DBG +#define DBG(...) EINA_LOG_DOM_DBG(_vsync_log_dom, __VA_ARGS__) + +#undef INF +#define INF(...) EINA_LOG_DOM_INFO(_vsync_log_dom, __VA_ARGS__) + +#undef WRN +#define WRN(...) EINA_LOG_DOM_WARN(_vsync_log_dom, __VA_ARGS__) + +#undef CRI +#define CRI(...) EINA_LOG_DOM_CRIT(_vsync_log_dom, __VA_ARGS__) + + +static void +_tick_send(char val) +{ + Msg *msg; + void *ref; + msg = eina_thread_queue_send(thq, sizeof(Msg), &ref); + msg->val = val; + eina_thread_queue_send_done(thq, ref); +} + +static void +_tdm_send_time(double t) +{ + double *tim = malloc(sizeof(*tim)); + if (tim) + { + *tim = t; + DBG("tdm send time @%1.5f ... send %1.8f\n", ecore_time_get(), t); + eina_spinlock_take(&tick_queue_lock); + tick_queue_count++; + eina_spinlock_release(&tick_queue_lock); + ecore_thread_feedback(tdm_thread, tim); + } +} + +static void +_tdm_vblank_handler(tdm_client_vblank *vblank EINA_UNUSED, tdm_error error EINA_UNUSED, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, void *user_data EINA_UNUSED) +{ + vblank_wait = 0; + + if (tdm_event_is_busy) + { + static unsigned int pseq = 0; + if (pseq != sequence) + { + double t = (double)tv_sec + ((double)tv_usec / 1000000); + double tnow = ecore_time_get(); + static double tdelta[DELTA_COUNT]; + static double tdelta_avg = 0.0; + static int tdelta_n = 0; + + if (t > tnow) + { + if (tdelta_n > DELTA_COUNT) + { + t = t + tdelta_avg; + } + else if (tdelta_n < DELTA_COUNT) + { + tdelta[tdelta_n] = tnow - t; + tdelta_n++; + t = tnow; + } + else if (tdelta_n == DELTA_COUNT) + { + int i; + for (i = 0; i < DELTA_COUNT; i++) + tdelta_avg += tdelta[i]; + tdelta_avg /= (double)(DELTA_COUNT); + tdelta_n++; + } + } + else + { + tdelta_avg = 0.0; + tdelta_n = 0; + } + _tdm_send_time(t); + pseq = sequence; + } + } +} + +static tdm_error +_tdm_tick_schedule(void) +{ + tdm_error err; + err = tdm_client_vblank_wait(vblank, 1, _tdm_vblank_handler, NULL); + if (err != TDM_ERROR_NONE) + ERR("tdm client vblank wait failed %d\n", err); + else vblank_wait = 1; + return err; +} + +static void +_tdm_tick_core(void *data EINA_UNUSED, Ecore_Thread *thread) +{ + Msg *msg; + void *ref; + int tick = 0, fail_cnt = 0; + tdm_error err; + eina_thread_name_set(eina_thread_self(), "Eanimator-vsync"); + struct pollfd fds; + + fds.events = POLLIN; + fds.fd = tdm_fd; + fds.revents = 0; + while (!ecore_thread_check(thread)) + { + DBG("------- tdm_event_is_busy=%i", tdm_event_is_busy); + if (!tdm_event_is_busy) + { + DBG("wait..."); + msg = eina_thread_queue_wait(thq, &ref); + if (msg) + { + tick = msg->val; + eina_thread_queue_wait_done(thq, ref); + } + } + else + { + do + { + DBG("poll..."); + msg = eina_thread_queue_poll(thq, &ref); + if (msg) + { + tick = msg->val; + eina_thread_queue_wait_done(thq, ref); + } + } + while (msg); + } + if (tick == -1) + goto done; + else if ((tick == 1) && (!vblank_wait)) + { + fd_set rfds; + int ret; + + if(_tdm_tick_schedule() != TDM_ERROR_NONE) + goto done; + + FD_ZERO(&rfds); + FD_SET(tdm_fd, &rfds); + + ret = poll(&fds, 1, _tdm_req_fps); + + if ((ret == 1) && (FD_ISSET(tdm_fd, &rfds))) + { + fail_cnt = 0; + err = tdm_client_handle_events(client); + if (err != TDM_ERROR_NONE) { + ERR("tdm_client_handle_events failed err %d\n", err); + vblank_wait = 0; + _tdm_send_time(ecore_time_get()); + } + } + else + { + if ((err < 0) && (errno != EINTR) && (errno != EAGAIN)) /* normal case */ + goto done; + + fail_cnt = 0; + vblank_wait = 0; + _tdm_send_time(ecore_time_get()); + } + + } + else + { + fail_cnt++; + if (fail_cnt > 1000) + { + vblank_wait = 0; + _tdm_send_time(ecore_time_get()); + ERR("tdm vblank handler issue\n"); + fail_cnt = 0; + } + } + } + +done: + if (vblank) + tdm_client_vblank_destroy(vblank); + if (client) + tdm_client_destroy(client); + tdm_fd = -1; + vblank_wait = 0; + vblank = client = output = NULL; + + return; + +} + +static void +_tdm_tick_notify(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED, void *msg) +{ + int tick_queued; + + eina_spinlock_take(&tick_queue_lock); + tick_queued = tick_queue_count; + tick_queue_count--; + eina_spinlock_release(&tick_queue_lock); + DBG("notify.... %3.3f %i", *((double *)msg), tdm_event_is_busy); + + if (tdm_event_is_busy) + { + double *t = msg; + static double pt = 0.0; + + DBG("VSYNC %1.8f = delt %1.8f", *t, *t - pt); + if ((!tick_skip) && (tick_queued == 1) && (*t > pt)) + { + ecore_loop_time_set(*t); + ecore_animator_custom_tick(); + pt = *t; + } + else if (tick_queued > 10) + { + DBG("skip this vsync for schedule queued %d\n", tick_queued); + } + } + free(msg); +} + +static Eina_Bool +_tdm_client_init(void) +{ + tdm_error error; + double fps; + + if (!client) + { + client = tdm_client_create(&error); + if (error != TDM_ERROR_NONE) { + ERR("tdm_client_create error %d\n", error); + goto done; + } + + error = tdm_client_get_fd(client, &tdm_fd); + if (error != TDM_ERROR_NONE) { + ERR("tdm_client_get_fd error %d\n", error); + goto done; + } + + output = tdm_client_get_output(client, NULL, &error); + if (error != TDM_ERROR_NONE) + { + ERR("tdm_client_get_output error %d\n", error); + goto done; + } + + + vblank = tdm_client_output_create_vblank(output, &error); + if (error != TDM_ERROR_NONE) { + ERR("tdm_client_output_create_vblank error %d\n", error); + goto done; + } + + tdm_client_vblank_set_enable_fake(vblank, 1); + } + + fps = ecore_animator_frametime_get(); + if (_tdm_req_fps != fps * 1000) + _tdm_req_fps = fps * 1000; + tdm_client_vblank_set_fps(vblank, _tdm_req_fps); + + return EINA_TRUE; + +done: + if (vblank) tdm_client_vblank_destroy(vblank); + if (client) tdm_client_destroy(client); + vblank = client = output = NULL; + tdm_fd = -1; + return EINA_FALSE; +} + +static void +_tdm_tick_finished(void *data EINA_UNUSED, Ecore_Thread *thread EINA_UNUSED) +{ + + if (vblank) + tdm_client_vblank_destroy(vblank); + + if (client) + tdm_client_destroy(client); + + if (_vsync_log_dom > 0) + eina_log_domain_unregister(_vsync_log_dom); + + _vsync_log_dom = -1; + tdm_fd = -1; + vblank_wait = 0; + vblank = client = output = NULL; + + eina_spinlock_free(&tick_queue_lock); + eina_thread_queue_free(thq); + tick_queue_count = 0; + tdm_thread = NULL; + thq = NULL; +} + +void +_ecore_wl_animator_vsync_tick_quit(EINA_UNUSED void *data) +{ + int i; + _tick_send(-1); + + if (!thq) return; + + for (i = 0; (i < 500) && (tdm_thread); i++) + { + usleep(1000); + } +} + +void +_ecore_wl_animator_vsync_tick_begin(EINA_UNUSED void *data) +{ + if (_vsync_log_dom < 0) + _vsync_log_dom = eina_log_domain_register("ecore_anim_vsync", EINA_COLOR_LIGHTRED); + + if (_tdm_client_init()) + { + // if (getenv("ECORE_ANIMATOR_SKIP")) tick_skip = EINA_TRUE; + tdm_event_is_busy = 1; + if (!tdm_thread) + { + eina_spinlock_new(&tick_queue_lock); + thq = eina_thread_queue_new(); + tdm_thread = ecore_thread_feedback_run(_tdm_tick_core, + _tdm_tick_notify, + _tdm_tick_finished, + _tdm_tick_finished, + NULL, EINA_TRUE); + } + tick_queue_count = 0; + _tick_send(1); + } + else + ERR("tdm tick begin failed\n"); +} + +void +_ecore_wl_animator_vsync_tick_end(EINA_UNUSED void *data) +{ + tdm_event_is_busy = 0; + tick_queue_count = 0; + _tick_send(0); +} + diff --git a/src/lib/ecore_wayland/ecore_wl_private.h b/src/lib/ecore_wayland/ecore_wl_private.h index f059b23..1de69d6 100644 --- a/src/lib/ecore_wayland/ecore_wl_private.h +++ b/src/lib/ecore_wayland/ecore_wl_private.h @@ -426,4 +426,10 @@ struct wl_subcompositor *_ecore_wl_subcompositor_get(void); void _ecore_wl_input_device_manager_setup(unsigned int id); int ecore_wl_keycode_from_keysym(struct xkb_keymap *keymap, xkb_keysym_t keysym, xkb_keycode_t **keycodes); +/* TIZEN_ONLY : To use vsync as a custom source of animator */ +void _ecore_wl_animator_vsync_tick_begin(void *data); +void _ecore_wl_animator_vsync_tick_end(void *data); +void _ecore_wl_animator_vsync_tick_quit(void *data); +/* TIZEN_ONLY : To use vsync as a custom source of animator */ + #endif