iris: share buffer managers accross screens
authorLionel Landwerlin <lionel.g.landwerlin@intel.com>
Fri, 6 Mar 2020 11:34:23 +0000 (13:34 +0200)
committerLionel Landwerlin <lionel.g.landwerlin@intel.com>
Sat, 11 Apr 2020 19:04:25 +0000 (22:04 +0300)
St happilly uses pipe_resources created with one screen with other
screens. Unfortunately our resources have a single identifier that
related to a given screen and its associated DRM file descriptor.

To workaround this, let's share the buffer manager between screens for
a given DRM device. That way handles are always valid.

v2: Don't forget to close the fd that bufmgr now owns
    Take a copy of the fd to ensure it stays alive even if the dri
    layer closes it

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Cc: <mesa-stable@lists.freedesktop.org>
Closes: https://gitlab.freedesktop.org/mesa/mesa/issues/1373
Reviewed-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Rafael Antognolli <rafael.antognolli@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/4086>

src/gallium/drivers/iris/iris_bufmgr.c
src/gallium/drivers/iris/iris_bufmgr.h
src/gallium/drivers/iris/iris_screen.c
src/gallium/drivers/iris/iris_screen.h

index b0259e7d6077a40842ffd3d992d93ddcb2bd0949..ca8db31aed3dafeedcacfe4da76e09f30e039530 100644 (file)
@@ -49,6 +49,7 @@
 #include <sys/types.h>
 #include <stdbool.h>
 #include <time.h>
+#include <unistd.h>
 
 #include "errno.h"
 #include "common/gen_aux_map.h"
@@ -126,6 +127,13 @@ struct bo_cache_bucket {
 };
 
 struct iris_bufmgr {
+   /**
+    * List into the list of bufmgr.
+    */
+   struct list_head link;
+
+   uint32_t refcount;
+
    int fd;
 
    mtx_t lock;
@@ -152,6 +160,12 @@ struct iris_bufmgr {
    struct gen_aux_map_context *aux_map_ctx;
 };
 
+static mtx_t global_bufmgr_list_mutex = _MTX_INITIALIZER_NP;
+static struct list_head global_bufmgr_list = {
+   .next = &global_bufmgr_list,
+   .prev = &global_bufmgr_list,
+};
+
 static int bo_set_tiling_internal(struct iris_bo *bo, uint32_t tiling_mode,
                                   uint32_t stride);
 
@@ -1201,7 +1215,7 @@ iris_bo_wait(struct iris_bo *bo, int64_t timeout_ns)
    return ret;
 }
 
-void
+static void
 iris_bufmgr_destroy(struct iris_bufmgr *bufmgr)
 {
    /* Free aux-map buffers */
@@ -1237,6 +1251,8 @@ iris_bufmgr_destroy(struct iris_bufmgr *bufmgr)
          util_vma_heap_finish(&bufmgr->vma_allocator[z]);
    }
 
+   close(bufmgr->fd);
+
    free(bufmgr);
 }
 
