Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2010 Thomas Balling Sørensen.
  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 <vdpau/vdpau.h>
  29.  
  30. #include "util/u_memory.h"
  31. #include "util/u_debug.h"
  32.  
  33. #include "vl/vl_csc.h"
  34.  
  35. #include "vdpau_private.h"
  36.  
  37. /**
  38.  * Create a VdpVideoMixer.
  39.  */
  40. VdpStatus
  41. vlVdpVideoMixerCreate(VdpDevice device,
  42.                       uint32_t feature_count,
  43.                       VdpVideoMixerFeature const *features,
  44.                       uint32_t parameter_count,
  45.                       VdpVideoMixerParameter const *parameters,
  46.                       void const *const *parameter_values,
  47.                       VdpVideoMixer *mixer)
  48. {
  49.    vlVdpVideoMixer *vmixer = NULL;
  50.    VdpStatus ret;
  51.    struct pipe_screen *screen;
  52.    unsigned max_width, max_height, i;
  53.  
  54.    vlVdpDevice *dev = vlGetDataHTAB(device);
  55.    if (!dev)
  56.       return VDP_STATUS_INVALID_HANDLE;
  57.    screen = dev->vscreen->pscreen;
  58.  
  59.    vmixer = CALLOC(1, sizeof(vlVdpVideoMixer));
  60.    if (!vmixer)
  61.       return VDP_STATUS_RESOURCES;
  62.  
  63.    DeviceReference(&vmixer->device, dev);
  64.  
  65.    pipe_mutex_lock(dev->mutex);
  66.  
  67.    vl_compositor_init_state(&vmixer->cstate, dev->context);
  68.  
  69.    vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, true, &vmixer->csc);
  70.    if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))
  71.       vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc);
  72.  
  73.    *mixer = vlAddDataHTAB(vmixer);
  74.    if (*mixer == 0) {
  75.       ret = VDP_STATUS_ERROR;
  76.       goto no_handle;
  77.    }
  78.  
  79.    ret = VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
  80.    for (i = 0; i < feature_count; ++i) {
  81.       switch (features[i]) {
  82.       /* they are valid, but we doesn't support them */
  83.       case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
  84.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
  85.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
  86.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
  87.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
  88.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
  89.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
  90.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
  91.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
  92.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
  93.       case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
  94.       case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
  95.          break;
  96.  
  97.       case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
  98.          vmixer->deint.supported = true;
  99.          break;
  100.  
  101.       case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
  102.          vmixer->sharpness.supported = true;
  103.          break;
  104.  
  105.       case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
  106.          vmixer->noise_reduction.supported = true;
  107.          break;
  108.  
  109.       default: goto no_params;
  110.       }
  111.    }
  112.  
  113.    vmixer->chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
  114.    ret = VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER;
  115.    for (i = 0; i < parameter_count; ++i) {
  116.       switch (parameters[i]) {
  117.       case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH:
  118.          vmixer->video_width = *(uint32_t*)parameter_values[i];
  119.          break;
  120.       case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT:
  121.          vmixer->video_height = *(uint32_t*)parameter_values[i];
  122.          break;
  123.       case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE:
  124.          vmixer->chroma_format = ChromaToPipe(*(VdpChromaType*)parameter_values[i]);
  125.          break;
  126.       case VDP_VIDEO_MIXER_PARAMETER_LAYERS:
  127.          vmixer->max_layers = *(uint32_t*)parameter_values[i];
  128.          break;
  129.       default: goto no_params;
  130.       }
  131.    }
  132.    ret = VDP_STATUS_INVALID_VALUE;
  133.    if (vmixer->max_layers > 4) {
  134.       VDPAU_MSG(VDPAU_WARN, "[VDPAU] Max layers > 4 not supported\n", vmixer->max_layers);
  135.       goto no_params;
  136.    }
  137.    max_width = screen->get_video_param(screen, PIPE_VIDEO_PROFILE_UNKNOWN,
  138.                                        PIPE_VIDEO_ENTRYPOINT_BITSTREAM, PIPE_VIDEO_CAP_MAX_WIDTH);
  139.    max_height = screen->get_video_param(screen, PIPE_VIDEO_PROFILE_UNKNOWN,
  140.                                         PIPE_VIDEO_ENTRYPOINT_BITSTREAM, PIPE_VIDEO_CAP_MAX_HEIGHT);
  141.    if (vmixer->video_width < 48 ||
  142.        vmixer->video_width > max_width) {
  143.       VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u not valid for width\n", vmixer->video_width, max_width);
  144.       goto no_params;
  145.    }
  146.    if (vmixer->video_height < 48 ||
  147.        vmixer->video_height > max_height) {
  148.       VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u  not valid for height\n", vmixer->video_height, max_height);
  149.       goto no_params;
  150.    }
  151.    vmixer->luma_key_min = 0.f;
  152.    vmixer->luma_key_max = 1.f;
  153.    pipe_mutex_unlock(dev->mutex);
  154.  
  155.    return VDP_STATUS_OK;
  156.  
  157. no_params:
  158.    vlRemoveDataHTAB(*mixer);
  159.  
  160. no_handle:
  161.    vl_compositor_cleanup_state(&vmixer->cstate);
  162.    pipe_mutex_unlock(dev->mutex);
  163.    DeviceReference(&vmixer->device, NULL);
  164.    FREE(vmixer);
  165.    return ret;
  166. }
  167.  
  168. /**
  169.  * Destroy a VdpVideoMixer.
  170.  */
  171. VdpStatus
  172. vlVdpVideoMixerDestroy(VdpVideoMixer mixer)
  173. {
  174.    vlVdpVideoMixer *vmixer;
  175.  
  176.    vmixer = vlGetDataHTAB(mixer);
  177.    if (!vmixer)
  178.       return VDP_STATUS_INVALID_HANDLE;
  179.  
  180.    pipe_mutex_lock(vmixer->device->mutex);
  181.  
  182.    vlVdpResolveDelayedRendering(vmixer->device, NULL, NULL);
  183.  
  184.    vlRemoveDataHTAB(mixer);
  185.  
  186.    vl_compositor_cleanup_state(&vmixer->cstate);
  187.  
  188.    if (vmixer->deint.filter) {
  189.       vl_deint_filter_cleanup(vmixer->deint.filter);
  190.       FREE(vmixer->deint.filter);
  191.    }
  192.  
  193.    if (vmixer->noise_reduction.filter) {
  194.       vl_median_filter_cleanup(vmixer->noise_reduction.filter);
  195.       FREE(vmixer->noise_reduction.filter);
  196.    }
  197.  
  198.    if (vmixer->sharpness.filter) {
  199.       vl_matrix_filter_cleanup(vmixer->sharpness.filter);
  200.       FREE(vmixer->sharpness.filter);
  201.    }
  202.    pipe_mutex_unlock(vmixer->device->mutex);
  203.    DeviceReference(&vmixer->device, NULL);
  204.  
  205.    FREE(vmixer);
  206.  
  207.    return VDP_STATUS_OK;
  208. }
  209.  
  210. /**
  211.  * Perform a video post-processing and compositing operation.
  212.  */
  213. VdpStatus vlVdpVideoMixerRender(VdpVideoMixer mixer,
  214.                                 VdpOutputSurface background_surface,
  215.                                 VdpRect const *background_source_rect,
  216.                                 VdpVideoMixerPictureStructure current_picture_structure,
  217.                                 uint32_t video_surface_past_count,
  218.                                 VdpVideoSurface const *video_surface_past,
  219.                                 VdpVideoSurface video_surface_current,
  220.                                 uint32_t video_surface_future_count,
  221.                                 VdpVideoSurface const *video_surface_future,
  222.                                 VdpRect const *video_source_rect,
  223.                                 VdpOutputSurface destination_surface,
  224.                                 VdpRect const *destination_rect,
  225.                                 VdpRect const *destination_video_rect,
  226.                                 uint32_t layer_count,
  227.                                 VdpLayer const *layers)
  228. {
  229.    enum vl_compositor_deinterlace deinterlace;
  230.    struct u_rect rect, clip, *prect;
  231.    unsigned i, layer = 0;
  232.    struct pipe_video_buffer *video_buffer;
  233.  
  234.    vlVdpVideoMixer *vmixer;
  235.    vlVdpSurface *surf;
  236.    vlVdpOutputSurface *dst, *bg = NULL;
  237.  
  238.    struct vl_compositor *compositor;
  239.  
  240.    vmixer = vlGetDataHTAB(mixer);
  241.    if (!vmixer)
  242.       return VDP_STATUS_INVALID_HANDLE;
  243.  
  244.    compositor = &vmixer->device->compositor;
  245.  
  246.    surf = vlGetDataHTAB(video_surface_current);
  247.    if (!surf)
  248.       return VDP_STATUS_INVALID_HANDLE;
  249.    video_buffer = surf->video_buffer;
  250.  
  251.    if (surf->device != vmixer->device)
  252.       return VDP_STATUS_HANDLE_DEVICE_MISMATCH;
  253.  
  254.    if (vmixer->video_width > video_buffer->width ||
  255.        vmixer->video_height > video_buffer->height ||
  256.        vmixer->chroma_format != video_buffer->chroma_format)
  257.       return VDP_STATUS_INVALID_SIZE;
  258.  
  259.    if (layer_count > vmixer->max_layers)
  260.       return VDP_STATUS_INVALID_VALUE;
  261.  
  262.    dst = vlGetDataHTAB(destination_surface);
  263.    if (!dst)
  264.       return VDP_STATUS_INVALID_HANDLE;
  265.  
  266.    if (background_surface != VDP_INVALID_HANDLE) {
  267.       bg = vlGetDataHTAB(background_surface);
  268.       if (!bg)
  269.          return VDP_STATUS_INVALID_HANDLE;
  270.    }
  271.  
  272.    pipe_mutex_lock(vmixer->device->mutex);
  273.    vlVdpResolveDelayedRendering(vmixer->device, NULL, NULL);
  274.  
  275.    vl_compositor_clear_layers(&vmixer->cstate);
  276.  
  277.    if (bg)
  278.       vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer++, bg->sampler_view,
  279.                                    RectToPipe(background_source_rect, &rect), NULL, NULL);
  280.  
  281.    switch (current_picture_structure) {
  282.    case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD:
  283.       deinterlace = VL_COMPOSITOR_BOB_TOP;
  284.       break;
  285.  
  286.    case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD:
  287.       deinterlace = VL_COMPOSITOR_BOB_BOTTOM;
  288.       break;
  289.  
  290.    case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME:
  291.       deinterlace = VL_COMPOSITOR_WEAVE;
  292.       break;
  293.  
  294.    default:
  295.       pipe_mutex_unlock(vmixer->device->mutex);
  296.       return VDP_STATUS_INVALID_VIDEO_MIXER_PICTURE_STRUCTURE;
  297.    };
  298.  
  299.    if (deinterlace != VL_COMPOSITOR_WEAVE && vmixer->deint.enabled &&
  300.        video_surface_past_count > 1 && video_surface_future_count > 0) {
  301.       vlVdpSurface *prevprev = vlGetDataHTAB(video_surface_past[1]);
  302.       vlVdpSurface *prev = vlGetDataHTAB(video_surface_past[0]);
  303.       vlVdpSurface *next = vlGetDataHTAB(video_surface_future[0]);
  304.       if (prevprev && prev && next &&
  305.           vl_deint_filter_check_buffers(vmixer->deint.filter,
  306.           prevprev->video_buffer, prev->video_buffer, surf->video_buffer, next->video_buffer)) {
  307.          vl_deint_filter_render(vmixer->deint.filter, prevprev->video_buffer,
  308.                                 prev->video_buffer, surf->video_buffer,
  309.                                 next->video_buffer,
  310.                                 deinterlace == VL_COMPOSITOR_BOB_BOTTOM);
  311.          deinterlace = VL_COMPOSITOR_WEAVE;
  312.          video_buffer = vmixer->deint.filter->video_buffer;
  313.       }
  314.    }
  315.  
  316.    prect = RectToPipe(video_source_rect, &rect);
  317.    if (!prect) {
  318.       rect.x0 = 0;
  319.       rect.y0 = 0;
  320.       rect.x1 = surf->templat.width;
  321.       rect.y1 = surf->templat.height;
  322.       prect = &rect;
  323.    }
  324.    vl_compositor_set_buffer_layer(&vmixer->cstate, compositor, layer, video_buffer, prect, NULL, deinterlace);
  325.    vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(destination_video_rect, &rect));
  326.  
  327.    for (i = 0; i < layer_count; ++i) {
  328.       vlVdpOutputSurface *src = vlGetDataHTAB(layers->source_surface);
  329.       if (!src) {
  330.          pipe_mutex_unlock(vmixer->device->mutex);
  331.          return VDP_STATUS_INVALID_HANDLE;
  332.       }
  333.  
  334.       assert(layers->struct_version == VDP_LAYER_VERSION);
  335.  
  336.       vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer, src->sampler_view,
  337.                                    RectToPipe(layers->source_rect, &rect), NULL, NULL);
  338.       vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(layers->destination_rect, &rect));
  339.  
  340.       ++layers;
  341.    }
  342.  
  343.    vl_compositor_set_dst_clip(&vmixer->cstate, RectToPipe(destination_rect, &clip));
  344.    if (!vmixer->noise_reduction.filter && !vmixer->sharpness.filter)
  345.       vlVdpSave4DelayedRendering(vmixer->device, destination_surface, &vmixer->cstate);
  346.    else {
  347.       vl_compositor_render(&vmixer->cstate, compositor, dst->surface, &dst->dirty_area, true);
  348.  
  349.       /* applying the noise reduction after scaling is actually not very
  350.          clever, but currently we should avoid to copy around the image
  351.          data once more. */
  352.       if (vmixer->noise_reduction.filter)
  353.          vl_median_filter_render(vmixer->noise_reduction.filter,
  354.                                  dst->sampler_view, dst->surface);
  355.  
  356.       if (vmixer->sharpness.filter)
  357.          vl_matrix_filter_render(vmixer->sharpness.filter,
  358.                                  dst->sampler_view, dst->surface);
  359.    }
  360.    pipe_mutex_unlock(vmixer->device->mutex);
  361.  
  362.    return VDP_STATUS_OK;
  363. }
  364.  
  365. static void
  366. vlVdpVideoMixerUpdateDeinterlaceFilter(vlVdpVideoMixer *vmixer)
  367. {
  368.    struct pipe_context *pipe = vmixer->device->context;
  369.    assert(vmixer);
  370.  
  371.    /* remove existing filter */
  372.    if (vmixer->deint.filter) {
  373.       vl_deint_filter_cleanup(vmixer->deint.filter);
  374.       FREE(vmixer->deint.filter);
  375.       vmixer->deint.filter = NULL;
  376.    }
  377.  
  378.    /* create a new filter if requested */
  379.    if (vmixer->deint.enabled && vmixer->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) {
  380.       vmixer->deint.filter = MALLOC(sizeof(struct vl_deint_filter));
  381.       vmixer->deint.enabled = vl_deint_filter_init(vmixer->deint.filter, pipe,
  382.             vmixer->video_width, vmixer->video_height,
  383.             vmixer->skip_chroma_deint, vmixer->deint.spatial);
  384.       if (!vmixer->deint.enabled) {
  385.          FREE(vmixer->deint.filter);
  386.       }
  387.    }
  388. }
  389.  
  390. /**
  391.  * Update the noise reduction setting
  392.  */
  393. static void
  394. vlVdpVideoMixerUpdateNoiseReductionFilter(vlVdpVideoMixer *vmixer)
  395. {
  396.    assert(vmixer);
  397.  
  398.    /* if present remove the old filter first */
  399.    if (vmixer->noise_reduction.filter) {
  400.       vl_median_filter_cleanup(vmixer->noise_reduction.filter);
  401.       FREE(vmixer->noise_reduction.filter);
  402.       vmixer->noise_reduction.filter = NULL;
  403.    }
  404.  
  405.    /* and create a new filter as needed */
  406.    if (vmixer->noise_reduction. enabled && vmixer->noise_reduction.level > 0) {
  407.       vmixer->noise_reduction.filter = MALLOC(sizeof(struct vl_median_filter));
  408.       vl_median_filter_init(vmixer->noise_reduction.filter, vmixer->device->context,
  409.                             vmixer->video_width, vmixer->video_height,
  410.                             vmixer->noise_reduction.level + 1,
  411.                             VL_MEDIAN_FILTER_CROSS);
  412.    }
  413. }
  414.  
  415. static void
  416. vlVdpVideoMixerUpdateSharpnessFilter(vlVdpVideoMixer *vmixer)
  417. {
  418.    assert(vmixer);
  419.  
  420.    /* if present remove the old filter first */
  421.    if (vmixer->sharpness.filter) {
  422.       vl_matrix_filter_cleanup(vmixer->sharpness.filter);
  423.       FREE(vmixer->sharpness.filter);
  424.       vmixer->sharpness.filter = NULL;
  425.    }
  426.  
  427.    /* and create a new filter as needed */
  428.    if (vmixer->sharpness.enabled && vmixer->sharpness.value != 0.0f) {
  429.       float matrix[9];
  430.       unsigned i;
  431.  
  432.       if (vmixer->sharpness.value > 0.0f) {
  433.          matrix[0] = -1.0f; matrix[1] = -1.0f; matrix[2] = -1.0f;
  434.          matrix[3] = -1.0f; matrix[4] =  8.0f; matrix[5] = -1.0f;
  435.          matrix[6] = -1.0f; matrix[7] = -1.0f; matrix[8] = -1.0f;
  436.  
  437.          for (i = 0; i < 9; ++i)
  438.             matrix[i] *= vmixer->sharpness.value;
  439.  
  440.          matrix[4] += 1.0f;
  441.  
  442.       } else {
  443.          matrix[0] = 1.0f; matrix[1] = 2.0f; matrix[2] = 1.0f;
  444.          matrix[3] = 2.0f; matrix[4] = 4.0f; matrix[5] = 2.0f;
  445.          matrix[6] = 1.0f; matrix[7] = 2.0f; matrix[8] = 1.0f;
  446.  
  447.          for (i = 0; i < 9; ++i)
  448.                matrix[i] *= fabsf(vmixer->sharpness.value) / 16.0f;
  449.  
  450.          matrix[4] += 1.0f - fabsf(vmixer->sharpness.value);
  451.       }
  452.  
  453.       vmixer->sharpness.filter = MALLOC(sizeof(struct vl_matrix_filter));
  454.       vl_matrix_filter_init(vmixer->sharpness.filter, vmixer->device->context,
  455.                             vmixer->video_width, vmixer->video_height,
  456.                             3, 3, matrix);
  457.    }
  458. }
  459.  
  460. /**
  461.  * Retrieve whether features were requested at creation time.
  462.  */
  463. VdpStatus
  464. vlVdpVideoMixerGetFeatureSupport(VdpVideoMixer mixer,
  465.                                  uint32_t feature_count,
  466.                                  VdpVideoMixerFeature const *features,
  467.                                  VdpBool *feature_supports)
  468. {
  469.    vlVdpVideoMixer *vmixer;
  470.    unsigned i;
  471.  
  472.    if (!(features && feature_supports))
  473.       return VDP_STATUS_INVALID_POINTER;
  474.  
  475.    vmixer = vlGetDataHTAB(mixer);
  476.    if (!vmixer)
  477.       return VDP_STATUS_INVALID_HANDLE;
  478.  
  479.    for (i = 0; i < feature_count; ++i) {
  480.       switch (features[i]) {
  481.       /* they are valid, but we doesn't support them */
  482.       case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
  483.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
  484.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
  485.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
  486.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
  487.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
  488.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
  489.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
  490.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
  491.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
  492.       case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
  493.       case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
  494.          feature_supports[i] = false;
  495.          break;
  496.  
  497.       case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
  498.          feature_supports[i] = vmixer->deint.supported;
  499.          break;
  500.  
  501.       case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
  502.          feature_supports[i] = vmixer->sharpness.supported;
  503.          break;
  504.  
  505.       case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
  506.          feature_supports[i] = vmixer->noise_reduction.supported;
  507.          break;
  508.  
  509.       default:
  510.          return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
  511.       }
  512.    }
  513.  
  514.    return VDP_STATUS_OK;
  515. }
  516.  
  517. /**
  518.  * Enable or disable features.
  519.  */
  520. VdpStatus
  521. vlVdpVideoMixerSetFeatureEnables(VdpVideoMixer mixer,
  522.                                  uint32_t feature_count,
  523.                                  VdpVideoMixerFeature const *features,
  524.                                  VdpBool const *feature_enables)
  525. {
  526.    vlVdpVideoMixer *vmixer;
  527.    unsigned i;
  528.  
  529.    if (!(features && feature_enables))
  530.       return VDP_STATUS_INVALID_POINTER;
  531.  
  532.    vmixer = vlGetDataHTAB(mixer);
  533.    if (!vmixer)
  534.       return VDP_STATUS_INVALID_HANDLE;
  535.  
  536.    pipe_mutex_lock(vmixer->device->mutex);
  537.    for (i = 0; i < feature_count; ++i) {
  538.       switch (features[i]) {
  539.       /* they are valid, but we doesn't support them */
  540.       case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
  541.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
  542.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
  543.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
  544.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
  545.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
  546.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
  547.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
  548.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
  549.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
  550.       case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
  551.       case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
  552.          break;
  553.  
  554.       case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
  555.          vmixer->deint.enabled = feature_enables[i];
  556.          vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer);
  557.          break;
  558.  
  559.       case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
  560.          vmixer->sharpness.enabled = feature_enables[i];
  561.          vlVdpVideoMixerUpdateSharpnessFilter(vmixer);
  562.          break;
  563.  
  564.       case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
  565.          vmixer->noise_reduction.enabled = feature_enables[i];
  566.          vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer);
  567.          break;
  568.  
  569.       default:
  570.          pipe_mutex_unlock(vmixer->device->mutex);
  571.          return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
  572.       }
  573.    }
  574.    pipe_mutex_unlock(vmixer->device->mutex);
  575.  
  576.    return VDP_STATUS_OK;
  577. }
  578.  
  579. /**
  580.  * Retrieve whether features are enabled.
  581.  */
  582. VdpStatus
  583. vlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer,
  584.                                  uint32_t feature_count,
  585.                                  VdpVideoMixerFeature const *features,
  586.                                  VdpBool *feature_enables)
  587. {
  588.    vlVdpVideoMixer *vmixer;
  589.    unsigned i;
  590.  
  591.    if (!(features && feature_enables))
  592.       return VDP_STATUS_INVALID_POINTER;
  593.  
  594.    vmixer = vlGetDataHTAB(mixer);
  595.    if (!vmixer)
  596.       return VDP_STATUS_INVALID_HANDLE;
  597.  
  598.    for (i = 0; i < feature_count; ++i) {
  599.       switch (features[i]) {
  600.       /* they are valid, but we doesn't support them */
  601.       case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
  602.       case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
  603.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
  604.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
  605.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
  606.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
  607.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
  608.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
  609.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
  610.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
  611.       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
  612.       case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
  613.       case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
  614.          break;
  615.  
  616.       case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
  617.          feature_enables[i] = vmixer->sharpness.enabled;
  618.          break;
  619.  
  620.       case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
  621.          feature_enables[i] = vmixer->noise_reduction.enabled;
  622.          break;
  623.  
  624.       default:
  625.          return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
  626.       }
  627.    }
  628.  
  629.    return VDP_STATUS_OK;
  630. }
  631.  
  632. /**
  633.  * Set attribute values.
  634.  */
  635. VdpStatus
  636. vlVdpVideoMixerSetAttributeValues(VdpVideoMixer mixer,
  637.                                   uint32_t attribute_count,
  638.                                   VdpVideoMixerAttribute const *attributes,
  639.                                   void const *const *attribute_values)
  640. {
  641.    const VdpColor *background_color;
  642.    union pipe_color_union color;
  643.    const float *vdp_csc;
  644.    float val;
  645.    unsigned i;
  646.    VdpStatus ret;
  647.  
  648.    if (!(attributes && attribute_values))
  649.       return VDP_STATUS_INVALID_POINTER;
  650.  
  651.    vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
  652.    if (!vmixer)
  653.       return VDP_STATUS_INVALID_HANDLE;
  654.  
  655.    pipe_mutex_lock(vmixer->device->mutex);
  656.    for (i = 0; i < attribute_count; ++i) {
  657.       switch (attributes[i]) {
  658.       case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR:
  659.          background_color = attribute_values[i];
  660.          color.f[0] = background_color->red;
  661.          color.f[1] = background_color->green;
  662.          color.f[2] = background_color->blue;
  663.          color.f[3] = background_color->alpha;
  664.          vl_compositor_set_clear_color(&vmixer->cstate, &color);
  665.          break;
  666.       case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX:
  667.          vdp_csc = attribute_values[i];
  668.          vmixer->custom_csc = !!vdp_csc;
  669.          if (!vdp_csc)
  670.             vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, 1, &vmixer->csc);
  671.          else
  672.             memcpy(vmixer->csc, vdp_csc, sizeof(vl_csc_matrix));
  673.          if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))
  674.             vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc);
  675.          break;
  676.  
  677.       case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL:
  678.  
  679.          val = *(float*)attribute_values[i];
  680.          if (val < 0.f || val > 1.f) {
  681.             ret = VDP_STATUS_INVALID_VALUE;
  682.             goto fail;
  683.          }
  684.  
  685.          vmixer->noise_reduction.level = val * 10;
  686.          vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer);
  687.          break;
  688.  
  689.       case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA:
  690.          val = *(float*)attribute_values[i];
  691.          if (val < 0.f || val > 1.f) {
  692.             ret = VDP_STATUS_INVALID_VALUE;
  693.             goto fail;
  694.          }
  695.          vmixer->luma_key_min = val;
  696.          break;
  697.       case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA:
  698.          val = *(float*)attribute_values[i];
  699.          if (val < 0.f || val > 1.f) {
  700.             ret = VDP_STATUS_INVALID_VALUE;
  701.             goto fail;
  702.          }
  703.          vmixer->luma_key_max = val;
  704.          break;
  705.  
  706.       case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL:
  707.  
  708.          val = *(float*)attribute_values[i];
  709.          if (val < -1.f || val > 1.f) {
  710.             ret = VDP_STATUS_INVALID_VALUE;
  711.             goto fail;
  712.          }
  713.  
  714.          vmixer->sharpness.value = val;
  715.          vlVdpVideoMixerUpdateSharpnessFilter(vmixer);
  716.          break;
  717.  
  718.       case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE:
  719.          if (*(uint8_t*)attribute_values[i] > 1) {
  720.             ret = VDP_STATUS_INVALID_VALUE;
  721.             goto fail;
  722.          }
  723.          vmixer->skip_chroma_deint = *(uint8_t*)attribute_values[i];
  724.          vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer);
  725.          break;
  726.       default:
  727.          ret = VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE;
  728.          goto fail;
  729.       }
  730.    }
  731.    pipe_mutex_unlock(vmixer->device->mutex);
  732.  
  733.    return VDP_STATUS_OK;
  734. fail:
  735.    pipe_mutex_unlock(vmixer->device->mutex);
  736.    return ret;
  737. }
  738.  
  739. /**
  740.  * Retrieve parameter values given at creation time.
  741.  */
  742. VdpStatus
  743. vlVdpVideoMixerGetParameterValues(VdpVideoMixer mixer,
  744.                                   uint32_t parameter_count,
  745.                                   VdpVideoMixerParameter const *parameters,
  746.                                   void *const *parameter_values)
  747. {
  748.    vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
  749.    unsigned i;
  750.    if (!vmixer)
  751.       return VDP_STATUS_INVALID_HANDLE;
  752.  
  753.    if (!parameter_count)
  754.       return VDP_STATUS_OK;
  755.    if (!(parameters && parameter_values))
  756.       return VDP_STATUS_INVALID_POINTER;
  757.    for (i = 0; i < parameter_count; ++i) {
  758.       switch (parameters[i]) {
  759.       case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH:
  760.          *(uint32_t*)parameter_values[i] = vmixer->video_width;
  761.          break;
  762.       case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT:
  763.          *(uint32_t*)parameter_values[i] = vmixer->video_height;
  764.          break;
  765.       case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE:
  766.          *(VdpChromaType*)parameter_values[i] = PipeToChroma(vmixer->chroma_format);
  767.          break;
  768.       case VDP_VIDEO_MIXER_PARAMETER_LAYERS:
  769.          *(uint32_t*)parameter_values[i] = vmixer->max_layers;
  770.          break;
  771.       default:
  772.          return VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER;
  773.       }
  774.    }
  775.    return VDP_STATUS_OK;
  776. }
  777.  
  778. /**
  779.  * Retrieve current attribute values.
  780.  */
  781. VdpStatus
  782. vlVdpVideoMixerGetAttributeValues(VdpVideoMixer mixer,
  783.                                   uint32_t attribute_count,
  784.                                   VdpVideoMixerAttribute const *attributes,
  785.                                   void *const *attribute_values)
  786. {
  787.    unsigned i;
  788.    VdpCSCMatrix **vdp_csc;
  789.  
  790.    if (!(attributes && attribute_values))
  791.       return VDP_STATUS_INVALID_POINTER;
  792.  
  793.    vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
  794.    if (!vmixer)
  795.       return VDP_STATUS_INVALID_HANDLE;
  796.  
  797.    pipe_mutex_lock(vmixer->device->mutex);
  798.    for (i = 0; i < attribute_count; ++i) {
  799.       switch (attributes[i]) {
  800.       case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR:
  801.          vl_compositor_get_clear_color(&vmixer->cstate, attribute_values[i]);
  802.          break;
  803.       case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX:
  804.          vdp_csc = attribute_values[i];
  805.          if (!vmixer->custom_csc) {
  806.              *vdp_csc = NULL;
  807.             break;
  808.          }
  809.          memcpy(*vdp_csc, vmixer->csc, sizeof(float)*12);
  810.          break;
  811.  
  812.       case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL:
  813.          *(float*)attribute_values[i] = (float)vmixer->noise_reduction.level / 10.0f;
  814.          break;
  815.  
  816.       case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA:
  817.          *(float*)attribute_values[i] = vmixer->luma_key_min;
  818.          break;
  819.       case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA:
  820.          *(float*)attribute_values[i] = vmixer->luma_key_max;
  821.          break;
  822.       case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL:
  823.          *(float*)attribute_values[i] = vmixer->sharpness.value;
  824.          break;
  825.       case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE:
  826.          *(uint8_t*)attribute_values[i] = vmixer->skip_chroma_deint;
  827.          break;
  828.       default:
  829.          pipe_mutex_unlock(vmixer->device->mutex);
  830.          return VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE;
  831.       }
  832.    }
  833.    pipe_mutex_unlock(vmixer->device->mutex);
  834.    return VDP_STATUS_OK;
  835. }
  836.  
  837. /**
  838.  * Generate a color space conversion matrix.
  839.  */
  840. VdpStatus
  841. vlVdpGenerateCSCMatrix(VdpProcamp *procamp,
  842.                        VdpColorStandard standard,
  843.                        VdpCSCMatrix *csc_matrix)
  844. {
  845.    enum VL_CSC_COLOR_STANDARD vl_std;
  846.    struct vl_procamp camp;
  847.  
  848.    if (!csc_matrix)
  849.       return VDP_STATUS_INVALID_POINTER;
  850.  
  851.    switch (standard) {
  852.       case VDP_COLOR_STANDARD_ITUR_BT_601: vl_std = VL_CSC_COLOR_STANDARD_BT_601; break;
  853.       case VDP_COLOR_STANDARD_ITUR_BT_709: vl_std = VL_CSC_COLOR_STANDARD_BT_709; break;
  854.       case VDP_COLOR_STANDARD_SMPTE_240M:  vl_std = VL_CSC_COLOR_STANDARD_SMPTE_240M; break;
  855.       default: return VDP_STATUS_INVALID_COLOR_STANDARD;
  856.    }
  857.  
  858.    if (procamp) {
  859.       if (procamp->struct_version > VDP_PROCAMP_VERSION)
  860.          return VDP_STATUS_INVALID_STRUCT_VERSION;
  861.       camp.brightness = procamp->brightness;
  862.       camp.contrast = procamp->contrast;
  863.       camp.saturation = procamp->saturation;
  864.       camp.hue = procamp->hue;
  865.    }
  866.  
  867.    vl_csc_get_matrix(vl_std, procamp ? &camp : NULL, true, csc_matrix);
  868.    return VDP_STATUS_OK;
  869. }
  870.