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 TUNGSTEN GRAPHICS 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_YUYV[3] = {
     66    PIPE_FORMAT_R8G8_R8B8_UNORM,
     67    PIPE_FORMAT_NONE,
     68    PIPE_FORMAT_NONE
     69 };
     70 
     71 const enum pipe_format const_resource_formats_UYVY[3] = {
     72    PIPE_FORMAT_G8R8_B8R8_UNORM,
     73    PIPE_FORMAT_NONE,
     74    PIPE_FORMAT_NONE
     75 };
     76 
     77 const unsigned const_resource_plane_order_YUV[3] = {
     78    0,
     79    1,
     80    2
     81 };
     82 
     83 const unsigned const_resource_plane_order_YVU[3] = {
     84    0,
     85    2,
     86    1
     87 };
     88 
     89 const enum pipe_format *
     90 vl_video_buffer_formats(struct pipe_screen *screen, enum pipe_format format)
     91 {
     92    switch(format) {
     93    case PIPE_FORMAT_YV12:
     94       return const_resource_formats_YV12;
     95 
     96    case PIPE_FORMAT_NV12:
     97       return const_resource_formats_NV12;
     98 
     99    case PIPE_FORMAT_R8G8B8A8_UNORM:
    100       return const_resource_formats_YUVA;
    101 
    102    case PIPE_FORMAT_B8G8R8A8_UNORM:
    103       return const_resource_formats_VUYA;
    104 
    105    case PIPE_FORMAT_YUYV:
    106       return const_resource_formats_YUYV;
    107 
    108    case PIPE_FORMAT_UYVY:
    109       return const_resource_formats_UYVY;
    110 
    111    default:
    112       return NULL;
    113    }
    114 }
    115 
    116 const unsigned *
    117 vl_video_buffer_plane_order(enum pipe_format format)
    118 {
    119    switch(format) {
    120    case PIPE_FORMAT_YV12:
    121       return const_resource_plane_order_YVU;
    122 
    123    case PIPE_FORMAT_NV12:
    124    case PIPE_FORMAT_R8G8B8A8_UNORM:
    125    case PIPE_FORMAT_B8G8R8A8_UNORM:
    126    case PIPE_FORMAT_YUYV:
    127    case PIPE_FORMAT_UYVY:
    128       return const_resource_plane_order_YUV;
    129 
    130    default:
    131       return NULL;
    132    }
    133 }
    134 
    135 static enum pipe_format
    136 vl_video_buffer_surface_format(enum pipe_format format)
    137 {
    138    const struct util_format_description *desc = util_format_description(format);
    139 
    140    /* a subsampled formats can't work as surface use RGBA instead */
    141    if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED)
    142       return PIPE_FORMAT_R8G8B8A8_UNORM;
    143 
    144    return format;
    145 }
    146 
    147 boolean
    148 vl_video_buffer_is_format_supported(struct pipe_screen *screen,
    149                                     enum pipe_format format,
    150                                     enum pipe_video_profile profile)
    151 {
    152    const enum pipe_format *resource_formats;
    153    unsigned i;
    154 
    155    resource_formats = vl_video_buffer_formats(screen, format);
    156    if (!resource_formats)
    157       return false;
    158 
    159    for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
    160       enum pipe_format format = resource_formats[i];
    161 
    162       if (format == PIPE_FORMAT_NONE)
    163          continue;
    164 
    165       /* we at least need to sample from it */
    166       if (!screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_SAMPLER_VIEW))
    167          return false;
    168 
    169       format = vl_video_buffer_surface_format(format);
    170       if (!screen->is_format_supported(screen, format, PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET))
    171          return false;
    172    }
    173 
    174    return true;
    175 }
    176 
    177 unsigned
    178 vl_video_buffer_max_size(struct pipe_screen *screen)
    179 {
    180    uint32_t max_2d_texture_level;
    181 
    182    max_2d_texture_level = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
    183 
    184    return 1 << (max_2d_texture_level-1);
    185 }
    186 
    187 void
    188 vl_video_buffer_set_associated_data(struct pipe_video_buffer *vbuf,
    189                                     struct pipe_video_decoder *vdec,
    190                                     void *associated_data,
    191                                     void (*destroy_associated_data)(void *))
    192 {
    193    vbuf->decoder = vdec;
    194 
    195    if (vbuf->associated_data == associated_data)
    196       return;
    197 
    198    if (vbuf->associated_data)
    199       vbuf->destroy_associated_data(vbuf->associated_data);
    200 
    201    vbuf->associated_data = associated_data;
    202    vbuf->destroy_associated_data = destroy_associated_data;
    203 }
    204 
    205 void *
    206 vl_video_buffer_get_associated_data(struct pipe_video_buffer *vbuf,
    207                                     struct pipe_video_decoder *vdec)
    208 {
    209    if (vbuf->decoder == vdec)
    210       return vbuf->associated_data;
    211    else
    212       return NULL;
    213 }
    214 
    215 void
    216 vl_vide_buffer_template(struct pipe_resource *templ,
    217                         const struct pipe_video_buffer *tmpl,
    218                         enum pipe_format resource_format,
    219                         unsigned depth, unsigned usage, unsigned plane)
    220 {
    221    memset(templ, 0, sizeof(*templ));
    222    templ->target = depth > 1 ? PIPE_TEXTURE_3D : PIPE_TEXTURE_2D;
    223    templ->format = resource_format;
    224    templ->width0 = tmpl->width;
    225    templ->height0 = tmpl->height;
    226    templ->depth0 = depth;
    227    templ->array_size = 1;
    228    templ->bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
    229    templ->usage = usage;
    230 
    231    if (plane > 0) {
    232       if (tmpl->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) {
    233          templ->width0 /= 2;
    234          templ->height0 /= 2;
    235       } else if (tmpl->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_422) {
    236          templ->height0 /= 2;
    237       }
    238    }
    239 }
    240 
    241 static void
    242 vl_video_buffer_destroy(struct pipe_video_buffer *buffer)
    243 {
    244    struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
    245    unsigned i;
    246 
    247    assert(buf);
    248 
    249    for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
    250       pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL);
    251       pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL);
    252       pipe_resource_reference(&buf->resources[i], NULL);
    253    }
    254 
    255    for (i = 0; i < VL_NUM_COMPONENTS * 2; ++i)
    256       pipe_surface_reference(&buf->surfaces[i], NULL);
    257 
    258    vl_video_buffer_set_associated_data(buffer, NULL, NULL, NULL);
    259 
    260    FREE(buffer);
    261 }
    262 
    263 static struct pipe_sampler_view **
    264 vl_video_buffer_sampler_view_planes(struct pipe_video_buffer *buffer)
    265 {
    266    struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
    267    struct pipe_sampler_view sv_templ;
    268    struct pipe_context *pipe;
    269    unsigned i;
    270 
    271    assert(buf);
    272 
    273    pipe = buf->base.context;
    274 
    275    for (i = 0; i < buf->num_planes; ++i ) {
    276       if (!buf->sampler_view_planes[i]) {
    277          memset(&sv_templ, 0, sizeof(sv_templ));
    278          u_sampler_view_default_template(&sv_templ, buf->resources[i], buf->resources[i]->format);
    279 
    280          if (util_format_get_nr_components(buf->resources[i]->format) == 1)
    281             sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = sv_templ.swizzle_a = PIPE_SWIZZLE_RED;
    282 
    283          buf->sampler_view_planes[i] = pipe->create_sampler_view(pipe, buf->resources[i], &sv_templ);
    284          if (!buf->sampler_view_planes[i])
    285             goto error;
    286       }
    287    }
    288 
    289    return buf->sampler_view_planes;
    290 
    291 error:
    292    for (i = 0; i < buf->num_planes; ++i )
    293       pipe_sampler_view_reference(&buf->sampler_view_planes[i], NULL);
    294 
    295    return NULL;
    296 }
    297 
    298 static struct pipe_sampler_view **
    299 vl_video_buffer_sampler_view_components(struct pipe_video_buffer *buffer)
    300 {
    301    struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
    302    struct pipe_sampler_view sv_templ;
    303    struct pipe_context *pipe;
    304    const enum pipe_format *sampler_format;
    305    const unsigned *plane_order;
    306    unsigned i, j, component;
    307 
    308    assert(buf);
    309 
    310    pipe = buf->base.context;
    311 
    312    sampler_format = vl_video_buffer_formats(pipe->screen, buf->base.buffer_format);
    313    plane_order = vl_video_buffer_plane_order(buf->base.buffer_format);
    314 
    315    for (component = 0, i = 0; i < buf->num_planes; ++i ) {
    316       struct pipe_resource *res = buf->resources[plane_order[i]];
    317       const struct util_format_description *desc = util_format_description(res->format);
    318       unsigned nr_components = util_format_get_nr_components(res->format);
    319       if (desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED)
    320          nr_components = 3;
    321 
    322       for (j = 0; j < nr_components && component < VL_NUM_COMPONENTS; ++j, ++component) {
    323          if (buf->sampler_view_components[component])
    324             continue;
    325 
    326          memset(&sv_templ, 0, sizeof(sv_templ));
    327          u_sampler_view_default_template(&sv_templ, res, sampler_format[plane_order[i]]);
    328          sv_templ.swizzle_r = sv_templ.swizzle_g = sv_templ.swizzle_b = PIPE_SWIZZLE_RED + j;
    329          sv_templ.swizzle_a = PIPE_SWIZZLE_ONE;
    330          buf->sampler_view_components[component] = pipe->create_sampler_view(pipe, res, &sv_templ);
    331          if (!buf->sampler_view_components[component])
    332             goto error;
    333       }
    334    }
    335    assert(component == VL_NUM_COMPONENTS);
    336 
    337    return buf->sampler_view_components;
    338 
    339 error:
    340    for (i = 0; i < VL_NUM_COMPONENTS; ++i )
    341       pipe_sampler_view_reference(&buf->sampler_view_components[i], NULL);
    342 
    343    return NULL;
    344 }
    345 
    346 static struct pipe_surface **
    347 vl_video_buffer_surfaces(struct pipe_video_buffer *buffer)
    348 {
    349    struct vl_video_buffer *buf = (struct vl_video_buffer *)buffer;
    350    struct pipe_surface surf_templ;
    351    struct pipe_context *pipe;
    352    unsigned i, j, depth, surf;
    353 
    354    assert(buf);
    355 
    356    pipe = buf->base.context;
    357 
    358    depth = buffer->interlaced ? 2 : 1;
    359    for (i = 0, surf = 0; i < depth; ++i ) {
    360       for (j = 0; j < VL_NUM_COMPONENTS; ++j, ++surf) {
    361          assert(surf < (VL_NUM_COMPONENTS * 2));
    362 
    363          if (!buf->resources[j]) {
    364             pipe_surface_reference(&buf->surfaces[surf], NULL);
    365             continue;
    366          }
    367 
    368          if (!buf->surfaces[surf]) {
    369             memset(&surf_templ, 0, sizeof(surf_templ));
    370             surf_templ.format = vl_video_buffer_surface_format(buf->resources[j]->format);
    371             surf_templ.usage = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
    372             surf_templ.u.tex.first_layer = surf_templ.u.tex.last_layer = i;
    373             buf->surfaces[surf] = pipe->create_surface(pipe, buf->resources[j], &surf_templ);
    374             if (!buf->surfaces[surf])
    375                goto error;
    376          }
    377       }
    378    }
    379 
    380    return buf->surfaces;
    381 
    382 error:
    383    for (i = 0; i < (VL_NUM_COMPONENTS * 2); ++i )
    384       pipe_surface_reference(&buf->surfaces[i], NULL);
    385 
    386    return NULL;
    387 }
    388 
    389 struct pipe_video_buffer *
    390 vl_video_buffer_create(struct pipe_context *pipe,
    391                        const struct pipe_video_buffer *tmpl)
    392 {
    393    const enum pipe_format *resource_formats;
    394    struct pipe_video_buffer templat, *result;
    395    bool pot_buffers;
    396 
    397    assert(pipe);
    398    assert(tmpl->width > 0 && tmpl->height > 0);
    399 
    400    pot_buffers = !pipe->screen->get_video_param
    401    (
    402       pipe->screen,
    403       PIPE_VIDEO_PROFILE_UNKNOWN,
    404       PIPE_VIDEO_CAP_NPOT_TEXTURES
    405    );
    406 
    407    resource_formats = vl_video_buffer_formats(pipe->screen, tmpl->buffer_format);
    408    if (!resource_formats)
    409       return NULL;
    410 
    411    templat = *tmpl;
    412    templat.width = pot_buffers ? util_next_power_of_two(tmpl->width)
    413                  : align(tmpl->width, VL_MACROBLOCK_WIDTH);
    414    templat.height = pot_buffers ? util_next_power_of_two(tmpl->height)
    415                   : align(tmpl->height, VL_MACROBLOCK_HEIGHT);
    416 
    417    if (tmpl->interlaced)
    418       templat.height /= 2;
    419 
    420    result = vl_video_buffer_create_ex
    421    (
    422       pipe, &templat, resource_formats,
    423       tmpl->interlaced ? 2 : 1, PIPE_USAGE_STATIC
    424    );
    425 
    426 
    427    if (result && tmpl->interlaced)
    428       result->height *= 2;
    429 
    430    return result;
    431 }
    432 
    433 struct pipe_video_buffer *
    434 vl_video_buffer_create_ex(struct pipe_context *pipe,
    435                           const struct pipe_video_buffer *tmpl,
    436                           const enum pipe_format resource_formats[VL_NUM_COMPONENTS],
    437                           unsigned depth, unsigned usage)
    438 {
    439    struct pipe_resource res_tmpl;
    440    struct pipe_resource *resources[VL_NUM_COMPONENTS];
    441    unsigned i;
    442 
    443    assert(pipe);
    444 
    445    memset(resources, 0, sizeof resources);
    446 
    447    vl_vide_buffer_template(&res_tmpl, tmpl, resource_formats[0], depth, usage, 0);
    448    resources[0] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
    449    if (!resources[0])
    450       goto error;
    451 
    452    if (resource_formats[1] == PIPE_FORMAT_NONE) {
    453       assert(resource_formats[2] == PIPE_FORMAT_NONE);
    454       return vl_video_buffer_create_ex2(pipe, tmpl, resources);
    455    }
    456 
    457    vl_vide_buffer_template(&res_tmpl, tmpl, resource_formats[1], depth, usage, 1);
    458    resources[1] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
    459    if (!resources[1])
    460       goto error;
    461 
    462    if (resource_formats[2] == PIPE_FORMAT_NONE)
    463       return vl_video_buffer_create_ex2(pipe, tmpl, resources);
    464 
    465    vl_vide_buffer_template(&res_tmpl, tmpl, resource_formats[2], depth, usage, 2);
    466    resources[2] = pipe->screen->resource_create(pipe->screen, &res_tmpl);
    467    if (!resources[2])
    468       goto error;
    469 
    470    return vl_video_buffer_create_ex2(pipe, tmpl, resources);
    471 
    472 error:
    473    for (i = 0; i < VL_NUM_COMPONENTS; ++i)
    474       pipe_resource_reference(&resources[i], NULL);
    475 
    476    return NULL;
    477 }
    478 
    479 struct pipe_video_buffer *
    480 vl_video_buffer_create_ex2(struct pipe_context *pipe,
    481                            const struct pipe_video_buffer *tmpl,
    482                            struct pipe_resource *resources[VL_NUM_COMPONENTS])
    483 {
    484    struct vl_video_buffer *buffer;
    485    unsigned i;
    486 
    487    buffer = CALLOC_STRUCT(vl_video_buffer);
    488 
    489    buffer->base = *tmpl;
    490    buffer->base.context = pipe;
    491    buffer->base.destroy = vl_video_buffer_destroy;
    492    buffer->base.get_sampler_view_planes = vl_video_buffer_sampler_view_planes;
    493    buffer->base.get_sampler_view_components = vl_video_buffer_sampler_view_components;
    494    buffer->base.get_surfaces = vl_video_buffer_surfaces;
    495    buffer->num_planes = 0;
    496 
    497    for (i = 0; i < VL_NUM_COMPONENTS; ++i) {
    498       buffer->resources[i] = resources[i];
    499       if (resources[i])
    500          buffer->num_planes++;
    501    }
    502 
    503    return &buffer->base;
    504 }
    505