discomfitor pushed a commit to branch enlightenment-0.20. http://git.enlightenment.org/core/enlightenment.git/commit/?id=7aef5e74fde0a3d53a0f10f30fb38f363a593ece
commit 7aef5e74fde0a3d53a0f10f30fb38f363a593ece Author: Derek Foreman <der...@osg.samsung.com> Date: Tue Feb 16 13:28:10 2016 -0600 Rework wayland buffer handling We need to keep wayland buffers around even if they'll never be written to again. This is part of Buffer_Reference's task in weston, but we already have our pixmap abstraction which can serve mostly the same purpose. Remove the "buffer reference" stuff from e_pixmap and replace it with a kept buffer for the last commit. Add shared memory pool references to keep pools from going away on us. --- src/bin/e_comp_wl.c | 6 +- src/bin/e_comp_wl.h | 3 + src/bin/e_pixmap.c | 155 +++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 130 insertions(+), 34 deletions(-) diff --git a/src/bin/e_comp_wl.c b/src/bin/e_comp_wl.c index 60c0a81..381c7a9 100644 --- a/src/bin/e_comp_wl.c +++ b/src/bin/e_comp_wl.c @@ -1699,7 +1699,6 @@ _e_comp_wl_subsurface_destroy(struct wl_resource *resource) } _e_comp_wl_surface_state_finish(&sdata->cached); - e_comp_wl_buffer_reference(&sdata->cached_buffer_ref, NULL); /* the client is getting deleted, which means the pixmap will be getting * freed. We need to unset the surface user data */ @@ -1746,8 +1745,9 @@ _e_comp_wl_subsurface_commit_to_cache(E_Client *ec) sdata->cached.new_attach = EINA_TRUE; _e_comp_wl_surface_state_buffer_set(&sdata->cached, cdata->pending.buffer); - e_comp_wl_buffer_reference(&sdata->cached_buffer_ref, - cdata->pending.buffer); + e_pixmap_resource_set(ec->pixmap, cdata->pending.buffer); + e_pixmap_dirty(ec->pixmap); + e_pixmap_refresh(ec->pixmap); } sdata->cached.sx = cdata->pending.sx; diff --git a/src/bin/e_comp_wl.h b/src/bin/e_comp_wl.h index 48c085f..3a18920 100644 --- a/src/bin/e_comp_wl.h +++ b/src/bin/e_comp_wl.h @@ -56,7 +56,10 @@ struct _E_Comp_Wl_Buffer struct wl_resource *resource; struct wl_signal destroy_signal; struct wl_listener destroy_listener; + struct wl_listener deferred_destroy_listener; struct wl_shm_buffer *shm_buffer; + struct wl_shm_pool *pool; + E_Pixmap *discarding_pixmap; int32_t w, h; uint32_t busy; }; diff --git a/src/bin/e_pixmap.c b/src/bin/e_pixmap.c index 80d4232..af7f852 100644 --- a/src/bin/e_pixmap.c +++ b/src/bin/e_pixmap.c @@ -42,11 +42,13 @@ struct _E_Pixmap #ifdef HAVE_WAYLAND E_Comp_Wl_Buffer *buffer; - E_Comp_Wl_Buffer_Ref buffer_ref; + E_Comp_Wl_Buffer *held_buffer; struct wl_listener buffer_destroy_listener; + struct wl_listener held_buffer_destroy_listener; void *data; Eina_Rectangle opaque; uuid_t uuid; + Eina_List *free_buffers; #endif Eina_Bool usable : 1; @@ -55,15 +57,36 @@ struct _E_Pixmap }; #ifdef HAVE_WAYLAND + +static void +_e_pixmap_cb_deferred_buffer_destroy(struct wl_listener *listener, void *data EINA_UNUSED) +{ + E_Comp_Wl_Buffer *buffer; + + buffer = container_of(listener, E_Comp_Wl_Buffer, deferred_destroy_listener); + buffer->discarding_pixmap->free_buffers = eina_list_remove(buffer->discarding_pixmap->free_buffers, buffer); + buffer->discarding_pixmap = NULL; +} + static void _e_pixmap_cb_buffer_destroy(struct wl_listener *listener, void *data EINA_UNUSED) { E_Pixmap *cp; cp = container_of(listener, E_Pixmap, buffer_destroy_listener); - cp->data = NULL; + cp->buffer = NULL; cp->buffer_destroy_listener.notify = NULL; } + +static void +_e_pixmap_cb_held_buffer_destroy(struct wl_listener *listener, void *data EINA_UNUSED) +{ + E_Pixmap *cp; + + cp = container_of(listener, E_Pixmap, held_buffer_destroy_listener); + cp->held_buffer = NULL; + cp->held_buffer_destroy_listener.notify = NULL; +} #endif static void @@ -102,6 +125,67 @@ _e_pixmap_image_clear_x(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_U } #endif +#ifdef HAVE_WAYLAND +static void +_e_pixmap_wayland_buffer_release(E_Pixmap *cp, E_Comp_Wl_Buffer *buffer) +{ + if (!buffer) return; + + if (e_comp->rendering) + { + if (buffer->discarding_pixmap) return; + + buffer->discarding_pixmap = cp; + buffer->deferred_destroy_listener.notify = _e_pixmap_cb_deferred_buffer_destroy; + wl_signal_add(&buffer->destroy_signal, &buffer->deferred_destroy_listener); + cp->free_buffers = eina_list_append(cp->free_buffers, buffer); + return; + } + + buffer->busy--; + if (buffer->busy) return; + + wl_resource_queue_event(buffer->resource, WL_BUFFER_RELEASE); + wl_shm_pool_unref(buffer->pool); + buffer->pool = NULL; +} + +static void +_e_pixmap_wl_buffers_free(E_Pixmap *cp) +{ + E_Comp_Wl_Buffer *b; + + if (e_comp->rendering) return; + + EINA_LIST_FREE(cp->free_buffers, b) + { + wl_list_remove(&b->deferred_destroy_listener.link); + b->deferred_destroy_listener.notify = NULL; + _e_pixmap_wayland_buffer_release(cp, b); + b->discarding_pixmap = NULL; + } +} + +static void +_e_pixmap_wayland_image_clear(E_Pixmap *cp) +{ + EINA_SAFETY_ON_NULL_RETURN(cp); + + if (!cp->held_buffer) return; + if (!cp->held_buffer->pool) return; + + _e_pixmap_wayland_buffer_release(cp, cp->held_buffer); + if (cp->held_buffer_destroy_listener.notify) + { + wl_list_remove(&cp->held_buffer_destroy_listener.link); + cp->held_buffer_destroy_listener.notify = NULL; + } + + cp->data = NULL; + cp->held_buffer = NULL; +} +#endif + static void _e_pixmap_free(E_Pixmap *cp) { @@ -124,6 +208,7 @@ _e_pixmap_free(E_Pixmap *cp) break; case E_PIXMAP_TYPE_WL: #ifdef HAVE_WAYLAND + _e_pixmap_wayland_image_clear(cp); #endif break; default: @@ -546,7 +631,25 @@ e_pixmap_resource_set(E_Pixmap *cp, void *resource) { if ((!cp) || (cp->type != E_PIXMAP_TYPE_WL)) return; #ifdef HAVE_WAYLAND + if (cp->buffer == resource) return; + + if (cp->buffer) + { + cp->buffer->busy--; + if (!cp->buffer->busy) wl_resource_queue_event(cp->buffer->resource, WL_BUFFER_RELEASE); + } + if (cp->buffer_destroy_listener.notify) + { + wl_list_remove(&cp->buffer_destroy_listener.link); + cp->buffer_destroy_listener.notify = NULL; + } cp->buffer = resource; + if (!cp->buffer) return; + cp->buffer_destroy_listener.notify = _e_pixmap_cb_buffer_destroy; + wl_signal_add(&cp->buffer->destroy_signal, + &cp->buffer_destroy_listener); + + cp->buffer->busy++; #else (void)resource; #endif @@ -607,7 +710,7 @@ e_pixmap_image_clear(E_Pixmap *cp, Eina_Bool cache) #endif #ifdef HAVE_WAYLAND if (cp->type == E_PIXMAP_TYPE_WL) - if (!cp->buffer_ref.buffer) return; + if (!cp->buffer) return; #endif } @@ -638,6 +741,8 @@ e_pixmap_image_clear(E_Pixmap *cp, Eina_Bool cache) struct wl_resource *cb; Eina_List *free_list; + if (!e_comp->rendering) _e_pixmap_wl_buffers_free(cp); + if ((!cp->client) || (!cp->client->comp_data)) return; cd = (E_Comp_Wl_Client_Data *)cp->client->comp_data; @@ -652,13 +757,6 @@ e_pixmap_image_clear(E_Pixmap *cp, Eina_Bool cache) wl_resource_destroy(cb); } } - if (cp->buffer_destroy_listener.notify) - { - wl_list_remove(&cp->buffer_destroy_listener.link); - cp->buffer_destroy_listener.notify = NULL; - } - e_comp_wl_buffer_reference(&cp->buffer_ref, NULL); - cp->data = NULL; #endif break; default: @@ -696,27 +794,22 @@ e_pixmap_image_refresh(E_Pixmap *cp) case E_PIXMAP_TYPE_WL: #ifdef HAVE_WAYLAND { - E_Comp_Wl_Buffer *buffer = cp->buffer; - struct wl_shm_buffer *shm_buffer; + if (cp->held_buffer == cp->buffer) return EINA_TRUE; - shm_buffer = buffer->shm_buffer; - if (cp->buffer_ref.buffer && (cp->buffer_ref.buffer != buffer)) - { - /* FIXME: wtf? */ - } - else if (cp->buffer_ref.buffer) return EINA_TRUE; - e_comp_wl_buffer_reference(&cp->buffer_ref, buffer); + if (cp->held_buffer) _e_pixmap_wayland_image_clear(cp); - if (cp->buffer_destroy_listener.notify) - { - wl_list_remove(&cp->buffer_destroy_listener.link); - cp->buffer_destroy_listener.notify = NULL; - } + if (!cp->buffer->shm_buffer) return EINA_TRUE; - cp->buffer_destroy_listener.notify = _e_pixmap_cb_buffer_destroy; - wl_signal_add(&buffer->destroy_signal, &cp->buffer_destroy_listener); - if (shm_buffer) - cp->data = wl_shm_buffer_get_data(shm_buffer); + cp->held_buffer = cp->buffer; + if (!cp->held_buffer) return EINA_TRUE; + + cp->held_buffer->pool = wl_shm_buffer_ref_pool(cp->held_buffer->shm_buffer); + cp->held_buffer->busy++; + cp->data = wl_shm_buffer_get_data(cp->buffer->shm_buffer); + + cp->held_buffer_destroy_listener.notify = _e_pixmap_cb_held_buffer_destroy; + wl_signal_add(&cp->held_buffer->destroy_signal, + &cp->held_buffer_destroy_listener); return EINA_TRUE; } #endif @@ -757,7 +850,7 @@ e_pixmap_image_is_argb(const E_Pixmap *cp) #endif case E_PIXMAP_TYPE_WL: #ifdef HAVE_WAYLAND - return ((cp->buffer_ref.buffer != NULL) && (cp->image_argb)); + return ((cp->buffer != NULL) && (cp->image_argb)); #endif default: break; } @@ -809,14 +902,14 @@ e_pixmap_image_data_argb_convert(E_Pixmap *cp, void *pix, void *ipix, Eina_Recta case E_PIXMAP_TYPE_WL: if (cp->image_argb) return EINA_TRUE; #ifdef HAVE_WAYLAND - if (cp->buffer_ref.buffer) + if (cp->buffer) { struct wl_shm_buffer *shm_buffer; uint32_t format; int i, x, y; unsigned int *src, *dst; - shm_buffer = cp->buffer_ref.buffer->shm_buffer; + shm_buffer = cp->buffer->shm_buffer; if (!shm_buffer) return EINA_FALSE; format = wl_shm_buffer_get_format(shm_buffer); --