Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian.
  4.  * Copyright 2014 Advanced Micro Devices, Inc.
  5.  * All Rights Reserved.
  6.  *
  7.  * Permission is hereby granted, free of charge, to any person obtaining a
  8.  * copy of this software and associated documentation files (the
  9.  * "Software"), to deal in the Software without restriction, including
  10.  * without limitation the rights to use, copy, modify, merge, publish,
  11.  * distribute, sub license, and/or sell copies of the Software, and to
  12.  * permit persons to whom the Software is furnished to do so, subject to
  13.  * the following conditions:
  14.  *
  15.  * The above copyright notice and this permission notice (including the
  16.  * next paragraph) shall be included in all copies or substantial portions
  17.  * of the Software.
  18.  *
  19.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  20.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  22.  * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
  23.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  24.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  25.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26.  *
  27.  **************************************************************************/
  28.  
  29. #include "pipe/p_screen.h"
  30.  
  31. #include "util/u_memory.h"
  32. #include "util/u_handle_table.h"
  33. #include "util/u_surface.h"
  34. #include "util/u_video.h"
  35.  
  36. #include "vl/vl_winsys.h"
  37.  
  38. #include "va_private.h"
  39.  
  40. static const VAImageFormat formats[VL_VA_MAX_IMAGE_FORMATS] =
  41. {
  42.    {VA_FOURCC('N','V','1','2')},
  43.    {VA_FOURCC('I','4','2','0')},
  44.    {VA_FOURCC('Y','V','1','2')},
  45.    {VA_FOURCC('Y','U','Y','V')},
  46.    {VA_FOURCC('U','Y','V','Y')},
  47.    {VA_FOURCC('B','G','R','A')}
  48. };
  49.  
  50. static void
  51. vlVaVideoSurfaceSize(vlVaSurface *p_surf, int component,
  52.                      unsigned *width, unsigned *height)
  53. {
  54.    *width = p_surf->templat.width;
  55.    *height = p_surf->templat.height;
  56.  
  57.    if (component > 0) {
  58.       if (p_surf->templat.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) {
  59.          *width /= 2;
  60.          *height /= 2;
  61.       } else if (p_surf->templat.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_422)
  62.          *width /= 2;
  63.    }
  64.    if (p_surf->templat.interlaced)
  65.       *height /= 2;
  66. }
  67.  
  68. VAStatus
  69. vlVaQueryImageFormats(VADriverContextP ctx, VAImageFormat *format_list, int *num_formats)
  70. {
  71.    struct pipe_screen *pscreen;
  72.    enum pipe_format format;
  73.    int i;
  74.  
  75.    if (!ctx)
  76.       return VA_STATUS_ERROR_INVALID_CONTEXT;
  77.  
  78.    if (!(format_list && num_formats))
  79.       return VA_STATUS_ERROR_INVALID_PARAMETER;
  80.  
  81.    *num_formats = 0;
  82.    pscreen = VL_VA_PSCREEN(ctx);
  83.    for (i = 0; i < VL_VA_MAX_IMAGE_FORMATS; ++i) {
  84.       format = YCbCrToPipe(formats[i].fourcc);
  85.       if (pscreen->is_video_format_supported(pscreen, format,
  86.           PIPE_VIDEO_PROFILE_UNKNOWN,
  87.           PIPE_VIDEO_ENTRYPOINT_BITSTREAM))
  88.          format_list[(*num_formats)++] = formats[i];
  89.    }
  90.  
  91.    return VA_STATUS_SUCCESS;
  92. }
  93.  
  94. VAStatus
  95. vlVaCreateImage(VADriverContextP ctx, VAImageFormat *format, int width, int height, VAImage *image)
  96. {
  97.    VAStatus status;
  98.    vlVaDriver *drv;
  99.    VAImage *img;
  100.    int w, h;
  101.  
  102.    if (!ctx)
  103.       return VA_STATUS_ERROR_INVALID_CONTEXT;
  104.  
  105.    if (!(format && image && width && height))
  106.       return VA_STATUS_ERROR_INVALID_PARAMETER;
  107.  
  108.    drv = VL_VA_DRIVER(ctx);
  109.  
  110.    img = CALLOC(1, sizeof(VAImage));
  111.    if (!img)
  112.       return VA_STATUS_ERROR_ALLOCATION_FAILED;
  113.    img->image_id = handle_table_add(drv->htab, img);
  114.  
  115.    img->format = *format;
  116.    img->width = width;
  117.    img->height = height;
  118.    w = align(width, 2);
  119.    h = align(width, 2);
  120.  
  121.    switch (format->fourcc) {
  122.    case VA_FOURCC('N','V','1','2'):
  123.       img->num_planes = 2;
  124.       img->pitches[0] = w;
  125.       img->offsets[0] = 0;
  126.       img->pitches[1] = w;
  127.       img->offsets[1] = w * h;
  128.       img->data_size  = w * h * 3 / 2;
  129.       break;
  130.  
  131.    case VA_FOURCC('I','4','2','0'):
  132.    case VA_FOURCC('Y','V','1','2'):
  133.       img->num_planes = 3;
  134.       img->pitches[0] = w;
  135.       img->offsets[0] = 0;
  136.       img->pitches[1] = w / 2;
  137.       img->offsets[1] = w * h;
  138.       img->pitches[2] = w / 2;
  139.       img->offsets[2] = w * h * 5 / 4;
  140.       img->data_size  = w * h * 3 / 2;
  141.       break;
  142.  
  143.    case VA_FOURCC('U','Y','V','Y'):
  144.    case VA_FOURCC('Y','U','Y','V'):
  145.       img->num_planes = 1;
  146.       img->pitches[0] = w * 2;
  147.       img->offsets[0] = 0;
  148.       img->data_size  = w * h * 2;
  149.       break;
  150.  
  151.    case VA_FOURCC('B','G','R','A'):
  152.       img->num_planes = 1;
  153.       img->pitches[0] = w * 4;
  154.       img->offsets[0] = 0;
  155.       img->data_size  = w * h * 4;
  156.       break;
  157.  
  158.    default:
  159.       return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
  160.    }
  161.  
  162.    status =  vlVaCreateBuffer(ctx, 0, VAImageBufferType,
  163.                            align(img->data_size, 16),
  164.                            1, NULL, &img->buf);
  165.    if (status != VA_STATUS_SUCCESS)
  166.       return status;
  167.    *image = *img;
  168.  
  169.    return status;
  170. }
  171.  
  172. VAStatus
  173. vlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image)
  174. {
  175.    if (!ctx)
  176.       return VA_STATUS_ERROR_INVALID_CONTEXT;
  177.  
  178.    return VA_STATUS_ERROR_UNIMPLEMENTED;
  179. }
  180.  
  181. VAStatus
  182. vlVaDestroyImage(VADriverContextP ctx, VAImageID image)
  183. {
  184.    VAImage  *vaimage;
  185.  
  186.    if (!ctx)
  187.       return VA_STATUS_ERROR_INVALID_CONTEXT;
  188.  
  189.    vaimage = handle_table_get(VL_VA_DRIVER(ctx)->htab, image);
  190.    if (!vaimage)
  191.       return VA_STATUS_ERROR_INVALID_IMAGE;
  192.  
  193.    handle_table_remove(VL_VA_DRIVER(ctx)->htab, image);
  194.    FREE(vaimage);
  195.    return vlVaDestroyBuffer(ctx, vaimage->buf);
  196. }
  197.  
  198. VAStatus
  199. vlVaSetImagePalette(VADriverContextP ctx, VAImageID image, unsigned char *palette)
  200. {
  201.    if (!ctx)
  202.       return VA_STATUS_ERROR_INVALID_CONTEXT;
  203.  
  204.    return VA_STATUS_ERROR_UNIMPLEMENTED;
  205. }
  206.  
  207. VAStatus
  208. vlVaGetImage(VADriverContextP ctx, VASurfaceID surface, int x, int y,
  209.              unsigned int width, unsigned int height, VAImageID image)
  210. {
  211.    vlVaDriver *drv;
  212.    vlVaSurface *surf;
  213.    vlVaBuffer *img_buf;
  214.    VAImage *vaimage;
  215.    struct pipe_sampler_view **views;
  216.    enum pipe_format format;
  217.    bool convert = false;
  218.    void *data[3];
  219.    unsigned pitches[3], i, j;
  220.  
  221.    if (!ctx)
  222.       return VA_STATUS_ERROR_INVALID_CONTEXT;
  223.  
  224.    drv = VL_VA_DRIVER(ctx);
  225.  
  226.    surf = handle_table_get(drv->htab, surface);
  227.    if (!surf || !surf->buffer)
  228.       return VA_STATUS_ERROR_INVALID_SURFACE;
  229.  
  230.    vaimage = handle_table_get(drv->htab, image);
  231.    if (!vaimage)
  232.       return VA_STATUS_ERROR_INVALID_IMAGE;
  233.  
  234.    img_buf = handle_table_get(drv->htab, vaimage->buf);
  235.    if (!img_buf)
  236.       return VA_STATUS_ERROR_INVALID_BUFFER;
  237.  
  238.    format = YCbCrToPipe(vaimage->format.fourcc);
  239.    if (format == PIPE_FORMAT_NONE)
  240.       return VA_STATUS_ERROR_OPERATION_FAILED;
  241.  
  242.    if (format != surf->buffer->buffer_format) {
  243.       /* support NV12 to YV12 conversion now only */
  244.       if (format == PIPE_FORMAT_YV12 &&
  245.           surf->buffer->buffer_format == PIPE_FORMAT_NV12)
  246.          convert = true;
  247.       else
  248.          return VA_STATUS_ERROR_OPERATION_FAILED;
  249.    }
  250.  
  251.    views = surf->buffer->get_sampler_view_planes(surf->buffer);
  252.    if (!views)
  253.       return VA_STATUS_ERROR_OPERATION_FAILED;
  254.  
  255.    for (i = 0; i < vaimage->num_planes; i++) {
  256.       data[i] = img_buf->data + vaimage->offsets[i];
  257.       pitches[i] = vaimage->pitches[i];
  258.    }
  259.    if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
  260.       void *tmp_d;
  261.       unsigned tmp_p;
  262.       tmp_d  = data[1];
  263.       data[1] = data[2];
  264.       data[2] = tmp_d;
  265.       tmp_p = pitches[1];
  266.       pitches[1] = pitches[2];
  267.       pitches[2] = tmp_p;
  268.    }
  269.  
  270.    for (i = 0; i < vaimage->num_planes; i++) {
  271.       unsigned width, height;
  272.       if (!views[i]) continue;
  273.       vlVaVideoSurfaceSize(surf, i, &width, &height);
  274.       for (j = 0; j < views[i]->texture->array_size; ++j) {
  275.          struct pipe_box box = {0, 0, j, width, height, 1};
  276.          struct pipe_transfer *transfer;
  277.          uint8_t *map;
  278.          map = drv->pipe->transfer_map(drv->pipe, views[i]->texture, 0,
  279.                   PIPE_TRANSFER_READ, &box, &transfer);
  280.          if (!map)
  281.             return VA_STATUS_ERROR_OPERATION_FAILED;
  282.  
  283.          if (i == 1 && convert) {
  284.             u_copy_nv12_to_yv12(data, pitches, i, j,
  285.                transfer->stride, views[i]->texture->array_size,
  286.                map, box.width, box.height);
  287.          } else {
  288.             util_copy_rect(data[i] + pitches[i] * j,
  289.                views[i]->texture->format,
  290.                pitches[i] * views[i]->texture->array_size, 0, 0,
  291.                box.width, box.height, map, transfer->stride, 0, 0);
  292.          }
  293.          pipe_transfer_unmap(drv->pipe, transfer);
  294.       }
  295.    }
  296.  
  297.    return VA_STATUS_SUCCESS;
  298. }
  299.  
  300. VAStatus
  301. vlVaPutImage(VADriverContextP ctx, VASurfaceID surface, VAImageID image,
  302.              int src_x, int src_y, unsigned int src_width, unsigned int src_height,
  303.              int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height)
  304. {
  305.    vlVaDriver *drv;
  306.    vlVaSurface *surf;
  307.    vlVaBuffer *img_buf;
  308.    VAImage *vaimage;
  309.    struct pipe_sampler_view **views;
  310.    enum pipe_format format;
  311.    void *data[3];
  312.    unsigned pitches[3], i, j;
  313.  
  314.    if (!ctx)
  315.       return VA_STATUS_ERROR_INVALID_CONTEXT;
  316.  
  317.    drv = VL_VA_DRIVER(ctx);
  318.  
  319.    surf = handle_table_get(drv->htab, surface);
  320.    if (!surf || !surf->buffer)
  321.       return VA_STATUS_ERROR_INVALID_SURFACE;
  322.  
  323.    vaimage = handle_table_get(drv->htab, image);
  324.    if (!vaimage)
  325.       return VA_STATUS_ERROR_INVALID_IMAGE;
  326.  
  327.    img_buf = handle_table_get(drv->htab, vaimage->buf);
  328.    if (!img_buf)
  329.       return VA_STATUS_ERROR_INVALID_BUFFER;
  330.  
  331.    format = YCbCrToPipe(vaimage->format.fourcc);
  332.    if (format == PIPE_FORMAT_NONE)
  333.       return VA_STATUS_ERROR_OPERATION_FAILED;
  334.  
  335.    if (surf->buffer == NULL || format != surf->buffer->buffer_format) {
  336.       if (surf->buffer)
  337.          surf->buffer->destroy(surf->buffer);
  338.       surf->templat.buffer_format = format;
  339.       surf->buffer = drv->pipe->create_video_buffer(drv->pipe, &surf->templat);
  340.       if (!surf->buffer)
  341.          return VA_STATUS_ERROR_ALLOCATION_FAILED;
  342.    }
  343.  
  344.    views = surf->buffer->get_sampler_view_planes(surf->buffer);
  345.    if (!views)
  346.       return VA_STATUS_ERROR_OPERATION_FAILED;
  347.  
  348.    for (i = 0; i < vaimage->num_planes; i++) {
  349.       data[i] = img_buf->data + vaimage->offsets[i];
  350.       pitches[i] = vaimage->pitches[i];
  351.    }
  352.    if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
  353.       void *tmp_d;
  354.       unsigned tmp_p;
  355.       tmp_d  = data[1];
  356.       data[1] = data[2];
  357.       data[2] = tmp_d;
  358.       tmp_p = pitches[1];
  359.       pitches[1] = pitches[2];
  360.       pitches[2] = tmp_p;
  361.    }
  362.  
  363.    for (i = 0; i < vaimage->num_planes; ++i) {
  364.       unsigned width, height;
  365.       if (!views[i]) continue;
  366.       vlVaVideoSurfaceSize(surf, i, &width, &height);
  367.       for (j = 0; j < views[i]->texture->array_size; ++j) {
  368.          struct pipe_box dst_box = {0, 0, j, width, height, 1};
  369.          drv->pipe->transfer_inline_write(drv->pipe, views[i]->texture, 0,
  370.             PIPE_TRANSFER_WRITE, &dst_box,
  371.             data[i] + pitches[i] * j,
  372.             pitches[i] * views[i]->texture->array_size, 0);
  373.       }
  374.    }
  375.  
  376.    return VA_STATUS_SUCCESS;
  377. }
  378.