[Mesa-dev] [PATCH 6/6] st/va: implement vlVa(Query|Create|Get|Put|Destroy)Image

Gwenole Beauchesne gb.devel at gmail.com
Thu Sep 25 22:25:06 PDT 2014


Hi Leo,

2014-09-26 0:36 GMT+02:00 Liu, Leo <Leo.Liu at amd.com>:
> Hi Gwenole,
>
>
>>-----Original Message-----
>>From: Gwenole Beauchesne [mailto:gb.devel at gmail.com]
>>Sent: Thursday, September 25, 2014 7:41 AM
>>To: Liu, Leo
>>Cc: mesa-dev at lists.freedesktop.org
>>Subject: Re: [Mesa-dev] [PATCH 6/6] st/va: implement
>>vlVa(Query|Create|Get|Put|Destroy)Image
>>
>>Hi,
>>
>>2014-09-23 18:44 GMT+02:00 Leo Liu <leo.liu at amd.com>:
>>> This patch implements functions for images support, which basically
>>> supports copy data between video surface and user buffers, in this
>>> case supports SW decode, and other video output
>>
>>My quick comments on this:
>>- Be careful of allocations of chroma planes for odd-sized images ;
>
> Right, width and height should align with 2 before divide by 2, thanks.
>
>>- I'd suggest you to expose I420 instead of YV12, even though that's just an U/V
>>plane swap.
>
> May I know the reason?

Yes, but you will be the one to know if this is beneficial to you. :)

The major multimedia frameworks (FFmpeg, GStreamer) use Y/U/V planes
order. So, if you were to expose I420 format, and that you have fast
access to that surface, then you could use vaDeriveImage() and expose
the data pointers as is. If you only expose YV12, the client
application developer has to remember to write special code for if
fourcc == YV12, then he needs to swap the data pointers.

Forget about my comment about "instead", and rather take it as "in
addition to". It shouldn't be a lot of work driver side, but it could
simplify developers life. Should there still be people interested in
having access to raw surface data for further processing, actually.

