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) <eduardo.lima@intel.com>



SVN revision: 77580
This commit is contained in:
Eduardo Lima (Etrunko) 2012-10-08 14:22:17 +00:00 committed by Eduardo de Barros Lima
parent 352926829e
commit 8a014153d4
6 changed files with 141 additions and 33 deletions

View File

@ -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.

View File

@ -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:

View File

@ -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);

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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 */