From 8a014153d437e9f41f15b6bdc72dd083c5f1447e Mon Sep 17 00:00:00 2001 From: "Eduardo Lima (Etrunko)" Date: Mon, 8 Oct 2012 14:22:17 +0000 Subject: [PATCH] Wayland_SHM: Add listener to frame callback This is the method necessary to synchronize Wayland and Evas rendering, similar to vblank sync that is used in X11. This solves the Wayland SHM render issues (tearing effect) without the need to add double buffering to the engine. In a near future, the SHM implementation will feature double (or triple) buffering and this syncrhonization mechanism will be changed to be optional. Patch based on the work started by Robert Bradford on ticket #1280 http://trac.enlightenment.org/e/ticket/1280 Signed-off-by: Eduardo Lima (Etrunko) SVN revision: 77580 --- legacy/ecore/ChangeLog | 6 ++ legacy/ecore/NEWS | 4 + .../src/lib/ecore_evas/ecore_evas_private.h | 3 + .../ecore_evas/ecore_evas_wayland_common.c | 90 ++++++++++++------- .../lib/ecore_evas/ecore_evas_wayland_shm.c | 69 +++++++++++++- .../src/lib/ecore_wayland/Ecore_Wayland.h | 2 + 6 files changed, 141 insertions(+), 33 deletions(-) diff --git a/legacy/ecore/ChangeLog b/legacy/ecore/ChangeLog index 5a7572561b..d9f5d9b39c 100644 --- a/legacy/ecore/ChangeLog +++ b/legacy/ecore/ChangeLog @@ -989,3 +989,9 @@ 2012-10-05 Cedric Bail * Properly reschedule call to curl. + +2012-10-05 Eduardo Lima (Etrunko) + + * Wayland SHM now features a mechanism to synchronize rendering with + the compositor, removing tearing effect in animations when using that + engine. diff --git a/legacy/ecore/NEWS b/legacy/ecore/NEWS index 708ed8fa48..f08395dfe0 100644 --- a/legacy/ecore/NEWS +++ b/legacy/ecore/NEWS @@ -15,6 +15,10 @@ Additions: * ecore_imf: - ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SIGNIN. - ECORE_IMF_PREEDIT_TYPE_SUB4~7 style. + * ecore_evas: + - Wayland SHM engine now features a mechanism to synchronize rendering with + the compositor, removing the tearing effect in animations when using that + engine. Fixes: * ecore_con_url: diff --git a/legacy/ecore/src/lib/ecore_evas/ecore_evas_private.h b/legacy/ecore/src/lib/ecore_evas/ecore_evas_private.h index be9032795f..664748cdc8 100644 --- a/legacy/ecore/src/lib/ecore_evas/ecore_evas_private.h +++ b/legacy/ecore/src/lib/ecore_evas/ecore_evas_private.h @@ -456,6 +456,9 @@ void _ecore_evas_wl_common_iconified_set(Ecore_Evas *ee, int iconify); void _ecore_evas_wl_common_maximized_set(Ecore_Evas *ee, int max); void _ecore_evas_wl_common_fullscreen_set(Ecore_Evas *ee, int full); void _ecore_evas_wl_common_ignore_events_set(Ecore_Evas *ee, int ignore); +int _ecore_evas_wl_common_pre_render(Ecore_Evas *ee); +int _ecore_evas_wl_common_render_updates(Ecore_Evas *ee); +void _ecore_evas_wl_common_post_render(Ecore_Evas *ee); int _ecore_evas_wl_common_render(Ecore_Evas *ee); void _ecore_evas_wl_common_screen_geometry_get(const Ecore_Evas *ee, int *x, int *y, int *w, int *h); void _ecore_evas_wl_common_screen_dpi_get(const Ecore_Evas *ee, int *xdpi, int *ydpi); diff --git a/legacy/ecore/src/lib/ecore_evas/ecore_evas_wayland_common.c b/legacy/ecore/src/lib/ecore_evas/ecore_evas_wayland_common.c index 748e022362..257fd6e11f 100644 --- a/legacy/ecore/src/lib/ecore_evas/ecore_evas_wayland_common.c +++ b/legacy/ecore/src/lib/ecore_evas/ecore_evas_wayland_common.c @@ -565,6 +565,57 @@ _ecore_evas_wl_common_ignore_events_set(Ecore_Evas *ee, int ignore) /* NB: Hmmm, may need to pass this to ecore_wl_window in the future */ } +int +_ecore_evas_wl_common_pre_render(Ecore_Evas *ee) +{ + int rend = 0; + Eina_List *ll = NULL; + Ecore_Evas *ee2 = NULL; + + if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); + + EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) + { + if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); + if (ee2->engine.func->fn_render) + rend |= ee2->engine.func->fn_render(ee2); + if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2); + } + + return rend; +} + +int +_ecore_evas_wl_common_render_updates(Ecore_Evas *ee) +{ + int rend = 0; + Eina_List *updates = NULL; + + if ((updates = evas_render_updates(ee->evas))) + { + Eina_List *l = NULL; + Eina_Rectangle *r; + + EINA_LIST_FOREACH(updates, l, r) + ecore_wl_window_damage(ee->engine.wl.win, + r->x, r->y, r->w, r->h); + + ecore_wl_flush(); + + evas_render_updates_free(updates); + rend = 1; + } + + return rend; +} + +void +_ecore_evas_wl_common_post_render(Ecore_Evas *ee) +{ + _ecore_evas_idle_timeout_update(ee); + if (ee->func.fn_post_render) ee->func.fn_post_render(ee); +} + int _ecore_evas_wl_common_render(Ecore_Evas *ee) { @@ -572,40 +623,15 @@ _ecore_evas_wl_common_render(Ecore_Evas *ee) if (!ee) return 0; if (!ee->visible) - evas_norender(ee->evas); - else { - Eina_List *ll = NULL, *updates = NULL; - Ecore_Evas *ee2 = NULL; - - if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee); - - EINA_LIST_FOREACH(ee->sub_ecore_evas, ll, ee2) - { - if (ee2->func.fn_pre_render) ee2->func.fn_pre_render(ee2); - if (ee2->engine.func->fn_render) - rend |= ee2->engine.func->fn_render(ee2); - if (ee2->func.fn_post_render) ee2->func.fn_post_render(ee2); - } - - if ((updates = evas_render_updates(ee->evas))) - { - Eina_List *l = NULL; - Eina_Rectangle *r; - - EINA_LIST_FOREACH(updates, l, r) - ecore_wl_window_damage(ee->engine.wl.win, - r->x, r->y, r->w, r->h); - - ecore_wl_flush(); - - evas_render_updates_free(updates); - _ecore_evas_idle_timeout_update(ee); - rend = 1; - } - - if (ee->func.fn_post_render) ee->func.fn_post_render(ee); + evas_norender(ee->evas); + return 0; } + + rend = _ecore_evas_wl_common_pre_render(ee); + rend |= _ecore_evas_wl_common_render_updates(ee); + _ecore_evas_wl_common_post_render(ee); + return rend; } diff --git a/legacy/ecore/src/lib/ecore_evas/ecore_evas_wayland_shm.c b/legacy/ecore/src/lib/ecore_evas/ecore_evas_wayland_shm.c index da98b32ecd..d2cf1b8640 100644 --- a/legacy/ecore/src/lib/ecore_evas/ecore_evas_wayland_shm.c +++ b/legacy/ecore/src/lib/ecore_evas/ecore_evas_wayland_shm.c @@ -37,11 +37,21 @@ static void _ecore_evas_wl_show(Ecore_Evas *ee); static void _ecore_evas_wl_hide(Ecore_Evas *ee); static void _ecore_evas_wl_alpha_set(Ecore_Evas *ee, int alpha); static void _ecore_evas_wl_transparent_set(Ecore_Evas *ee, int transparent); +static int _ecore_evas_wl_render(Ecore_Evas *ee); + +/* SHM Only */ static void _ecore_evas_wl_shm_pool_free(Ecore_Evas *ee); static void _ecore_evas_wl_shm_pool_create(Ecore_Evas *ee, size_t size); static void _ecore_evas_wl_buffer_free(Ecore_Evas *ee); static void _ecore_evas_wl_buffer_new(Ecore_Evas *ee, int w, int h); +/* Frame listener */ +static void _ecore_evas_wl_frame_complete(void *data, struct wl_callback *callback, uint32_t time); +static const struct wl_callback_listener frame_listener = +{ + _ecore_evas_wl_frame_complete, +}; + static Ecore_Evas_Engine_Func _ecore_wl_engine_func = { _ecore_evas_wl_free, @@ -97,7 +107,7 @@ static Ecore_Evas_Engine_Func _ecore_wl_engine_func = NULL, // modal set NULL, // demand attention set NULL, // focus skip set - _ecore_evas_wl_common_render, + _ecore_evas_wl_render, _ecore_evas_wl_common_screen_geometry_get, _ecore_evas_wl_common_screen_dpi_get }; @@ -476,6 +486,63 @@ _ecore_evas_wl_transparent_set(Ecore_Evas *ee, int transparent) } } +static void +_ecore_evas_wl_frame_complete(void *data, struct wl_callback *callback, uint32_t time __UNUSED__) +{ + Ecore_Evas *ee = data; + Ecore_Wl_Window *win = NULL; + + if (!ee) return; + if (!(win = ee->engine.wl.win)) return; + + win->frame_callback = NULL; + win->frame_pending = EINA_FALSE; + wl_callback_destroy(callback); + + if (win->surface) + { + win->frame_callback = wl_surface_frame(win->surface); + wl_callback_add_listener(win->frame_callback, &frame_listener, ee); + } +} + +static int +_ecore_evas_wl_render(Ecore_Evas *ee) +{ + int rend = 0; + Ecore_Wl_Window *win = NULL; + + if (!ee) return 0; + if (!ee->visible) + { + evas_norender(ee->evas); + return 0; + } + + if (!(win = ee->engine.wl.win)) return 0; + + rend = _ecore_evas_wl_common_pre_render(ee); + if (!(win->frame_pending)) + { + /* FIXME - ideally have an evas_changed_get to return the value + * of evas->changed to avoid creating this callback and + * destroying it again + */ + + if (!win->frame_callback) + { + win->frame_callback = wl_surface_frame(win->surface); + wl_callback_add_listener(win->frame_callback, &frame_listener, ee); + } + + rend |= _ecore_evas_wl_common_render_updates(ee); + if (rend) + win->frame_pending = EINA_TRUE; + } + _ecore_evas_wl_common_post_render(ee); + return rend; +} + static void _ecore_evas_wl_shm_pool_free(Ecore_Evas *ee) { diff --git a/legacy/ecore/src/lib/ecore_wayland/Ecore_Wayland.h b/legacy/ecore/src/lib/ecore_wayland/Ecore_Wayland.h index 02f3c1a6ce..8cd0f9d75a 100644 --- a/legacy/ecore/src/lib/ecore_wayland/Ecore_Wayland.h +++ b/legacy/ecore/src/lib/ecore_wayland/Ecore_Wayland.h @@ -198,6 +198,8 @@ struct _Ecore_Wl_Window Ecore_Wl_Input *pointer_device; Ecore_Wl_Input *keyboard_device; + Eina_Bool frame_pending; + struct wl_callback *frame_callback; /* FIXME: Ideally we should record the cursor name for this window * so we can compare and avoid unnecessary cursor set calls to wayland */