[Mesa-dev] [PATCH v2 9/9] gbm: Add map/unmap functions
Rob Herring
robh at kernel.org
Wed May 4 02:02:47 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>
---
v2:
- split out dumb map renaming
- move context create to mapping function
- add pthreadstubs for mutex
- separate assert conditions
src/gbm/Makefile.am | 6 ++--
src/gbm/backends/dri/gbm_dri.c | 62 +++++++++++++++++++++++++++++++++++++++
src/gbm/backends/dri/gbm_driint.h | 3 ++
src/gbm/gbm-symbols-check | 2 ++
src/gbm/main/gbm.c | 53 +++++++++++++++++++++++++++++++++
src/gbm/main/gbm.h | 35 ++++++++++++++++++++++
src/gbm/main/gbmint.h | 6 ++++
7 files changed, 165 insertions(+), 2 deletions(-)
diff --git a/src/gbm/Makefile.am b/src/gbm/Makefile.am
index 45fb762..aba8d1e 100644
--- a/src/gbm/Makefile.am
+++ b/src/gbm/Makefile.am
@@ -41,10 +41,12 @@ libgbm_la_SOURCES += \
AM_CFLAGS += \
-DDEFAULT_DRIVER_DIR='"$(DRI_DRIVER_SEARCH_DIR)"' \
- $(LIBDRM_CFLAGS)
+ $(LIBDRM_CFLAGS) \
+ $(PTHREADSTUBS_CFLAGS)
libgbm_la_LIBADD += \
- $(LIBDRM_LIBS)
+ $(LIBDRM_LIBS) \
+ $(PTHREADSTUBS_LIBS)
endif
TESTS = gbm-symbols-check
diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c
index 51d51dd..c3626e3 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>
@@ -924,6 +925,60 @@ 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;
+ }
+
+ mtx_lock(&dri->mutex);
+ if (!dri->context)
+ dri->context = dri->dri2->createNewContext(dri->screen, NULL,
+ NULL, NULL);
+ assert(dri->context);
+ mtx_unlock(&dri->mutex);
+
+ /* 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, (int *)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 and check the pointer is in range */
+ if (bo->map) {
+ assert(map_data >= bo->map);
+ assert(map_data < (bo->map + bo->size));
+ return;
+ }
+
+ if (!dri->context || !dri->image || 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 +1013,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 +1039,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;
@@ -992,6 +1052,8 @@ dri_device_create(int fd)
dri->base.type = GBM_DRM_DRIVER_TYPE_DRI;
dri->base.base.name = "drm";
+ mtx_init(&dri->mutex, mtx_plain);
+
force_sw = getenv("GBM_ALWAYS_SOFTWARE") != NULL;
if (!force_sw) {
ret = dri_screen_create(dri);
diff --git a/src/gbm/backends/dri/gbm_driint.h b/src/gbm/backends/dri/gbm_driint.h
index b51cc4d..46bb5c1 100644
--- a/src/gbm/backends/dri/gbm_driint.h
+++ b/src/gbm/backends/dri/gbm_driint.h
@@ -30,6 +30,7 @@
#include <sys/mman.h>
#include "gbmint.h"
+#include "c11/threads.h"
#include "common_drm.h"
@@ -45,6 +46,8 @@ struct gbm_dri_device {
void *driver;
__DRIscreen *screen;
+ __DRIcontext *context;
+ mtx_t mutex;
const __DRIcoreExtension *core;
const __DRIdri2Extension *dri2;
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..b0cab51 100644
--- a/src/gbm/main/gbm.c
+++ b/src/gbm/main/gbm.c
@@ -386,6 +386,59 @@ 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 (top left origin) starting position of the mapped region for
+ * the buffer
+ * \param y The Y (top left origin) 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 GBM_BO_TRANSFER_* flags for this buffer
+ * \param stride Ptr for returned stride in bytes of the mapped region
+ * \param map_data Returned opaque ptr for the mapped region
+ *
+ * \return Address of the mapped buffer that should be unmapped with
+ * 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..fcdeb43 100644
--- a/src/gbm/main/gbm.h
+++ b/src/gbm/main/gbm.h
@@ -253,6 +253,41 @@ 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.
+ *
+ * These flags are independent of the GBM_BO_USE_* creation flags. However,
+ * mapping the buffer may require copying to/from a staging buffer.
+ *
+ * See also: pipe_transfer_usage
+ */
+enum gbm_bo_transfer_flags {
+ /**
+ * Buffer contents read back (or accessed directly) at transfer
+ * create time.
+ */
+ GBM_BO_TRANSFER_READ = (1 << 0),
+ /**
+ * Buffer contents will be written back at unmap time
+ * (or modified as a result of being accessed directly).
+ */
+ GBM_BO_TRANSFER_WRITE = (1 << 1),
+ /**
+ * Read/modify/write
+ */
+ 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