If two jobs use the same GEM object at the same time, the job that
finishes first will (previous to this commit) close the GEM object, even
if there's a job still referencing it.

To prevent this, have all jobs use the same panfrost_bo for a given GEM
object, so it's only closed once the last job is done with it.

Signed-off-by: Tomeu Vizoso <tomeu.viz...@collabora.com>
---
 src/gallium/drivers/panfrost/pan_allocate.h |  2 +-
 src/gallium/drivers/panfrost/pan_drm.c      | 46 +++++++++++++++++++--
 src/gallium/drivers/panfrost/pan_resource.c | 20 ++++++++-
 src/gallium/drivers/panfrost/pan_screen.h   |  6 +++
 4 files changed, 68 insertions(+), 6 deletions(-)

diff --git a/src/gallium/drivers/panfrost/pan_allocate.h 
b/src/gallium/drivers/panfrost/pan_allocate.h
index 20ba204dee86..2dfa913b8c4d 100644
--- a/src/gallium/drivers/panfrost/pan_allocate.h
+++ b/src/gallium/drivers/panfrost/pan_allocate.h
@@ -59,7 +59,7 @@ struct panfrost_transfer {
 };
 
 struct panfrost_bo {
-        struct pipe_reference reference;
+        int refcnt;
 
         /* Mapping for the entire object (all levels) */
         uint8_t *cpu;
diff --git a/src/gallium/drivers/panfrost/pan_drm.c 
b/src/gallium/drivers/panfrost/pan_drm.c
index b89f8e66a877..9648ac1d452d 100644
--- a/src/gallium/drivers/panfrost/pan_drm.c
+++ b/src/gallium/drivers/panfrost/pan_drm.c
@@ -103,7 +103,12 @@ panfrost_drm_create_bo(struct panfrost_screen *screen, 
size_t size,
         // TODO map and unmap on demand?
         panfrost_drm_mmap_bo(screen, bo);
 
-        pipe_reference_init(&bo->reference, 1);
+        p_atomic_set(&bo->refcnt, 1);
+
+        pthread_mutex_lock(&screen->handle_table_lock);
+        _mesa_hash_table_insert(screen->handle_table, &bo->gem_handle, bo);
+        pthread_mutex_unlock(&screen->handle_table_lock);
+
         return bo;
 }
 
@@ -116,6 +121,9 @@ panfrost_drm_release_bo(struct panfrost_screen *screen, 
struct panfrost_bo *bo)
         if (!bo)
                 return;
 
+        pthread_mutex_lock(&screen->handle_table_lock);
+        _mesa_hash_table_remove_key(screen->handle_table, &bo->gem_handle);
+
         panfrost_drm_munmap_bo(screen, bo);
 
         ret = drmIoctl(screen->fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
@@ -125,6 +133,8 @@ panfrost_drm_release_bo(struct panfrost_screen *screen, 
struct panfrost_bo *bo)
         }
 
         ralloc_free(bo);
+
+        pthread_mutex_unlock(&screen->handle_table_lock);
 }
 
 void
@@ -150,17 +160,41 @@ panfrost_drm_free_slab(struct panfrost_screen *screen, 
struct panfrost_memory *m
         mem->bo = NULL;
 }
 
+/* lookup a buffer, call w/ table_lock held: */
+static struct panfrost_bo *lookup_bo(struct hash_table *tbl, uint32_t key)
+{
+       struct panfrost_bo *bo = NULL;
+       struct hash_entry *entry = _mesa_hash_table_search(tbl, &key);
+       if (entry) {
+               /* found, incr refcnt and return: */
+               bo = entry->data;
+               panfrost_bo_reference(bo);
+       }
+       return bo;
+}
+
 struct panfrost_bo *
 panfrost_drm_import_bo(struct panfrost_screen *screen, int fd)
 {
-       struct panfrost_bo *bo = rzalloc(screen, struct panfrost_bo);
+       struct panfrost_bo *bo = NULL;
         struct drm_panfrost_get_bo_offset get_bo_offset = {0,};
         int ret;
         unsigned gem_handle;
 
+        pthread_mutex_lock(&screen->handle_table_lock);
+
        ret = drmPrimeFDToHandle(screen->fd, fd, &gem_handle);
        assert(!ret);
 
+        if (ret)
+                goto out_unlock;
+
+        bo = lookup_bo(screen->handle_table, gem_handle);
+        if (bo)
+                goto out_unlock;
+
+        bo = rzalloc(screen, struct panfrost_bo);
+
        get_bo_offset.handle = gem_handle;
         ret = drmIoctl(screen->fd, DRM_IOCTL_PANFROST_GET_BO_OFFSET, 
&get_bo_offset);
         assert(!ret);
@@ -169,10 +203,16 @@ panfrost_drm_import_bo(struct panfrost_screen *screen, 
int fd)
         bo->gpu = (mali_ptr) get_bo_offset.offset;
         bo->size = lseek(fd, 0, SEEK_END);
         assert(bo->size > 0);
-        pipe_reference_init(&bo->reference, 1);
+        p_atomic_set(&bo->refcnt, 1);
 
         // TODO map and unmap on demand?
         panfrost_drm_mmap_bo(screen, bo);
+
+        _mesa_hash_table_insert(screen->handle_table, &bo->gem_handle, bo);
+
+out_unlock:
+        pthread_mutex_unlock(&screen->handle_table_lock);
+
         return bo;
 }
 
