diff options
author | Leo Liu <[email protected]> | 2014-09-18 12:21:58 -0400 |
---|---|---|
committer | Leo Liu <[email protected]> | 2014-10-01 13:21:36 -0400 |
commit | 4f7916ab4f8093fa33519dfa3d08e73b4d35ebe3 (patch) | |
tree | 348e3538add5d9fb29376c57534c992d43498b41 | |
parent | 7913c8943a1d1dd1b3f77f34bb4b0108a10a1d20 (diff) |
st/va: implement vlVa(Query|Create|Get|Put|Destroy)Image
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 <[email protected]>
-rw-r--r-- | src/gallium/state_trackers/va/context.c | 2 | ||||
-rw-r--r-- | src/gallium/state_trackers/va/image.c | 266 | ||||
-rw-r--r-- | 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 1819ec56289..ae87d3b2b15 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 8aaa29cee2d..cd4044a1a76 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 34e1f3ed661..060a1faeb9c 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) { |