Mesa (main): llvmpipe: add support for EXT_memory_object(_fd)

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Wed Oct 6 14:18:21 UTC 2021


Module: Mesa
Branch: main
Commit: 1608a815e3305d229091c346373c379900a8351f
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=1608a815e3305d229091c346373c379900a8351f

Author: Thomas Wagner <twagner at snap.com>
Date:   Wed Aug 11 10:31:41 2021 +0200

llvmpipe: add support for EXT_memory_object(_fd)

Enable the import of memory via opaque fd handles, which
are based upon memory-fds. The extension is necessary for sharing
images and buffers from Vulkan.

Reviewed-by: Dave Airlie <airlied at redhat.com>
Tested-by: Heinrich Fink <hfink at snap.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12345>

---

 src/gallium/drivers/llvmpipe/lp_texture.c | 139 +++++++++++++++++++++++++++++-
 src/gallium/drivers/llvmpipe/lp_texture.h |  14 +++
 src/gallium/include/pipe/p_defines.h      |   4 +
 3 files changed, 154 insertions(+), 3 deletions(-)

diff --git a/src/gallium/drivers/llvmpipe/lp_texture.c b/src/gallium/drivers/llvmpipe/lp_texture.c
index eb635b6fc94..d303e8abbd5 100644
--- a/src/gallium/drivers/llvmpipe/lp_texture.c
+++ b/src/gallium/drivers/llvmpipe/lp_texture.c
@@ -52,6 +52,7 @@
 #include "lp_rast.h"
 
 #include "frontend/sw_winsys.h"
+#include "git_sha1.h"
 
 #ifndef _WIN32
 #include "drm-uapi/drm_fourcc.h"
@@ -334,6 +335,104 @@ llvmpipe_resource_create_unbacked(struct pipe_screen *_screen,
    return pt;
 }
 
+static struct pipe_memory_object *
+llvmpipe_memobj_create_from_handle(struct pipe_screen *pscreen,
+                                   struct winsys_handle *handle,
+                                   bool dedicated)
+{
+#ifdef PIPE_MEMORY_FD
+   struct llvmpipe_memory_object *memobj = CALLOC_STRUCT(llvmpipe_memory_object);
+
+   if (handle->type == WINSYS_HANDLE_TYPE_FD && 
+       pscreen->import_memory_fd(pscreen, handle->handle, &memobj->data, &memobj->size)) {
+      return &memobj->b;
+   }
+   free(memobj);
+#endif
+   return NULL;
+}
+
+static void
+llvmpipe_memobj_destroy(struct pipe_screen *pscreen,
+                        struct pipe_memory_object *memobj)
+{
+   if (!memobj)
+      return;
+   struct llvmpipe_memory_object *lpmo = llvmpipe_memory_object(memobj);
+#ifdef PIPE_MEMORY_FD
+   pscreen->free_memory_fd(pscreen, lpmo->data);
+#endif
+   free(lpmo);
+}
+
+static struct pipe_resource *
+llvmpipe_resource_from_memobj(struct pipe_screen *pscreen,
+                              const struct pipe_resource *templat,
+                              struct pipe_memory_object *memobj,
+                              uint64_t offset)
+{
+   if (!memobj)
+      return NULL;
+   struct llvmpipe_screen *screen = llvmpipe_screen(pscreen);
+   struct llvmpipe_memory_object *lpmo = llvmpipe_memory_object(memobj);
+   struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource);
+   lpr->base = *templat;
+
+   lpr->screen = screen;
+   pipe_reference_init(&lpr->base.reference, 1);
+   lpr->base.screen = &screen->base;
+
+   if (llvmpipe_resource_is_texture(&lpr->base)) {
+      /* texture map */
+      if (!llvmpipe_texture_layout(screen, lpr, false))
+         goto fail;
+      if(lpmo->size < lpr->size_required)
+         goto fail;
+      lpr->tex_data = lpmo->data;
+   }
+   else {
+      /* other data (vertex buffer, const buffer, etc) */
+      const uint bytes = templat->width0;
+      assert(util_format_get_blocksize(templat->format) == 1);
+      assert(templat->height0 == 1);
+      assert(templat->depth0 == 1);
+      assert(templat->last_level == 0);
+      /*
+       * Reserve some extra storage since if we'd render to a buffer we
+       * read/write always LP_RASTER_BLOCK_SIZE pixels, but the element
+       * offset doesn't need to be aligned to LP_RASTER_BLOCK_SIZE.
+       */
+      /*
+       * buffers don't really have stride but it's probably safer
+       * (for code doing same calculations for buffers and textures)
+       * to put something reasonable in there.
+       */
+      lpr->row_stride[0] = bytes;
+
+      lpr->size_required = bytes;
+      if (!(templat->flags & PIPE_RESOURCE_FLAG_DONT_OVER_ALLOCATE))
+         lpr->size_required += (LP_RASTER_BLOCK_SIZE - 1) * 4 * sizeof(float);
+
+      if(lpmo->size < lpr->size_required)
+         goto fail;
+      lpr->data = lpmo->data;
+   }
+   lpr->id = id_counter++;
+   lpr->imported_memory = true;
+
+#ifdef DEBUG
+   mtx_lock(&resource_list_mutex);
+   insert_at_tail(&resource_list, lpr);
+   mtx_unlock(&resource_list_mutex);
+#endif
+
+   return &lpr->base;
+
+fail:
+   free(lpr);
+   return NULL;
+}
+
 static void
 llvmpipe_resource_destroy(struct pipe_screen *pscreen,
                           struct pipe_resource *pt)
