From 57bdbf6793fc8131b7e312598fec653bb16cecfa Mon Sep 17 00:00:00 2001 From: Chris Michael Date: Thu, 19 Mar 2015 16:15:11 -0400 Subject: [PATCH] evas-wayland-shm: Fix redrawing issues that were causing 'flashing' in latest engine code. Summary: As reported by derek & zmike, the previous engine refactor left some issues where the app would 'flash' during redraws due to buffer handling. This commit fixes that issue along with flashing during resize. @fix Signed-off-by: Chris Michael --- src/modules/evas/engines/wayland_shm/evas_engine.h | 7 +- src/modules/evas/engines/wayland_shm/evas_outbuf.c | 112 ++++++-- src/modules/evas/engines/wayland_shm/evas_shm.c | 292 ++++++++++++--------- 3 files changed, 250 insertions(+), 161 deletions(-) diff --git a/src/modules/evas/engines/wayland_shm/evas_engine.h b/src/modules/evas/engines/wayland_shm/evas_engine.h index 4a74f4f..3c4fcc2 100644 --- a/src/modules/evas/engines/wayland_shm/evas_engine.h +++ b/src/modules/evas/engines/wayland_shm/evas_engine.h @@ -67,6 +67,7 @@ struct _Shm_Leaf Shm_Data *data; Shm_Pool *resize_pool; Eina_Bool valid : 1; + Eina_Bool reconfigure : 1; }; typedef struct _Shm_Surface Shm_Surface; @@ -79,6 +80,8 @@ struct _Shm_Surface int w, h; int dx, dy; int num_buff; + int last_buff; + int curr_buff; Shm_Leaf leaf[MAX_BUFFERS]; Shm_Leaf *current; @@ -116,9 +119,9 @@ struct _Outbuf } priv; }; -Shm_Surface *_evas_shm_surface_create(struct wl_shm *shm, struct wl_surface *surface, int w, int h, Eina_Bool alpha); +Shm_Surface *_evas_shm_surface_create(struct wl_shm *shm, struct wl_surface *surface, int w, int h, int num_buff, Eina_Bool alpha); void _evas_shm_surface_destroy(Shm_Surface *surface); -void _evas_shm_surface_prepare(Shm_Surface *surface, int dx, int dy, int w, int h, int num_buff, uint32_t flags); +void _evas_shm_surface_reconfigure(Shm_Surface *surface, int dx, int dy, int w, int h, int num_buff, uint32_t flags); void _evas_shm_surface_swap(Shm_Surface *surface, Eina_Rectangle *rects, unsigned int count); void *_evas_shm_surface_data_get(Shm_Surface *surface, int *w, int *h); void _evas_shm_surface_redraw(Shm_Surface *surface); diff --git a/src/modules/evas/engines/wayland_shm/evas_outbuf.c b/src/modules/evas/engines/wayland_shm/evas_outbuf.c index cedd2f1..ab12299 100644 --- a/src/modules/evas/engines/wayland_shm/evas_outbuf.c +++ b/src/modules/evas/engines/wayland_shm/evas_outbuf.c @@ -5,9 +5,9 @@ #endif #include "evas_engine.h" -#define RED_MASK 0x00ff0000 -#define GREEN_MASK 0x0000ff00 -#define BLUE_MASK 0x000000ff +#define RED_MASK 0xff0000 +#define GREEN_MASK 0x00ff00 +#define BLUE_MASK 0x0000ff Outbuf * _evas_outbuf_setup(int w, int h, int rot, Outbuf_Depth depth, Eina_Bool alpha, struct wl_shm *shm, struct wl_surface *surface) @@ -43,13 +43,10 @@ _evas_outbuf_setup(int w, int h, int rot, Outbuf_Depth depth, Eina_Bool alpha, s } /* try to create the outbuf surface */ - if (!(ob->surface = _evas_shm_surface_create(shm, surface, w, h, alpha))) + if (!(ob->surface = + _evas_shm_surface_create(shm, surface, w, h, ob->num_buff, alpha))) goto surf_err; - /* call prepare function to setup first buffer */ - _evas_shm_surface_prepare(ob->surface, 0, 0, w, h, - ob->num_buff, ob->surface->flags); - eina_array_step_set(&ob->priv.onebuf_regions, sizeof(Eina_Array), 8); return ob; @@ -64,6 +61,27 @@ _evas_outbuf_free(Outbuf *ob) { LOGFN(__FILE__, __LINE__, __FUNCTION__); + while (ob->priv.pending_writes) + { + RGBA_Image *img; + Eina_Rectangle *rect; + + img = ob->priv.pending_writes->data; + ob->priv.pending_writes = + eina_list_remove_list(ob->priv.pending_writes, ob->priv.pending_writes); + + rect = img->extended_info; + +#ifdef EVAS_CSERVE2 + if (evas_cserve2_use_get()) + evas_cache2_image_close(&img->cache_entry); + else +#endif + evas_cache_image_drop(&img->cache_entry); + + eina_rectangle_free(rect); + } + _evas_outbuf_flush(ob, NULL, MODE_FULL); _evas_outbuf_idle_flush(ob); @@ -77,7 +95,43 @@ _evas_outbuf_free(Outbuf *ob) void _evas_outbuf_idle_flush(Outbuf *ob) { - _evas_shm_surface_redraw(ob->surface); + RGBA_Image *img; + Eina_Rectangle *rect; + + if (ob->priv.onebuf) + { + img = ob->priv.onebuf; + ob->priv.onebuf = NULL; + + rect = img->extended_info; + eina_rectangle_free(rect); + +#ifdef EVAS_CSERVE2 + if (evas_cserve2_use_get()) + evas_cache2_image_close(&img->cache_entry); + else +#endif + evas_cache_image_drop(&img->cache_entry); + } + else + { + while (ob->priv.prev_pending_writes) + { + img = ob->priv.prev_pending_writes->data; + ob->priv.prev_pending_writes = + eina_list_remove_list(ob->priv.prev_pending_writes, + ob->priv.prev_pending_writes); + rect = img->extended_info; +#ifdef EVAS_CSERVE2 + if (evas_cserve2_use_get()) + evas_cache2_image_close(&img->cache_entry); + else +#endif + evas_cache_image_drop(&img->cache_entry); + + eina_rectangle_free(rect); + } + } } void @@ -91,12 +145,6 @@ _evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects EINA_UNUSED, Evas_Render_Mode if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) return; - if (!ob->surface->current) - { - WRN("Cannot Flush. No Current Leaf !!"); - return; - } - /* check for pending writes */ if (!ob->priv.pending_writes) { @@ -114,6 +162,8 @@ _evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects EINA_UNUSED, Evas_Render_Mode EINA_ARRAY_ITER_NEXT(&ob->priv.onebuf_regions, i, rect, it) result[i] = *rect; + _evas_shm_surface_redraw(ob->surface); + /* force a buffer swap */ _evas_shm_surface_swap(ob->surface, result, n); @@ -197,27 +247,25 @@ _evas_outbuf_flush(Outbuf *ob, Tilebuf_Rect *rects EINA_UNUSED, Evas_Render_Mode i++; } + _evas_shm_surface_redraw(ob->surface); + /* force a buffer swap */ _evas_shm_surface_swap(ob->surface, result, n); } - - _evas_shm_surface_redraw(ob->surface); } Render_Engine_Swap_Mode _evas_outbuf_swapmode_get(Outbuf *ob) { - int i = 0, count = 0; + int i = 0; LOGFN(__FILE__, __LINE__, __FUNCTION__); - for (; i < ob->num_buff; i++) - { - if (ob->surface->leaf[i].busy) - count++; - } + i = (ob->surface->last_buff - ob->surface->curr_buff + + (ob->surface->last_buff > ob->surface->last_buff ? + 0 : ob->surface->num_buff)) % ob->surface->num_buff; - switch (count) + switch (i) { case 0: return MODE_COPY; @@ -263,8 +311,10 @@ _evas_outbuf_reconfigure(Outbuf *ob, int x, int y, int w, int h, int rot, Outbuf else ob->surface->flags = 0; - _evas_shm_surface_prepare(ob->surface, x, y, w, h, - ob->num_buff, ob->surface->flags); + _evas_shm_surface_reconfigure(ob->surface, x, y, w, h, + ob->num_buff, ob->surface->flags); + + _evas_outbuf_idle_flush(ob); } void * @@ -287,7 +337,7 @@ _evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, if (!(data = _evas_shm_surface_data_get(ob->surface, &bw, &bh))) { - ERR("Could not get surface data"); + /* ERR("Could not get surface data"); */ return NULL; } @@ -360,6 +410,8 @@ _evas_outbuf_update_region_new(Outbuf *ob, int x, int y, int w, int h, int *cx, return NULL; } + img->cache_entry.w = w; + img->cache_entry.h = h; img->cache_entry.flags.alpha |= ob->priv.destination_alpha ? 1 : 0; #ifdef EVAS_CSERVE2 @@ -462,7 +514,11 @@ _evas_outbuf_update_region_push(Outbuf *ob, RGBA_Image *update, int x, int y, in if (bpp <= 0) return; /* check for valid desination data */ - if (!(dst = _evas_shm_surface_data_get(ob->surface, &ww, &hh))) return; + if (!(dst = _evas_shm_surface_data_get(ob->surface, &ww, &hh))) + { + /* ERR("Could not get surface data"); */ + return; + } bpl = (ww * sizeof(int)); diff --git a/src/modules/evas/engines/wayland_shm/evas_shm.c b/src/modules/evas/engines/wayland_shm/evas_shm.c index 16c7d27..b9c0a6a 100644 --- a/src/modules/evas/engines/wayland_shm/evas_shm.c +++ b/src/modules/evas/engines/wayland_shm/evas_shm.c @@ -1,30 +1,10 @@ #include "evas_common_private.h" #include "evas_private.h" -#ifdef EVAS_CSERVE2 -# include "evas_cs2_private.h" -#endif #include "evas_engine.h" #include -static void -_evas_shm_surface_cb_frame(void *data, struct wl_callback *callback, uint32_t timestamp EINA_UNUSED) -{ - Shm_Surface *surf; - - LOGFN(__FILE__, __LINE__, __FUNCTION__); - - if (!(surf = data)) return; - if (callback != surf->frame_cb) return; - - wl_callback_destroy(callback); - surf->frame_cb = NULL; - surf->redraw = EINA_FALSE; -} - -static const struct wl_callback_listener _frame_listener = -{ - _evas_shm_surface_cb_frame -}; +static Eina_Bool _shm_leaf_create(Shm_Surface *surface, Shm_Leaf *leaf, int w, int h); +static void _shm_leaf_release(Shm_Leaf *leaf); static struct wl_shm_pool * _shm_pool_make(struct wl_shm *shm, int size, void **data) @@ -132,7 +112,10 @@ _shm_pool_allocate(Shm_Pool *pool, size_t size, int *offset) LOGFN(__FILE__, __LINE__, __FUNCTION__); if ((pool->used + size) > pool->size) - return NULL; + { + WRN("Shm Pool Too Small"); + return NULL; + } *offset = pool->used; pool->used += size; @@ -148,6 +131,26 @@ _shm_pool_reset(Shm_Pool *pool) pool->used = 0; } +static void +_shm_frame_release(void *data, struct wl_callback *callback, uint32_t timestamp EINA_UNUSED) +{ + Shm_Surface *surf; + + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (!(surf = data)) return; + if (callback != surf->frame_cb) return; + + wl_callback_destroy(surf->frame_cb); + surf->frame_cb = NULL; + surf->redraw = EINA_FALSE; +} + +static const struct wl_callback_listener _shm_frame_listener = +{ + _shm_frame_release +}; + static Shm_Data * _shm_data_create_from_pool(Shm_Pool *pool, int w, int h, Eina_Bool alpha) { @@ -170,8 +173,7 @@ _shm_data_create_from_pool(Shm_Pool *pool, int w, int h, Eina_Bool alpha) if (!(data->map = _shm_pool_allocate(pool, len, &offset))) { ERR("Could not map leaf data"); - free(data); - return NULL; + goto err; } if (alpha) @@ -183,14 +185,17 @@ _shm_data_create_from_pool(Shm_Pool *pool, int w, int h, Eina_Bool alpha) if (!data->buffer) { ERR("Could not create buffer from pool: %m"); - free(data); - return NULL; + goto err; } return data; + +err: + free(data); + return NULL; } -static void +static void _shm_data_create(Shm_Pool *alt_pool, Shm_Data **ret, Shm_Surface *surface, int w, int h) { Shm_Pool *pool; @@ -198,6 +203,8 @@ _shm_data_create(Shm_Pool *alt_pool, Shm_Data **ret, Shm_Surface *surface, int w LOGFN(__FILE__, __LINE__, __FUNCTION__); + if (ret) *ret = NULL; + if (alt_pool) { _shm_pool_reset(alt_pool); @@ -208,23 +215,20 @@ _shm_data_create(Shm_Pool *alt_pool, Shm_Data **ret, Shm_Surface *surface, int w if (!(pool = _shm_pool_create(surface->shm, ((w * sizeof(int)) * h)))) { ERR("Could not create shm pool"); - goto err; + return; } if (!(data = _shm_data_create_from_pool(pool, w, h, surface->alpha))) { ERR("Could not create data from pool"); _shm_pool_destroy(pool); - goto err; + return; } data->pool = pool; out: if (ret) *ret = data; - return; -err: - if (ret) *ret = NULL; } static void @@ -238,16 +242,6 @@ _shm_data_destroy(Shm_Data *data) } static void -_shm_leaf_release(Shm_Leaf *leaf) -{ - LOGFN(__FILE__, __LINE__, __FUNCTION__); - - if (leaf->data) _shm_data_destroy(leaf->data); - if (leaf->resize_pool) _shm_pool_destroy(leaf->resize_pool); - memset(leaf, 0, sizeof(*leaf)); -} - -static void _shm_buffer_release(void *data, struct wl_buffer *buffer) { Shm_Surface *surf; @@ -257,13 +251,20 @@ _shm_buffer_release(void *data, struct wl_buffer *buffer) LOGFN(__FILE__, __LINE__, __FUNCTION__); surf = data; - for (; i < surf->num_buff; i++) { leaf = &surf->leaf[i]; if ((leaf->data) && (leaf->data->buffer == buffer)) { +// DBG("Buffer Released: %d", (int)(leaf - &surf->leaf[0])); leaf->busy = 0; + + if (leaf->reconfigure) + { + _shm_leaf_release(leaf); + _shm_leaf_create(surf, leaf, surf->w, surf->h); + } + break; } } @@ -274,10 +275,43 @@ static const struct wl_buffer_listener _shm_buffer_listener = _shm_buffer_release }; +static Eina_Bool +_shm_leaf_create(Shm_Surface *surface, Shm_Leaf *leaf, int w, int h) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + _shm_data_create(leaf->resize_pool, &leaf->data, surface, w, h); + if (!leaf->data) + { + CRI("Failed to create leaf data"); + abort(); + } + + leaf->w = w; + leaf->h = h; + leaf->valid = EINA_TRUE; + + wl_buffer_add_listener(leaf->data->buffer, &_shm_buffer_listener, surface); + + return EINA_TRUE; +} + +static void +_shm_leaf_release(Shm_Leaf *leaf) +{ + LOGFN(__FILE__, __LINE__, __FUNCTION__); + + if (leaf->data) _shm_data_destroy(leaf->data); + if (leaf->resize_pool) _shm_pool_destroy(leaf->resize_pool); + memset(leaf, 0, sizeof(*leaf)); + leaf->valid = EINA_FALSE; +} + Shm_Surface * -_evas_shm_surface_create(struct wl_shm *shm, struct wl_surface *surface, int w, int h, Eina_Bool alpha) +_evas_shm_surface_create(struct wl_shm *shm, struct wl_surface *surface, int w, int h, int num_buff, Eina_Bool alpha) { Shm_Surface *surf; + int i = 0; LOGFN(__FILE__, __LINE__, __FUNCTION__); @@ -289,10 +323,25 @@ _evas_shm_surface_create(struct wl_shm *shm, struct wl_surface *surface, int w, surf->h = h; surf->shm = shm; surf->surface = surface; + surf->num_buff = num_buff; surf->alpha = alpha; surf->flags = 0; + /* create surface buffers */ + for (; i < surf->num_buff; i++) + { + if (!_shm_leaf_create(surf, &(surf->leaf[i]), w, h)) + { + ERR("Could not create surface leaf"); + goto err; + } + } + return surf; + +err: + _evas_shm_surface_destroy(surf); + return NULL; } void @@ -309,152 +358,133 @@ _evas_shm_surface_destroy(Shm_Surface *surface) } void -_evas_shm_surface_prepare(Shm_Surface *surface, int dx, int dy, int w, int h, int num_buff, uint32_t flags) +_evas_shm_surface_reconfigure(Shm_Surface *surface, int dx, int dy, int w, int h, int num_buff, uint32_t flags) { - Shm_Leaf *leaf = NULL; int i = 0, resize = 0; LOGFN(__FILE__, __LINE__, __FUNCTION__); resize = !!(flags & SURFACE_HINT_RESIZING); - /* update surface properties */ + for (; i < surface->num_buff; i++) + { + /* don't resize any busy leafs */ + if (surface->leaf[i].busy) + { + surface->leaf[i].reconfigure = EINA_TRUE; + continue; + } + + /* clear this leaf */ + _shm_leaf_release(&surface->leaf[i]); + } + surface->w = w; surface->h = h; surface->dx = dx; surface->dy = dy; + surface->flags = flags; surface->num_buff = num_buff; - for (; i < num_buff; i++) + for (i = 0; i < surface->num_buff; i++) { if (surface->leaf[i].busy) continue; - if ((!leaf) || (leaf->valid)) + + if ((resize) && (!surface->leaf[i].resize_pool)) { - leaf = &surface->leaf[i]; - break; + surface->leaf[i].resize_pool = + _shm_pool_create(surface->shm, 10 * 1024 * 1024); } - } - if (!leaf) - { - CRI("All buffers held by server"); - return; - } - - if ((!resize) && (leaf->resize_pool)) - { - _shm_data_destroy(leaf->data); - leaf->data = NULL; - - _shm_pool_destroy(leaf->resize_pool); - leaf->resize_pool = NULL; - } - - if (leaf->valid) - { - if ((leaf->w == w) && (leaf->h == h)) goto out; - } - - if (leaf->data) _shm_data_destroy(leaf->data); - leaf->data = NULL; - - if ((resize) && (!leaf->resize_pool)) - { - leaf->resize_pool = - _shm_pool_create(surface->shm, 6 * 1024 * 1024); - } - - _shm_data_create(leaf->resize_pool, &leaf->data, surface, w, h); - if (!leaf->data) - { - CRI("Failed to create leaf data"); - abort(); + if (!_shm_leaf_create(surface, &surface->leaf[i], w, h)) + { + CRI("Failed to create leaf data"); + abort(); + } } - - leaf->w = w; - leaf->h = h; - leaf->valid = EINA_TRUE; - - wl_buffer_add_listener(leaf->data->buffer, &_shm_buffer_listener, surface); - -out: - surface->current = leaf; } void _evas_shm_surface_swap(Shm_Surface *surface, Eina_Rectangle *rects, unsigned int count) { - Shm_Leaf *leaf; - Eina_Rectangle *rect; + Shm_Leaf *leaf = NULL; + int i = 0; LOGFN(__FILE__, __LINE__, __FUNCTION__); - if (!(leaf = surface->current)) + for (; i < surface->num_buff; i++) { - ERR("No Current Leaf"); - return; + if (surface->leaf[i].busy) continue; + if ((!leaf) || (leaf->valid)) + { + leaf = &surface->leaf[i]; + break; + } } - if (!leaf->valid) + if (!leaf) { - ERR("Leaf Not Valid"); + /* WRN("All buffers held by server"); */ return; } - rect = eina_rectangle_new(0, 0, 0, 0); + /* DBG("Current Leaf %d", (int)(leaf - &surface->leaf[0])); */ + + wl_surface_attach(surface->surface, leaf->data->buffer, 0, 0); + if ((rects) && (count > 0)) { unsigned int i = 0; for (; i < count; i++) - eina_rectangle_union(rect, &rects[i]); + wl_surface_damage(surface->surface, + rects[i].x, rects[i].y, + rects[i].w, rects[i].h); } else - { - Eina_Rectangle r; - - r.x = 0; r.y = 0; - r.w = leaf->w; r.h = leaf->h; + wl_surface_damage(surface->surface, 0, 0, leaf->w, leaf->h); - eina_rectangle_union(rect, &r); - } - - wl_surface_attach(surface->surface, leaf->data->buffer, 0, 0); - wl_surface_damage(surface->surface, rect->x, rect->y, rect->w, rect->h); wl_surface_commit(surface->surface); - eina_rectangle_free(rect); - leaf->busy = 1; surface->dx = 0; surface->dy = 0; surface->redraw = EINA_TRUE; + surface->last_buff = surface->curr_buff; + surface->curr_buff = (int)(leaf - &surface->leaf[0]); } void * -_evas_shm_surface_data_get(Shm_Surface *surface, int *bw, int *bh) +_evas_shm_surface_data_get(Shm_Surface *surface, int *w, int *h) { - Shm_Leaf *leaf; + Shm_Leaf *leaf = NULL; + int i = 0; LOGFN(__FILE__, __LINE__, __FUNCTION__); - if (bw) *bw = 0; - if (bh) *bh = 0; + if (w) *w = 0; + if (h) *h = 0; - if (!(leaf = surface->current)) + for (; i < surface->num_buff; i++) { - _evas_shm_surface_prepare(surface, 0, 0, surface->w, surface->h, - surface->num_buff, surface->flags); - - if (!(leaf = surface->current)) + if (surface->leaf[i].busy) continue; + if ((!leaf) || (leaf->valid)) { - CRI("NO Current Surface"); - return NULL; + leaf = &surface->leaf[i]; + break; } } - if (bw) *bw = leaf->w; - if (bh) *bh = leaf->h; + if (!leaf) + { + /* WRN("All buffers held by server"); */ + return NULL; + } + + /* DBG("Leaf Data Get %d", (int)(leaf - &surface->leaf[0])); */ + + if (w) *w = leaf->w; + if (h) *h = leaf->h; return leaf->data->map; } @@ -473,5 +503,5 @@ _evas_shm_surface_redraw(Shm_Surface *surface) if (!surface->surface) return; surface->frame_cb = wl_surface_frame(surface->surface); - wl_callback_add_listener(surface->frame_cb, &_frame_listener, surface); + wl_callback_add_listener(surface->frame_cb, &_shm_frame_listener, surface); } -- 2.7.4