Home | History | Annotate | Download | only in vl
      1 /**************************************************************************
      2  *
      3  * Copyright 2011 Christian Knig.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 #include <assert.h>
     29 
     30 #include "pipe/p_screen.h"
     31 #include "pipe/p_context.h"
     32 #include "pipe/p_state.h"
     33 
     34 #include "util/u_format.h"
     35 #include "util/u_inlines.h"
     36 #include "util/u_sampler.h"
     37 #include "util/u_memory.h"
     38 
     39 #include "vl_video_buffer.h"
     40 
     41 const enum pipe_format const_resource_formats_YV12[3] = {
     42    PIPE_FORMAT_R8_UNORM,
     43    PIPE_FORMAT_R8_UNORM,
     44    PIPE_FORMAT_R8_UNORM
     45 };
     46 
     47 const enum pipe_format const_resource_formats_NV12[3] = {
     48    PIPE_FORMAT_R8_UNORM,
     49    PIPE_FORMAT_R8G8_UNORM,
     50    PIPE_FORMAT_NONE
     51 };
     52 
     53 const enum pipe_format const_resource_formats_YUVA[3] = {
     54    PIPE_FORMAT_R8G8B8A8_UNORM,
     55    PIPE_FORMAT_NONE,
     56    PIPE_FORMAT_NONE
     57 };
     58 
     59 const enum pipe_format const_resource_formats_VUYA[3] = {
     60    PIPE_FORMAT_B8G8R8A8_UNORM,
     61    PIPE_FORMAT_NONE,
     62    PIPE_FORMAT_NONE
     63 };
     64 
     65 const enum pipe_format const_resource_formats_YUVX[3] = {
     66    PIPE_FORMAT_R8G8B8X8_UNORM,
     67    PIPE_FORMAT_NONE,
     68    PIPE_FORMAT_NONE
     69 };
     70 
     71 const enum pipe_format const_resource_formats_VUYX[3] = {
     72    PIPE_FORMAT_B8G8R8X8_UNORM,
     73    PIPE_FORMAT_NONE,
     74    PIPE_FORMAT_NONE
     75 };
     76 
     77 const enum pipe_format const_resource_formats_YUYV[3] = {
     78    PIPE_FORMAT_R8G8_R8B8_UNORM,
     79    PIPE_FORMAT_NONE,
     80    PIPE_FORMAT_NONE
     81 };
     82 
     83 const enum pipe_format const_resource_formats_UYVY[3] = {
     84    PIPE_FORMAT_G8R8_B8R8_UNORM,
     85    PIPE_FORMAT_NONE,
     86    PIPE_FORMAT_NONE
     87 };
     88 
     89 const unsigned const_resource_plane_order_YUV[3] = {
     90    0,
     91    1,
     92    2
     93 };
     94 
     95 const unsigned const_resource_plane_order_YVU[3] = {
     96    0,
     97    2,
     98    1
     99 };
    100 
    101 const enum pipe_format *
    102 vl_video_buffer_formats(struct pipe_screen *screen, enum pipe_format format)
    103 {
    104    switch(format) {
    105    case PIPE_FORMAT_YV12:
    106       return const_resource_formats_YV12;
    107 
    108    case PIPE_FORMAT_NV12:
    109       return const_resource_formats_NV12;
    110 
    111    case PIPE_FORMAT_R8G8B8A8_UNORM:
    112       return const_resource_formats_YUVA;
    113 
    114    case PIPE_FORMAT_B8G8R8A8_UNORM:
    115       return const_resource_formats_VUYA;
    116 
    117    case PIPE_FORMAT_R8G8B8X8_UNORM:
    118       return const_resource_formats_YUVX;
    119 
    120    case PIPE_FORMAT_B8G8R8X8_UNORM:
    121       return const_resource_formats_VUYX;
    122 
    123    case PIPE_FORMAT_YUYV:
    124       return const_resource_formats_YUYV;
    125 
    126    case PIPE_FORMAT_UYVY:
    127       return const_resource_formats_UYVY;
    128 
    129    default:
    130       return NULL;
    131    }
    132 }
    133 
    134 const unsigned *
    135 vl_video_buffer_plane_order(enum pipe_format format)
    136 {
    137    switch(format) {
    138    case PIPE_FORMAT_YV12:
    139       return const_resource_plane_order_YVU;
    140 
    141    case PIPE_FORMAT_NV12:
    142    case PIPE_FORMAT_R8G8B8A8_UNORM:
    143    case PIPE_FORMAT_B8G8R8A8_UNORM:
    144    case PIPE_FORMAT_YUYV:
    145    case PIPE_FORMAT_UYVY:
    146       return const_resource_plane_order_YUV;
    147 
    148    default:
    149       return NULL;
    150    }
    151 }
    152 
    153 static enum pipe_format
    154 vl_video_buffer_surface_format(enum pipe_format format)
    155 {
    156    const struct util_format_description *desc = util_format_description(format);
    157 
    158    /* a subsampled formats can't work as surface use RGBA instead */
    159    if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED)
    160       return PIPE_FORMAT_R8G8B8A8_UNORM;
    161 
    162    return format;
    163 }
    164 
    165 boolean
    166 vl_video_buffer_is_format_supported(struct pipe_screen *screen,
    167                                     enum pipe_format format,
    168                                     enum pipe_video_profile profile,
    169                                     enum pipe_video_entrypoint entrypoint)
    170 {
    171    const enum pipe_format *resource_formats;
    172    unsigned i;
    173 
    174    resource_formats = vl_video_buffer_formats(screen, format);
    175    if (!resource_formats)
    176       return false;
    177 
    178    for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
    179       enum pipe_format format = resource_formats[i];
    180 
    181       if (format == PIPE_FORMAT_NONE)
    182          continue;
    183 
    184       /* we at least need to sample from it */
    185       if (!screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW))
    186          return false;
    187 
    188       format = vl_video_buffer_surface_format(format);
    189       if (!screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET))
    190          return false;
    191    }
    192 
    193    return true;
    194 }
    195 
    196 unsigned
    197 vl_video_buffer_max_size(struct pipe_screen *screen)
    198 {
    199    uint32_t max_2d_texture_level;
    200 
    201    max_2d_texture_level = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
    202 
    203    return 1 << (max_2d_texture_level-1);
    204 }
    205 
    206 void
    207 vl_video_buffer_set_associated_data(struct pipe_video_buffer *vbuf,
    208                                     struct pipe_video_codec *vcodec,
    209                                     void *associated_data,
    210                                     void (*destroy_associated_data)(void *))
    211 {
    212    vbuf->codec = vcodec;
    213 
    214    if (vbuf->associated_data == associated_data)
    215       return;
    216 
    217    if (vbuf->associated_data)
    218       vbuf->destroy_associated_data(vbuf->associated_data);
    219 
    220    vbuf->associated_data = associated_data;
    221    vbuf->destroy_associated_data = destroy_associated_data;
    222 }
    223 
    224 void *
    225 vl_video_buffer_get_associated_data(struct pipe_video_buffer *vbuf,
    226                                     struct pipe_video_codec *vcodec)
    227 {
    228    if (vbuf->codec == vcodec)
    229       return vbuf->associated_data;
    230    else
    231       return NULL;
    232 }
    233 
    234 void
    235 vl_video_buffer_template(struct pipe_resource *templ,
    236                          const struct pipe_video_buffer *tmpl,
    237                          enum pipe_format resource_format,
    238                          unsigned depth, unsigned array_size,
    239                          unsigned usage, unsigned plane)
    240 {
    241    memset(templ, 0, sizeof(*templ));
    242    if (depth > 1)
    243       templ->target = PIPE_TEXTURE_3D;
    244    else if (array_size > 1)
    245       templ->target = PIPE_TEXTURE_2D_ARRAY;
    246    else
    247       templ->target = PIPE_TEXTURE_2D;
    248    templ->format = resource_format;
    249    templ->width0 = tmpl->width;
    250    templ->height0 = tmpl->height;
    251    templ->depth0 = depth;
    252    templ->array_size = array_size;
    253    templ->bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET | tmpl->bind;
    254    templ->usage = usage;
    255 
    256    vl_video_buffer_adjust_size(&templ->width0, &templ->height0, plane,
    257                                tmpl->chroma_format, false);
    258 }
    259 
    260 static void
    261 vl_video_buffer_destroy(struct pipe_video_buffer *buffer)
    262 {
    263    struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
    264    unsigned i;
    265 
    266    assert(buf);
    267 
    268    for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
    269       pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL);
    270       pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL);
    271       pipe_resource_reference(&buf->resources[i], NULL);
    272    }
    273 
    274    for (i = 0; i < VL_MAX_SURFACES; ++i)
    275       pipe_surface_reference(&buf->surfaces[i], NULL);
    276 
    277    vl_video_buffer_set_associated_data(buffer, NULL, NULL, NULL);
    278 
    279    FREE(buffer);
    280 }
    281 
    282 static struct pipe_sampler_view **
    283 vl_video_buffer_sampler_view_planes(struct pipe_video_buffer *buffer)
    284 {
    285    struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
    286    struct pipe_sampler_view sv_templ;
    287    struct pipe_context *pipe;
    288    unsigned i;
    289 
    290    assert(buf);
    291 
    292    pipe = buf->base.context;
    293 
    294    for (i = 0; i < buf->num_planes; ++i ) {
    295       if (!buf->sampler_view_planes[i]) {
    296          memset(&sv_templ, 0, sizeof(sv_templ));
    297          u_sampler_view_default_template(&sv_templ, buf->resources[i], buf->resources[i]->format);
    298 
    299          if (util_format_get_nr_components(buf->resources[i]->format) == 1)
    300             sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = sv_templ.swizzle_a = PIPE_SWIZZLE_X;
    301 
    302          buf->sampler_view_planes[i] = pipe->create_sampler_view(pipe, buf->resources[i], &sv_templ);
    303          if (!buf->sampler_view_planes[i])
    304             goto error;
    305       }
    306    }
    307 
    308    return buf->sampler_view_planes;
    309 
    310 error:
    311    for (i = 0; i < buf->num_planes; ++i )
    312       pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL);
    313 
    314    return NULL;
    315 }
    316 
    317 static struct pipe_sampler_view **
    318 vl_video_buffer_sampler_view_components(struct pipe_video_buffer *buffer)
    319 {
    320    struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
    321    struct pipe_sampler_view sv_templ;
    322    struct pipe_context *pipe;
    323    const enum pipe_format *sampler_format;
    324    const unsigned *plane_order;
    325    unsigned i, j, component;
    326 
    327    assert(buf);
    328 
    329    pipe = buf->base.context;
    330 
    331    sampler_format = vl_video_buffer_formats(pipe->screen, buf->base.buffer_format);
    332    plane_order = vl_video_buffer_plane_order(buf->base.buffer_format);
    333 
    334    for (component = 0, i = 0; i < buf->num_planes; ++i ) {
    335       struct pipe_resource *res = buf->resources[plane_order[i]];
    336       const struct util_format_description *desc = util_format_description(res->format);
    337       unsigned nr_components = util_format_get_nr_components(res->format);
    338       if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED)
    339          nr_components = 3;
    340 
    341       for (j = 0; j < nr_components && component < VL_NUM_COMPONENTS; ++j, ++component) {
    342          if (buf->sampler_view_components[component])
    343             continue;
    344 
    345          memset(&sv_templ, 0, sizeof(sv_templ));
    346          u_sampler_view_default_template(&sv_templ, res, sampler_format[plane_order[i]]);
    347          sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = PIPE_SWIZZLE_X + j;
    348          sv_templ.swizzle_a = PIPE_SWIZZLE_1;
    349          buf->sampler_view_components[component] = pipe->create_sampler_view(pipe, res, &sv_templ);
    350          if (!buf->sampler_view_components[component])
    351             goto error;
    352       }
    353    }
    354    assert(component == VL_NUM_COMPONENTS);
    355 
    356    return buf->sampler_view_components;
    357 
    358 error:
    359    for (i = 0; i < VL_NUM_COMPONENTS; ++i )
    360       pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL);
    361 
    362    return NULL;
    363 }
    364 
    365 static struct pipe_surface **
    366 vl_video_buffer_surfaces(struct pipe_video_buffer *buffer)
    367 {
    368    struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
    369    struct pipe_surface surf_templ;
    370    struct pipe_context *pipe;
    371    unsigned i, j, array_size, surf;
    372 
    373    assert(buf);
    374 
    375    pipe = buf->base.context;
    376 
    377    array_size = buffer->interlaced ? 2 : 1;
    378    for (i = 0, surf = 0; i < VL_NUM_COMPONENTS; ++i) {
    379       for (j = 0; j < array_size; ++j, ++surf) {
    380          assert(surf < VL_MAX_SURFACES);
    381 
    382          if (!buf->resources[i]) {
    383             pipe_surface_reference(&buf->surfaces[surf], NULL);
    384             continue;
    385          }
    386 
    387          if (!buf->surfaces[surf]) {
    388             memset(&surf_templ, 0, sizeof(surf_templ));
    389             surf_templ.format = vl_video_buffer_surface_format(buf->resources[i]->format);
    390             surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = j;
    391             buf->surfaces[surf] = pipe->create_surface(pipe, buf->resources[i], &surf_templ);
    392             if (!buf->surfaces[surf])
    393                goto error;
    394          }
    395       }
    396    }
    397 
    398    return buf->surfaces;
    399 
    400 error:
    401    for (i = 0; i < VL_MAX_SURFACES; ++i )
    402       pipe_surface_reference(&buf->surfaces[i], NULL);
    403 
    404    return NULL;
    405 }
    406 
    407 struct pipe_video_buffer *
    408 vl_video_buffer_create(struct pipe_context *pipe,
    409                        const struct pipe_video_buffer *tmpl)
    410 {
    411    const enum pipe_format *resource_formats;
    412    struct pipe_video_buffer templat, *result;
    413    bool pot_buffers;
    414 
    415    assert(pipe);
    416    assert(tmpl->width > 0 && tmpl->height > 0);
    417 
    418    pot_buffers = !pipe->screen->get_video_param
    419    (
    420       pipe->screen,
    421       PIPE_VIDEO_PROFILE_UNKNOWN,
    422       PIPE_VIDEO_ENTRYPOINT_UNKNOWN,
    423       PIPE_VIDEO_CAP_NPOT_TEXTURES
    424    );
    425 
    426    resource_formats = vl_video_buffer_formats(pipe->screen, tmpl->buffer_format);
    427    if (!resource_formats)
    428       return NULL;
    429 
    430    templat = *tmpl;
    431    templat.width = pot_buffers ? util_next_power_of_two(tmpl->width)
    432                  : align(tmpl->width, VL_MACROBLOCK_WIDTH);
    433    templat.height = pot_buffers ? util_next_power_of_two(tmpl->height)
    434                   : align(tmpl->height, VL_MACROBLOCK_HEIGHT);
    435 
    436    if (tmpl->interlaced)
    437       templat.height /= 2;
    438 
    439    result = vl_video_buffer_create_ex
    440    (
    441       pipe, &templat, resource_formats,
    442       1, tmpl->interlaced ? 2 : 1, PIPE_USAGE_DEFAULT
    443    );
    444 
    445 
    446    if (result && tmpl->interlaced)
    447       result->height *= 2;
    448 
    449    return result;
    450 }
    451 
    452 struct pipe_video_buffer *
    453 vl_video_buffer_create_ex(struct pipe_context *pipe,
    454                           const struct pipe_video_buffer *tmpl,
    455                           const enum pipe_format resource_formats[VL_NUM_COMPONENTS],
    456                           unsigned depth, unsigned array_size, unsigned usage)
    457 {
    458    struct pipe_resource res_tmpl;
    459    struct pipe_resource *resources[VL_NUM_COMPONENTS];
    460    unsigned i;
    461 
    462    assert(pipe);
    463 
    464    memset(resources, 0, sizeof resources);
    465 
    466    vl_video_buffer_template(&res_tmpl, tmpl, resource_formats[0], depth, array_size, usage, 0);
    467    resources[0] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
    468    if (!resources[0])
    469       goto error;
    470 
    471    if (resource_formats[1] == PIPE_FORMAT_NONE) {
    472       assert(resource_formats[2] == PIPE_FORMAT_NONE);
    473       return vl_video_buffer_create_ex2(pipe, tmpl, resources);
    474    }
    475 
    476    vl_video_buffer_template(&res_tmpl, tmpl, resource_formats[1], depth, array_size, usage, 1);
    477    resources[1] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
    478    if (!resources[1])
    479       goto error;
    480 
    481    if (resource_formats[2] == PIPE_FORMAT_NONE)
    482       return vl_video_buffer_create_ex2(pipe, tmpl, resources);
    483 
    484    vl_video_buffer_template(&res_tmpl, tmpl, resource_formats[2], depth, array_size, usage, 2);
    485    resources[2] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
    486    if (!resources[2])
    487       goto error;
    488 
    489    return vl_video_buffer_create_ex2(pipe, tmpl, resources);
    490 
    491 error:
    492    for (i = 0; i < VL_NUM_COMPONENTS; ++i)
    493       pipe_resource_reference(&resources[i], NULL);
    494 
    495    return NULL;
    496 }
    497 
    498 struct pipe_video_buffer *
    499 vl_video_buffer_create_ex2(struct pipe_context *pipe,
    500                            const struct pipe_video_buffer *tmpl,
    501                            struct pipe_resource *resources[VL_NUM_COMPONENTS])
    502 {
    503    struct vl_video_buffer *buffer;
    504    unsigned i;
    505 
    506    buffer = CALLOC_STRUCT(vl_video_buffer);
    507    if (!buffer)
    508       return NULL;
    509 
    510    buffer->base = *tmpl;
    511    buffer->base.context = pipe;
    512    buffer->base.destroy = vl_video_buffer_destroy;
    513    buffer->base.get_sampler_view_planes = vl_video_buffer_sampler_view_planes;
    514    buffer->base.get_sampler_view_components = vl_video_buffer_sampler_view_components;
    515    buffer->base.get_surfaces = vl_video_buffer_surfaces;
    516    buffer->num_planes = 0;
    517 
    518    for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
    519       buffer->resources[i] = resources[i];
    520       if (resources[i])
    521          buffer->num_planes++;
    522    }
    523 
    524    return &buffer->base;
    525 }
    526