@@ -350,13 +449,16 @@ llvmpipe_resource_destroy(struct pipe_screen *pscreen,
       else if (llvmpipe_resource_is_texture(pt)) {
          /* free linear image data */
          if (lpr->tex_data) {
-            align_free(lpr->tex_data);
+            if (!lpr->imported_memory)
+               align_free(lpr->tex_data);
             lpr->tex_data = NULL;
          }
       }
       else if (!lpr->userBuffer) {
-         if (lpr->data)
-            align_free(lpr->data);
+         if (lpr->data) {
+            if (!lpr->imported_memory)
+               align_free(lpr->data);
+         }
       }
    }
 #ifdef DEBUG
@@ -850,6 +952,28 @@ static void llvmpipe_free_memory(struct pipe_screen *screen,
    os_free_aligned(pmem);
 }
 
+#ifdef PIPE_MEMORY_FD
+
+static const char *driver_id = "llvmpipe" MESA_GIT_SHA1;
+
+static struct pipe_memory_allocation *llvmpipe_allocate_memory_fd(struct pipe_screen *screen, uint64_t size, int *fd)
+{
+   return os_malloc_aligned_fd(size, 256, fd, "llvmpipe memory fd", driver_id);
+}
+
+static bool llvmpipe_import_memory_fd(struct pipe_screen *screen, int fd, struct pipe_memory_allocation **ptr, uint64_t *size)
+{
+   return os_import_memory_fd(fd, (void**)ptr, size, driver_id);
+}
+
+static void llvmpipe_free_memory_fd(struct pipe_screen *screen,
+                                    struct pipe_memory_allocation *pmem)
+{
+   os_free_fd(pmem);
+}
+
+#endif
+
 static bool llvmpipe_resource_bind_backing(struct pipe_screen *screen,
                                            struct pipe_resource *pt,
                                            struct pipe_memory_allocation *pmem,
@@ -995,16 +1119,25 @@ llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen)
 /*   screen->resource_create_front = llvmpipe_resource_create_front; */
    screen->resource_destroy = llvmpipe_resource_destroy;
    screen->resource_from_handle = llvmpipe_resource_from_handle;
+   screen->resource_from_memobj = llvmpipe_resource_from_memobj;
    screen->resource_get_handle = llvmpipe_resource_get_handle;
    screen->can_create_resource = llvmpipe_can_create_resource;
 
    screen->resource_create_unbacked = llvmpipe_resource_create_unbacked;
 
+   screen->memobj_create_from_handle = llvmpipe_memobj_create_from_handle;
+   screen->memobj_destroy = llvmpipe_memobj_destroy;
+
    screen->resource_get_info = llvmpipe_get_resource_info;
    screen->resource_get_param = llvmpipe_resource_get_param;
    screen->resource_from_user_memory = llvmpipe_resource_from_user_memory;
    screen->allocate_memory = llvmpipe_allocate_memory;
    screen->free_memory = llvmpipe_free_memory;
+#ifdef PIPE_MEMORY_FD
+   screen->allocate_memory_fd = llvmpipe_allocate_memory_fd;
+   screen->import_memory_fd = llvmpipe_import_memory_fd;
+   screen->free_memory_fd = llvmpipe_free_memory_fd;
+#endif
    screen->map_memory = llvmpipe_map_memory;
    screen->unmap_memory = llvmpipe_unmap_memory;
 
diff --git a/src/gallium/drivers/llvmpipe/lp_texture.h b/src/gallium/drivers/llvmpipe/lp_texture.h
index d1ba22b2685..eabfbeca8f0 100644
--- a/src/gallium/drivers/llvmpipe/lp_texture.h
+++ b/src/gallium/drivers/llvmpipe/lp_texture.h
@@ -99,6 +99,7 @@ struct llvmpipe_resource
    uint64_t size_required;
    uint64_t backing_offset;
    bool backable;
+   bool imported_memory;
 #ifdef DEBUG
    /** for linked list */
    struct llvmpipe_resource *prev, *next;
@@ -111,6 +112,13 @@ struct llvmpipe_transfer
    struct pipe_transfer base;
 };
 
+struct llvmpipe_memory_object
+{
+   struct pipe_memory_object b;
+   struct pipe_memory_allocation *data;
+   uint64_t size;
+};
+
 
 /** cast wrappers */
 static inline struct llvmpipe_resource *
@@ -133,6 +141,12 @@ llvmpipe_transfer(struct pipe_transfer *pt)
    return (struct llvmpipe_transfer *) pt;
 }
 
+static inline struct llvmpipe_memory_object *
+llvmpipe_memory_object(struct pipe_memory_object *pt)
+{
+   return (struct llvmpipe_memory_object *) pt;
+}
+
 
 void llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen);
 void llvmpipe_init_context_resource_funcs(struct pipe_context *pipe);
diff --git a/src/gallium/include/pipe/p_defines.h b/src/gallium/include/pipe/p_defines.h
index 123c2b4d0f6..608667b1468 100644
--- a/src/gallium/include/pipe/p_defines.h
+++ b/src/gallium/include/pipe/p_defines.h
@@ -1354,6 +1354,10 @@ enum pipe_perf_counter_data_type
 
 #define PIPE_UUID_SIZE 16
 
+#ifdef PIPE_OS_UNIX
+#define PIPE_MEMORY_FD
+#endif
+
 #ifdef __cplusplus
 }
 #endif



More information about the mesa-commit mailing list