Home | History | Annotate | Download | only in va
      1 /**************************************************************************
      2  *
      3  * Copyright 2010 Thomas Balling Srensen & 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 #include "vl/vl_video_buffer.h"
     38 
     39 #include "va_private.h"
     40 
     41 static const VAImageFormat formats[] =
     42 {
     43    {VA_FOURCC('N','V','1','2')},
     44    {VA_FOURCC('P','0','1','0')},
     45    {VA_FOURCC('P','0','1','6')},
     46    {VA_FOURCC('I','4','2','0')},
     47    {VA_FOURCC('Y','V','1','2')},
     48    {VA_FOURCC('Y','U','Y','V')},
     49    {VA_FOURCC('U','Y','V','Y')},
     50    {.fourcc = VA_FOURCC('B','G','R','A'), .byte_order = VA_LSB_FIRST, 32, 32,
     51     0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000},
     52    {.fourcc = VA_FOURCC('R','G','B','A'), .byte_order = VA_LSB_FIRST, 32, 32,
     53     0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000},
     54    {.fourcc = VA_FOURCC('B','G','R','X'), .byte_order = VA_LSB_FIRST, 32, 24,
     55     0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000},
     56    {.fourcc = VA_FOURCC('R','G','B','X'), .byte_order = VA_LSB_FIRST, 32, 24,
     57     0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000}
     58 };
     59 
     60 static void
     61 vlVaVideoSurfaceSize(vlVaSurface *p_surf, int component,
     62                      unsigned *width, unsigned *height)
     63 {
     64    *width = p_surf->templat.width;
     65    *height = p_surf->templat.height;
     66 
     67    vl_video_buffer_adjust_size(width, height, component,
     68                                p_surf->templat.chroma_format,
     69                                p_surf->templat.interlaced);
     70 }
     71 
     72 VAStatus
     73 vlVaQueryImageFormats(VADriverContextP ctx, VAImageFormat *format_list, int *num_formats)
     74 {
     75    struct pipe_screen *pscreen;
     76    enum pipe_format format;
     77    int i;
     78 
     79    STATIC_ASSERT(ARRAY_SIZE(formats) == VL_VA_MAX_IMAGE_FORMATS);
     80 
     81    if (!ctx)
     82       return VA_STATUS_ERROR_INVALID_CONTEXT;
     83 
     84    if (!(format_list && num_formats))
     85       return VA_STATUS_ERROR_INVALID_PARAMETER;
     86 
     87    *num_formats = 0;
     88    pscreen = VL_VA_PSCREEN(ctx);
     89    for (i = 0; i < ARRAY_SIZE(formats); ++i) {
     90       format = VaFourccToPipeFormat(formats[i].fourcc);
     91       if (pscreen->is_video_format_supported(pscreen, format,
     92           PIPE_VIDEO_PROFILE_UNKNOWN,
     93           PIPE_VIDEO_ENTRYPOINT_BITSTREAM))
     94          format_list[(*num_formats)++] = formats[i];
     95    }
     96 
     97    return VA_STATUS_SUCCESS;
     98 }
     99 
    100 VAStatus
    101 vlVaCreateImage(VADriverContextP ctx, VAImageFormat *format, int width, int height, VAImage *image)
    102 {
    103    VAStatus status;
    104    vlVaDriver *drv;
    105    VAImage *img;
    106    int w, h;
    107 
    108    if (!ctx)
    109       return VA_STATUS_ERROR_INVALID_CONTEXT;
    110 
    111    if (!(format && image && width && height))
    112       return VA_STATUS_ERROR_INVALID_PARAMETER;
    113 
    114    drv = VL_VA_DRIVER(ctx);
    115 
    116    img = CALLOC(1, sizeof(VAImage));
    117    if (!img)
    118       return VA_STATUS_ERROR_ALLOCATION_FAILED;
    119    mtx_lock(&drv->mutex);
    120    img->image_id = handle_table_add(drv->htab, img);
    121    mtx_unlock(&drv->mutex);
    122 
    123    img->format = *format;
    124    img->width = width;
    125    img->height = height;
    126    w = align(width, 2);
    127    h = align(height, 2);
    128 
    129    switch (format->fourcc) {
    130    case VA_FOURCC('N','V','1','2'):
    131       img->num_planes = 2;
    132       img->pitches[0] = w;
    133       img->offsets[0] = 0;
    134       img->pitches[1] = w;
    135       img->offsets[1] = w * h;
    136       img->data_size  = w * h * 3 / 2;
    137       break;
    138 
    139    case VA_FOURCC('P','0','1','0'):
    140    case VA_FOURCC('P','0','1','6'):
    141       img->num_planes = 2;
    142       img->pitches[0] = w * 2;
    143       img->offsets[0] = 0;
    144       img->pitches[1] = w * 2;
    145       img->offsets[1] = w * h * 2;
    146       img->data_size  = w * h * 3;
    147       break;
    148 
    149    case VA_FOURCC('I','4','2','0'):
    150    case VA_FOURCC('Y','V','1','2'):
    151       img->num_planes = 3;
    152       img->pitches[0] = w;
    153       img->offsets[0] = 0;
    154       img->pitches[1] = w / 2;
    155       img->offsets[1] = w * h;
    156       img->pitches[2] = w / 2;
    157       img->offsets[2] = w * h * 5 / 4;
    158       img->data_size  = w * h * 3 / 2;
    159       break;
    160 
    161    case VA_FOURCC('U','Y','V','Y'):
    162    case VA_FOURCC('Y','U','Y','V'):
    163       img->num_planes = 1;
    164       img->pitches[0] = w * 2;
    165       img->offsets[0] = 0;
    166       img->data_size  = w * h * 2;
    167       break;
    168 
    169    case VA_FOURCC('B','G','R','A'):
    170    case VA_FOURCC('R','G','B','A'):
    171    case VA_FOURCC('B','G','R','X'):
    172    case VA_FOURCC('R','G','B','X'):
    173       img->num_planes = 1;
    174       img->pitches[0] = w * 4;
    175       img->offsets[0] = 0;
    176       img->data_size  = w * h * 4;
    177       break;
    178 
    179    default:
    180       return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
    181    }
    182 
    183    status =  vlVaCreateBuffer(ctx, 0, VAImageBufferType,
    184                            align(img->data_size, 16),
    185                            1, NULL, &img->buf);
    186    if (status != VA_STATUS_SUCCESS)
    187       return status;
    188    *image = *img;
    189 
    190    return status;
    191 }
    192 
    193 VAStatus
    194 vlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image)
    195 {
    196    vlVaDriver *drv;
    197    vlVaSurface *surf;
    198    vlVaBuffer *img_buf;
    199    VAImage *img;
    200    struct pipe_surface **surfaces;
    201    int w;
    202    int h;
    203    int i;
    204 
    205    if (!ctx)
    206       return VA_STATUS_ERROR_INVALID_CONTEXT;
    207 
    208    drv = VL_VA_DRIVER(ctx);
    209 
    210    if (!drv)
    211       return VA_STATUS_ERROR_INVALID_CONTEXT;
    212 
    213    surf = handle_table_get(drv->htab, surface);
    214 
    215    if (!surf || !surf->buffer || surf->buffer->interlaced)
    216       return VA_STATUS_ERROR_INVALID_SURFACE;
    217 
    218    surfaces = surf->buffer->get_surfaces(surf->buffer);
    219    if (!surfaces || !surfaces[0]->texture)
    220       return VA_STATUS_ERROR_ALLOCATION_FAILED;
    221 
    222    img = CALLOC(1, sizeof(VAImage));
    223    if (!img)
    224       return VA_STATUS_ERROR_ALLOCATION_FAILED;
    225 
    226    img->format.fourcc = PipeFormatToVaFourcc(surf->buffer->buffer_format);
    227    img->buf = VA_INVALID_ID;
    228    img->width = surf->buffer->width;
    229    img->height = surf->buffer->height;
    230    img->num_palette_entries = 0;
    231    img->entry_bytes = 0;
    232    w = align(surf->buffer->width, 2);
    233    h = align(surf->buffer->height, 2);
    234 
    235    for (i = 0; i < ARRAY_SIZE(formats); ++i) {
    236       if (img->format.fourcc == formats[i].fourcc) {
    237          img->format = formats[i];
    238          break;
    239       }
    240    }
    241 
    242    switch (img->format.fourcc) {
    243    case VA_FOURCC('U','Y','V','Y'):
    244    case VA_FOURCC('Y','U','Y','V'):
    245       img->num_planes = 1;
    246       img->pitches[0] = w * 2;
    247       img->offsets[0] = 0;
    248       img->data_size  = w * h * 2;
    249       break;
    250 
    251    case VA_FOURCC('B','G','R','A'):
    252    case VA_FOURCC('R','G','B','A'):
    253    case VA_FOURCC('B','G','R','X'):
    254    case VA_FOURCC('R','G','B','X'):
    255       img->num_planes = 1;
    256       img->pitches[0] = w * 4;
    257       img->offsets[0] = 0;
    258       img->data_size  = w * h * 4;
    259       break;
    260 
    261    default:
    262       /* VaDeriveImage is designed for contiguous planes. */
    263       FREE(img);
    264       return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
    265    }
    266 
    267    img_buf = CALLOC(1, sizeof(vlVaBuffer));
    268    if (!img_buf) {
    269       FREE(img);
    270       return VA_STATUS_ERROR_ALLOCATION_FAILED;
    271    }
    272 
    273    mtx_lock(&drv->mutex);
    274    img->image_id = handle_table_add(drv->htab, img);
    275 
    276    img_buf->type = VAImageBufferType;
    277    img_buf->size = img->data_size;
    278    img_buf->num_elements = 1;
    279 
    280    pipe_resource_reference(&img_buf->derived_surface.resource, surfaces[0]->texture);
    281 
    282    img->buf = handle_table_add(VL_VA_DRIVER(ctx)->htab, img_buf);
    283    mtx_unlock(&drv->mutex);
    284 
    285    *image = *img;
    286 
    287    return VA_STATUS_SUCCESS;
    288 }
    289 
    290 VAStatus
    291 vlVaDestroyImage(VADriverContextP ctx, VAImageID image)
    292 {
    293    vlVaDriver *drv;
    294    VAImage  *vaimage;
    295    VAStatus status;
    296 
    297    if (!ctx)
    298       return VA_STATUS_ERROR_INVALID_CONTEXT;
    299 
    300    drv = VL_VA_DRIVER(ctx);
    301    mtx_lock(&drv->mutex);
    302    vaimage = handle_table_get(drv->htab, image);
    303    if (!vaimage) {
    304       mtx_unlock(&drv->mutex);
    305       return VA_STATUS_ERROR_INVALID_IMAGE;
    306    }
    307 
    308    handle_table_remove(VL_VA_DRIVER(ctx)->htab, image);
    309    mtx_unlock(&drv->mutex);
    310    status = vlVaDestroyBuffer(ctx, vaimage->buf);
    311    FREE(vaimage);
    312    return status;
    313 }
    314 
    315 VAStatus
    316 vlVaSetImagePalette(VADriverContextP ctx, VAImageID image, unsigned char *palette)
    317 {
    318    if (!ctx)
    319       return VA_STATUS_ERROR_INVALID_CONTEXT;
    320 
    321    return VA_STATUS_ERROR_UNIMPLEMENTED;
    322 }
    323 
    324 VAStatus
    325 vlVaGetImage(VADriverContextP ctx, VASurfaceID surface, int x, int y,
    326              unsigned int width, unsigned int height, VAImageID image)
    327 {
    328    vlVaDriver *drv;
    329    vlVaSurface *surf;
    330    vlVaBuffer *img_buf;
    331    VAImage *vaimage;
    332    struct pipe_sampler_view **views;
    333    enum pipe_format format;
    334    bool convert = false;
    335    void *data[3];
    336    unsigned pitches[3], i, j;
    337 
    338    if (!ctx)
    339       return VA_STATUS_ERROR_INVALID_CONTEXT;
    340 
    341    drv = VL_VA_DRIVER(ctx);
    342 
    343    mtx_lock(&drv->mutex);
    344    surf = handle_table_get(drv->htab, surface);
    345    if (!surf || !surf->buffer) {
    346       mtx_unlock(&drv->mutex);
    347       return VA_STATUS_ERROR_INVALID_SURFACE;
    348    }
    349 
    350    vaimage = handle_table_get(drv->htab, image);
    351    if (!vaimage) {
    352       mtx_unlock(&drv->mutex);
    353       return VA_STATUS_ERROR_INVALID_IMAGE;
    354    }
    355 
    356    img_buf = handle_table_get(drv->htab, vaimage->buf);
    357    if (!img_buf) {
    358       mtx_unlock(&drv->mutex);
    359       return VA_STATUS_ERROR_INVALID_BUFFER;
    360    }
    361 
    362    format = VaFourccToPipeFormat(vaimage->format.fourcc);
    363    if (format == PIPE_FORMAT_NONE) {
    364       mtx_unlock(&drv->mutex);
    365       return VA_STATUS_ERROR_OPERATION_FAILED;
    366    }
    367 
    368    if (format != surf->buffer->buffer_format) {
    369       /* support NV12 to YV12 and IYUV conversion now only */
    370       if ((format == PIPE_FORMAT_YV12 &&
    371           surf->buffer->buffer_format == PIPE_FORMAT_NV12) ||
    372           (format == PIPE_FORMAT_IYUV &&
    373           surf->buffer->buffer_format == PIPE_FORMAT_NV12))
    374          convert = true;
    375       else {
    376          mtx_unlock(&drv->mutex);
    377          return VA_STATUS_ERROR_OPERATION_FAILED;
    378       }
    379    }
    380 
    381    views = surf->buffer->get_sampler_view_planes(surf->buffer);
    382    if (!views) {
    383       mtx_unlock(&drv->mutex);
    384       return VA_STATUS_ERROR_OPERATION_FAILED;
    385    }
    386 
    387    for (i = 0; i < vaimage->num_planes; i++) {
    388       data[i] = img_buf->data + vaimage->offsets[i];
    389       pitches[i] = vaimage->pitches[i];
    390    }
    391    if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
    392       void *tmp_d;
    393       unsigned tmp_p;
    394       tmp_d  = data[1];
    395       data[1] = data[2];
    396       data[2] = tmp_d;
    397       tmp_p = pitches[1];
    398       pitches[1] = pitches[2];
    399       pitches[2] = tmp_p;
    400    }
    401 
    402    for (i = 0; i < vaimage->num_planes; i++) {
    403       unsigned width, height;
    404       if (!views[i]) continue;
    405       vlVaVideoSurfaceSize(surf, i, &width, &height);
    406       for (j = 0; j < views[i]->texture->array_size; ++j) {
    407          struct pipe_box box = {0, 0, j, width, height, 1};
    408          struct pipe_transfer *transfer;
    409          uint8_t *map;
    410          map = drv->pipe->transfer_map(drv->pipe, views[i]->texture, 0,
    411                   PIPE_TRANSFER_READ, &box, &transfer);
    412          if (!map) {
    413             mtx_unlock(&drv->mutex);
    414             return VA_STATUS_ERROR_OPERATION_FAILED;
    415          }
    416 
    417          if (i == 1 && convert) {
    418             u_copy_nv12_to_yv12(data, pitches, i, j,
    419                transfer->stride, views[i]->texture->array_size,
    420                map, box.width, box.height);
    421          } else {
    422             util_copy_rect(data[i] + pitches[i] * j,
    423                views[i]->texture->format,
    424                pitches[i] * views[i]->texture->array_size, 0, 0,
    425                box.width, box.height, map, transfer->stride, 0, 0);
    426          }
    427          pipe_transfer_unmap(drv->pipe, transfer);
    428       }
    429    }
    430    mtx_unlock(&drv->mutex);
    431 
    432    return VA_STATUS_SUCCESS;
    433 }
    434 
    435 VAStatus
    436 vlVaPutImage(VADriverContextP ctx, VASurfaceID surface, VAImageID image,
    437              int src_x, int src_y, unsigned int src_width, unsigned int src_height,
    438              int dest_x, int dest_y, unsigned int dest_width, unsigned int dest_height)
    439 {
    440    vlVaDriver *drv;
    441    vlVaSurface *surf;
    442    vlVaBuffer *img_buf;
    443    VAImage *vaimage;
    444    struct pipe_sampler_view **views;
    445    enum pipe_format format;
    446    void *data[3];
    447    unsigned pitches[3], i, j;
    448 
    449    if (!ctx)
    450       return VA_STATUS_ERROR_INVALID_CONTEXT;
    451 
    452    drv = VL_VA_DRIVER(ctx);
    453    mtx_lock(&drv->mutex);
    454 
    455    surf = handle_table_get(drv->htab, surface);
    456    if (!surf || !surf->buffer) {
    457       mtx_unlock(&drv->mutex);
    458       return VA_STATUS_ERROR_INVALID_SURFACE;
    459    }
    460 
    461    vaimage = handle_table_get(drv->htab, image);
    462    if (!vaimage) {
    463       mtx_unlock(&drv->mutex);
    464       return VA_STATUS_ERROR_INVALID_IMAGE;
    465    }
    466 
    467    img_buf = handle_table_get(drv->htab, vaimage->buf);
    468    if (!img_buf) {
    469       mtx_unlock(&drv->mutex);
    470       return VA_STATUS_ERROR_INVALID_BUFFER;
    471    }
    472 
    473    if (img_buf->derived_surface.resource) {
    474       /* Attempting to transfer derived image to surface */
    475       mtx_unlock(&drv->mutex);
    476       return VA_STATUS_ERROR_UNIMPLEMENTED;
    477    }
    478 
    479    format = VaFourccToPipeFormat(vaimage->format.fourcc);
    480 
    481    if (format == PIPE_FORMAT_NONE) {
    482       mtx_unlock(&drv->mutex);
    483       return VA_STATUS_ERROR_OPERATION_FAILED;
    484    }
    485 
    486    if ((format != surf->buffer->buffer_format) &&
    487          ((format != PIPE_FORMAT_YV12) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12)) &&
    488          ((format != PIPE_FORMAT_IYUV) || (surf->buffer->buffer_format != PIPE_FORMAT_NV12))) {
    489       struct pipe_video_buffer *tmp_buf;
    490 
    491       surf->templat.buffer_format = format;
    492       if (format == PIPE_FORMAT_YUYV || format == PIPE_FORMAT_UYVY ||
    493           format == PIPE_FORMAT_B8G8R8A8_UNORM || format == PIPE_FORMAT_B8G8R8X8_UNORM ||
    494           format == PIPE_FORMAT_R8G8B8A8_UNORM || format == PIPE_FORMAT_R8G8B8X8_UNORM)
    495          surf->templat.interlaced = false;
    496       tmp_buf = drv->pipe->create_video_buffer(drv->pipe, &surf->templat);
    497 
    498       if (!tmp_buf) {
    499          mtx_unlock(&drv->mutex);
    500          return VA_STATUS_ERROR_ALLOCATION_FAILED;
    501       }
    502 
    503       surf->buffer->destroy(surf->buffer);
    504       surf->buffer = tmp_buf;
    505    }
    506 
    507    views = surf->buffer->get_sampler_view_planes(surf->buffer);
    508    if (!views) {
    509       mtx_unlock(&drv->mutex);
    510       return VA_STATUS_ERROR_OPERATION_FAILED;
    511    }
    512 
    513    for (i = 0; i < vaimage->num_planes; i++) {
    514       data[i] = img_buf->data + vaimage->offsets[i];
    515       pitches[i] = vaimage->pitches[i];
    516    }
    517    if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) {
    518       void *tmp_d;
    519       unsigned tmp_p;
    520       tmp_d  = data[1];
    521       data[1] = data[2];
    522       data[2] = tmp_d;
    523       tmp_p = pitches[1];
    524       pitches[1] = pitches[2];
    525       pitches[2] = tmp_p;
    526    }
    527 
    528    for (i = 0; i < vaimage->num_planes; ++i) {
    529       unsigned width, height;
    530       struct pipe_resource *tex;
    531 
    532       if (!views[i]) continue;
    533       tex = views[i]->texture;
    534 
    535       vlVaVideoSurfaceSize(surf, i, &width, &height);
    536       for (j = 0; j < tex->array_size; ++j) {
    537          struct pipe_box dst_box = {0, 0, j, width, height, 1};
    538 
    539          if (((format == PIPE_FORMAT_YV12) || (format == PIPE_FORMAT_IYUV))
    540              && (surf->buffer->buffer_format == PIPE_FORMAT_NV12)
    541              && i == 1) {
    542             struct pipe_transfer *transfer = NULL;
    543             uint8_t *map = NULL;
    544 
    545             map = drv->pipe->transfer_map(drv->pipe,
    546                                           tex,
    547                                           0,
    548                                           PIPE_TRANSFER_WRITE |
    549                                           PIPE_TRANSFER_DISCARD_RANGE,
    550                                           &dst_box, &transfer);
    551             if (map == NULL) {
    552                mtx_unlock(&drv->mutex);
    553                return VA_STATUS_ERROR_OPERATION_FAILED;
    554             }
    555 
    556             u_copy_nv12_from_yv12((const void * const*) data, pitches, i, j,
    557                                   transfer->stride, tex->array_size,
    558                                   map, dst_box.width, dst_box.height);
    559             pipe_transfer_unmap(drv->pipe, transfer);
    560          } else {
    561             drv->pipe->texture_subdata(drv->pipe, tex, 0,
    562                                        PIPE_TRANSFER_WRITE, &dst_box,
    563                                        data[i] + pitches[i] * j,
    564                                        pitches[i] * views[i]->texture->array_size, 0);
    565          }
    566       }
    567    }
    568    mtx_unlock(&drv->mutex);
    569 
    570    return VA_STATUS_SUCCESS;
    571 }
    572