Hi, 2014-09-23 18:44 GMT+02:00 Leo Liu <leo....@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 ; - I'd suggest you to expose I420 instead of YV12, even though that's just an U/V plane swap. > Signed-off-by: Leo Liu <leo....@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@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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev