Home | History | Annotate | Download | only in vdpau
      1 /**************************************************************************
      2  *
      3  * Copyright 2010 Thomas Balling Srensen.
      4  * Copyright 2011 Christian Knig.
      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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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 <assert.h>
     30 
     31 #include "pipe/p_state.h"
     32 
     33 #include "util/u_memory.h"
     34 #include "util/u_debug.h"
     35 #include "util/u_rect.h"
     36 #include "vl/vl_defines.h"
     37 
     38 #include "vdpau_private.h"
     39 
     40 /**
     41  * Create a VdpVideoSurface.
     42  */
     43 VdpStatus
     44 vlVdpVideoSurfaceCreate(VdpDevice device, VdpChromaType chroma_type,
     45                         uint32_t width, uint32_t height,
     46                         VdpVideoSurface *surface)
     47 {
     48    struct pipe_context *pipe;
     49    vlVdpSurface *p_surf;
     50    VdpStatus ret;
     51 
     52    if (!(width && height)) {
     53       ret = VDP_STATUS_INVALID_SIZE;
     54       goto inv_size;
     55    }
     56 
     57    if (!vlCreateHTAB()) {
     58       ret = VDP_STATUS_RESOURCES;
     59       goto no_htab;
     60    }
     61 
     62    p_surf = CALLOC(1, sizeof(vlVdpSurface));
     63    if (!p_surf) {
     64       ret = VDP_STATUS_RESOURCES;
     65       goto no_res;
     66    }
     67 
     68    vlVdpDevice *dev = vlGetDataHTAB(device);
     69    if (!dev) {
     70       ret = VDP_STATUS_INVALID_HANDLE;
     71       goto inv_device;
     72    }
     73 
     74    p_surf->device = dev;
     75    pipe = dev->context;
     76 
     77    pipe_mutex_lock(dev->mutex);
     78    memset(&p_surf->templat, 0, sizeof(p_surf->templat));
     79    p_surf->templat.buffer_format = pipe->screen->get_video_param
     80    (
     81       pipe->screen,
     82       PIPE_VIDEO_PROFILE_UNKNOWN,
     83       PIPE_VIDEO_CAP_PREFERED_FORMAT
     84    );
     85    p_surf->templat.chroma_format = ChromaToPipe(chroma_type);
     86    p_surf->templat.width = width;
     87    p_surf->templat.height = height;
     88    p_surf->templat.interlaced = pipe->screen->get_video_param
     89    (
     90       pipe->screen,
     91       PIPE_VIDEO_PROFILE_UNKNOWN,
     92       PIPE_VIDEO_CAP_PREFERS_INTERLACED
     93    );
     94    p_surf->video_buffer = pipe->create_video_buffer(pipe, &p_surf->templat);
     95    vlVdpVideoSurfaceClear(p_surf);
     96    pipe_mutex_unlock(dev->mutex);
     97 
     98    *surface = vlAddDataHTAB(p_surf);
     99    if (*surface == 0) {
    100       ret = VDP_STATUS_ERROR;
    101       goto no_handle;
    102    }
    103 
    104    return VDP_STATUS_OK;
    105 
    106 no_handle:
    107    p_surf->video_buffer->destroy(p_surf->video_buffer);
    108 
    109 inv_device:
    110    FREE(p_surf);
    111 
    112 no_res:
    113 no_htab:
    114 inv_size:
    115    return ret;
    116 }
    117 
    118 /**
    119  * Destroy a VdpVideoSurface.
    120  */
    121 VdpStatus
    122 vlVdpVideoSurfaceDestroy(VdpVideoSurface surface)
    123 {
    124    vlVdpSurface *p_surf;
    125 
    126    p_surf = (vlVdpSurface *)vlGetDataHTAB((vlHandle)surface);
    127    if (!p_surf)
    128       return VDP_STATUS_INVALID_HANDLE;
    129 
    130    pipe_mutex_lock(p_surf->device->mutex);
    131    if (p_surf->video_buffer)
    132       p_surf->video_buffer->destroy(p_surf->video_buffer);
    133    pipe_mutex_unlock(p_surf->device->mutex);
    134 
    135    FREE(p_surf);
    136    return VDP_STATUS_OK;
    137 }
    138 
    139 /**
    140  * Retrieve the parameters used to create a VdpVideoSurface.
    141  */
    142 VdpStatus
    143 vlVdpVideoSurfaceGetParameters(VdpVideoSurface surface,
    144                                VdpChromaType *chroma_type,
    145                                uint32_t *width, uint32_t *height)
    146 {
    147    if (!(width && height && chroma_type))
    148       return VDP_STATUS_INVALID_POINTER;
    149 
    150    vlVdpSurface *p_surf = vlGetDataHTAB(surface);
    151    if (!p_surf)
    152       return VDP_STATUS_INVALID_HANDLE;
    153 
    154    if (p_surf->video_buffer) {
    155       *width = p_surf->video_buffer->width;
    156       *height = p_surf->video_buffer->height;
    157       *chroma_type = PipeToChroma(p_surf->video_buffer->chroma_format);
    158    } else {
    159       *width = p_surf->templat.width;
    160       *height = p_surf->templat.height;
    161       *chroma_type = PipeToChroma(p_surf->templat.chroma_format);
    162    }
    163 
    164    return VDP_STATUS_OK;
    165 }
    166 
    167 static void
    168 vlVdpVideoSurfaceSize(vlVdpSurface *p_surf, int component,
    169                       unsigned *width, unsigned *height)
    170 {
    171    *width = p_surf->templat.width;
    172    *height = p_surf->templat.height;
    173 
    174    if (component > 0) {
    175       if (p_surf->templat.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) {
    176          *width /= 2;
    177          *height /= 2;
    178       } else if (p_surf->templat.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_422) {
    179          *height /= 2;
    180       }
    181       if (p_surf->templat.interlaced)
    182          *height /= 2;
    183    }
    184 }
    185 
    186 /**
    187  * Copy image data from a VdpVideoSurface to application memory in a specified
    188  * YCbCr format.
    189  */
    190 VdpStatus
    191 vlVdpVideoSurfaceGetBitsYCbCr(VdpVideoSurface surface,
    192                               VdpYCbCrFormat destination_ycbcr_format,
    193                               void *const *destination_data,
    194                               uint32_t const *destination_pitches)
    195 {
    196    vlVdpSurface *vlsurface;
    197    struct pipe_context *pipe;
    198    enum pipe_format format;
    199    struct pipe_sampler_view **sampler_views;
    200    unsigned i, j;
    201 
    202    vlsurface = vlGetDataHTAB(surface);
    203    if (!vlsurface)
    204       return VDP_STATUS_INVALID_HANDLE;
    205 
    206    pipe = vlsurface->device->context;
    207    if (!pipe)
    208       return VDP_STATUS_INVALID_HANDLE;
    209 
    210    format = FormatYCBCRToPipe(destination_ycbcr_format);
    211    if (format == PIPE_FORMAT_NONE)
    212        return VDP_STATUS_INVALID_Y_CB_CR_FORMAT;
    213 
    214    if (vlsurface->video_buffer == NULL || format != vlsurface->video_buffer->buffer_format)
    215       return VDP_STATUS_NO_IMPLEMENTATION; /* TODO We don't support conversion (yet) */
    216 
    217    pipe_mutex_lock(vlsurface->device->mutex);
    218    sampler_views = vlsurface->video_buffer->get_sampler_view_planes(vlsurface->video_buffer);
    219    if (!sampler_views) {
    220       pipe_mutex_unlock(vlsurface->device->mutex);
    221       return VDP_STATUS_RESOURCES;
    222    }
    223 
    224    for (i = 0; i < 3; ++i) {
    225       unsigned width, height;
    226       struct pipe_sampler_view *sv = sampler_views[i];
    227       if (!sv) continue;
    228 
    229       vlVdpVideoSurfaceSize(vlsurface, i, &width, &height);
    230 
    231       for (j = 0; j < sv->texture->depth0; ++j) {
    232          struct pipe_box box = {
    233             0, 0, j,
    234             width, height, 1
    235          };
    236          struct pipe_transfer *transfer;
    237          uint8_t *map;
    238 
    239          transfer = pipe->get_transfer(pipe, sv->texture, 0, PIPE_TRANSFER_READ, &box);
    240          if (transfer == NULL) {
    241             pipe_mutex_unlock(vlsurface->device->mutex);
    242             return VDP_STATUS_RESOURCES;
    243          }
    244 
    245          map = pipe_transfer_map(pipe, transfer);
    246          if (map == NULL) {
    247             pipe_transfer_destroy(pipe, transfer);
    248             pipe_mutex_unlock(vlsurface->device->mutex);
    249             return VDP_STATUS_RESOURCES;
    250          }
    251 
    252          util_copy_rect(destination_data[i] + destination_pitches[i] * j, sv->texture->format,
    253                         destination_pitches[i] * sv->texture->depth0, 0, 0,
    254                         box.width, box.height, map, transfer->stride, 0, 0);
    255 
    256          pipe_transfer_unmap(pipe, transfer);
    257          pipe_transfer_destroy(pipe, transfer);
    258       }
    259    }
    260    pipe_mutex_unlock(vlsurface->device->mutex);
    261 
    262    return VDP_STATUS_OK;
    263 }
    264 
    265 /**
    266  * Copy image data from application memory in a specific YCbCr format to
    267  * a VdpVideoSurface.
    268  */
    269 VdpStatus
    270 vlVdpVideoSurfacePutBitsYCbCr(VdpVideoSurface surface,
    271                               VdpYCbCrFormat source_ycbcr_format,
    272                               void const *const *source_data,
    273                               uint32_t const *source_pitches)
    274 {
    275    enum pipe_format pformat = FormatYCBCRToPipe(source_ycbcr_format);
    276    struct pipe_context *pipe;
    277    struct pipe_sampler_view **sampler_views;
    278    unsigned i, j;
    279 
    280    if (!vlCreateHTAB())
    281       return VDP_STATUS_RESOURCES;
    282 
    283    vlVdpSurface *p_surf = vlGetDataHTAB(surface);
    284    if (!p_surf)
    285       return VDP_STATUS_INVALID_HANDLE;
    286 
    287    pipe = p_surf->device->context;
    288    if (!pipe)
    289       return VDP_STATUS_INVALID_HANDLE;
    290 
    291    pipe_mutex_lock(p_surf->device->mutex);
    292    if (p_surf->video_buffer == NULL || pformat != p_surf->video_buffer->buffer_format) {
    293 
    294       /* destroy the old one */
    295       if (p_surf->video_buffer)
    296          p_surf->video_buffer->destroy(p_surf->video_buffer);
    297 
    298       /* adjust the template parameters */
    299       p_surf->templat.buffer_format = pformat;
    300 
    301       /* and try to create the video buffer with the new format */
    302       p_surf->video_buffer = pipe->create_video_buffer(pipe, &p_surf->templat);
    303 
    304       /* stil no luck? ok forget it we don't support it */
    305       if (!p_surf->video_buffer) {
    306          pipe_mutex_unlock(p_surf->device->mutex);
    307          return VDP_STATUS_NO_IMPLEMENTATION;
    308       }
    309       vlVdpVideoSurfaceClear(p_surf);
    310    }
    311 
    312    sampler_views = p_surf->video_buffer->get_sampler_view_planes(p_surf->video_buffer);
    313    if (!sampler_views) {
    314       pipe_mutex_unlock(p_surf->device->mutex);
    315       return VDP_STATUS_RESOURCES;
    316    }
    317 
    318    for (i = 0; i < 3; ++i) {
    319       unsigned width, height;
    320       struct pipe_sampler_view *sv = sampler_views[i];
    321       if (!sv || !source_pitches[i]) continue;
    322 
    323       vlVdpVideoSurfaceSize(p_surf, i, &width, &height);
    324 
    325       for (j = 0; j < sv->texture->depth0; ++j) {
    326          struct pipe_box dst_box = {
    327             0, 0, j,
    328             width, height, 1
    329          };
    330 
    331          pipe->transfer_inline_write(pipe, sv->texture, 0,
    332                                      PIPE_TRANSFER_WRITE, &dst_box,
    333                                      source_data[i] + source_pitches[i] * j,
    334                                      source_pitches[i] * sv->texture->depth0,
    335                                      0);
    336       }
    337    }
    338    pipe_mutex_unlock(p_surf->device->mutex);
    339 
    340    return VDP_STATUS_OK;
    341 }
    342 
    343 /**
    344  * Helper function to initially clear the VideoSurface after (re-)creation
    345  */
    346 void
    347 vlVdpVideoSurfaceClear(vlVdpSurface *vlsurf)
    348 {
    349    struct pipe_context *pipe = vlsurf->device->context;
    350    struct pipe_surface **surfaces;
    351    unsigned i;
    352 
    353    if (!vlsurf->video_buffer)
    354       return;
    355 
    356    surfaces = vlsurf->video_buffer->get_surfaces(vlsurf->video_buffer);
    357    for (i = 0; i < VL_MAX_SURFACES; ++i) {
    358       union pipe_color_union c = {};
    359 
    360       if (!surfaces[i])
    361          continue;
    362 
    363       if (i > !!vlsurf->templat.interlaced)
    364          c.f[0] = c.f[1] = c.f[2] = c.f[3] = 0.5f;
    365 
    366       pipe->clear_render_target(pipe, surfaces[i], &c, 0, 0,
    367                                 surfaces[i]->width, surfaces[i]->height);
    368    }
    369    pipe->flush(pipe, NULL);
    370 }
    371