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

Emil Velikov emil.l.velikov at gmail.com
Fri Apr 22 23:32:50 UTC 2016


Hi Rob,

On 22 April 2016 at 16:50, Rob Herring <robh at kernel.org> wrote:
> This adds map and unmap functions to GBM utilizing the DRIimage extension
> mapImage/unmapImage functions or existing internal mapping for dumb
> buffers.
Ftr that this is quite sensitive and apart from the obvious breakage
(coming in a second) it will need some testing on a gnome-continuous
setup (iirc some used to hand out in #xorg-devel)

> 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);
Trivial things first - please split the renames to a separate patch.
As is the egl+gbm on swrast is broken - it should be using the *_dumb
functions.

>        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;
How did you test this ? I'm not sure if we'll even hit it (or we
should hit it actually).

> +   }
> +
> +   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)));
Nit: try to avoid multiple expressions within single assert. Then
again the whole if statement should go imho (similar to the map above)

> +      return;
> +   }
> +
> +   if (!dri->image || !dri->context || dri->image->base.version < 12)
Bikeshed: flip the order - context, image, image.foo

> +      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);
> +
Have you measured how much this costs us (cpu time and/or memory) ?

> --- 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
Nice one. Thanks !


> --- 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
Since this is the first time we mention X and Y, we should clearly
define the point of origin.

> + * \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
Something went wrong here - this does not look right.

> + * and errno is set.
> + *
> + * \sa enum gbm_bo_transfer_flags for the list of flags
> + */
Imho the documentation would be better in the header - for users to
see. Actually same goes for the rest of the file.

Can we take a look at the GBM gralloc as well. One thing that worries
me is that (most likely) you are requesting/creating a bo without
GBM_BO_USE_WRITE whist using MAP + CPU write UNMAP. If you do set the
USE_WRITE flag, you're getting a dumb buffer, which I'm not sure how
well is going to work.

Whichever way one goes, we want to clearly define/describe the
expected behaviour with the different GBM_BO_USE and GBM_BO_TRANSFER
flags.

Emil


More information about the mesa-dev mailing list