discomfitor pushed a commit to branch master.

http://git.enlightenment.org/core/enlightenment.git/commit/?id=dfc7c26ce4c5f47a253e027c70e7614a5b37ac7a

commit dfc7c26ce4c5f47a253e027c70e7614a5b37ac7a
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 5da860b..47ff0bd 100644
--- a/src/bin/e_comp_wl.c
+++ b/src/bin/e_comp_wl.c
@@ -1696,7 +1696,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 */
@@ -1743,8 +1742,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 7857db1..d60bb63 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);

-- 


Reply via email to