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