discomfitor pushed a commit to branch enlightenment-0.20.
http://git.enlightenment.org/core/enlightenment.git/commit/?id=7aef5e74fde0a3d53a0f10f30fb38f363a593ece
commit 7aef5e74fde0a3d53a0f10f30fb38f363a593ece
Author: Derek Foreman <***@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);
--