On Fri, Sep 26, 2014 at 4:30 PM, Leo Liu <leo....@amd.com> wrote: > 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 > > Signed-off-by: Leo Liu <leo....@amd.com> > --- > src/gallium/state_trackers/va/context.c | 2 +- > src/gallium/state_trackers/va/image.c | 254 > ++++++++++++++++++++++++++++- > src/gallium/state_trackers/va/va_private.h | 22 +++ > 3 files changed, 269 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..d3c9f20 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 * 4; > + image->offsets[0] = 0; > + image->data_size = w * h * 4;
Is this right? YUYV/UYVY stores 2 pixels in 4 bytes, so it should be * 2, no? Also, for this case, h probably doesn't need to be even, although it may still be a good idea... > + 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,87 @@ 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++) > + data[i] = img_buf->data + vaimage->offsets[i]; > + if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) { > + void *tmp = data[1]; > + data[1] = data[2]; > + data[2] = tmp; > + } > + > + 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) { > + 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 +275,70 @@ 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 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]; > + if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) { > + void *tmp = data[1]; > + data[1] = data[2]; > + data[2] = tmp; > + } > + > + 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] + 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 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 > > _______________________________________________ > mesa-dev mailing list > mesa-dev@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/mesa-dev _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev