[Mesa-dev] [PATCH 4/4] gbm: Add map/unmap functions

Rob Herring robh at kernel.org
Fri Apr 22 15:50:18 UTC 2016


This adds map and unmap functions to GBM utilizing the DRIimage extension
mapImage/unmapImage functions or existing internal mapping for dumb
buffers. Unlike prior attempts, this version provides a region to map and
usage flags for the mapping. The operation follows the same semantics as
the gallium transfer_map() function.

This was tested with GBM based gralloc on Android.

This still creates a context, but I've moved it into gbm_create_device
rather than in the map function. This should remove any need for reference
counting and problems with memory leaks.

Signed-off-by: Rob Herring <robh at kernel.org>
---
 src/gbm/backends/dri/gbm_dri.c    | 62 +++++++++++++++++++++++++++++++++++++--
 src/gbm/backends/dri/gbm_driint.h |  5 ++--
 src/gbm/gbm-symbols-check         |  2 ++
 src/gbm/main/gbm.c                | 51 ++++++++++++++++++++++++++++++++
 src/gbm/main/gbm.h                | 25 ++++++++++++++++
 src/gbm/main/gbmint.h             |  6 ++++
 6 files changed, 147 insertions(+), 4 deletions(-)

diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c
index 0625422..c93dc9c 100644
--- a/src/gbm/backends/dri/gbm_dri.c
+++ b/src/gbm/backends/dri/gbm_dri.c
@@ -32,6 +32,7 @@
 #include <string.h>
 #include <errno.h>
 #include <limits.h>
+#include <assert.h>
 
 #include <sys/types.h>
 #include <unistd.h>
