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 <r...@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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev