From 1647fbe1196e21cb314a4c9b950846393e1dbc6a Mon Sep 17 00:00:00 2001 From: Gurchetan Singh Date: Wed, 3 Aug 2016 17:14:55 -0700 Subject: [PATCH] minigbm: Add userspace reference counting MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit When a dmabuf is imported multiple times, further imports after the first one are not refcounted, i.e. the first close() will lose the dmabuf. To avoid this, user space needs to track the number of imports and only close() the dmabuf once the last import is closed. BUG=None TEST=Ran graphics_Gbm on minnie. Still passes. Change-Id: Iba63556ccc94ac5d49be2f827ceead85e0e22c9c Reviewed-on: https://chromium-review.googlesource.com/366041 Commit-Ready: Gurchetan Singh Tested-by: Gurchetan Singh Reviewed-by: Stéphane Marchesin --- drv.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- drv_priv.h | 2 ++ helpers.c | 35 +++++++++++++++++++++++++++++++++++ helpers.h | 7 ++++++- 4 files changed, 87 insertions(+), 2 deletions(-) diff --git a/drv.c b/drv.c index 54d1d39..de5b87f 100644 --- a/drv.c +++ b/drv.c @@ -5,6 +5,7 @@ */ #include #include +#include #include #include #include @@ -103,6 +104,17 @@ struct driver *drv_create(int fd) return NULL; } + if (pthread_mutex_init(&drv->table_lock, NULL)) { + free(drv); + return NULL; + } + + drv->buffer_table = drmHashCreate(); + if (!drv->buffer_table) { + free(drv); + return NULL; + } + if (drv->backend->init) { ret = drv->backend->init(drv); if (ret) { @@ -119,6 +131,9 @@ void drv_destroy(struct driver *drv) if (drv->backend->close) drv->backend->close(drv); + pthread_mutex_destroy(&drv->table_lock); + drmHashDestroy(drv->buffer_table); + free(drv); } @@ -182,6 +197,7 @@ struct bo *drv_bo_create(struct driver *drv, uint32_t width, uint32_t height, drv_format_t format, uint64_t flags) { int ret; + size_t plane; struct bo *bo; bo = drv_bo_new(drv, width, height, format); @@ -196,12 +212,35 @@ struct bo *drv_bo_create(struct driver *drv, uint32_t width, uint32_t height, return NULL; } + pthread_mutex_lock(&drv->table_lock); + + for (plane = 0; plane < bo->num_planes; plane++) + drv_increment_reference_count(drv, bo, plane); + + pthread_mutex_unlock(&drv->table_lock); + return bo; } void drv_bo_destroy(struct bo *bo) { - bo->drv->backend->bo_destroy(bo); + size_t plane; + uintptr_t total = 0; + struct driver *drv = bo->drv; + + pthread_mutex_lock(&drv->table_lock); + + for (plane = 0; plane < bo->num_planes; plane++) + drv_decrement_reference_count(drv, bo, plane); + + for (plane = 0; plane < bo->num_planes; plane++) + total += drv_get_reference_count(drv, bo, plane); + + pthread_mutex_unlock(&drv->table_lock); + + if (total == 0) + bo->drv->backend->bo_destroy(bo); + free(bo); } @@ -235,6 +274,10 @@ struct bo *drv_bo_import(struct driver *drv, struct drv_import_fd_data *data) bo->sizes[0] = data->height * data->stride; bo->handles[0].u32 = prime_handle.handle; + pthread_mutex_lock(&drv->table_lock); + drv_increment_reference_count(drv, bo, 0); + pthread_mutex_unlock(&drv->table_lock); + return bo; } diff --git a/drv_priv.h b/drv_priv.h index d49c9da..349d02e 100644 --- a/drv_priv.h +++ b/drv_priv.h @@ -33,6 +33,8 @@ struct driver { int fd; struct backend *backend; void *priv; + void *buffer_table; + pthread_mutex_t table_lock; }; struct backend diff --git a/helpers.c b/helpers.c index 378b01f..ed7c0c8 100644 --- a/helpers.c +++ b/helpers.c @@ -224,3 +224,38 @@ int drv_gem_bo_destroy(struct bo *bo) return error; } + +uintptr_t drv_get_reference_count(struct driver *drv, struct bo *bo, + size_t plane) +{ + void *count; + uintptr_t num = 0; + + if (!drmHashLookup(drv->buffer_table, bo->handles[plane].u32, &count)) + num = (uintptr_t) (count); + + return num; +} + +void drv_increment_reference_count(struct driver *drv, struct bo *bo, + size_t plane) +{ + uintptr_t num = drv_get_reference_count(drv, bo, plane); + + /* If a value isn't in the table, drmHashDelete is a no-op */ + drmHashDelete(drv->buffer_table, bo->handles[plane].u32); + drmHashInsert(drv->buffer_table, bo->handles[plane].u32, + (void *) (num + 1)); +} + +void drv_decrement_reference_count(struct driver *drv, struct bo *bo, + size_t plane) +{ + uintptr_t num = drv_get_reference_count(drv, bo, plane); + + drmHashDelete(drv->buffer_table, bo->handles[plane].u32); + + if (num > 0) + drmHashInsert(drv->buffer_table, bo->handles[plane].u32, + (void *) (num - 1)); +} diff --git a/helpers.h b/helpers.h index ecb49f3..de17f7f 100644 --- a/helpers.h +++ b/helpers.h @@ -16,5 +16,10 @@ int drv_dumb_bo_create(struct bo *bo, uint32_t width, uint32_t height, uint32_t format, uint32_t flags); int drv_dumb_bo_destroy(struct bo *bo); int drv_gem_bo_destroy(struct bo *bo); - +uintptr_t drv_get_reference_count(struct driver *drv, struct bo *bo, + size_t plane); +void drv_increment_reference_count(struct driver *drv, struct bo *bo, + size_t plane); +void drv_decrement_reference_count(struct driver *drv, struct bo *bo, + size_t plane); #endif -- 2.11.0