nouveau/winsys: Add dma-buf import support
authorFaith Ekstrand <faith.ekstrand@collabora.com>
Mon, 17 Jul 2023 22:37:24 +0000 (17:37 -0500)
committerMarge Bot <emma+marge@anholt.net>
Fri, 4 Aug 2023 21:32:06 +0000 (21:32 +0000)
This requires a lock and a buffer cache on the nouveau_ws_device.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/24326>

src/nouveau/winsys/meson.build
src/nouveau/winsys/nouveau_bo.c
src/nouveau/winsys/nouveau_bo.h
src/nouveau/winsys/nouveau_device.c
src/nouveau/winsys/nouveau_device.h

index 80d6fba..738ef30 100644 (file)
@@ -18,6 +18,7 @@ libnouveau_ws = static_library(
   dependencies : [
     dep_libdrm,
     dep_libdrm_nouveau,
+    dep_valgrind,
     idep_nvidia_headers,
   ],
   gnu_symbol_visibility : 'hidden',
index 3684a5d..569ecd0 100644 (file)
@@ -1,5 +1,7 @@
 #include "nouveau_bo.h"
 
+#include <util/hash_table.h>
+
 #include <nouveau_drm.h>
 #include <xf86drm.h>
 
@@ -67,19 +69,71 @@ nouveau_ws_bo_new_tiled(struct nouveau_ws_device *dev,
    req.info.size = size;
    req.align = align;
 
+   simple_mtx_lock(&dev->bos_lock);
+
    int ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_GEM_NEW, &req, sizeof(req));
-   if (ret) {
+   if (ret == 0) {
+      bo->size = req.info.size;
+      bo->offset = req.info.offset;
+      bo->handle = req.info.handle;
+      bo->map_handle = req.info.map_handle;
+      bo->dev = dev;
+      bo->flags = flags;
+      bo->refcnt = 1;
+
+      _mesa_hash_table_insert(dev->bos, (void *)(uintptr_t)bo->handle, bo);
+   } else {
       FREE(bo);
-      return NULL;
+      bo = NULL;
+   }
+
+   simple_mtx_unlock(&dev->bos_lock);
+
+   return bo;
+}
+
+struct nouveau_ws_bo *
+nouveau_ws_bo_from_dma_buf(struct nouveau_ws_device *dev, int fd)
+{
+   struct nouveau_ws_bo *bo = NULL;
+
+   simple_mtx_lock(&dev->bos_lock);
+
+   uint32_t handle;
+   int ret = drmPrimeFDToHandle(dev->fd, fd, &handle);
+   if (ret == 0) {
+      struct hash_entry *entry =
+         _mesa_hash_table_search(dev->bos, (void *)(uintptr_t)handle);
+      if (entry != NULL) {
+         bo = entry->data;
+      } else {
+         struct drm_nouveau_gem_info info = {
+            .handle = handle
+         };
+         ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_GEM_INFO,
+                                   &info, sizeof(info));
+         if (ret == 0) {
+            enum nouveau_ws_bo_flags flags = 0;
+            if (info.domain & NOUVEAU_GEM_DOMAIN_GART)
+               flags |= NOUVEAU_WS_BO_GART;
+            if (info.map_handle)
+               flags |= NOUVEAU_WS_BO_MAP;
+
+            bo = CALLOC_STRUCT(nouveau_ws_bo);
+            bo->size = info.size;
+            bo->offset = info.offset;
+            bo->handle = info.handle;
+            bo->map_handle = info.map_handle;
+            bo->dev = dev;
+            bo->flags = flags;
+            bo->refcnt = 1;
+
+            _mesa_hash_table_insert(dev->bos, (void *)(uintptr_t)handle, bo);
+         }
+      }
    }
 
-   bo->size = req.info.size;
-   bo->offset = req.info.offset;
-   bo->handle = req.info.handle;
-   bo->map_handle = req.info.map_handle;
-   bo->dev = dev;
-   bo->flags = flags;
-   bo->refcnt = 1;
+   simple_mtx_unlock(&dev->bos_lock);
 
    return bo;
 }
@@ -90,8 +144,15 @@ nouveau_ws_bo_destroy(struct nouveau_ws_bo *bo)
    if (--bo->refcnt)
       return;
 
+   struct nouveau_ws_device *dev = bo->dev;
+
+   simple_mtx_lock(&dev->bos_lock);
+
+   _mesa_hash_table_remove_key(dev->bos, (void *)(uintptr_t)bo->handle);
    drmCloseBufferHandle(bo->dev->fd, bo->handle);
    FREE(bo);
+
+   simple_mtx_unlock(&dev->bos_lock);
 }
 
 void *
index bb355f3..63fdb90 100644 (file)
@@ -54,6 +54,8 @@ struct nouveau_ws_bo *nouveau_ws_bo_new_tiled(struct nouveau_ws_device *,
                                               uint8_t pte_kind,
                                               uint16_t tile_mode,
                                               enum nouveau_ws_bo_flags);
+struct nouveau_ws_bo *nouveau_ws_bo_from_dma_buf(struct nouveau_ws_device *,
+                                                 int fd);
 void nouveau_ws_bo_destroy(struct nouveau_ws_bo *);
 void *nouveau_ws_bo_map(struct nouveau_ws_bo *, enum nouveau_ws_bo_map_flags);
 bool nouveau_ws_bo_wait(struct nouveau_ws_bo *, enum nouveau_ws_bo_map_flags flags);
index dfade7e..1c246ba 100644 (file)
@@ -7,6 +7,7 @@
 #include <nouveau/nvif/ioctl.h>
 #include <nvif/cl0080.h>
 #include <nvif/class.h>
+#include <util/hash_table.h>
 
 #include "nouveau_context.h"
 
@@ -266,6 +267,9 @@ nouveau_ws_device_new(drmDevicePtr drm_device)
 
    nouveau_ws_context_destroy(tmp_ctx);
 
+   simple_mtx_init(&device->bos_lock, mtx_plain);
+   device->bos = _mesa_pointer_hash_table_create(NULL);
+
    return device;
 
 out_err:
@@ -282,6 +286,8 @@ nouveau_ws_device_destroy(struct nouveau_ws_device *device)
    if (!device)
       return;
 
+   _mesa_hash_table_destroy(device->bos, NULL);
+   simple_mtx_destroy(&device->bos_lock);
    close(device->fd);
    FREE(device->chipset_name);
    FREE(device->device_name);
index 6744c92..b07da5d 100644 (file)
@@ -3,10 +3,12 @@
 
 #include "nouveau_private.h"
 #include "nv_device_info.h"
+#include "util/simple_mtx.h"
 
 #include <stddef.h>
 
 struct _drmDevice;
+struct hash_table;
 
 #ifdef __cplusplus
 extern "C" {
@@ -52,6 +54,9 @@ struct nouveau_ws_device {
    uint16_t mp_count;
 
    enum nvk_debug debug_flags;
+
+   simple_mtx_t bos_lock;
+   struct hash_table *bos;
 };
 
 struct nouveau_ws_device *nouveau_ws_device_new(struct _drmDevice *drm_device);