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

Leo Liu leo.liu at amd.com
Mon Sep 29 08:49:53 PDT 2014


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

v2: fix buffer size for odd-sized image case
    expose I420 format as well
v3: fix YUV 4:2:2 format data buffer size
    cleanup I420 format  exposure

Signed-off-by: Leo Liu <leo.liu at amd.com>
---
 src/gallium/state_trackers/va/context.c    |   2 +-
 src/gallium/state_trackers/va/image.c      | 266 ++++++++++++++++++++++++++++-
 src/gallium/state_trackers/va/va_private.h |  22 +++
 3 files changed, 281 insertions(+), 9 deletions(-)

diff --git a/src/gallium/state_trackers/va/context.c b/src/gallium/state_trackers/va/context.c
index 1819ec5..ae87d3b 100644
--- a/src/gallium/state_trackers/va/context.c
+++ b/src/gallium/state_trackers/va/context.c
@@ -121,7 +121,7 @@ VA_DRIVER_INIT_FUNC(VADriverContextP ctx)
    ctx->max_profiles = PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH - PIPE_VIDEO_PROFILE_UNKNOWN;
    ctx->max_entrypoints = 1;
    ctx->max_attributes = 1;
-   ctx->max_image_formats = 1;
+   ctx->max_image_formats = VL_VA_MAX_IMAGE_FORMATS;
    ctx->max_subpic_formats = 1;
    ctx->max_display_attributes = 1;
    ctx->str_vendor = "mesa gallium vaapi";
diff --git a/src/gallium/state_trackers/va/image.c b/src/gallium/state_trackers/va/image.c
index 8aaa29c..cd4044a 100644
--- a/src/gallium/state_trackers/va/image.c
+++ b/src/gallium/state_trackers/va/image.c
@@ -26,18 +26,66 @@
  *
  **************************************************************************/
 
+#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('I','4','2','0')},
+   {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 < VL_VA_MAX_IMAGE_FORMATS; ++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 +93,61 @@ vlVaQueryImageFormats(VADriverContextP ctx, VAImageFormat *format_list, int *num
 VAStatus
 vlVaCreateImage(VADriverContextP ctx, VAImageFormat *format, int width, int height, VAImage *image)
 {
+   vlVaDriver *drv;
+   int w, h;
+
    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;
+
+   drv = VL_VA_DRIVER(ctx);
 
-   if (!(width && height))
+   image->image_id = handle_table_add(drv->htab, image);
+   image->format = *format;
+   image->width = width;
+   image->height = height;
+   w = align(width, 2);
+   h = align(width, 2);
+
+   switch (format->fourcc) {
+   case VA_FOURCC('N','V','1','2'):
+      image->num_planes = 2;
+      image->pitches[0] = w;
+      image->offsets[0] = 0;
+      image->pitches[1] = w;
+      image->offsets[1] = w * h;
+      image->data_size  = w * h * 3 / 2;
+      break;
+
+   case VA_FOURCC('I','4','2','0'):
+   case VA_FOURCC('Y','V','1','2'):
+      image->num_planes = 3;
+      image->pitches[0] = w;
+      image->offsets[0] = 0;
+      image->pitches[1] = w / 2;
+      image->offsets[1] = w * h;
+      image->pitches[2] = w / 2;
+      image->offsets[2] = w * h * 5 / 4;
+      image->data_size  = w * h * 3 / 2;
+      break;
+
+   case VA_FOURCC('U','Y','V','Y'):
+   case VA_FOURCC('Y','U','Y','V'):
+      image->num_planes = 1;
+      image->pitches[0] = w * 2;
+      image->offsets[0] = 0;
+      image->data_size  = w * h * 2;
+      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 +162,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 +187,93 @@ 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;
+   bool convert = false;
+   void *data[3];
+   unsigned pitches[3], 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++) {
+      data[i] = img_buf->data + vaimage->offsets[i];
+      pitches[i] = vaimage->pitches[i];
+   }
+   if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
+      void *tmp_d;
+      unsigned tmp_p;
+      tmp_d  = data[1];
+      data[1] = data[2];
+      data[2] = tmp_d;
+      tmp_p = pitches[1];
+      pitches[1] = pitches[2];
+      pitches[2] = tmp_p;
+   }
+
+   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 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) {
+            u_copy_nv12_to_yv12(data, pitches, i, j,
+               transfer->stride, views[i]->texture->array_size,
+               map, box.width, box.height);
+         } else {
+            util_copy_rect(data[i] + pitches[i] * j,
+               views[i]->texture->format,
+               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 +281,76 @@ 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;
+   void *data[3];
+   unsigned pitches[3], 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++) {
+      data[i] = img_buf->data + vaimage->offsets[i];
+      pitches[i] = vaimage->pitches[i];
+   }
+   if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
+      void *tmp_d;
+      unsigned tmp_p;
+      tmp_d  = data[1];
+      data[1] = data[2];
+      data[2] = tmp_d;
+      tmp_p = pitches[1];
+      pitches[1] = pitches[2];
+      pitches[2] = tmp_p;
+   }
+
+   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,
+            data[i] + pitches[i] * j,
+            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 34e1f3e..060a1fa 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 5
+
 static inline enum pipe_video_chroma_format
 ChromaToPipe(int format)
 {
@@ -60,6 +62,26 @@ 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('I','4','2','0'):
+      return PIPE_FORMAT_IYUV;
+   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



More information about the mesa-dev mailing list