@@ -1622,8 +1638,8 @@ static struct gen_mapped_pinned_buffer_alloc aux_map_allocator = {
  *
  * \param fd File descriptor of the opened DRM device.
  */
-struct iris_bufmgr *
-iris_bufmgr_init(struct gen_device_info *devinfo, int fd, bool bo_reuse)
+static struct iris_bufmgr *
+iris_bufmgr_create(struct gen_device_info *devinfo, int fd, bool bo_reuse)
 {
    uint64_t gtt_size = iris_gtt_size(fd);
    if (gtt_size <= IRIS_MEMZONE_OTHER_START)
@@ -1642,9 +1658,12 @@ iris_bufmgr_init(struct gen_device_info *devinfo, int fd, bool bo_reuse)
     * Don't do this! Ensure that each library/bufmgr has its own device
     * fd so that its namespace does not clash with another.
     */
-   bufmgr->fd = fd;
+   bufmgr->fd = dup(fd);
+
+   p_atomic_set(&bufmgr->refcount, 1);
 
    if (mtx_init(&bufmgr->lock, mtx_plain) != 0) {
+      close(bufmgr->fd);
       free(bufmgr);
       return NULL;
    }
@@ -1700,6 +1719,67 @@ iris_bufmgr_init(struct gen_device_info *devinfo, int fd, bool bo_reuse)
    return bufmgr;
 }
 
+static struct iris_bufmgr *
+iris_bufmgr_ref(struct iris_bufmgr *bufmgr)
+{
+   p_atomic_inc(&bufmgr->refcount);
+   return bufmgr;
+}
+
+void
+iris_bufmgr_unref(struct iris_bufmgr *bufmgr)
+{
+   mtx_lock(&global_bufmgr_list_mutex);
+   if (p_atomic_dec_zero(&bufmgr->refcount)) {
+      list_del(&bufmgr->link);
+      iris_bufmgr_destroy(bufmgr);
+   }
+   mtx_unlock(&global_bufmgr_list_mutex);
+}
+
+/**
+ * Gets an already existing GEM buffer manager or create a new one.
+ *
+ * \param fd File descriptor of the opened DRM device.
+ */
+struct iris_bufmgr *
+iris_bufmgr_get_for_fd(struct gen_device_info *devinfo, int fd, bool bo_reuse)
+{
+   struct stat st;
+
+   if (fstat(fd, &st))
+      return NULL;
+
+   struct iris_bufmgr *bufmgr = NULL;
+
+   mtx_lock(&global_bufmgr_list_mutex);
+   list_for_each_entry(struct iris_bufmgr, iter_bufmgr, &global_bufmgr_list, link) {
+      struct stat iter_st;
+      if (fstat(iter_bufmgr->fd, &iter_st))
+         continue;
+
+      if (st.st_rdev == iter_st.st_rdev) {
+         assert(iter_bufmgr->bo_reuse == bo_reuse);
+         bufmgr = iris_bufmgr_ref(iter_bufmgr);
+         goto unlock;
+      }
+   }
+
+   bufmgr = iris_bufmgr_create(devinfo, fd, bo_reuse);
+   list_addtail(&bufmgr->link, &global_bufmgr_list);
+
+ unlock:
+   mtx_unlock(&global_bufmgr_list_mutex);
+
+   return bufmgr;
+}
+
+int
+iris_bufmgr_get_fd(struct iris_bufmgr *bufmgr)
+{
+   return bufmgr->fd;
+}
+
 void*
 iris_bufmgr_get_aux_map_context(struct iris_bufmgr *bufmgr)
 {
index 1d6ef975559dcb8e6fd158969f23b28d3108f413..caeba61a650ba670a831370f42d4537a682cdf4b 100644 (file)
@@ -285,10 +285,11 @@ static inline int iris_bo_unmap(struct iris_bo *bo) { return 0; }
  */
 void iris_bo_wait_rendering(struct iris_bo *bo);
 
+
 /**
- * Tears down the buffer manager instance.
+ * Unref a buffer manager instance.
  */
-void iris_bufmgr_destroy(struct iris_bufmgr *bufmgr);
+void iris_bufmgr_unref(struct iris_bufmgr *bufmgr);
 
 /**
  * Get the current tiling (and resulting swizzling) mode for the bo.
@@ -329,8 +330,10 @@ int iris_bo_busy(struct iris_bo *bo);
 int iris_bo_madvise(struct iris_bo *bo, int madv);
 
 /* drm_bacon_bufmgr_gem.c */
-struct iris_bufmgr *iris_bufmgr_init(struct gen_device_info *devinfo, int fd,
-                                     bool bo_reuse);
+struct iris_bufmgr *iris_bufmgr_get_for_fd(struct gen_device_info *devinfo, int fd,
+                                           bool bo_reuse);
+int iris_bufmgr_get_fd(struct iris_bufmgr *bufmgr);
+
 struct iris_bo *iris_bo_gem_create_from_name(struct iris_bufmgr *bufmgr,
                                              const char *name,
                                              unsigned handle);
index d6c7e4b0ac5755d0c0e699d9d05854b65d69cde4..6afd1235f8ca10147119dbfaad00d919bebdf145 100644 (file)
@@ -527,9 +527,8 @@ iris_destroy_screen(struct pipe_screen *pscreen)
    struct iris_screen *screen = (struct iris_screen *) pscreen;
    iris_bo_unreference(screen->workaround_bo);
    u_transfer_helper_destroy(pscreen->transfer_helper);
-   iris_bufmgr_destroy(screen->bufmgr);
+   iris_bufmgr_unref(screen->bufmgr);
    disk_cache_destroy(screen->disk_cache);
-   close(screen->fd);
    ralloc_free(screen);
 }
 
@@ -635,8 +634,6 @@ iris_screen_create(int fd, const struct pipe_screen_config *config)
    if (!screen)
       return NULL;
 
-   screen->fd = fd;
-
    if (!gen_get_device_info_from_fd(fd, &screen->devinfo))
       return NULL;
    screen->pci_id = screen->devinfo.chipset_id;
@@ -645,11 +642,6 @@ iris_screen_create(int fd, const struct pipe_screen_config *config)
    if (screen->devinfo.gen < 8 || screen->devinfo.is_cherryview)
       return NULL;
 
-   screen->aperture_bytes = get_aperture_size(fd);
-
-   if (getenv("INTEL_NO_HW") != NULL)
-      screen->no_hw = true;
-
    bool bo_reuse = false;
    int bo_reuse_mode = driQueryOptioni(config->options, "bo_reuse");
    switch (bo_reuse_mode) {
@@ -660,10 +652,17 @@ iris_screen_create(int fd, const struct pipe_screen_config *config)
       break;
    }
 
-   screen->bufmgr = iris_bufmgr_init(&screen->devinfo, fd, bo_reuse);
+   screen->bufmgr = iris_bufmgr_get_for_fd(&screen->devinfo, fd, bo_reuse);
    if (!screen->bufmgr)
       return NULL;
 
+   screen->fd = iris_bufmgr_get_fd(screen->bufmgr);
+
+   screen->aperture_bytes = get_aperture_size(fd);
+
+   if (getenv("INTEL_NO_HW") != NULL)
+      screen->no_hw = true;
+
    screen->workaround_bo =
       iris_bo_alloc(screen->bufmgr, "workaround", 4096, IRIS_MEMZONE_OTHER);
    if (!screen->workaround_bo)
index 34f6fd1c16bd1312f9f1003a155bb1a79893f2b7..cd5bac9e54ec4b700cb9b3abefd2079f6f0c4221 100644 (file)
@@ -49,7 +49,7 @@ struct iris_screen {
    /** Global slab allocator for iris_transfer_map objects */
    struct slab_parent_pool transfer_pool;
 
-   /** drm device file descriptor */
+   /** drm device file descriptor, on shared with bufmgr, do not close. */
    int fd;
 
    /** PCI ID for our GPU device */