diff --git a/src/gallium/drivers/panfrost/pan_resource.c 
b/src/gallium/drivers/panfrost/pan_resource.c
index b651fcffb111..beef26a5ded0 100644
--- a/src/gallium/drivers/panfrost/pan_resource.c
+++ b/src/gallium/drivers/panfrost/pan_resource.c
@@ -47,6 +47,18 @@
 #include "pan_util.h"
 #include "pan_tiling.h"
 
+static uint32_t
+u32_hash(const void *key)
+{
+        return _mesa_hash_data(key, sizeof(uint32_t));
+}
+
+static bool
+u32_equals(const void *key1, const void *key2)
+{
+        return *(const uint32_t *)key1 == *(const uint32_t *)key2;
+}
+
 static struct pipe_resource *
 panfrost_resource_from_handle(struct pipe_screen *pscreen,
                               const struct pipe_resource *templat,
@@ -434,7 +446,7 @@ panfrost_resource_create(struct pipe_screen *screen,
 void
 panfrost_bo_reference(struct panfrost_bo *bo)
 {
-        pipe_reference(NULL, &bo->reference);
+        p_atomic_inc(&bo->refcnt);
 }
 
 void
@@ -442,7 +454,7 @@ panfrost_bo_unreference(struct pipe_screen *screen, struct 
panfrost_bo *bo)
 {
         /* When the reference count goes to zero, we need to cleanup */
 
-        if (pipe_reference(&bo->reference, NULL))
+        if (p_atomic_dec_zero(&bo->refcnt))
                 panfrost_drm_release_bo(pan_screen(screen), bo);
 }
 
@@ -795,11 +807,15 @@ panfrost_resource_screen_init(struct panfrost_screen 
*pscreen)
                         panfrost_slab_can_reclaim,
                         panfrost_slab_alloc,
                         panfrost_slab_free);
+
+        pscreen->handle_table = _mesa_hash_table_create(NULL, u32_hash, 
u32_equals);
+        pthread_mutex_init(&pscreen->handle_table_lock, NULL);
 }
 
 void
 panfrost_resource_screen_deinit(struct panfrost_screen *pscreen)
 {
+        _mesa_hash_table_destroy(pscreen->handle_table, NULL);
         pb_slabs_deinit(&pscreen->slabs);
 }
 
diff --git a/src/gallium/drivers/panfrost/pan_screen.h 
b/src/gallium/drivers/panfrost/pan_screen.h
index 9bcea6114285..db47e63fda6c 100644
--- a/src/gallium/drivers/panfrost/pan_screen.h
+++ b/src/gallium/drivers/panfrost/pan_screen.h
@@ -29,9 +29,12 @@
 #ifndef PAN_SCREEN_H
 #define PAN_SCREEN_H
 
+#include <pthread.h>
+
 #include "pipe/p_screen.h"
 #include "pipe/p_defines.h"
 #include "renderonly/renderonly.h"
+#include "util/hash_table.h"
 
 #include <panfrost-misc.h>
 #include "pan_allocate.h"
@@ -63,6 +66,9 @@ struct panfrost_screen {
          * yesterjob */
        int last_fragment_flushed;
         struct panfrost_job *last_job;
+
+        pthread_mutex_t handle_table_lock;
+        struct hash_table *handle_table;
 };
 
 static inline struct panfrost_screen *
-- 
2.20.1

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to