>>> Signed-off-by: Leo Liu <leo.liu at amd.com>
>>> ---
>>>  src/gallium/state_trackers/va/image.c      | 233
>>++++++++++++++++++++++++++++-
>>>  src/gallium/state_trackers/va/va_private.h |  20 +++
>>>  2 files changed, 245 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/src/gallium/state_trackers/va/image.c
>>> b/src/gallium/state_trackers/va/image.c
>>> index 8aaa29c..8a7d226 100644
>>> --- a/src/gallium/state_trackers/va/image.c
>>> +++ b/src/gallium/state_trackers/va/image.c
>>> @@ -26,18 +26,65 @@
>>>   *
>>>
>>>
>>******************************************************************
>>****
>>> ****/
>>>
>>> +#include "pipe/p_screen.h"
>>> +
>>> +#include "util/u_memory.h"
>>> +#include "util/u_handle_table.h"
>>> +#include "util/u_surface.h"
>>> +#include "util/u_video.h"
>>> +
>>> +#include "vl/vl_winsys.h"
>>> +
>>>  #include "va_private.h"
>>>
>>> +static const VAImageFormat formats[VL_VA_MAX_IMAGE_FORMATS] = {
>>> +   {VA_FOURCC('N','V','1','2')},
>>> +   {VA_FOURCC('Y','V','1','2')},
>>> +   {VA_FOURCC('Y','U','Y','V')},
>>> +   {VA_FOURCC('U','Y','V','Y')},
>>> +};
>>> +
>>> +static void
>>> +vlVaVideoSurfaceSize(vlVaSurface *p_surf, int component,
>>> +                     unsigned *width, unsigned *height) {
>>> +   *width = p_surf->templat.width;
>>> +   *height = p_surf->templat.height;
>>> +
>>> +   if (component > 0) {
>>> +      if (p_surf->templat.chroma_format ==
>>PIPE_VIDEO_CHROMA_FORMAT_420) {
>>> +         *width /= 2;
>>> +         *height /= 2;
>>> +      } else if (p_surf->templat.chroma_format ==
>>PIPE_VIDEO_CHROMA_FORMAT_422)
>>> +         *width /= 2;
>>> +   }
>>> +   if (p_surf->templat.interlaced)
>>> +      *height /= 2;
>>> +}
>>> +
>>>  VAStatus
>>>  vlVaQueryImageFormats(VADriverContextP ctx, VAImageFormat
>>> *format_list, int *num_formats)  {
>>> +   struct pipe_screen *pscreen;
>>> +   enum pipe_format format;
>>> +   int i;
>>> +
>>>     if (!ctx)
>>>        return VA_STATUS_ERROR_INVALID_CONTEXT;
>>>
>>>     if (!(format_list && num_formats))
>>> -      return VA_STATUS_ERROR_UNKNOWN;
>>> +      return VA_STATUS_ERROR_INVALID_PARAMETER;
>>>
>>>     *num_formats = 0;
>>> +   pscreen = VL_VA_PSCREEN(ctx);
>>> +   for (i = 0; i < sizeof(formats) / sizeof(formats[0]); ++i) {
>>> +      format = YCbCrToPipe(formats[i].fourcc);
>>> +      if (pscreen->is_video_format_supported(pscreen, format,
>>> +          PIPE_VIDEO_PROFILE_UNKNOWN,
>>> +          PIPE_VIDEO_ENTRYPOINT_BITSTREAM))
>>> +         format_list[(*num_formats)++] = formats[i];
>>> +   }
>>>
>>>     return VA_STATUS_SUCCESS;
>>>  }
>>> @@ -45,16 +92,57 @@ vlVaQueryImageFormats(VADriverContextP ctx,
>>> VAImageFormat *format_list, int *num  VAStatus
>>> vlVaCreateImage(VADriverContextP ctx, VAImageFormat *format, int
>>> width, int height, VAImage *image)  {
>>> +   vlVaDriver *drv;
>>> +
>>>     if (!ctx)
>>>        return VA_STATUS_ERROR_INVALID_CONTEXT;
>>>
>>> -   if(!format)
>>> -      return VA_STATUS_ERROR_UNKNOWN;
>>> +   if (!(format && image && width && height))
>>> +      return VA_STATUS_ERROR_INVALID_PARAMETER;
>>>
>>> -   if (!(width && height))
>>> +   drv = VL_VA_DRIVER(ctx);
>>> +
>>> +   image->image_id = handle_table_add(drv->htab, image);
>>> +   image->format = *format;
>>> +   image->width = width;
>>> +   image->height = height;
>>> +
>>> +   switch (format->fourcc) {
>>> +   case VA_FOURCC('N','V','1','2'):
>>> +      image->num_planes = 2;
>>> +      image->pitches[0] = width;
>>> +      image->offsets[0] = 0;
>>> +      image->pitches[1] = width;
>>> +      image->offsets[1] = width * height;
>>> +      image->data_size  = width * height * 3 / 2;
>>> +      break;
>>> +
>>> +   case VA_FOURCC('Y','V','1','2'):
>>> +      image->num_planes = 3;
>>> +      image->pitches[0] = width;
>>> +      image->offsets[0] = 0;
>>> +      image->pitches[1] = width / 2;
>>> +      image->offsets[1] = width * height;
>>> +      image->pitches[2] = width / 2;
>>> +      image->offsets[2] = width * height * 5 / 4;
>>> +      image->data_size  = width * height * 3 / 2;
>>> +      break;
>>> +
>>> +   case VA_FOURCC('U','Y','V','Y'):
>>> +   case VA_FOURCC('Y','U','Y','V'):
>>> +      image->num_planes = 1;
>>> +      image->pitches[0] = width * 4;
>>> +      image->offsets[0] = 0;
>>> +      image->data_size  = width * height * 4;
>>> +      break;
>>> +
>>> +   default:
>>>        return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
>>> +   }
>>>
>>> -   return VA_STATUS_ERROR_UNIMPLEMENTED;
>>> +   return vlVaCreateBuffer(ctx, 0, VAImageBufferType,
>>> +                           align(image->data_size, 16),
>>> +                           1, NULL, &image->buf);
>>>  }
>>>
>>>  VAStatus
>>> @@ -69,10 +157,16 @@ vlVaDeriveImage(VADriverContextP ctx, VASurfaceID
>>> surface, VAImage *image)  VAStatus  vlVaDestroyImage(VADriverContextP
>>> ctx, VAImageID image)  {
>>> +   VAImage  *vaimage;
>>> +
>>>     if (!ctx)
>>>        return VA_STATUS_ERROR_INVALID_CONTEXT;
>>>
>>> -   return VA_STATUS_ERROR_UNIMPLEMENTED;
>>> +   vaimage = handle_table_get(VL_VA_DRIVER(ctx)->htab, image);
>>> +   if (!vaimage)
>>> +      return VA_STATUS_ERROR_INVALID_IMAGE;
>>> +
>>> +   return vlVaDestroyBuffer(ctx, vaimage->buf);
>>>  }
>>>
>>>  VAStatus
>>> @@ -88,10 +182,80 @@ VAStatus
>>>  vlVaGetImage(VADriverContextP ctx, VASurfaceID surface, int x, int y,
>>>               unsigned int width, unsigned int height, VAImageID
>>> image)  {
>>> +   vlVaDriver *drv;
>>> +   vlVaSurface *surf;
>>> +   vlVaBuffer *img_buf;
>>> +   VAImage *vaimage;
>>> +   struct pipe_sampler_view **views;
>>> +   enum pipe_format format;
>>> +   void *data[3];
>>> +   bool convert = false;
>>> +   unsigned i, j;
>>> +
>>>     if (!ctx)
>>>        return VA_STATUS_ERROR_INVALID_CONTEXT;
>>>
>>> -   return VA_STATUS_ERROR_UNIMPLEMENTED;
>>> +   drv = VL_VA_DRIVER(ctx);
>>> +
>>> +   surf = handle_table_get(drv->htab, surface);
>>> +   if (!surf || !surf->buffer)
>>> +      return VA_STATUS_ERROR_INVALID_SURFACE;
>>> +
>>> +   vaimage = handle_table_get(drv->htab, image);
>>> +   if (!vaimage)
>>> +      return VA_STATUS_ERROR_INVALID_IMAGE;
>>> +
>>> +   img_buf = handle_table_get(drv->htab, vaimage->buf);
>>> +   if (!img_buf)
>>> +      return VA_STATUS_ERROR_INVALID_BUFFER;
>>> +
>>> +   format = YCbCrToPipe(vaimage->format.fourcc);
>>> +   if (format == PIPE_FORMAT_NONE)
>>> +      return VA_STATUS_ERROR_OPERATION_FAILED;
>>> +
>>> +   if (format != surf->buffer->buffer_format) {
>>> +      /* support NV12 to YV12 conversion now only */
>>> +      if (format == PIPE_FORMAT_YV12 &&
>>> +          surf->buffer->buffer_format == PIPE_FORMAT_NV12)
>>> +         convert = true;
>>> +      else
>>> +         return VA_STATUS_ERROR_OPERATION_FAILED;
>>> +   }
>>> +
>>> +   views = surf->buffer->get_sampler_view_planes(surf->buffer);
>>> +   if (!views)
>>> +      return VA_STATUS_ERROR_OPERATION_FAILED;
>>> +
>>> +   for (i = 0; i < vaimage->num_planes; i++) {
>>> +      unsigned width, height;
>>> +      if (!views[i]) continue;
>>> +      data[i] = img_buf->data + vaimage->offsets[i];
>>> +      vlVaVideoSurfaceSize(surf, i, &width, &height);
>>> +      for (j = 0; j < views[i]->texture->array_size; ++j) {
>>> +         struct pipe_box box = {0, 0, j, width, height, 1};
>>> +         struct pipe_transfer *transfer;
>>> +         uint8_t *map;
>>> +         map = drv->pipe->transfer_map(drv->pipe, views[i]->texture, 0,
>>> +                  PIPE_TRANSFER_READ, &box, &transfer);
>>> +         if (!map)
>>> +            return VA_STATUS_ERROR_OPERATION_FAILED;
>>> +
>>> +         if (i == 1 && convert) {
>>> +            data[2] = img_buf->data + vaimage->offsets[2];
>>> +            u_copy_nv12_to_yv12(data, vaimage->pitches,
>>> +               i, j, transfer->stride, views[i]->texture->array_size,
>>> +               map, box.width, box.height);
>>> +         } else {
>>> +            util_copy_rect(data[i] + vaimage->pitches[i] * j,
>>> +               views[i]->texture->format,
>>> +               vaimage->pitches[i] * views[i]->texture->array_size, 0, 0,
>>> +               box.width, box.height, map, transfer->stride, 0, 0);
>>> +         }
>>> +         pipe_transfer_unmap(drv->pipe, transfer);
>>> +      }
>>> +   }
>>> +
>>> +   return VA_STATUS_SUCCESS;
>>>  }
>>>
>>>  VAStatus
>>> @@ -99,8 +263,61 @@ vlVaPutImage(VADriverContextP ctx, VASurfaceID
>>surface, VAImageID image,
>>>               int src_x, int src_y, unsigned int src_width, unsigned int src_height,
>>>               int dest_x, int dest_y, unsigned int dest_width,
>>> unsigned int dest_height)  {
>>> +   vlVaDriver *drv;
>>> +   vlVaSurface *surf;
>>> +   vlVaBuffer *img_buf;
>>> +   VAImage *vaimage;
>>> +   struct pipe_sampler_view **views;
>>> +   enum pipe_format format;
>>> +   unsigned i, j;
>>> +
>>>     if (!ctx)
>>>        return VA_STATUS_ERROR_INVALID_CONTEXT;
>>>
>>> -   return VA_STATUS_ERROR_UNIMPLEMENTED;
>>> +   drv = VL_VA_DRIVER(ctx);
>>> +
>>> +   surf = handle_table_get(drv->htab, surface);
>>> +   if (!surf || !surf->buffer)
>>> +      return VA_STATUS_ERROR_INVALID_SURFACE;
>>> +
>>> +   vaimage = handle_table_get(drv->htab, image);
>>> +   if (!vaimage)
>>> +      return VA_STATUS_ERROR_INVALID_IMAGE;
>>> +
>>> +   img_buf = handle_table_get(drv->htab, vaimage->buf);
>>> +   if (!img_buf)
>>> +      return VA_STATUS_ERROR_INVALID_BUFFER;
>>> +
>>> +   format = YCbCrToPipe(vaimage->format.fourcc);
>>> +   if (format == PIPE_FORMAT_NONE)
>>> +      return VA_STATUS_ERROR_OPERATION_FAILED;
>>> +
>>> +   if (surf->buffer == NULL || format != surf->buffer->buffer_format) {
>>> +      if (surf->buffer)
>>> +         surf->buffer->destroy(surf->buffer);
>>> +      surf->templat.buffer_format = format;
>>> +      surf->buffer = drv->pipe->create_video_buffer(drv->pipe, &surf->templat);
>>> +      if (!surf->buffer)
>>> +         return VA_STATUS_ERROR_ALLOCATION_FAILED;
>>> +   }
>>> +
>>> +   views = surf->buffer->get_sampler_view_planes(surf->buffer);
>>> +   if (!views)
>>> +      return VA_STATUS_ERROR_OPERATION_FAILED;
>>> +
>>> +   for (i = 0; i < vaimage->num_planes; ++i) {
>>> +      unsigned width, height;
>>> +      if (!views[i]) continue;
>>> +      vlVaVideoSurfaceSize(surf, i, &width, &height);
>>> +      for (j = 0; j < views[i]->texture->array_size; ++j) {
>>> +         struct pipe_box dst_box = {0, 0, j, width, height, 1};
>>> +         drv->pipe->transfer_inline_write(drv->pipe, views[i]->texture, 0,
>>> +            PIPE_TRANSFER_WRITE, &dst_box,
>>> +            img_buf->data + vaimage->offsets[i] + vaimage->pitches[i] * j,
>>> +            vaimage->pitches[i] * views[i]->texture->array_size,
>>> +            0);
>>> +      }
>>> +   }
>>> +
>>> +   return VA_STATUS_SUCCESS;
>>>  }
>>> diff --git a/src/gallium/state_trackers/va/va_private.h
>>> b/src/gallium/state_trackers/va/va_private.h
>>> index 1f82677..fb0577f 100644
>>> --- a/src/gallium/state_trackers/va/va_private.h
>>> +++ b/src/gallium/state_trackers/va/va_private.h
>>> @@ -44,6 +44,8 @@
>>>  #define VL_VA_DRIVER(ctx) ((vlVaDriver *)ctx->pDriverData)  #define
>>> VL_VA_PSCREEN(ctx) (VL_VA_DRIVER(ctx)->vscreen->pscreen)
>>>
>>> +#define VL_VA_MAX_IMAGE_FORMATS 4
>>> +
>>>  static inline enum pipe_video_chroma_format  ChromaToPipe(int format)
>>> { @@ -60,6 +62,24 @@ ChromaToPipe(int format)
>>>     }
>>>  }
>>>
>>> +static inline enum pipe_format
>>> +YCbCrToPipe(unsigned format)
>>> +{
>>> +   switch(format) {
>>> +   case VA_FOURCC('N','V','1','2'):
>>> +      return PIPE_FORMAT_NV12;
>>> +   case VA_FOURCC('Y','V','1','2'):
>>> +      return PIPE_FORMAT_YV12;
>>> +   case VA_FOURCC('Y','U','Y','V'):
>>> +      return PIPE_FORMAT_YUYV;
>>> +   case VA_FOURCC('U','Y','V','Y'):
>>> +      return PIPE_FORMAT_UYVY;
>>> +   default:
>>> +      assert(0);
>>> +      return PIPE_FORMAT_NONE;
>>> +   }
>>> +}
>>> +
>>>  static inline VAProfile
>>>  PipeToProfile(enum pipe_video_profile profile)  {
>>> --
>>> 1.9.1
>>>
>>> _______________________________________________
>>> mesa-dev mailing list
>>> mesa-dev at lists.freedesktop.org
>>> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
>>
>>
>>Regards,
>>--
>>Gwenole Beauchesne
>>Intel Corporation SAS / 2 rue de Paris, 92196 Meudon Cedex, France Registration
>>Number (RCS): Nanterre B 302 456 199

Regards,
-- 
Gwenole Beauchesne
Intel Corporation SAS / 2 rue de Paris, 92196 Meudon Cedex, France
Registration Number (RCS): Nanterre B 302 456 199


More information about the mesa-dev mailing list