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