[Mesa-dev] [PATCH 11/11] gbm: Add entry points for mapping and unmapping bos

Ander Conselvan de Oliveira conselvan2 at gmail.com
Tue Apr 8 13:28:48 PDT 2014


From: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira at intel.com>

Add gbm_bo_map() and gbm_bo_unmap(). This lets a user access the
contents of a bo using the CPU.

v2:
  - improve documentation to clarify this is an optional interface;
  - make gbm_bo_create() fail with ENOSYS if the GBM_BO_USE_MAP flag
    was supplied and gbm_bo_map() is not implemented.
---
 src/gbm/backends/dri/gbm_dri.c     |  3 +++
 src/gbm/backends/intel/gbm_intel.c | 24 +++++++++++++++++
 src/gbm/backends/intel/gbm_intel.h |  2 ++
 src/gbm/main/gbm.c                 | 53 ++++++++++++++++++++++++++++++++++++++
 src/gbm/main/gbm.h                 | 11 ++++++++
 src/gbm/main/gbmint.h              |  2 ++
 6 files changed, 95 insertions(+)

diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c
index cbb4c8c..8295a25 100644
--- a/src/gbm/backends/dri/gbm_dri.c
+++ b/src/gbm/backends/dri/gbm_dri.c
@@ -346,6 +346,9 @@ gbm_dri_is_format_supported(struct gbm_device *gbm,
        usage & GBM_BO_USE_RENDERING)
       return 0;
 
+   if (usage & GBM_BO_USE_MAP)
+      return 0;
+
    return 1;
 }
 
diff --git a/src/gbm/backends/intel/gbm_intel.c b/src/gbm/backends/intel/gbm_intel.c
index c897f70..ced75d5 100644
--- a/src/gbm/backends/intel/gbm_intel.c
+++ b/src/gbm/backends/intel/gbm_intel.c
@@ -76,6 +76,24 @@ gbm_intel_bo_write(struct gbm_bo *bo, const void *buf, size_t count)
    return drm_intel_bo_unmap(ibo->bo);
 }
 
