From bb5f2e32ab18af3a261b0e076adda3c1190d3593 Mon Sep 17 00:00:00 2001 From: Derek Foreman Date: Tue, 6 Dec 2016 12:40:35 -0600 Subject: wayland_shm: Refcount the dmabuf buffer manager Because we async render into buffers before the compositor has told us we can use them, we can end up kicking over to fallback while still rendering into a buffer. Refcount the manager to let us clean up properly without crashing when this happens. --- src/modules/evas/engines/wayland_shm/evas_dmabuf.c | 77 ++++++++++++++++++---- 1 file changed, 64 insertions(+), 13 deletions(-) diff --git a/src/modules/evas/engines/wayland_shm/evas_dmabuf.c b/src/modules/evas/engines/wayland_shm/evas_dmabuf.c index df04b5e57b..9511e09ff6 100644 --- a/src/modules/evas/engines/wayland_shm/evas_dmabuf.c +++ b/src/modules/evas/engines/wayland_shm/evas_dmabuf.c @@ -42,6 +42,8 @@ struct _Buffer_Manager void (*manager_destroy)(void); void *priv; void *dl_handle; + int refcount; + Eina_Bool destroyed; }; Buffer_Manager *buffer_manager = NULL; @@ -316,6 +318,7 @@ _buffer_manager_get(void) if (!success) goto err_bm; drm_fd = fd; + buffer_manager->refcount = 1; return buffer_manager; err_bm: @@ -328,16 +331,67 @@ err_alloc: } static void -_buffer_manager_destroy(void) +_buffer_manager_ref(void) { - if (!buffer_manager) return; + buffer_manager->refcount++; +} + +static void +_buffer_manager_deref(void) +{ + buffer_manager->refcount--; + if (buffer_manager->refcount || !buffer_manager->destroyed) return; - if (buffer_manager->manager_destroy) buffer_manager->manager_destroy(); free(buffer_manager); buffer_manager = NULL; close(drm_fd); } +static void +_buffer_manager_destroy(void) +{ + if (buffer_manager->manager_destroy) buffer_manager->manager_destroy(); + buffer_manager->destroyed = EINA_TRUE; + _buffer_manager_deref(); + close(drm_fd); +} + + +static Buffer_Handle * +_buffer_manager_alloc(const char *name, int w, int h, unsigned long *stride, int32_t *fd) +{ + Buffer_Handle *out; + + _buffer_manager_ref(); + out = buffer_manager->alloc(buffer_manager, name, w, h, stride, fd); + if (!out) _buffer_manager_deref(); + return out; +} + +static void * +_buffer_manager_map(Dmabuf_Buffer *buf) +{ + void *out; + + _buffer_manager_ref(); + out = buffer_manager->map(buf); + if (!out) _buffer_manager_deref(); + return out; +} + +static void +_buffer_manager_unmap(Dmabuf_Buffer *buf) +{ + buffer_manager->unmap(buf); + _buffer_manager_deref(); +} +static void +_buffer_manager_discard(Dmabuf_Buffer *buf) +{ + buffer_manager->discard(buf); + _buffer_manager_deref(); +} + static void buffer_release(void *data, struct wl_buffer *buffer EINA_UNUSED) { @@ -379,7 +433,7 @@ _fallback(Dmabuf_Surface *s, int w, int h) if (!b) b = s->current; if (!b) goto out; - if (!b->mapping) b->mapping = buffer_manager->map(b); + if (!b->mapping) b->mapping = _buffer_manager_map(b); if (!b->mapping) goto out; epd = efl_data_scope_get(surf->info->evas, EVAS_CANVAS_CLASS); @@ -391,7 +445,7 @@ _fallback(Dmabuf_Surface *s, int w, int h) for (y = 0; y < h; y++) memcpy(new_data + y * w * 4, old_data + y * b->stride, w * 4); surf->funcs.post(surf, NULL, 0, EINA_FALSE); - buffer_manager->unmap(b); + _buffer_manager_unmap(b); out: _internal_evas_dmabuf_surface_destroy(s); @@ -468,7 +522,7 @@ static const struct zwp_linux_buffer_params_v1_listener params_listener = static void _evas_dmabuf_buffer_unlock(Dmabuf_Buffer *b) { - buffer_manager->unmap(b); + _buffer_manager_unmap(b); b->mapping = NULL; b->locked = EINA_FALSE; } @@ -485,9 +539,7 @@ _evas_dmabuf_buffer_destroy(Dmabuf_Buffer *b) return; } if (b->fd != -1) close(b->fd); - /* The buffer manager may have been destroyed already if we're - * doing fallback */ - if (buffer_manager) buffer_manager->discard(b); + _buffer_manager_discard(b); if (b->wl_buffer) wl_buffer_destroy(b->wl_buffer); b->wl_buffer = NULL; free(b); @@ -542,7 +594,7 @@ _evas_dmabuf_surface_data_get(Surface *s, int *w, int *h) if (h) *h = b->h; if (b->locked) return b->mapping; - ptr = buffer_manager->map(b); + ptr = _buffer_manager_map(b); if (!ptr) return NULL; @@ -644,17 +696,16 @@ _evas_dmabuf_buffer_init(Dmabuf_Surface *s, int w, int h) { Dmabuf_Buffer *out; struct zwp_linux_buffer_params_v1 *dp; - Buffer_Manager *bm = _buffer_manager_get(); uint32_t flags = 0; - if (!bm) return NULL; + if (!_buffer_manager_get()) return NULL; out = calloc(1, sizeof(Dmabuf_Buffer)); if (!out) return NULL; out->fd = -1; out->surface = s; - out->bh = bm->alloc(bm, "name", w, h, &out->stride, &out->fd); + out->bh = _buffer_manager_alloc("name", w, h, &out->stride, &out->fd); if (!out->bh) { free(out); -- cgit v1.2.1