[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