+static void *
+gbm_intel_bo_map(struct gbm_bo *bo)
+{
+   struct gbm_intel_bo *ibo = gbm_intel_bo(bo);
+
+   drm_intel_bo_map(ibo->bo, 1);
+
+   return ibo->bo->virtual;
+}
+
+static void
+gbm_intel_bo_unmap(struct gbm_bo *bo)
+{
+   struct gbm_intel_bo *ibo = gbm_intel_bo(bo);
+
+   drm_intel_bo_unmap(ibo->bo);
+}
+
 static void
 gbm_intel_bo_destroy(struct gbm_bo *_bo)
 {
@@ -99,6 +117,7 @@ gbm_intel_bo_create_with_bo(struct gbm_device *gbm,
       return NULL;
 
    ibo->bo = bo;
+   ibo->usage = usage;
 
    ibo->base.base.gbm = gbm;
    ibo->base.base.width = width;
@@ -141,6 +160,9 @@ gbm_intel_bo_create(struct gbm_device *gbm,
       tiling = I915_TILING_NONE;
    }
 
+   if (usage & GBM_BO_USE_MAP)
+      tiling = I915_TILING_NONE;
+
    if (usage & GBM_BO_USE_RENDERING)
       flags |= BO_ALLOC_FOR_RENDER;
 
@@ -233,6 +255,8 @@ gbm_intel_device_create(int fd)
    igbm->base.base.is_format_supported = gbm_intel_is_format_supported;
    igbm->base.base.bo_write = gbm_intel_bo_write;
    igbm->base.base.bo_get_fd = gbm_intel_bo_get_fd;
+   igbm->base.base.bo_map = gbm_intel_bo_map;
+   igbm->base.base.bo_unmap = gbm_intel_bo_unmap;
    igbm->base.base.bo_destroy = gbm_intel_bo_destroy;
    igbm->base.base.destroy = gbm_intel_destroy;
    igbm->base.base.surface_create = gbm_intel_surface_create;
diff --git a/src/gbm/backends/intel/gbm_intel.h b/src/gbm/backends/intel/gbm_intel.h
index af0689b..1958355 100644
--- a/src/gbm/backends/intel/gbm_intel.h
+++ b/src/gbm/backends/intel/gbm_intel.h
@@ -46,6 +46,8 @@ struct gbm_intel_device {
 struct gbm_intel_bo {
    struct gbm_drm_bo base;
 
+   uint32_t usage;
+
    drm_intel_bo *bo;
 };
 
diff --git a/src/gbm/main/gbm.c b/src/gbm/main/gbm.c
index 907ca3c..42d0d78 100644
--- a/src/gbm/main/gbm.c
+++ b/src/gbm/main/gbm.c
@@ -267,6 +267,49 @@ gbm_bo_write(struct gbm_bo *bo, const void *buf, size_t count)
    return bo->gbm->bo_write(bo, buf, count);
 }
 
+/** Map a buffer object in CPU accesible memory
+ *
+ * \remark A GBM backend may not implement this interface. Users should
+ * implement a fallback path.
+ *
+ * This makes the content of the bo available for CPU access until
+ * \ref gbm_bo_unmap() is called. Synchronization between CPU and GPU
+ * will be done at unmap time, so the caller shouldn't assume coherency
+ * for mapped buffers.
+ *
+ * A GBM backend may choose not to implement this functionality. In that
+ * case, both this function and \ref gbm_bo_create() with the \ref
+ * GBM_BO_USE_MAP flag should fail, and errno set to ENOSYS.
+ *
+ * \param bo The buffer object to be mapped
+ * \return Pointer to the mapped buffer object or NULL on failure
+ */
+GBM_EXPORT void *
+gbm_bo_map(struct gbm_bo *bo)
+{
+   if (!bo->gbm->bo_map) {
+      errno = ENOSYS;
+      return NULL;
+   }
+
+   return bo->gbm->bo_map(bo);
+}
+
+/** Unmap a previously mapped buffer object
+ *
+ * Unmaps the given bo and perform any necessary synchronization such as
+ * cache flushing, copying, etc, so that the GPU sees the same data as
+ * written by the CPU.
+ *
+ * \param The buffer object to be unmapped
+ */
+GBM_EXPORT void
+gbm_bo_unmap(struct gbm_bo *bo)
+{
+   if (bo->gbm->bo_unmap)
+      bo->gbm->bo_unmap(bo);
+}
+
 /** Get the gbm device used to create the buffer object
  *
  * \param bo The buffer object
@@ -335,6 +378,11 @@ gbm_bo_destroy(struct gbm_bo *bo)
  * when no longer needed. If an error occurs during allocation %NULL will be
  * returned and errno set.
  *
+ * Allocation may also fail due to an unsupported usage type. For instance,
+ * the flag \ref GBM_BO_USE_MAP may cause the allocation to fail if that
+ * optional functionality is not implemented. In that case, errno is set to
+ * ENOSYS.
+ *
  * \sa enum gbm_bo_format for the list of formats
  * \sa enum gbm_bo_flags for the list of usage flags
  */
@@ -343,6 +391,11 @@ gbm_bo_create(struct gbm_device *gbm,
               uint32_t width, uint32_t height,
               uint32_t format, uint32_t usage)
 {
+   if ((usage & GBM_BO_USE_MAP) && !gbm->bo_map) {
+      errno = ENOSYS;
+      return NULL;
+   }
+
    if (width == 0 || height == 0) {
       errno = EINVAL;
       return NULL;
diff --git a/src/gbm/main/gbm.h b/src/gbm/main/gbm.h
index 92d472a..036232d 100644
--- a/src/gbm/main/gbm.h
+++ b/src/gbm/main/gbm.h
@@ -207,6 +207,11 @@ enum gbm_bo_flags {
     * combinations.
     */
    GBM_BO_USE_WRITE    = (1 << 3),
+   /**
+    * Buffer can be mapped with gbm_bo_map().  Implementation of this
+    * functionality is not mandatory.
+    */
+   GBM_BO_USE_MAP = (1 << 4),
 };
 
 int
@@ -270,6 +275,12 @@ gbm_bo_get_fd(struct gbm_bo *bo);
 int
 gbm_bo_write(struct gbm_bo *bo, const void *buf, size_t count);
 
+void *
+gbm_bo_map(struct gbm_bo *bo);
+
+void
+gbm_bo_unmap(struct gbm_bo *bo);
+
 void
 gbm_bo_set_user_data(struct gbm_bo *bo, void *data,
 		     void (*destroy_user_data)(struct gbm_bo *, void *));
diff --git a/src/gbm/main/gbmint.h b/src/gbm/main/gbmint.h
index d7520ad..eea7d4d 100644
--- a/src/gbm/main/gbmint.h
+++ b/src/gbm/main/gbmint.h
@@ -70,6 +70,8 @@ struct gbm_device {
                                void *buffer, uint32_t usage);
    int (*bo_write)(struct gbm_bo *bo, const void *buf, size_t data);
    int (*bo_get_fd)(struct gbm_bo *bo);
+   void *(*bo_map)(struct gbm_bo *bo);
+   void (*bo_unmap)(struct gbm_bo *bo);
    void (*bo_destroy)(struct gbm_bo *bo);
 
    struct gbm_surface *(*surface_create)(struct gbm_device *gbm,
-- 
1.8.3.2



More information about the mesa-dev mailing list