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