wayland_shm: Fix dmabuf fallback to shm
authorDerek Foreman <derekf@osg.samsung.com>
Wed, 27 Apr 2016 16:41:13 +0000 (11:41 -0500)
committerDerek Foreman <derekf@osg.samsung.com>
Tue, 3 May 2016 19:24:45 +0000 (14:24 -0500)
The outbuf code should free the surface structure, not the dmabuf
abstraction or a use after free occurs on fallback.

Re-organize some code to make sure we don't rely on anything that may
have already been freed.

Add a wl_surface_commit() to keep the animation timer alive through
the fallback process.

src/modules/evas/engines/wayland_shm/evas_dmabuf.c
src/modules/evas/engines/wayland_shm/evas_outbuf.c

index 81cb806..df16114 100644 (file)
@@ -60,10 +60,8 @@ struct _Dmabuf_Surface
    Dmabuf_Buffer *pre;
    Dmabuf_Buffer **buffer;
    int nbuf;
-   int pending;
 
    Eina_Bool alpha : 1;
-   Eina_Bool failed : 1;
 };
 
 static void _internal_evas_dmabuf_surface_destroy(Dmabuf_Surface *surface);
@@ -121,12 +119,6 @@ buffer_release(void *data, struct wl_buffer *buffer EINA_UNUSED)
 {
    Dmabuf_Buffer *b = data;
 
-   if (dmabuf_totally_hosed)
-     {
-        _internal_evas_dmabuf_surface_destroy(b->surface);
-        return;
-     }
-
    b->busy = EINA_FALSE;
    if (b->orphaned) _evas_dmabuf_buffer_destroy(b);
 }
@@ -143,9 +135,10 @@ _allocation_complete(Dmabuf_Buffer *b)
    int w, h, num_buf;
    Eina_Bool recovered;
 
-   b->surface->pending--;
    b->pending = EINA_FALSE;
-   if (!b->surface->failed) return;
+   if (!dmabuf_totally_hosed) return;
+
+   if (!b->surface) return;
 
    /* Something went wrong, better try to fall back to a different
     * buffer type...
@@ -154,7 +147,11 @@ _allocation_complete(Dmabuf_Buffer *b)
    w = b->w;
    h = b->h;
    num_buf = b->surface->nbuf;
-   dmabuf_totally_hosed = EINA_TRUE;
+
+   /* Depending when things broke we may need this commit to get
+    * the frame callback to fire and keep the animator running
+    */
+   wl_surface_commit(b->surface->wl_surface);
    _evas_dmabuf_surface_destroy(b->surface->surface);
    recovered = _evas_surface_init(s, w, h, num_buf);
    if (recovered) return;
@@ -169,7 +166,6 @@ _create_succeeded(void *data,
                  struct wl_buffer *new_buffer)
 {
    Dmabuf_Buffer *b = data;
-   Eina_Bool failed;
 
    b->wl_buffer = new_buffer;
    wl_buffer_add_listener(b->wl_buffer, &buffer_listener, b);
@@ -177,16 +173,17 @@ _create_succeeded(void *data,
 
    if (b->orphaned)
      {
-        _evas_dmabuf_buffer_destroy(b);
         _allocation_complete(b);
+        _evas_dmabuf_buffer_destroy(b);
         return;
      }
+
+   _allocation_complete(b);
+   if (dmabuf_totally_hosed) return;
+
    if (!b->busy) return;
    if (b != b->surface->pre) return;
 
-   failed = b->surface->failed;
-   _allocation_complete(b);
-   if (failed) return;
    /* This buffer was drawn into before it had a handle */
    wl_surface_attach(b->surface->wl_surface, b->wl_buffer, 0, 0);
    _evas_surface_damage(b->surface->wl_surface, b->surface->compositor_version,
@@ -203,8 +200,8 @@ _create_failed(void *data, struct zwp_linux_buffer_params_v1 *params)
 
    zwp_linux_buffer_params_v1_destroy(params);
 
-   b->surface->failed = EINA_TRUE;
-   if (b->orphaned) _evas_dmabuf_buffer_destroy(b);
+   dmabuf_totally_hosed = EINA_TRUE;
+   _evas_dmabuf_buffer_destroy(b);
    _allocation_complete(b);
 }
 
@@ -224,12 +221,12 @@ _evas_dmabuf_buffer_unlock(Dmabuf_Buffer *b)
 static void
 _evas_dmabuf_buffer_destroy(Dmabuf_Buffer *b)
 {
-   if (b->busy || b->pending)
+   if (b->locked || b->busy || b->pending)
      {
         b->orphaned = EINA_TRUE;
+        b->surface = NULL;
         return;
      }
-   if (b->locked) _evas_dmabuf_buffer_unlock(b);
    sym_drm_intel_bo_unreference(b->bo);
    if (b->wl_buffer) wl_buffer_destroy(b->wl_buffer);
    b->wl_buffer = NULL;
@@ -393,7 +390,6 @@ _evas_dmabuf_buffer_init(Dmabuf_Surface *s, int w, int h)
    zwp_linux_buffer_params_v1_add_listener(dp, &params_listener, out);
    zwp_linux_buffer_params_v1_create(dp, out->w, out->h,
                                      DRM_FORMAT_ARGB8888, flags);
-   s->pending++;
    return out;
 err:
    _evas_dmabuf_buffer_destroy(out);
@@ -409,7 +405,6 @@ _internal_evas_dmabuf_surface_destroy(Dmabuf_Surface *surface)
       _evas_dmabuf_buffer_destroy(surface->buffer[i]);
 
    free(surface->buffer);
-   free(surface);
 }
 
 static void
index f66ca2a..4501e9f 100644 (file)
@@ -125,6 +125,7 @@ _evas_outbuf_free(Outbuf *ob)
    _evas_outbuf_idle_flush(ob);
 
    if (ob->surface) ob->surface->funcs.destroy(ob->surface);
+   free(ob->surface);
 
    eina_array_flush(&ob->priv.onebuf_regions);