17ec681f3Smrg/************************************************************************** 27ec681f3Smrg * 37ec681f3Smrg * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian. 47ec681f3Smrg * Copyright 2014 Advanced Micro Devices, Inc. 57ec681f3Smrg * All Rights Reserved. 67ec681f3Smrg * 77ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 87ec681f3Smrg * copy of this software and associated documentation files (the 97ec681f3Smrg * "Software"), to deal in the Software without restriction, including 107ec681f3Smrg * without limitation the rights to use, copy, modify, merge, publish, 117ec681f3Smrg * distribute, sub license, and/or sell copies of the Software, and to 127ec681f3Smrg * permit persons to whom the Software is furnished to do so, subject to 137ec681f3Smrg * the following conditions: 147ec681f3Smrg * 157ec681f3Smrg * The above copyright notice and this permission notice (including the 167ec681f3Smrg * next paragraph) shall be included in all copies or substantial portions 177ec681f3Smrg * of the Software. 187ec681f3Smrg * 197ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 207ec681f3Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 217ec681f3Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 227ec681f3Smrg * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR 237ec681f3Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 247ec681f3Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 257ec681f3Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 267ec681f3Smrg * 277ec681f3Smrg **************************************************************************/ 287ec681f3Smrg 297ec681f3Smrg#include "pipe/p_screen.h" 307ec681f3Smrg 317ec681f3Smrg#include "util/u_memory.h" 327ec681f3Smrg#include "util/u_handle_table.h" 337ec681f3Smrg#include "util/u_surface.h" 347ec681f3Smrg#include "util/u_video.h" 357ec681f3Smrg#include "util/u_process.h" 367ec681f3Smrg 377ec681f3Smrg#include "vl/vl_winsys.h" 387ec681f3Smrg#include "vl/vl_video_buffer.h" 397ec681f3Smrg 407ec681f3Smrg#include "va_private.h" 417ec681f3Smrg 427ec681f3Smrgstatic const VAImageFormat formats[] = 437ec681f3Smrg{ 447ec681f3Smrg {VA_FOURCC('N','V','1','2')}, 457ec681f3Smrg {VA_FOURCC('P','0','1','0')}, 467ec681f3Smrg {VA_FOURCC('P','0','1','6')}, 477ec681f3Smrg {VA_FOURCC('I','4','2','0')}, 487ec681f3Smrg {VA_FOURCC('Y','V','1','2')}, 497ec681f3Smrg {VA_FOURCC('Y','U','Y','V')}, 507ec681f3Smrg {VA_FOURCC('Y','U','Y','2')}, 517ec681f3Smrg {VA_FOURCC('U','Y','V','Y')}, 527ec681f3Smrg {.fourcc = VA_FOURCC('B','G','R','A'), .byte_order = VA_LSB_FIRST, 32, 32, 537ec681f3Smrg 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000}, 547ec681f3Smrg {.fourcc = VA_FOURCC('R','G','B','A'), .byte_order = VA_LSB_FIRST, 32, 32, 557ec681f3Smrg 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000}, 567ec681f3Smrg {.fourcc = VA_FOURCC('B','G','R','X'), .byte_order = VA_LSB_FIRST, 32, 24, 577ec681f3Smrg 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000}, 587ec681f3Smrg {.fourcc = VA_FOURCC('R','G','B','X'), .byte_order = VA_LSB_FIRST, 32, 24, 597ec681f3Smrg 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000} 607ec681f3Smrg}; 617ec681f3Smrg 627ec681f3Smrgstatic void 637ec681f3SmrgvlVaVideoSurfaceSize(vlVaSurface *p_surf, int component, 647ec681f3Smrg unsigned *width, unsigned *height) 657ec681f3Smrg{ 667ec681f3Smrg *width = p_surf->templat.width; 677ec681f3Smrg *height = p_surf->templat.height; 687ec681f3Smrg 697ec681f3Smrg vl_video_buffer_adjust_size(width, height, component, 707ec681f3Smrg pipe_format_to_chroma_format(p_surf->templat.buffer_format), 717ec681f3Smrg p_surf->templat.interlaced); 727ec681f3Smrg} 737ec681f3Smrg 747ec681f3SmrgVAStatus 757ec681f3SmrgvlVaQueryImageFormats(VADriverContextP ctx, VAImageFormat *format_list, int *num_formats) 767ec681f3Smrg{ 777ec681f3Smrg struct pipe_screen *pscreen; 787ec681f3Smrg enum pipe_format format; 797ec681f3Smrg int i; 807ec681f3Smrg 817ec681f3Smrg STATIC_ASSERT(ARRAY_SIZE(formats) == VL_VA_MAX_IMAGE_FORMATS); 827ec681f3Smrg 837ec681f3Smrg if (!ctx) 847ec681f3Smrg return VA_STATUS_ERROR_INVALID_CONTEXT; 857ec681f3Smrg 867ec681f3Smrg if (!(format_list && num_formats)) 877ec681f3Smrg return VA_STATUS_ERROR_INVALID_PARAMETER; 887ec681f3Smrg 897ec681f3Smrg *num_formats = 0; 907ec681f3Smrg pscreen = VL_VA_PSCREEN(ctx); 917ec681f3Smrg for (i = 0; i < ARRAY_SIZE(formats); ++i) { 927ec681f3Smrg format = VaFourccToPipeFormat(formats[i].fourcc); 937ec681f3Smrg if (pscreen->is_video_format_supported(pscreen, format, 947ec681f3Smrg PIPE_VIDEO_PROFILE_UNKNOWN, 957ec681f3Smrg PIPE_VIDEO_ENTRYPOINT_BITSTREAM)) 967ec681f3Smrg format_list[(*num_formats)++] = formats[i]; 977ec681f3Smrg } 987ec681f3Smrg 997ec681f3Smrg return VA_STATUS_SUCCESS; 1007ec681f3Smrg} 1017ec681f3Smrg 1027ec681f3SmrgVAStatus 1037ec681f3SmrgvlVaCreateImage(VADriverContextP ctx, VAImageFormat *format, int width, int height, VAImage *image) 1047ec681f3Smrg{ 1057ec681f3Smrg VAStatus status; 1067ec681f3Smrg vlVaDriver *drv; 1077ec681f3Smrg VAImage *img; 1087ec681f3Smrg int w, h; 1097ec681f3Smrg 1107ec681f3Smrg if (!ctx) 1117ec681f3Smrg return VA_STATUS_ERROR_INVALID_CONTEXT; 1127ec681f3Smrg 1137ec681f3Smrg if (!(format && image && width && height)) 1147ec681f3Smrg return VA_STATUS_ERROR_INVALID_PARAMETER; 1157ec681f3Smrg 1167ec681f3Smrg drv = VL_VA_DRIVER(ctx); 1177ec681f3Smrg 1187ec681f3Smrg img = CALLOC(1, sizeof(VAImage)); 1197ec681f3Smrg if (!img) 1207ec681f3Smrg return VA_STATUS_ERROR_ALLOCATION_FAILED; 1217ec681f3Smrg mtx_lock(&drv->mutex); 1227ec681f3Smrg img->image_id = handle_table_add(drv->htab, img); 1237ec681f3Smrg mtx_unlock(&drv->mutex); 1247ec681f3Smrg 1257ec681f3Smrg img->format = *format; 1267ec681f3Smrg img->width = width; 1277ec681f3Smrg img->height = height; 1287ec681f3Smrg w = align(width, 2); 1297ec681f3Smrg h = align(height, 2); 1307ec681f3Smrg 1317ec681f3Smrg switch (format->fourcc) { 1327ec681f3Smrg case VA_FOURCC('N','V','1','2'): 1337ec681f3Smrg img->num_planes = 2; 1347ec681f3Smrg img->pitches[0] = w; 1357ec681f3Smrg img->offsets[0] = 0; 1367ec681f3Smrg img->pitches[1] = w; 1377ec681f3Smrg img->offsets[1] = w * h; 1387ec681f3Smrg img->data_size = w * h * 3 / 2; 1397ec681f3Smrg break; 1407ec681f3Smrg 1417ec681f3Smrg case VA_FOURCC('P','0','1','0'): 1427ec681f3Smrg case VA_FOURCC('P','0','1','6'): 1437ec681f3Smrg img->num_planes = 2; 1447ec681f3Smrg img->pitches[0] = w * 2; 1457ec681f3Smrg img->offsets[0] = 0; 1467ec681f3Smrg img->pitches[1] = w * 2; 1477ec681f3Smrg img->offsets[1] = w * h * 2; 1487ec681f3Smrg img->data_size = w * h * 3; 1497ec681f3Smrg break; 1507ec681f3Smrg 1517ec681f3Smrg case VA_FOURCC('I','4','2','0'): 1527ec681f3Smrg case VA_FOURCC('Y','V','1','2'): 1537ec681f3Smrg img->num_planes = 3; 1547ec681f3Smrg img->pitches[0] = w; 1557ec681f3Smrg img->offsets[0] = 0; 1567ec681f3Smrg img->pitches[1] = w / 2; 1577ec681f3Smrg img->offsets[1] = w * h; 1587ec681f3Smrg img->pitches[2] = w / 2; 1597ec681f3Smrg img->offsets[2] = w * h * 5 / 4; 1607ec681f3Smrg img->data_size = w * h * 3 / 2; 1617ec681f3Smrg break; 1627ec681f3Smrg 1637ec681f3Smrg case VA_FOURCC('U','Y','V','Y'): 1647ec681f3Smrg case VA_FOURCC('Y','U','Y','V'): 1657ec681f3Smrg case VA_FOURCC('Y','U','Y','2'): 1667ec681f3Smrg img->num_planes = 1; 1677ec681f3Smrg img->pitches[0] = w * 2; 1687ec681f3Smrg img->offsets[0] = 0; 1697ec681f3Smrg img->data_size = w * h * 2; 1707ec681f3Smrg break; 1717ec681f3Smrg 1727ec681f3Smrg case VA_FOURCC('B','G','R','A'): 1737ec681f3Smrg case VA_FOURCC('R','G','B','A'): 1747ec681f3Smrg case VA_FOURCC('B','G','R','X'): 1757ec681f3Smrg case VA_FOURCC('R','G','B','X'): 1767ec681f3Smrg img->num_planes = 1; 1777ec681f3Smrg img->pitches[0] = w * 4; 1787ec681f3Smrg img->offsets[0] = 0; 1797ec681f3Smrg img->data_size = w * h * 4; 1807ec681f3Smrg break; 1817ec681f3Smrg 1827ec681f3Smrg default: 1837ec681f3Smrg return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT; 1847ec681f3Smrg } 1857ec681f3Smrg 1867ec681f3Smrg status = vlVaCreateBuffer(ctx, 0, VAImageBufferType, 1877ec681f3Smrg align(img->data_size, 16), 1887ec681f3Smrg 1, NULL, &img->buf); 1897ec681f3Smrg if (status != VA_STATUS_SUCCESS) 1907ec681f3Smrg return status; 1917ec681f3Smrg *image = *img; 1927ec681f3Smrg 1937ec681f3Smrg return status; 1947ec681f3Smrg} 1957ec681f3Smrg 1967ec681f3SmrgVAStatus 1977ec681f3SmrgvlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image) 1987ec681f3Smrg{ 1997ec681f3Smrg vlVaDriver *drv; 2007ec681f3Smrg vlVaSurface *surf; 2017ec681f3Smrg vlVaBuffer *img_buf; 2027ec681f3Smrg VAImage *img; 2037ec681f3Smrg VAStatus status; 2047ec681f3Smrg struct pipe_screen *screen; 2057ec681f3Smrg struct pipe_surface **surfaces; 2067ec681f3Smrg struct pipe_video_buffer *new_buffer = NULL; 2077ec681f3Smrg int w; 2087ec681f3Smrg int h; 2097ec681f3Smrg int i; 2107ec681f3Smrg unsigned stride = 0; 2117ec681f3Smrg unsigned offset = 0; 2127ec681f3Smrg 2137ec681f3Smrg /* This function is used by some programs to test for hardware decoding, but on 2147ec681f3Smrg * AMD devices, the buffers default to interlaced, which causes this function to fail. 2157ec681f3Smrg * Some programs expect this function to fail, while others, assume this means 2167ec681f3Smrg * hardware acceleration is not available and give up without trying the fall-back 2177ec681f3Smrg * vaCreateImage + vaPutImage 2187ec681f3Smrg */ 2197ec681f3Smrg const char *proc = util_get_process_name(); 2207ec681f3Smrg const char *derive_interlaced_allowlist[] = { 2217ec681f3Smrg "vlc", 2227ec681f3Smrg "h264encode", 2237ec681f3Smrg "hevcencode" 2247ec681f3Smrg }; 2257ec681f3Smrg 2267ec681f3Smrg if (!ctx) 2277ec681f3Smrg return VA_STATUS_ERROR_INVALID_CONTEXT; 2287ec681f3Smrg 2297ec681f3Smrg drv = VL_VA_DRIVER(ctx); 2307ec681f3Smrg 2317ec681f3Smrg if (!drv) 2327ec681f3Smrg return VA_STATUS_ERROR_INVALID_CONTEXT; 2337ec681f3Smrg 2347ec681f3Smrg screen = VL_VA_PSCREEN(ctx); 2357ec681f3Smrg 2367ec681f3Smrg if (!screen) 2377ec681f3Smrg return VA_STATUS_ERROR_INVALID_CONTEXT; 2387ec681f3Smrg 2397ec681f3Smrg surf = handle_table_get(drv->htab, surface); 2407ec681f3Smrg 2417ec681f3Smrg if (!surf || !surf->buffer) 2427ec681f3Smrg return VA_STATUS_ERROR_INVALID_SURFACE; 2437ec681f3Smrg 2447ec681f3Smrg if (surf->buffer->interlaced) { 2457ec681f3Smrg for (i = 0; i < ARRAY_SIZE(derive_interlaced_allowlist); i++) 2467ec681f3Smrg if ((strcmp(derive_interlaced_allowlist[i], proc) == 0)) 2477ec681f3Smrg break; 2487ec681f3Smrg 2497ec681f3Smrg if (i >= ARRAY_SIZE(derive_interlaced_allowlist) || 2507ec681f3Smrg !screen->get_video_param(screen, PIPE_VIDEO_PROFILE_UNKNOWN, 2517ec681f3Smrg PIPE_VIDEO_ENTRYPOINT_BITSTREAM, 2527ec681f3Smrg PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE)) 2537ec681f3Smrg return VA_STATUS_ERROR_OPERATION_FAILED; 2547ec681f3Smrg } 2557ec681f3Smrg 2567ec681f3Smrg surfaces = surf->buffer->get_surfaces(surf->buffer); 2577ec681f3Smrg if (!surfaces || !surfaces[0]->texture) 2587ec681f3Smrg return VA_STATUS_ERROR_ALLOCATION_FAILED; 2597ec681f3Smrg 2607ec681f3Smrg img = CALLOC(1, sizeof(VAImage)); 2617ec681f3Smrg if (!img) 2627ec681f3Smrg return VA_STATUS_ERROR_ALLOCATION_FAILED; 2637ec681f3Smrg 2647ec681f3Smrg img->format.fourcc = PipeFormatToVaFourcc(surf->buffer->buffer_format); 2657ec681f3Smrg img->buf = VA_INVALID_ID; 2667ec681f3Smrg /* Use the visible dimensions. */ 2677ec681f3Smrg img->width = surf->templat.width; 2687ec681f3Smrg img->height = surf->templat.height; 2697ec681f3Smrg img->num_palette_entries = 0; 2707ec681f3Smrg img->entry_bytes = 0; 2717ec681f3Smrg /* Image data size is computed using internal dimensions. */ 2727ec681f3Smrg w = align(surf->buffer->width, 2); 2737ec681f3Smrg h = align(surf->buffer->height, 2); 2747ec681f3Smrg 2757ec681f3Smrg for (i = 0; i < ARRAY_SIZE(formats); ++i) { 2767ec681f3Smrg if (img->format.fourcc == formats[i].fourcc) { 2777ec681f3Smrg img->format = formats[i]; 2787ec681f3Smrg break; 2797ec681f3Smrg } 2807ec681f3Smrg } 2817ec681f3Smrg 2827ec681f3Smrg mtx_lock(&drv->mutex); 2837ec681f3Smrg if (screen->resource_get_info) { 2847ec681f3Smrg screen->resource_get_info(screen, surfaces[0]->texture, &stride, 2857ec681f3Smrg &offset); 2867ec681f3Smrg if (!stride) 2877ec681f3Smrg offset = 0; 2887ec681f3Smrg } 2897ec681f3Smrg 2907ec681f3Smrg img->num_planes = 1; 2917ec681f3Smrg img->offsets[0] = offset; 2927ec681f3Smrg 2937ec681f3Smrg switch (img->format.fourcc) { 2947ec681f3Smrg case VA_FOURCC('U','Y','V','Y'): 2957ec681f3Smrg case VA_FOURCC('Y','U','Y','V'): 2967ec681f3Smrg img->pitches[0] = stride > 0 ? stride : w * 2; 2977ec681f3Smrg assert(img->pitches[0] >= (w * 2)); 2987ec681f3Smrg img->data_size = img->pitches[0] * h; 2997ec681f3Smrg break; 3007ec681f3Smrg 3017ec681f3Smrg case VA_FOURCC('B','G','R','A'): 3027ec681f3Smrg case VA_FOURCC('R','G','B','A'): 3037ec681f3Smrg case VA_FOURCC('B','G','R','X'): 3047ec681f3Smrg case VA_FOURCC('R','G','B','X'): 3057ec681f3Smrg img->pitches[0] = stride > 0 ? stride : w * 4; 3067ec681f3Smrg assert(img->pitches[0] >= (w * 4)); 3077ec681f3Smrg img->data_size = img->pitches[0] * h; 3087ec681f3Smrg break; 3097ec681f3Smrg 3107ec681f3Smrg case VA_FOURCC('N','V','1','2'): 3117ec681f3Smrg case VA_FOURCC('P','0','1','0'): 3127ec681f3Smrg case VA_FOURCC('P','0','1','6'): 3137ec681f3Smrg if (surf->buffer->interlaced) { 3147ec681f3Smrg struct u_rect src_rect, dst_rect; 3157ec681f3Smrg struct pipe_video_buffer new_template; 3167ec681f3Smrg 3177ec681f3Smrg new_template = surf->templat; 3187ec681f3Smrg new_template.interlaced = false; 3197ec681f3Smrg new_buffer = drv->pipe->create_video_buffer(drv->pipe, &new_template); 3207ec681f3Smrg 3217ec681f3Smrg /* not all devices support non-interlaced buffers */ 3227ec681f3Smrg if (!new_buffer) { 3237ec681f3Smrg status = VA_STATUS_ERROR_OPERATION_FAILED; 3247ec681f3Smrg goto exit_on_error; 3257ec681f3Smrg } 3267ec681f3Smrg 3277ec681f3Smrg /* convert the interlaced to the progressive */ 3287ec681f3Smrg src_rect.x0 = dst_rect.x0 = 0; 3297ec681f3Smrg src_rect.x1 = dst_rect.x1 = surf->templat.width; 3307ec681f3Smrg src_rect.y0 = dst_rect.y0 = 0; 3317ec681f3Smrg src_rect.y1 = dst_rect.y1 = surf->templat.height; 3327ec681f3Smrg 3337ec681f3Smrg vl_compositor_yuv_deint_full(&drv->cstate, &drv->compositor, 3347ec681f3Smrg surf->buffer, new_buffer, 3357ec681f3Smrg &src_rect, &dst_rect, 3367ec681f3Smrg VL_COMPOSITOR_WEAVE); 3377ec681f3Smrg 3387ec681f3Smrg /* recalculate the values now that we have a new surface */ 3397ec681f3Smrg surfaces = surf->buffer->get_surfaces(new_buffer); 3407ec681f3Smrg if (screen->resource_get_info) { 3417ec681f3Smrg screen->resource_get_info(screen, surfaces[0]->texture, &stride, 3427ec681f3Smrg &offset); 3437ec681f3Smrg if (!stride) 3447ec681f3Smrg offset = 0; 3457ec681f3Smrg } 3467ec681f3Smrg 3477ec681f3Smrg w = align(new_buffer->width, 2); 3487ec681f3Smrg h = align(new_buffer->height, 2); 3497ec681f3Smrg } 3507ec681f3Smrg 3517ec681f3Smrg img->num_planes = 2; 3527ec681f3Smrg img->pitches[0] = stride > 0 ? stride : w; 3537ec681f3Smrg img->pitches[1] = stride > 0 ? stride : w; 3547ec681f3Smrg img->offsets[1] = (stride > 0 ? stride : w) * h; 3557ec681f3Smrg img->data_size = (stride > 0 ? stride : w) * h * 3 / 2; 3567ec681f3Smrg break; 3577ec681f3Smrg 3587ec681f3Smrg default: 3597ec681f3Smrg /* VaDeriveImage only supports contiguous planes. But there is now a 3607ec681f3Smrg more generic api vlVaExportSurfaceHandle. */ 3617ec681f3Smrg status = VA_STATUS_ERROR_OPERATION_FAILED; 3627ec681f3Smrg goto exit_on_error; 3637ec681f3Smrg } 3647ec681f3Smrg 3657ec681f3Smrg img_buf = CALLOC(1, sizeof(vlVaBuffer)); 3667ec681f3Smrg if (!img_buf) { 3677ec681f3Smrg status = VA_STATUS_ERROR_ALLOCATION_FAILED; 3687ec681f3Smrg goto exit_on_error; 3697ec681f3Smrg } 3707ec681f3Smrg 3717ec681f3Smrg img->image_id = handle_table_add(drv->htab, img); 3727ec681f3Smrg 3737ec681f3Smrg img_buf->type = VAImageBufferType; 3747ec681f3Smrg img_buf->size = img->data_size; 3757ec681f3Smrg img_buf->num_elements = 1; 3767ec681f3Smrg 3777ec681f3Smrg pipe_resource_reference(&img_buf->derived_surface.resource, surfaces[0]->texture); 3787ec681f3Smrg img_buf->derived_image_buffer = new_buffer; 3797ec681f3Smrg 3807ec681f3Smrg img->buf = handle_table_add(VL_VA_DRIVER(ctx)->htab, img_buf); 3817ec681f3Smrg mtx_unlock(&drv->mutex); 3827ec681f3Smrg 3837ec681f3Smrg *image = *img; 3847ec681f3Smrg 3857ec681f3Smrg return VA_STATUS_SUCCESS; 3867ec681f3Smrg 3877ec681f3Smrgexit_on_error: 3887ec681f3Smrg FREE(img); 3897ec681f3Smrg mtx_unlock(&drv->mutex); 3907ec681f3Smrg return status; 3917ec681f3Smrg} 3927ec681f3Smrg 3937ec681f3SmrgVAStatus 3947ec681f3SmrgvlVaDestroyImage(VADriverContextP ctx, VAImageID image) 3957ec681f3Smrg{ 3967ec681f3Smrg vlVaDriver *drv; 3977ec681f3Smrg VAImage *vaimage; 3987ec681f3Smrg VAStatus status; 3997ec681f3Smrg 4007ec681f3Smrg if (!ctx) 4017ec681f3Smrg return VA_STATUS_ERROR_INVALID_CONTEXT; 4027ec681f3Smrg 4037ec681f3Smrg drv = VL_VA_DRIVER(ctx); 4047ec681f3Smrg mtx_lock(&drv->mutex); 4057ec681f3Smrg vaimage = handle_table_get(drv->htab, image); 4067ec681f3Smrg if (!vaimage) { 4077ec681f3Smrg mtx_unlock(&drv->mutex); 4087ec681f3Smrg return VA_STATUS_ERROR_INVALID_IMAGE; 4097ec681f3Smrg } 4107ec681f3Smrg 4117ec681f3Smrg handle_table_remove(VL_VA_DRIVER(ctx)->htab, image); 4127ec681f3Smrg mtx_unlock(&drv->mutex); 4137ec681f3Smrg status = vlVaDestroyBuffer(ctx, vaimage->buf); 4147ec681f3Smrg FREE(vaimage); 4157ec681f3Smrg return status; 4167ec681f3Smrg} 4177ec681f3Smrg 4187ec681f3SmrgVAStatus 4197ec681f3SmrgvlVaSetImagePalette(VADriverContextP ctx, VAImageID image, unsigned char *palette) 4207ec681f3Smrg{ 4217ec681f3Smrg if (!ctx) 4227ec681f3Smrg return VA_STATUS_ERROR_INVALID_CONTEXT; 4237ec681f3Smrg 4247ec681f3Smrg return VA_STATUS_ERROR_UNIMPLEMENTED; 4257ec681f3Smrg} 4267ec681f3Smrg 4277ec681f3SmrgVAStatus 4287ec681f3SmrgvlVaGetImage(VADriverContextP ctx, VASurfaceID surface, int x, int y, 4297ec681f3Smrg unsigned int width, unsigned int height, VAImageID image) 4307ec681f3Smrg{ 4317ec681f3Smrg vlVaDriver *drv; 4327ec681f3Smrg vlVaSurface *surf; 4337ec681f3Smrg vlVaBuffer *img_buf; 4347ec681f3Smrg VAImage *vaimage; 4357ec681f3Smrg struct pipe_sampler_view **views; 4367ec681f3Smrg enum pipe_format format; 4377ec681f3Smrg bool convert = false; 4387ec681f3Smrg void *data[3]; 4397ec681f3Smrg unsigned pitches[3], i, j; 4407ec681f3Smrg 4417ec681f3Smrg if (!ctx) 4427ec681f3Smrg return VA_STATUS_ERROR_INVALID_CONTEXT; 4437ec681f3Smrg 4447ec681f3Smrg drv = VL_VA_DRIVER(ctx); 4457ec681f3Smrg 4467ec681f3Smrg mtx_lock(&drv->mutex); 4477ec681f3Smrg surf = handle_table_get(drv->htab, surface); 4487ec681f3Smrg if (!surf || !surf->buffer) { 4497ec681f3Smrg mtx_unlock(&drv->mutex); 4507ec681f3Smrg return VA_STATUS_ERROR_INVALID_SURFACE; 4517ec681f3Smrg } 4527ec681f3Smrg 4537ec681f3Smrg vaimage = handle_table_get(drv->htab, image); 4547ec681f3Smrg if (!vaimage) { 4557ec681f3Smrg mtx_unlock(&drv->mutex); 4567ec681f3Smrg return VA_STATUS_ERROR_INVALID_IMAGE; 4577ec681f3Smrg } 4587ec681f3Smrg 4597ec681f3Smrg if (x < 0 || y < 0) { 4607ec681f3Smrg mtx_unlock(&drv->mutex); 4617ec681f3Smrg return VA_STATUS_ERROR_INVALID_PARAMETER; 4627ec681f3Smrg } 4637ec681f3Smrg 4647ec681f3Smrg if (x + width > surf->templat.width || 4657ec681f3Smrg y + height > surf->templat.height) { 4667ec681f3Smrg mtx_unlock(&drv->mutex); 4677ec681f3Smrg return VA_STATUS_ERROR_INVALID_PARAMETER; 4687ec681f3Smrg } 4697ec681f3Smrg 4707ec681f3Smrg if (width > vaimage->width || 4717ec681f3Smrg height > vaimage->height) { 4727ec681f3Smrg mtx_unlock(&drv->mutex); 4737ec681f3Smrg return VA_STATUS_ERROR_INVALID_PARAMETER; 4747ec681f3Smrg } 4757ec681f3Smrg 4767ec681f3Smrg img_buf = handle_table_get(drv->htab, vaimage->buf); 4777ec681f3Smrg if (!img_buf) { 4787ec681f3Smrg mtx_unlock(&drv->mutex); 4797ec681f3Smrg return VA_STATUS_ERROR_INVALID_BUFFER; 4807ec681f3Smrg } 4817ec681f3Smrg 4827ec681f3Smrg format = VaFourccToPipeFormat(vaimage->format.fourcc); 4837ec681f3Smrg if (format == PIPE_FORMAT_NONE) { 4847ec681f3Smrg mtx_unlock(&drv->mutex); 4857ec681f3Smrg return VA_STATUS_ERROR_OPERATION_FAILED; 4867ec681f3Smrg } 4877ec681f3Smrg 4887ec681f3Smrg 4897ec681f3Smrg if (format != surf->buffer->buffer_format) { 4907ec681f3Smrg /* support NV12 to YV12 and IYUV conversion now only */ 4917ec681f3Smrg if ((format == PIPE_FORMAT_YV12 && 4927ec681f3Smrg surf->buffer->buffer_format == PIPE_FORMAT_NV12) || 4937ec681f3Smrg (format == PIPE_FORMAT_IYUV && 4947ec681f3Smrg surf->buffer->buffer_format == PIPE_FORMAT_NV12)) 4957ec681f3Smrg convert = true; 4967ec681f3Smrg else if (format == PIPE_FORMAT_NV12 && 4977ec681f3Smrg (surf->buffer->buffer_format == PIPE_FORMAT_P010 || 4987ec681f3Smrg surf->buffer->buffer_format == PIPE_FORMAT_P016)) { 4997ec681f3Smrg mtx_unlock(&drv->mutex); 5007ec681f3Smrg return VA_STATUS_ERROR_OPERATION_FAILED; 5017ec681f3Smrg } 5027ec681f3Smrg else { 5037ec681f3Smrg mtx_unlock(&drv->mutex); 5047ec681f3Smrg return VA_STATUS_ERROR_OPERATION_FAILED; 5057ec681f3Smrg } 5067ec681f3Smrg } 5077ec681f3Smrg 5087ec681f3Smrg views = surf->buffer->get_sampler_view_planes(surf->buffer); 5097ec681f3Smrg if (!views) { 5107ec681f3Smrg mtx_unlock(&drv->mutex); 5117ec681f3Smrg return VA_STATUS_ERROR_OPERATION_FAILED; 5127ec681f3Smrg } 5137ec681f3Smrg 5147ec681f3Smrg for (i = 0; i < vaimage->num_planes; i++) { 5157ec681f3Smrg data[i] = img_buf->data + vaimage->offsets[i]; 5167ec681f3Smrg pitches[i] = vaimage->pitches[i]; 5177ec681f3Smrg } 5187ec681f3Smrg if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) { 5197ec681f3Smrg void *tmp_d; 5207ec681f3Smrg unsigned tmp_p; 5217ec681f3Smrg tmp_d = data[1]; 5227ec681f3Smrg data[1] = data[2]; 5237ec681f3Smrg data[2] = tmp_d; 5247ec681f3Smrg tmp_p = pitches[1]; 5257ec681f3Smrg pitches[1] = pitches[2]; 5267ec681f3Smrg pitches[2] = tmp_p; 5277ec681f3Smrg } 5287ec681f3Smrg 5297ec681f3Smrg for (i = 0; i < vaimage->num_planes; i++) { 5307ec681f3Smrg unsigned box_w = align(width, 2); 5317ec681f3Smrg unsigned box_h = align(height, 2); 5327ec681f3Smrg unsigned box_x = x & ~1; 5337ec681f3Smrg unsigned box_y = y & ~1; 5347ec681f3Smrg if (!views[i]) continue; 5357ec681f3Smrg vl_video_buffer_adjust_size(&box_w, &box_h, i, 5367ec681f3Smrg pipe_format_to_chroma_format(surf->templat.buffer_format), 5377ec681f3Smrg surf->templat.interlaced); 5387ec681f3Smrg vl_video_buffer_adjust_size(&box_x, &box_y, i, 5397ec681f3Smrg pipe_format_to_chroma_format(surf->templat.buffer_format), 5407ec681f3Smrg surf->templat.interlaced); 5417ec681f3Smrg for (j = 0; j < views[i]->texture->array_size; ++j) { 5427ec681f3Smrg struct pipe_box box = {box_x, box_y, j, box_w, box_h, 1}; 5437ec681f3Smrg struct pipe_transfer *transfer; 5447ec681f3Smrg uint8_t *map; 5457ec681f3Smrg map = drv->pipe->texture_map(drv->pipe, views[i]->texture, 0, 5467ec681f3Smrg PIPE_MAP_READ, &box, &transfer); 5477ec681f3Smrg if (!map) { 5487ec681f3Smrg mtx_unlock(&drv->mutex); 5497ec681f3Smrg return VA_STATUS_ERROR_OPERATION_FAILED; 5507ec681f3Smrg } 5517ec681f3Smrg 5527ec681f3Smrg if (i == 1 && convert) { 5537ec681f3Smrg u_copy_nv12_to_yv12(data, pitches, i, j, 5547ec681f3Smrg transfer->stride, views[i]->texture->array_size, 5557ec681f3Smrg map, box.width, box.height); 5567ec681f3Smrg } else { 5577ec681f3Smrg util_copy_rect(data[i] + pitches[i] * j, 5587ec681f3Smrg views[i]->texture->format, 5597ec681f3Smrg pitches[i] * views[i]->texture->array_size, 0, 0, 5607ec681f3Smrg box.width, box.height, map, transfer->stride, 0, 0); 5617ec681f3Smrg } 5627ec681f3Smrg pipe_texture_unmap(drv->pipe, transfer); 5637ec681f3Smrg } 5647ec681f3Smrg } 5657ec681f3Smrg mtx_unlock(&drv->mutex); 5667ec681f3Smrg 5677ec681f3Smrg return VA_STATUS_SUCCESS; 5687ec681f3Smrg} 5697ec681f3Smrg 5707ec681f3SmrgVAStatus 5717ec681f3SmrgvlVaPutImage(VADriverContextP ctx, VASurfaceID surface, VAImageID image, 5727ec681f3Smrg int src_x, int src_y, unsigned int src_width, unsigned int src_height, 5737ec681f3Smrg int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height) 5747ec681f3Smrg{ 5757ec681f3Smrg vlVaDriver *drv; 5767ec681f3Smrg vlVaSurface *surf; 5777ec681f3Smrg vlVaBuffer *img_buf; 5787ec681f3Smrg VAImage *vaimage; 5797ec681f3Smrg struct pipe_sampler_view **views; 5807ec681f3Smrg enum pipe_format format; 5817ec681f3Smrg void *data[3]; 5827ec681f3Smrg unsigned pitches[3], i, j; 5837ec681f3Smrg 5847ec681f3Smrg if (!ctx) 5857ec681f3Smrg return VA_STATUS_ERROR_INVALID_CONTEXT; 5867ec681f3Smrg 5877ec681f3Smrg drv = VL_VA_DRIVER(ctx); 5887ec681f3Smrg mtx_lock(&drv->mutex); 5897ec681f3Smrg 5907ec681f3Smrg surf = handle_table_get(drv->htab, surface); 5917ec681f3Smrg if (!surf || !surf->buffer) { 5927ec681f3Smrg mtx_unlock(&drv->mutex); 5937ec681f3Smrg return VA_STATUS_ERROR_INVALID_SURFACE; 5947ec681f3Smrg } 5957ec681f3Smrg 5967ec681f3Smrg vaimage = handle_table_get(drv->htab, image); 5977ec681f3Smrg if (!vaimage) { 5987ec681f3Smrg mtx_unlock(&drv->mutex); 5997ec681f3Smrg return VA_STATUS_ERROR_INVALID_IMAGE; 6007ec681f3Smrg } 6017ec681f3Smrg 6027ec681f3Smrg img_buf = handle_table_get(drv->htab, vaimage->buf); 6037ec681f3Smrg if (!img_buf) { 6047ec681f3Smrg mtx_unlock(&drv->mutex); 6057ec681f3Smrg return VA_STATUS_ERROR_INVALID_BUFFER; 6067ec681f3Smrg } 6077ec681f3Smrg 6087ec681f3Smrg if (img_buf->derived_surface.resource) { 6097ec681f3Smrg /* Attempting to transfer derived image to surface */ 6107ec681f3Smrg mtx_unlock(&drv->mutex); 6117ec681f3Smrg return VA_STATUS_ERROR_UNIMPLEMENTED; 6127ec681f3Smrg } 6137ec681f3Smrg 6147ec681f3Smrg format = VaFourccToPipeFormat(vaimage->format.fourcc); 6157ec681f3Smrg 6167ec681f3Smrg if (format == PIPE_FORMAT_NONE) { 6177ec681f3Smrg mtx_unlock(&drv->mutex); 6187ec681f3Smrg return VA_STATUS_ERROR_OPERATION_FAILED; 6197ec681f3Smrg } 6207ec681f3Smrg 6217ec681f3Smrg if ((format != surf->buffer->buffer_format) && 6227ec681f3Smrg ((format != PIPE_FORMAT_YV12) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12)) && 6237ec681f3Smrg ((format != PIPE_FORMAT_IYUV) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12))) { 6247ec681f3Smrg struct pipe_video_buffer *tmp_buf; 6257ec681f3Smrg 6267ec681f3Smrg surf->templat.buffer_format = format; 6277ec681f3Smrg if (format == PIPE_FORMAT_YUYV || format == PIPE_FORMAT_UYVY || 6287ec681f3Smrg format == PIPE_FORMAT_B8G8R8A8_UNORM || format == PIPE_FORMAT_B8G8R8X8_UNORM || 6297ec681f3Smrg format == PIPE_FORMAT_R8G8B8A8_UNORM || format == PIPE_FORMAT_R8G8B8X8_UNORM) 6307ec681f3Smrg surf->templat.interlaced = false; 6317ec681f3Smrg tmp_buf = drv->pipe->create_video_buffer(drv->pipe, &surf->templat); 6327ec681f3Smrg 6337ec681f3Smrg if (!tmp_buf) { 6347ec681f3Smrg mtx_unlock(&drv->mutex); 6357ec681f3Smrg return VA_STATUS_ERROR_ALLOCATION_FAILED; 6367ec681f3Smrg } 6377ec681f3Smrg 6387ec681f3Smrg surf->buffer->destroy(surf->buffer); 6397ec681f3Smrg surf->buffer = tmp_buf; 6407ec681f3Smrg } 6417ec681f3Smrg 6427ec681f3Smrg views = surf->buffer->get_sampler_view_planes(surf->buffer); 6437ec681f3Smrg if (!views) { 6447ec681f3Smrg mtx_unlock(&drv->mutex); 6457ec681f3Smrg return VA_STATUS_ERROR_OPERATION_FAILED; 6467ec681f3Smrg } 6477ec681f3Smrg 6487ec681f3Smrg for (i = 0; i < vaimage->num_planes; i++) { 6497ec681f3Smrg data[i] = img_buf->data + vaimage->offsets[i]; 6507ec681f3Smrg pitches[i] = vaimage->pitches[i]; 6517ec681f3Smrg } 6527ec681f3Smrg if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) { 6537ec681f3Smrg void *tmp_d; 6547ec681f3Smrg unsigned tmp_p; 6557ec681f3Smrg tmp_d = data[1]; 6567ec681f3Smrg data[1] = data[2]; 6577ec681f3Smrg data[2] = tmp_d; 6587ec681f3Smrg tmp_p = pitches[1]; 6597ec681f3Smrg pitches[1] = pitches[2]; 6607ec681f3Smrg pitches[2] = tmp_p; 6617ec681f3Smrg } 6627ec681f3Smrg 6637ec681f3Smrg for (i = 0; i < vaimage->num_planes; ++i) { 6647ec681f3Smrg unsigned width, height; 6657ec681f3Smrg struct pipe_resource *tex; 6667ec681f3Smrg 6677ec681f3Smrg if (!views[i]) continue; 6687ec681f3Smrg tex = views[i]->texture; 6697ec681f3Smrg 6707ec681f3Smrg vlVaVideoSurfaceSize(surf, i, &width, &height); 6717ec681f3Smrg for (j = 0; j < tex->array_size; ++j) { 6727ec681f3Smrg struct pipe_box dst_box = {0, 0, j, width, height, 1}; 6737ec681f3Smrg 6747ec681f3Smrg if (((format == PIPE_FORMAT_YV12) || (format == PIPE_FORMAT_IYUV)) 6757ec681f3Smrg && (surf->buffer->buffer_format == PIPE_FORMAT_NV12) 6767ec681f3Smrg && i == 1) { 6777ec681f3Smrg struct pipe_transfer *transfer = NULL; 6787ec681f3Smrg uint8_t *map = NULL; 6797ec681f3Smrg 6807ec681f3Smrg map = drv->pipe->texture_map(drv->pipe, 6817ec681f3Smrg tex, 6827ec681f3Smrg 0, 6837ec681f3Smrg PIPE_MAP_WRITE | 6847ec681f3Smrg PIPE_MAP_DISCARD_RANGE, 6857ec681f3Smrg &dst_box, &transfer); 6867ec681f3Smrg if (map == NULL) { 6877ec681f3Smrg mtx_unlock(&drv->mutex); 6887ec681f3Smrg return VA_STATUS_ERROR_OPERATION_FAILED; 6897ec681f3Smrg } 6907ec681f3Smrg 6917ec681f3Smrg u_copy_nv12_from_yv12((const void * const*) data, pitches, i, j, 6927ec681f3Smrg transfer->stride, tex->array_size, 6937ec681f3Smrg map, dst_box.width, dst_box.height); 6947ec681f3Smrg pipe_texture_unmap(drv->pipe, transfer); 6957ec681f3Smrg } else { 6967ec681f3Smrg drv->pipe->texture_subdata(drv->pipe, tex, 0, 6977ec681f3Smrg PIPE_MAP_WRITE, &dst_box, 6987ec681f3Smrg data[i] + pitches[i] * j, 6997ec681f3Smrg pitches[i] * views[i]->texture->array_size, 0); 7007ec681f3Smrg } 7017ec681f3Smrg } 7027ec681f3Smrg } 7037ec681f3Smrg drv->pipe->flush(drv->pipe, NULL, 0); 7047ec681f3Smrg mtx_unlock(&drv->mutex); 7057ec681f3Smrg 7067ec681f3Smrg return VA_STATUS_SUCCESS; 7077ec681f3Smrg} 708