Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

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