Hi Gwenole,
>-----Original Message----- >From: Gwenole Beauchesne [mailto:gb.de...@gmail.com] >Sent: Thursday, September 25, 2014 7:41 AM >To: Liu, Leo >Cc: mesa-dev@lists.freedesktop.org >Subject: Re: [Mesa-dev] [PATCH 6/6] st/va: implement >vlVa(Query|Create|Get|Put|Destroy)Image > >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 ; Right, width and height should align with 2 before divide by 2, thanks. >- I'd suggest you to expose I420 instead of YV12, even though that's just an >U/V >plane swap. May I know the reason? Thanks, Leo >> 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