@@ -603,7 +604,7 @@ gbm_dri_bo_destroy(struct gbm_bo *_bo)
    if (bo->image != NULL) {
       dri->image->destroyImage(bo->image);
    } else {
-      gbm_dri_bo_unmap(bo);
+      gbm_dri_bo_unmap_dumb(bo);
       memset(&arg, 0, sizeof(arg));
       arg.handle = bo->handle;
       drmIoctl(dri->base.base.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg);
@@ -828,7 +829,7 @@ create_dumb(struct gbm_device *gbm,
    bo->handle = create_arg.handle;
    bo->size = create_arg.size;
 
-   if (gbm_dri_bo_map(bo) == NULL)
+   if (gbm_dri_bo_map_dumb(bo) == NULL)
       goto destroy_dumb;
 
    return &bo->base.base;
@@ -924,6 +925,54 @@ failed:
    return NULL;
 }
 
+static void *
+gbm_dri_bo_map(struct gbm_bo *_bo,
+              uint32_t x, uint32_t y,
+              uint32_t width, uint32_t height,
+              uint32_t flags, uint32_t *stride, void **map_data)
+{
+   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
+   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
+
+   /* If it's a dumb buffer, we already have a mapping */
+   if (bo->map) {
+      *map_data = (char *)bo->map + (bo->base.base.stride * y) + (x * 4);
+      *stride = bo->base.base.stride;
+      return *map_data;
+   }
+
+   if (!dri->image || dri->image->base.version < 12) {
+      errno = ENOSYS;
+      return NULL;
+   }
+
+   if (!dri->context)
+      return NULL;
+
+   /* GBM flags and DRI flags are the same, so just pass them on */
+   return dri->image->mapImage(dri->context, bo->image, x, y,
+                               width, height, flags, stride, map_data);
+}
+
+static void
+gbm_dri_bo_unmap(struct gbm_bo *_bo, void *map_data)
+{
+   struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm);
+   struct gbm_dri_bo *bo = gbm_dri_bo(_bo);
+
+   /* Check if it's a dumb buffer */
+   if (bo->map) {
+      assert((map_data >= bo->map) && (map_data < (bo->map + bo->size)));
+      return;
+   }
+
+   if (!dri->image || !dri->context || dri->image->base.version < 12)
+      return;
+
+   dri->image->unmapImage(dri->context, bo->image, map_data);
+}
+
+
 static struct gbm_surface *
 gbm_dri_surface_create(struct gbm_device *gbm,
                        uint32_t width, uint32_t height,
@@ -958,6 +1007,9 @@ dri_destroy(struct gbm_device *gbm)
    struct gbm_dri_device *dri = gbm_dri_device(gbm);
    unsigned i;
 
+   if (dri->context)
+      dri->core->destroyContext(dri->context);
+
    dri->core->destroyScreen(dri->screen);
    for (i = 0; dri->driver_configs[i]; i++)
       free((__DRIconfig *) dri->driver_configs[i]);
@@ -981,6 +1033,8 @@ dri_device_create(int fd)
    dri->base.base.fd = fd;
    dri->base.base.bo_create = gbm_dri_bo_create;
    dri->base.base.bo_import = gbm_dri_bo_import;
+   dri->base.base.bo_map = gbm_dri_bo_map;
+   dri->base.base.bo_unmap = gbm_dri_bo_unmap;
    dri->base.base.is_format_supported = gbm_dri_is_format_supported;
    dri->base.base.bo_write = gbm_dri_bo_write;
    dri->base.base.bo_get_fd = gbm_dri_bo_get_fd;
@@ -1004,6 +1058,10 @@ dri_device_create(int fd)
    if (ret)
       goto err_dri;
 
+   if (dri->image->base.version >= 12)
+      dri->context = dri->dri2->createNewContext(dri->screen, NULL,
+                                                 NULL, NULL);
+
    return &dri->base.base;
 
 err_dri:
diff --git a/src/gbm/backends/dri/gbm_driint.h b/src/gbm/backends/dri/gbm_driint.h
index 3f46eff..11613f2 100644
--- a/src/gbm/backends/dri/gbm_driint.h
+++ b/src/gbm/backends/dri/gbm_driint.h
@@ -45,6 +45,7 @@ struct gbm_dri_device {
    void *driver;
 
    __DRIscreen *screen;
+   __DRIcontext *context;
 
    const __DRIcoreExtension   *core;
    const __DRIdri2Extension   *dri2;
@@ -130,7 +131,7 @@ gbm_dri_surface(struct gbm_surface *surface)
 }
 
 static inline void *
-gbm_dri_bo_map(struct gbm_dri_bo *bo)
+gbm_dri_bo_map_dumb(struct gbm_dri_bo *bo)
 {
    struct drm_mode_map_dumb map_arg;
    int ret;
@@ -159,7 +160,7 @@ gbm_dri_bo_map(struct gbm_dri_bo *bo)
 }
 
 static inline void
-gbm_dri_bo_unmap(struct gbm_dri_bo *bo)
+gbm_dri_bo_unmap_dumb(struct gbm_dri_bo *bo)
 {
    munmap(bo->map, bo->size);
    bo->map = NULL;
diff --git a/src/gbm/gbm-symbols-check b/src/gbm/gbm-symbols-check
index f2dde58..5a333ff 100755
--- a/src/gbm/gbm-symbols-check
+++ b/src/gbm/gbm-symbols-check
@@ -9,6 +9,8 @@ gbm_device_destroy
 gbm_create_device
 gbm_bo_create
 gbm_bo_import
+gbm_bo_map
+gbm_bo_unmap
 gbm_bo_get_width
 gbm_bo_get_height
 gbm_bo_get_stride
diff --git a/src/gbm/main/gbm.c b/src/gbm/main/gbm.c
index c046b1a..0f70bbd 100644
--- a/src/gbm/main/gbm.c
+++ b/src/gbm/main/gbm.c
@@ -386,6 +386,57 @@ gbm_bo_import(struct gbm_device *gbm,
 }
 
 /**
+ * Map a region of a gbm buffer object for cpu access
+ *
+ * This function maps a region of a gbm bo for cpu read and/or write
+ * access.
+ *
+ * \param bo The buffer object
+ * \param x The X starting position of the mapped region for the buffer
+ * \param y The Y starting position of the mapped region for the buffer
+ * \param width The width of the mapped region for the buffer
+ * \param height The height of the mapped region for the buffer
+ * \param flags The union of the usage flags for this buffer
+ * \param stride Returned stride in bytes of the mapped region.
+ * \param map_data Returned opaque ptr for the mapped region
+ *
+ * \return Address of the mapped buffer
+ * gbm_bo_unmap() when no longer needed. On error, %NULL is returned
+ * and errno is set.
+ *
+ * \sa enum gbm_bo_transfer_flags for the list of flags
+ */
+GBM_EXPORT void *
+gbm_bo_map(struct gbm_bo *bo,
+              uint32_t x, uint32_t y,
+              uint32_t width, uint32_t height,
+              uint32_t flags, uint32_t *stride, void **map_data)
+{
+   if (!bo || width == 0 || height == 0 || !stride || !map_data) {
+      errno = EINVAL;
+      return NULL;
+   }
+
+   return bo->gbm->bo_map(bo, x, y, width, height,
+                          flags, stride, map_data);
+}
+
+/**
+ * Unmap a previously mapped region of a gbm buffer object
+ *
+ * This function unmaps a region of a gbm bo for cpu read and/or write
+ * access.
+ *
+ * \param bo The buffer object
+ * \param map_data opaque ptr returned from prior gbm_bo_map
+ */
+GBM_EXPORT void
+gbm_bo_unmap(struct gbm_bo *bo, void *map_data)
+{
+   bo->gbm->bo_unmap(bo, map_data);
+}
+
+/**
  * Allocate a surface object
  *
  * \param gbm The gbm device returned from gbm_create_device()
diff --git a/src/gbm/main/gbm.h b/src/gbm/main/gbm.h
index 15a2b73..d2ef9bb 100644
--- a/src/gbm/main/gbm.h
+++ b/src/gbm/main/gbm.h
@@ -253,6 +253,31 @@ struct gbm_bo *
 gbm_bo_import(struct gbm_device *gbm, uint32_t type,
               void *buffer, uint32_t usage);
 
+/**
+ * Flags to indicate the type of mapping for the buffer - these are
+ * passed into gbm_bo_map(). The caller must set the union of all the
+ * flags that are appropriate.
+ */
+enum gbm_bo_transfer_flags {
+   /**
+    * Buffer is going to be read from
+    */
+   GBM_BO_TRANSFER_READ       = (1 << 0),
+   /**
+    * Buffer is going to be written to
+    */
+   GBM_BO_TRANSFER_WRITE      = (1 << 1),
+   GBM_BO_TRANSFER_READ_WRITE = (GBM_BO_TRANSFER_READ | GBM_BO_TRANSFER_WRITE),
+};
+
+void *
+gbm_bo_map(struct gbm_bo *bo,
+           uint32_t x, uint32_t y, uint32_t width, uint32_t height,
+           uint32_t flags, uint32_t *stride, void **map_data);
+
+void
+gbm_bo_unmap(struct gbm_bo *bo, void *map_data);
+
 uint32_t
 gbm_bo_get_width(struct gbm_bo *bo);
 
diff --git a/src/gbm/main/gbmint.h b/src/gbm/main/gbmint.h
index 155eb12..914e2c1 100644
--- a/src/gbm/main/gbmint.h
+++ b/src/gbm/main/gbmint.h
@@ -68,6 +68,12 @@ struct gbm_device {
                                uint32_t usage);
    struct gbm_bo *(*bo_import)(struct gbm_device *gbm, uint32_t type,
                                void *buffer, uint32_t usage);
+   void *(*bo_map)(struct gbm_bo *bo,
+                               uint32_t x, uint32_t y,
+                               uint32_t width, uint32_t height,
+                               uint32_t flags, uint32_t *stride,
+                               void **map_data);
+   void (*bo_unmap)(struct gbm_bo *bo, void *map_data);
    int (*bo_write)(struct gbm_bo *bo, const void *buf, size_t data);
    int (*bo_get_fd)(struct gbm_bo *bo);
    void (*bo_destroy)(struct gbm_bo *bo);
-- 
2.7.4



More information about the mesa-dev mailing list