1848b8605Smrg/************************************************************************** 2848b8605Smrg * 3848b8605Smrg * Copyright 2010 Thomas Balling Sørensen. 4848b8605Smrg * All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the 8848b8605Smrg * "Software"), to deal in the Software without restriction, including 9848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish, 10848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to 11848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to 12848b8605Smrg * the following conditions: 13848b8605Smrg * 14848b8605Smrg * The above copyright notice and this permission notice (including the 15848b8605Smrg * next paragraph) shall be included in all copies or substantial portions 16848b8605Smrg * of the Software. 17848b8605Smrg * 18848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21848b8605Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22848b8605Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23848b8605Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24848b8605Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25848b8605Smrg * 26848b8605Smrg **************************************************************************/ 27848b8605Smrg 28848b8605Smrg#include <vdpau/vdpau.h> 29848b8605Smrg 30848b8605Smrg#include "util/u_memory.h" 31848b8605Smrg#include "util/u_debug.h" 32848b8605Smrg 33848b8605Smrg#include "vl/vl_csc.h" 34848b8605Smrg 35848b8605Smrg#include "vdpau_private.h" 36848b8605Smrg 37848b8605Smrg/** 38848b8605Smrg * Create a VdpVideoMixer. 39848b8605Smrg */ 40848b8605SmrgVdpStatus 41848b8605SmrgvlVdpVideoMixerCreate(VdpDevice device, 42848b8605Smrg uint32_t feature_count, 43848b8605Smrg VdpVideoMixerFeature const *features, 44848b8605Smrg uint32_t parameter_count, 45848b8605Smrg VdpVideoMixerParameter const *parameters, 46848b8605Smrg void const *const *parameter_values, 47848b8605Smrg VdpVideoMixer *mixer) 48848b8605Smrg{ 49848b8605Smrg vlVdpVideoMixer *vmixer = NULL; 50848b8605Smrg VdpStatus ret; 51848b8605Smrg struct pipe_screen *screen; 52b8e80941Smrg uint32_t max_2d_texture_level; 53b8e80941Smrg unsigned max_size, i; 54848b8605Smrg 55848b8605Smrg vlVdpDevice *dev = vlGetDataHTAB(device); 56848b8605Smrg if (!dev) 57848b8605Smrg return VDP_STATUS_INVALID_HANDLE; 58848b8605Smrg screen = dev->vscreen->pscreen; 59848b8605Smrg 60848b8605Smrg vmixer = CALLOC(1, sizeof(vlVdpVideoMixer)); 61848b8605Smrg if (!vmixer) 62848b8605Smrg return VDP_STATUS_RESOURCES; 63848b8605Smrg 64848b8605Smrg DeviceReference(&vmixer->device, dev); 65848b8605Smrg 66b8e80941Smrg mtx_lock(&dev->mutex); 67848b8605Smrg 68b8e80941Smrg if (!vl_compositor_init_state(&vmixer->cstate, dev->context)) { 69b8e80941Smrg ret = VDP_STATUS_ERROR; 70b8e80941Smrg goto no_compositor_state; 71b8e80941Smrg } 72848b8605Smrg 73848b8605Smrg vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, true, &vmixer->csc); 74b8e80941Smrg if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) { 75b8e80941Smrg if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 1.0f, 0.0f)) { 76b8e80941Smrg ret = VDP_STATUS_ERROR; 77b8e80941Smrg goto err_csc_matrix; 78b8e80941Smrg } 79b8e80941Smrg } 80848b8605Smrg 81848b8605Smrg *mixer = vlAddDataHTAB(vmixer); 82848b8605Smrg if (*mixer == 0) { 83848b8605Smrg ret = VDP_STATUS_ERROR; 84848b8605Smrg goto no_handle; 85848b8605Smrg } 86848b8605Smrg 87848b8605Smrg ret = VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE; 88848b8605Smrg for (i = 0; i < feature_count; ++i) { 89848b8605Smrg switch (features[i]) { 90848b8605Smrg /* they are valid, but we doesn't support them */ 91848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL: 92848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2: 93848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3: 94848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4: 95848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5: 96848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6: 97848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7: 98848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8: 99848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9: 100848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE: 101848b8605Smrg break; 102848b8605Smrg 103848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL: 104848b8605Smrg vmixer->deint.supported = true; 105848b8605Smrg break; 106848b8605Smrg 107848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_SHARPNESS: 108848b8605Smrg vmixer->sharpness.supported = true; 109848b8605Smrg break; 110848b8605Smrg 111848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION: 112848b8605Smrg vmixer->noise_reduction.supported = true; 113848b8605Smrg break; 114848b8605Smrg 115b8e80941Smrg case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY: 116b8e80941Smrg vmixer->luma_key.supported = true; 117b8e80941Smrg break; 118b8e80941Smrg 119b8e80941Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1: 120b8e80941Smrg vmixer->bicubic.supported = true; 121b8e80941Smrg break; 122848b8605Smrg default: goto no_params; 123848b8605Smrg } 124848b8605Smrg } 125848b8605Smrg 126848b8605Smrg vmixer->chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420; 127848b8605Smrg ret = VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER; 128848b8605Smrg for (i = 0; i < parameter_count; ++i) { 129848b8605Smrg switch (parameters[i]) { 130848b8605Smrg case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH: 131848b8605Smrg vmixer->video_width = *(uint32_t*)parameter_values[i]; 132848b8605Smrg break; 133848b8605Smrg case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT: 134848b8605Smrg vmixer->video_height = *(uint32_t*)parameter_values[i]; 135848b8605Smrg break; 136848b8605Smrg case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE: 137848b8605Smrg vmixer->chroma_format = ChromaToPipe(*(VdpChromaType*)parameter_values[i]); 138848b8605Smrg break; 139848b8605Smrg case VDP_VIDEO_MIXER_PARAMETER_LAYERS: 140848b8605Smrg vmixer->max_layers = *(uint32_t*)parameter_values[i]; 141848b8605Smrg break; 142848b8605Smrg default: goto no_params; 143848b8605Smrg } 144848b8605Smrg } 145848b8605Smrg ret = VDP_STATUS_INVALID_VALUE; 146848b8605Smrg if (vmixer->max_layers > 4) { 147848b8605Smrg VDPAU_MSG(VDPAU_WARN, "[VDPAU] Max layers > 4 not supported\n", vmixer->max_layers); 148848b8605Smrg goto no_params; 149848b8605Smrg } 150b8e80941Smrg 151b8e80941Smrg max_2d_texture_level = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS); 152b8e80941Smrg max_size = pow(2, max_2d_texture_level-1); 153b8e80941Smrg if (vmixer->video_width < 48 || vmixer->video_width > max_size) { 154b8e80941Smrg VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u not valid for width\n", 155b8e80941Smrg vmixer->video_width, max_size); 156848b8605Smrg goto no_params; 157848b8605Smrg } 158b8e80941Smrg if (vmixer->video_height < 48 || vmixer->video_height > max_size) { 159b8e80941Smrg VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u not valid for height\n", 160b8e80941Smrg vmixer->video_height, max_size); 161848b8605Smrg goto no_params; 162848b8605Smrg } 163b8e80941Smrg vmixer->luma_key.luma_min = 1.0f; 164b8e80941Smrg vmixer->luma_key.luma_max = 0.0f; 165b8e80941Smrg mtx_unlock(&dev->mutex); 166848b8605Smrg 167848b8605Smrg return VDP_STATUS_OK; 168848b8605Smrg 169848b8605Smrgno_params: 170848b8605Smrg vlRemoveDataHTAB(*mixer); 171848b8605Smrg 172848b8605Smrgno_handle: 173b8e80941Smrgerr_csc_matrix: 174848b8605Smrg vl_compositor_cleanup_state(&vmixer->cstate); 175b8e80941Smrgno_compositor_state: 176b8e80941Smrg mtx_unlock(&dev->mutex); 177848b8605Smrg DeviceReference(&vmixer->device, NULL); 178848b8605Smrg FREE(vmixer); 179848b8605Smrg return ret; 180848b8605Smrg} 181848b8605Smrg 182848b8605Smrg/** 183848b8605Smrg * Destroy a VdpVideoMixer. 184848b8605Smrg */ 185848b8605SmrgVdpStatus 186848b8605SmrgvlVdpVideoMixerDestroy(VdpVideoMixer mixer) 187848b8605Smrg{ 188848b8605Smrg vlVdpVideoMixer *vmixer; 189848b8605Smrg 190848b8605Smrg vmixer = vlGetDataHTAB(mixer); 191848b8605Smrg if (!vmixer) 192848b8605Smrg return VDP_STATUS_INVALID_HANDLE; 193848b8605Smrg 194b8e80941Smrg mtx_lock(&vmixer->device->mutex); 195848b8605Smrg 196848b8605Smrg vlRemoveDataHTAB(mixer); 197848b8605Smrg 198848b8605Smrg vl_compositor_cleanup_state(&vmixer->cstate); 199848b8605Smrg 200848b8605Smrg if (vmixer->deint.filter) { 201848b8605Smrg vl_deint_filter_cleanup(vmixer->deint.filter); 202848b8605Smrg FREE(vmixer->deint.filter); 203848b8605Smrg } 204848b8605Smrg 205848b8605Smrg if (vmixer->noise_reduction.filter) { 206848b8605Smrg vl_median_filter_cleanup(vmixer->noise_reduction.filter); 207848b8605Smrg FREE(vmixer->noise_reduction.filter); 208848b8605Smrg } 209848b8605Smrg 210848b8605Smrg if (vmixer->sharpness.filter) { 211848b8605Smrg vl_matrix_filter_cleanup(vmixer->sharpness.filter); 212848b8605Smrg FREE(vmixer->sharpness.filter); 213848b8605Smrg } 214b8e80941Smrg 215b8e80941Smrg if (vmixer->bicubic.filter) { 216b8e80941Smrg vl_bicubic_filter_cleanup(vmixer->bicubic.filter); 217b8e80941Smrg FREE(vmixer->bicubic.filter); 218b8e80941Smrg } 219b8e80941Smrg mtx_unlock(&vmixer->device->mutex); 220848b8605Smrg DeviceReference(&vmixer->device, NULL); 221848b8605Smrg 222848b8605Smrg FREE(vmixer); 223848b8605Smrg 224848b8605Smrg return VDP_STATUS_OK; 225848b8605Smrg} 226848b8605Smrg 227848b8605Smrg/** 228848b8605Smrg * Perform a video post-processing and compositing operation. 229848b8605Smrg */ 230848b8605SmrgVdpStatus vlVdpVideoMixerRender(VdpVideoMixer mixer, 231848b8605Smrg VdpOutputSurface background_surface, 232848b8605Smrg VdpRect const *background_source_rect, 233848b8605Smrg VdpVideoMixerPictureStructure current_picture_structure, 234848b8605Smrg uint32_t video_surface_past_count, 235848b8605Smrg VdpVideoSurface const *video_surface_past, 236848b8605Smrg VdpVideoSurface video_surface_current, 237848b8605Smrg uint32_t video_surface_future_count, 238848b8605Smrg VdpVideoSurface const *video_surface_future, 239848b8605Smrg VdpRect const *video_source_rect, 240848b8605Smrg VdpOutputSurface destination_surface, 241848b8605Smrg VdpRect const *destination_rect, 242848b8605Smrg VdpRect const *destination_video_rect, 243848b8605Smrg uint32_t layer_count, 244848b8605Smrg VdpLayer const *layers) 245848b8605Smrg{ 246848b8605Smrg enum vl_compositor_deinterlace deinterlace; 247b8e80941Smrg struct u_rect rect, clip, *prect, dirty_area; 248848b8605Smrg unsigned i, layer = 0; 249848b8605Smrg struct pipe_video_buffer *video_buffer; 250b8e80941Smrg struct pipe_sampler_view *sampler_view, sv_templ; 251b8e80941Smrg struct pipe_surface *surface, surf_templ; 252b8e80941Smrg struct pipe_context *pipe = NULL; 253b8e80941Smrg struct pipe_resource res_tmpl, *res; 254848b8605Smrg 255848b8605Smrg vlVdpVideoMixer *vmixer; 256848b8605Smrg vlVdpSurface *surf; 257848b8605Smrg vlVdpOutputSurface *dst, *bg = NULL; 258848b8605Smrg 259848b8605Smrg struct vl_compositor *compositor; 260848b8605Smrg 261848b8605Smrg vmixer = vlGetDataHTAB(mixer); 262848b8605Smrg if (!vmixer) 263848b8605Smrg return VDP_STATUS_INVALID_HANDLE; 264848b8605Smrg 265848b8605Smrg compositor = &vmixer->device->compositor; 266848b8605Smrg 267848b8605Smrg surf = vlGetDataHTAB(video_surface_current); 268848b8605Smrg if (!surf) 269848b8605Smrg return VDP_STATUS_INVALID_HANDLE; 270848b8605Smrg video_buffer = surf->video_buffer; 271848b8605Smrg 272848b8605Smrg if (surf->device != vmixer->device) 273848b8605Smrg return VDP_STATUS_HANDLE_DEVICE_MISMATCH; 274848b8605Smrg 275848b8605Smrg if (vmixer->video_width > video_buffer->width || 276848b8605Smrg vmixer->video_height > video_buffer->height || 277848b8605Smrg vmixer->chroma_format != video_buffer->chroma_format) 278848b8605Smrg return VDP_STATUS_INVALID_SIZE; 279848b8605Smrg 280848b8605Smrg if (layer_count > vmixer->max_layers) 281848b8605Smrg return VDP_STATUS_INVALID_VALUE; 282848b8605Smrg 283848b8605Smrg dst = vlGetDataHTAB(destination_surface); 284848b8605Smrg if (!dst) 285848b8605Smrg return VDP_STATUS_INVALID_HANDLE; 286848b8605Smrg 287848b8605Smrg if (background_surface != VDP_INVALID_HANDLE) { 288848b8605Smrg bg = vlGetDataHTAB(background_surface); 289848b8605Smrg if (!bg) 290848b8605Smrg return VDP_STATUS_INVALID_HANDLE; 291848b8605Smrg } 292848b8605Smrg 293b8e80941Smrg mtx_lock(&vmixer->device->mutex); 294848b8605Smrg 295848b8605Smrg vl_compositor_clear_layers(&vmixer->cstate); 296848b8605Smrg 297848b8605Smrg if (bg) 298848b8605Smrg vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer++, bg->sampler_view, 299848b8605Smrg RectToPipe(background_source_rect, &rect), NULL, NULL); 300848b8605Smrg 301848b8605Smrg switch (current_picture_structure) { 302848b8605Smrg case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD: 303848b8605Smrg deinterlace = VL_COMPOSITOR_BOB_TOP; 304848b8605Smrg break; 305848b8605Smrg 306848b8605Smrg case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD: 307848b8605Smrg deinterlace = VL_COMPOSITOR_BOB_BOTTOM; 308848b8605Smrg break; 309848b8605Smrg 310848b8605Smrg case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME: 311848b8605Smrg deinterlace = VL_COMPOSITOR_WEAVE; 312848b8605Smrg break; 313848b8605Smrg 314848b8605Smrg default: 315b8e80941Smrg mtx_unlock(&vmixer->device->mutex); 316848b8605Smrg return VDP_STATUS_INVALID_VIDEO_MIXER_PICTURE_STRUCTURE; 317b8e80941Smrg } 318848b8605Smrg 319848b8605Smrg if (deinterlace != VL_COMPOSITOR_WEAVE && vmixer->deint.enabled && 320848b8605Smrg video_surface_past_count > 1 && video_surface_future_count > 0) { 321848b8605Smrg vlVdpSurface *prevprev = vlGetDataHTAB(video_surface_past[1]); 322848b8605Smrg vlVdpSurface *prev = vlGetDataHTAB(video_surface_past[0]); 323848b8605Smrg vlVdpSurface *next = vlGetDataHTAB(video_surface_future[0]); 324848b8605Smrg if (prevprev && prev && next && 325848b8605Smrg vl_deint_filter_check_buffers(vmixer->deint.filter, 326848b8605Smrg prevprev->video_buffer, prev->video_buffer, surf->video_buffer, next->video_buffer)) { 327848b8605Smrg vl_deint_filter_render(vmixer->deint.filter, prevprev->video_buffer, 328848b8605Smrg prev->video_buffer, surf->video_buffer, 329848b8605Smrg next->video_buffer, 330848b8605Smrg deinterlace == VL_COMPOSITOR_BOB_BOTTOM); 331848b8605Smrg deinterlace = VL_COMPOSITOR_WEAVE; 332848b8605Smrg video_buffer = vmixer->deint.filter->video_buffer; 333848b8605Smrg } 334848b8605Smrg } 335848b8605Smrg 336848b8605Smrg prect = RectToPipe(video_source_rect, &rect); 337848b8605Smrg if (!prect) { 338848b8605Smrg rect.x0 = 0; 339848b8605Smrg rect.y0 = 0; 340848b8605Smrg rect.x1 = surf->templat.width; 341848b8605Smrg rect.y1 = surf->templat.height; 342848b8605Smrg prect = ▭ 343848b8605Smrg } 344848b8605Smrg vl_compositor_set_buffer_layer(&vmixer->cstate, compositor, layer, video_buffer, prect, NULL, deinterlace); 345b8e80941Smrg 346b8e80941Smrg if (vmixer->bicubic.filter || vmixer->sharpness.filter || vmixer->noise_reduction.filter) { 347b8e80941Smrg pipe = vmixer->device->context; 348b8e80941Smrg memset(&res_tmpl, 0, sizeof(res_tmpl)); 349b8e80941Smrg 350b8e80941Smrg res_tmpl.target = PIPE_TEXTURE_2D; 351b8e80941Smrg res_tmpl.format = dst->sampler_view->format; 352b8e80941Smrg res_tmpl.depth0 = 1; 353b8e80941Smrg res_tmpl.array_size = 1; 354b8e80941Smrg res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; 355b8e80941Smrg res_tmpl.usage = PIPE_USAGE_DEFAULT; 356b8e80941Smrg 357b8e80941Smrg if (!vmixer->bicubic.filter) { 358b8e80941Smrg res_tmpl.width0 = dst->surface->width; 359b8e80941Smrg res_tmpl.height0 = dst->surface->height; 360b8e80941Smrg } else { 361b8e80941Smrg res_tmpl.width0 = surf->templat.width; 362b8e80941Smrg res_tmpl.height0 = surf->templat.height; 363b8e80941Smrg } 364b8e80941Smrg 365b8e80941Smrg res = pipe->screen->resource_create(pipe->screen, &res_tmpl); 366b8e80941Smrg 367b8e80941Smrg vlVdpDefaultSamplerViewTemplate(&sv_templ, res); 368b8e80941Smrg sampler_view = pipe->create_sampler_view(pipe, res, &sv_templ); 369b8e80941Smrg 370b8e80941Smrg memset(&surf_templ, 0, sizeof(surf_templ)); 371b8e80941Smrg surf_templ.format = res->format; 372b8e80941Smrg surface = pipe->create_surface(pipe, res, &surf_templ); 373b8e80941Smrg 374b8e80941Smrg vl_compositor_reset_dirty_area(&dirty_area); 375b8e80941Smrg pipe_resource_reference(&res, NULL); 376b8e80941Smrg } else { 377b8e80941Smrg surface = dst->surface; 378b8e80941Smrg sampler_view = dst->sampler_view; 379b8e80941Smrg dirty_area = dst->dirty_area; 380b8e80941Smrg } 381b8e80941Smrg 382b8e80941Smrg if (!vmixer->bicubic.filter) { 383b8e80941Smrg vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(destination_video_rect, &rect)); 384b8e80941Smrg vl_compositor_set_dst_clip(&vmixer->cstate, RectToPipe(destination_rect, &clip)); 385b8e80941Smrg } 386848b8605Smrg 387848b8605Smrg for (i = 0; i < layer_count; ++i) { 388848b8605Smrg vlVdpOutputSurface *src = vlGetDataHTAB(layers->source_surface); 389848b8605Smrg if (!src) { 390b8e80941Smrg mtx_unlock(&vmixer->device->mutex); 391848b8605Smrg return VDP_STATUS_INVALID_HANDLE; 392848b8605Smrg } 393848b8605Smrg 394848b8605Smrg assert(layers->struct_version == VDP_LAYER_VERSION); 395848b8605Smrg 396848b8605Smrg vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer, src->sampler_view, 397848b8605Smrg RectToPipe(layers->source_rect, &rect), NULL, NULL); 398848b8605Smrg vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(layers->destination_rect, &rect)); 399848b8605Smrg 400848b8605Smrg ++layers; 401848b8605Smrg } 402848b8605Smrg 403b8e80941Smrg vl_compositor_render(&vmixer->cstate, compositor, surface, &dirty_area, true); 404b8e80941Smrg 405b8e80941Smrg if (vmixer->noise_reduction.filter) { 406b8e80941Smrg if (!vmixer->sharpness.filter && !vmixer->bicubic.filter) { 407b8e80941Smrg vl_median_filter_render(vmixer->noise_reduction.filter, 408b8e80941Smrg sampler_view, dst->surface); 409b8e80941Smrg } else { 410b8e80941Smrg res = pipe->screen->resource_create(pipe->screen, &res_tmpl); 411b8e80941Smrg struct pipe_sampler_view *sampler_view_temp = pipe->create_sampler_view(pipe, res, &sv_templ); 412b8e80941Smrg struct pipe_surface *surface_temp = pipe->create_surface(pipe, res, &surf_templ); 413b8e80941Smrg pipe_resource_reference(&res, NULL); 414848b8605Smrg 415848b8605Smrg vl_median_filter_render(vmixer->noise_reduction.filter, 416b8e80941Smrg sampler_view, surface_temp); 417b8e80941Smrg 418b8e80941Smrg pipe_sampler_view_reference(&sampler_view, NULL); 419b8e80941Smrg pipe_surface_reference(&surface, NULL); 420b8e80941Smrg 421b8e80941Smrg sampler_view = sampler_view_temp; 422b8e80941Smrg surface = surface_temp; 423b8e80941Smrg } 424b8e80941Smrg } 425b8e80941Smrg 426b8e80941Smrg if (vmixer->sharpness.filter) { 427b8e80941Smrg if (!vmixer->bicubic.filter) { 428b8e80941Smrg vl_matrix_filter_render(vmixer->sharpness.filter, 429b8e80941Smrg sampler_view, dst->surface); 430b8e80941Smrg } else { 431b8e80941Smrg res = pipe->screen->resource_create(pipe->screen, &res_tmpl); 432b8e80941Smrg struct pipe_sampler_view *sampler_view_temp = pipe->create_sampler_view(pipe, res, &sv_templ); 433b8e80941Smrg struct pipe_surface *surface_temp = pipe->create_surface(pipe, res, &surf_templ); 434b8e80941Smrg pipe_resource_reference(&res, NULL); 435848b8605Smrg 436848b8605Smrg vl_matrix_filter_render(vmixer->sharpness.filter, 437b8e80941Smrg sampler_view, surface_temp); 438b8e80941Smrg 439b8e80941Smrg pipe_sampler_view_reference(&sampler_view, NULL); 440b8e80941Smrg pipe_surface_reference(&surface, NULL); 441b8e80941Smrg 442b8e80941Smrg sampler_view = sampler_view_temp; 443b8e80941Smrg surface = surface_temp; 444b8e80941Smrg } 445848b8605Smrg } 446b8e80941Smrg 447b8e80941Smrg if (vmixer->bicubic.filter) 448b8e80941Smrg vl_bicubic_filter_render(vmixer->bicubic.filter, 449b8e80941Smrg sampler_view, dst->surface, 450b8e80941Smrg RectToPipe(destination_video_rect, &rect), 451b8e80941Smrg RectToPipe(destination_rect, &clip)); 452b8e80941Smrg 453b8e80941Smrg if(surface != dst->surface) { 454b8e80941Smrg pipe_sampler_view_reference(&sampler_view, NULL); 455b8e80941Smrg pipe_surface_reference(&surface, NULL); 456b8e80941Smrg } 457b8e80941Smrg mtx_unlock(&vmixer->device->mutex); 458848b8605Smrg 459848b8605Smrg return VDP_STATUS_OK; 460848b8605Smrg} 461848b8605Smrg 462848b8605Smrgstatic void 463848b8605SmrgvlVdpVideoMixerUpdateDeinterlaceFilter(vlVdpVideoMixer *vmixer) 464848b8605Smrg{ 465848b8605Smrg struct pipe_context *pipe = vmixer->device->context; 466848b8605Smrg assert(vmixer); 467848b8605Smrg 468848b8605Smrg /* remove existing filter */ 469848b8605Smrg if (vmixer->deint.filter) { 470848b8605Smrg vl_deint_filter_cleanup(vmixer->deint.filter); 471848b8605Smrg FREE(vmixer->deint.filter); 472848b8605Smrg vmixer->deint.filter = NULL; 473848b8605Smrg } 474848b8605Smrg 475848b8605Smrg /* create a new filter if requested */ 476848b8605Smrg if (vmixer->deint.enabled && vmixer->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) { 477848b8605Smrg vmixer->deint.filter = MALLOC(sizeof(struct vl_deint_filter)); 478848b8605Smrg vmixer->deint.enabled = vl_deint_filter_init(vmixer->deint.filter, pipe, 479848b8605Smrg vmixer->video_width, vmixer->video_height, 480848b8605Smrg vmixer->skip_chroma_deint, vmixer->deint.spatial); 481848b8605Smrg if (!vmixer->deint.enabled) { 482848b8605Smrg FREE(vmixer->deint.filter); 483848b8605Smrg } 484848b8605Smrg } 485848b8605Smrg} 486848b8605Smrg 487848b8605Smrg/** 488848b8605Smrg * Update the noise reduction setting 489848b8605Smrg */ 490848b8605Smrgstatic void 491848b8605SmrgvlVdpVideoMixerUpdateNoiseReductionFilter(vlVdpVideoMixer *vmixer) 492848b8605Smrg{ 493848b8605Smrg assert(vmixer); 494848b8605Smrg 495848b8605Smrg /* if present remove the old filter first */ 496848b8605Smrg if (vmixer->noise_reduction.filter) { 497848b8605Smrg vl_median_filter_cleanup(vmixer->noise_reduction.filter); 498848b8605Smrg FREE(vmixer->noise_reduction.filter); 499848b8605Smrg vmixer->noise_reduction.filter = NULL; 500848b8605Smrg } 501848b8605Smrg 502848b8605Smrg /* and create a new filter as needed */ 503848b8605Smrg if (vmixer->noise_reduction. enabled && vmixer->noise_reduction.level > 0) { 504848b8605Smrg vmixer->noise_reduction.filter = MALLOC(sizeof(struct vl_median_filter)); 505848b8605Smrg vl_median_filter_init(vmixer->noise_reduction.filter, vmixer->device->context, 506848b8605Smrg vmixer->video_width, vmixer->video_height, 507848b8605Smrg vmixer->noise_reduction.level + 1, 508848b8605Smrg VL_MEDIAN_FILTER_CROSS); 509848b8605Smrg } 510848b8605Smrg} 511848b8605Smrg 512848b8605Smrgstatic void 513848b8605SmrgvlVdpVideoMixerUpdateSharpnessFilter(vlVdpVideoMixer *vmixer) 514848b8605Smrg{ 515848b8605Smrg assert(vmixer); 516848b8605Smrg 517848b8605Smrg /* if present remove the old filter first */ 518848b8605Smrg if (vmixer->sharpness.filter) { 519848b8605Smrg vl_matrix_filter_cleanup(vmixer->sharpness.filter); 520848b8605Smrg FREE(vmixer->sharpness.filter); 521848b8605Smrg vmixer->sharpness.filter = NULL; 522848b8605Smrg } 523848b8605Smrg 524848b8605Smrg /* and create a new filter as needed */ 525848b8605Smrg if (vmixer->sharpness.enabled && vmixer->sharpness.value != 0.0f) { 526848b8605Smrg float matrix[9]; 527848b8605Smrg unsigned i; 528848b8605Smrg 529848b8605Smrg if (vmixer->sharpness.value > 0.0f) { 530848b8605Smrg matrix[0] = -1.0f; matrix[1] = -1.0f; matrix[2] = -1.0f; 531848b8605Smrg matrix[3] = -1.0f; matrix[4] = 8.0f; matrix[5] = -1.0f; 532848b8605Smrg matrix[6] = -1.0f; matrix[7] = -1.0f; matrix[8] = -1.0f; 533848b8605Smrg 534848b8605Smrg for (i = 0; i < 9; ++i) 535848b8605Smrg matrix[i] *= vmixer->sharpness.value; 536848b8605Smrg 537848b8605Smrg matrix[4] += 1.0f; 538848b8605Smrg 539848b8605Smrg } else { 540848b8605Smrg matrix[0] = 1.0f; matrix[1] = 2.0f; matrix[2] = 1.0f; 541848b8605Smrg matrix[3] = 2.0f; matrix[4] = 4.0f; matrix[5] = 2.0f; 542848b8605Smrg matrix[6] = 1.0f; matrix[7] = 2.0f; matrix[8] = 1.0f; 543848b8605Smrg 544848b8605Smrg for (i = 0; i < 9; ++i) 545848b8605Smrg matrix[i] *= fabsf(vmixer->sharpness.value) / 16.0f; 546848b8605Smrg 547848b8605Smrg matrix[4] += 1.0f - fabsf(vmixer->sharpness.value); 548848b8605Smrg } 549848b8605Smrg 550848b8605Smrg vmixer->sharpness.filter = MALLOC(sizeof(struct vl_matrix_filter)); 551848b8605Smrg vl_matrix_filter_init(vmixer->sharpness.filter, vmixer->device->context, 552848b8605Smrg vmixer->video_width, vmixer->video_height, 553848b8605Smrg 3, 3, matrix); 554848b8605Smrg } 555848b8605Smrg} 556848b8605Smrg 557b8e80941Smrg/** 558b8e80941Smrg * Update the bicubic filter 559b8e80941Smrg */ 560b8e80941Smrgstatic void 561b8e80941SmrgvlVdpVideoMixerUpdateBicubicFilter(vlVdpVideoMixer *vmixer) 562b8e80941Smrg{ 563b8e80941Smrg assert(vmixer); 564b8e80941Smrg 565b8e80941Smrg /* if present remove the old filter first */ 566b8e80941Smrg if (vmixer->bicubic.filter) { 567b8e80941Smrg vl_bicubic_filter_cleanup(vmixer->bicubic.filter); 568b8e80941Smrg FREE(vmixer->bicubic.filter); 569b8e80941Smrg vmixer->bicubic.filter = NULL; 570b8e80941Smrg } 571b8e80941Smrg /* and create a new filter as needed */ 572b8e80941Smrg if (vmixer->bicubic.enabled) { 573b8e80941Smrg vmixer->bicubic.filter = MALLOC(sizeof(struct vl_bicubic_filter)); 574b8e80941Smrg vl_bicubic_filter_init(vmixer->bicubic.filter, vmixer->device->context, 575b8e80941Smrg vmixer->video_width, vmixer->video_height); 576b8e80941Smrg } 577b8e80941Smrg} 578b8e80941Smrg 579848b8605Smrg/** 580848b8605Smrg * Retrieve whether features were requested at creation time. 581848b8605Smrg */ 582848b8605SmrgVdpStatus 583848b8605SmrgvlVdpVideoMixerGetFeatureSupport(VdpVideoMixer mixer, 584848b8605Smrg uint32_t feature_count, 585848b8605Smrg VdpVideoMixerFeature const *features, 586848b8605Smrg VdpBool *feature_supports) 587848b8605Smrg{ 588848b8605Smrg vlVdpVideoMixer *vmixer; 589848b8605Smrg unsigned i; 590848b8605Smrg 591848b8605Smrg if (!(features && feature_supports)) 592848b8605Smrg return VDP_STATUS_INVALID_POINTER; 593848b8605Smrg 594848b8605Smrg vmixer = vlGetDataHTAB(mixer); 595848b8605Smrg if (!vmixer) 596848b8605Smrg return VDP_STATUS_INVALID_HANDLE; 597848b8605Smrg 598848b8605Smrg for (i = 0; i < feature_count; ++i) { 599848b8605Smrg switch (features[i]) { 600848b8605Smrg /* they are valid, but we doesn't support them */ 601848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL: 602848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2: 603848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3: 604848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4: 605848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5: 606848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6: 607848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7: 608848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8: 609848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9: 610848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE: 611848b8605Smrg feature_supports[i] = false; 612848b8605Smrg break; 613848b8605Smrg 614848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL: 615848b8605Smrg feature_supports[i] = vmixer->deint.supported; 616848b8605Smrg break; 617848b8605Smrg 618848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_SHARPNESS: 619848b8605Smrg feature_supports[i] = vmixer->sharpness.supported; 620848b8605Smrg break; 621848b8605Smrg 622848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION: 623848b8605Smrg feature_supports[i] = vmixer->noise_reduction.supported; 624848b8605Smrg break; 625848b8605Smrg 626b8e80941Smrg case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY: 627b8e80941Smrg feature_supports[i] = vmixer->luma_key.supported; 628b8e80941Smrg break; 629b8e80941Smrg 630b8e80941Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1: 631b8e80941Smrg feature_supports[i] = vmixer->bicubic.supported; 632b8e80941Smrg break; 633b8e80941Smrg 634848b8605Smrg default: 635848b8605Smrg return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE; 636848b8605Smrg } 637848b8605Smrg } 638848b8605Smrg 639848b8605Smrg return VDP_STATUS_OK; 640848b8605Smrg} 641848b8605Smrg 642848b8605Smrg/** 643848b8605Smrg * Enable or disable features. 644848b8605Smrg */ 645848b8605SmrgVdpStatus 646848b8605SmrgvlVdpVideoMixerSetFeatureEnables(VdpVideoMixer mixer, 647848b8605Smrg uint32_t feature_count, 648848b8605Smrg VdpVideoMixerFeature const *features, 649848b8605Smrg VdpBool const *feature_enables) 650848b8605Smrg{ 651848b8605Smrg vlVdpVideoMixer *vmixer; 652848b8605Smrg unsigned i; 653848b8605Smrg 654848b8605Smrg if (!(features && feature_enables)) 655848b8605Smrg return VDP_STATUS_INVALID_POINTER; 656848b8605Smrg 657848b8605Smrg vmixer = vlGetDataHTAB(mixer); 658848b8605Smrg if (!vmixer) 659848b8605Smrg return VDP_STATUS_INVALID_HANDLE; 660848b8605Smrg 661b8e80941Smrg mtx_lock(&vmixer->device->mutex); 662848b8605Smrg for (i = 0; i < feature_count; ++i) { 663848b8605Smrg switch (features[i]) { 664848b8605Smrg /* they are valid, but we doesn't support them */ 665848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL: 666848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2: 667848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3: 668848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4: 669848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5: 670848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6: 671848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7: 672848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8: 673848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9: 674848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE: 675848b8605Smrg break; 676848b8605Smrg 677848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL: 678848b8605Smrg vmixer->deint.enabled = feature_enables[i]; 679848b8605Smrg vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer); 680848b8605Smrg break; 681848b8605Smrg 682848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_SHARPNESS: 683848b8605Smrg vmixer->sharpness.enabled = feature_enables[i]; 684848b8605Smrg vlVdpVideoMixerUpdateSharpnessFilter(vmixer); 685848b8605Smrg break; 686848b8605Smrg 687848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION: 688848b8605Smrg vmixer->noise_reduction.enabled = feature_enables[i]; 689848b8605Smrg vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer); 690848b8605Smrg break; 691848b8605Smrg 692b8e80941Smrg case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY: 693b8e80941Smrg vmixer->luma_key.enabled = feature_enables[i]; 694b8e80941Smrg if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) 695b8e80941Smrg if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 696b8e80941Smrg vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) { 697b8e80941Smrg mtx_unlock(&vmixer->device->mutex); 698b8e80941Smrg return VDP_STATUS_ERROR; 699b8e80941Smrg } 700b8e80941Smrg break; 701b8e80941Smrg 702b8e80941Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1: 703b8e80941Smrg vmixer->bicubic.enabled = feature_enables[i]; 704b8e80941Smrg vlVdpVideoMixerUpdateBicubicFilter(vmixer); 705b8e80941Smrg break; 706b8e80941Smrg 707848b8605Smrg default: 708b8e80941Smrg mtx_unlock(&vmixer->device->mutex); 709848b8605Smrg return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE; 710848b8605Smrg } 711848b8605Smrg } 712b8e80941Smrg mtx_unlock(&vmixer->device->mutex); 713848b8605Smrg 714848b8605Smrg return VDP_STATUS_OK; 715848b8605Smrg} 716848b8605Smrg 717848b8605Smrg/** 718848b8605Smrg * Retrieve whether features are enabled. 719848b8605Smrg */ 720848b8605SmrgVdpStatus 721848b8605SmrgvlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer, 722848b8605Smrg uint32_t feature_count, 723848b8605Smrg VdpVideoMixerFeature const *features, 724848b8605Smrg VdpBool *feature_enables) 725848b8605Smrg{ 726848b8605Smrg vlVdpVideoMixer *vmixer; 727848b8605Smrg unsigned i; 728848b8605Smrg 729848b8605Smrg if (!(features && feature_enables)) 730848b8605Smrg return VDP_STATUS_INVALID_POINTER; 731848b8605Smrg 732848b8605Smrg vmixer = vlGetDataHTAB(mixer); 733848b8605Smrg if (!vmixer) 734848b8605Smrg return VDP_STATUS_INVALID_HANDLE; 735848b8605Smrg 736848b8605Smrg for (i = 0; i < feature_count; ++i) { 737848b8605Smrg switch (features[i]) { 738848b8605Smrg /* they are valid, but we doesn't support them */ 739848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL: 740848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL: 741848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2: 742848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3: 743848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4: 744848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5: 745848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6: 746848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7: 747848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8: 748848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9: 749848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE: 750848b8605Smrg break; 751848b8605Smrg 752848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_SHARPNESS: 753848b8605Smrg feature_enables[i] = vmixer->sharpness.enabled; 754848b8605Smrg break; 755848b8605Smrg 756848b8605Smrg case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION: 757848b8605Smrg feature_enables[i] = vmixer->noise_reduction.enabled; 758848b8605Smrg break; 759848b8605Smrg 760b8e80941Smrg case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY: 761b8e80941Smrg feature_enables[i] = vmixer->luma_key.enabled; 762b8e80941Smrg break; 763b8e80941Smrg 764b8e80941Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1: 765b8e80941Smrg feature_enables[i] = vmixer->bicubic.enabled; 766b8e80941Smrg break; 767b8e80941Smrg 768848b8605Smrg default: 769848b8605Smrg return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE; 770848b8605Smrg } 771848b8605Smrg } 772848b8605Smrg 773848b8605Smrg return VDP_STATUS_OK; 774848b8605Smrg} 775848b8605Smrg 776848b8605Smrg/** 777848b8605Smrg * Set attribute values. 778848b8605Smrg */ 779848b8605SmrgVdpStatus 780848b8605SmrgvlVdpVideoMixerSetAttributeValues(VdpVideoMixer mixer, 781848b8605Smrg uint32_t attribute_count, 782848b8605Smrg VdpVideoMixerAttribute const *attributes, 783848b8605Smrg void const *const *attribute_values) 784848b8605Smrg{ 785848b8605Smrg const VdpColor *background_color; 786848b8605Smrg union pipe_color_union color; 787848b8605Smrg const float *vdp_csc; 788848b8605Smrg float val; 789848b8605Smrg unsigned i; 790b8e80941Smrg VdpStatus ret; 791848b8605Smrg 792848b8605Smrg if (!(attributes && attribute_values)) 793848b8605Smrg return VDP_STATUS_INVALID_POINTER; 794848b8605Smrg 795848b8605Smrg vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer); 796848b8605Smrg if (!vmixer) 797848b8605Smrg return VDP_STATUS_INVALID_HANDLE; 798848b8605Smrg 799b8e80941Smrg mtx_lock(&vmixer->device->mutex); 800848b8605Smrg for (i = 0; i < attribute_count; ++i) { 801848b8605Smrg switch (attributes[i]) { 802848b8605Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR: 803848b8605Smrg background_color = attribute_values[i]; 804848b8605Smrg color.f[0] = background_color->red; 805848b8605Smrg color.f[1] = background_color->green; 806848b8605Smrg color.f[2] = background_color->blue; 807848b8605Smrg color.f[3] = background_color->alpha; 808848b8605Smrg vl_compositor_set_clear_color(&vmixer->cstate, &color); 809848b8605Smrg break; 810848b8605Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX: 811848b8605Smrg vdp_csc = attribute_values[i]; 812848b8605Smrg vmixer->custom_csc = !!vdp_csc; 813848b8605Smrg if (!vdp_csc) 814848b8605Smrg vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, 1, &vmixer->csc); 815848b8605Smrg else 816848b8605Smrg memcpy(vmixer->csc, vdp_csc, sizeof(vl_csc_matrix)); 817848b8605Smrg if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) 818b8e80941Smrg if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 819b8e80941Smrg vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) { 820b8e80941Smrg ret = VDP_STATUS_ERROR; 821b8e80941Smrg goto fail; 822b8e80941Smrg } 823848b8605Smrg break; 824848b8605Smrg 825848b8605Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL: 826848b8605Smrg 827848b8605Smrg val = *(float*)attribute_values[i]; 828b8e80941Smrg if (val < 0.0f || val > 1.0f) { 829b8e80941Smrg ret = VDP_STATUS_INVALID_VALUE; 830b8e80941Smrg goto fail; 831b8e80941Smrg } 832848b8605Smrg 833848b8605Smrg vmixer->noise_reduction.level = val * 10; 834848b8605Smrg vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer); 835848b8605Smrg break; 836848b8605Smrg 837848b8605Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA: 838848b8605Smrg val = *(float*)attribute_values[i]; 839b8e80941Smrg if (val < 0.0f || val > 1.0f) { 840b8e80941Smrg ret = VDP_STATUS_INVALID_VALUE; 841b8e80941Smrg goto fail; 842b8e80941Smrg } 843b8e80941Smrg vmixer->luma_key.luma_min = val; 844b8e80941Smrg if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) 845b8e80941Smrg if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 846b8e80941Smrg vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) { 847b8e80941Smrg ret = VDP_STATUS_ERROR; 848b8e80941Smrg goto fail; 849b8e80941Smrg } 850848b8605Smrg break; 851b8e80941Smrg 852848b8605Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA: 853848b8605Smrg val = *(float*)attribute_values[i]; 854b8e80941Smrg if (val < 0.0f || val > 1.0f) { 855b8e80941Smrg ret = VDP_STATUS_INVALID_VALUE; 856b8e80941Smrg goto fail; 857b8e80941Smrg } 858b8e80941Smrg vmixer->luma_key.luma_max = val; 859b8e80941Smrg if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) 860b8e80941Smrg if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 861b8e80941Smrg vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) { 862b8e80941Smrg ret = VDP_STATUS_ERROR; 863b8e80941Smrg goto fail; 864b8e80941Smrg } 865848b8605Smrg break; 866848b8605Smrg 867848b8605Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL: 868848b8605Smrg 869848b8605Smrg val = *(float*)attribute_values[i]; 870b8e80941Smrg if (val < -1.0f || val > 1.0f) { 871b8e80941Smrg ret = VDP_STATUS_INVALID_VALUE; 872b8e80941Smrg goto fail; 873b8e80941Smrg } 874848b8605Smrg 875848b8605Smrg vmixer->sharpness.value = val; 876848b8605Smrg vlVdpVideoMixerUpdateSharpnessFilter(vmixer); 877848b8605Smrg break; 878848b8605Smrg 879848b8605Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE: 880b8e80941Smrg if (*(uint8_t*)attribute_values[i] > 1) { 881b8e80941Smrg ret = VDP_STATUS_INVALID_VALUE; 882b8e80941Smrg goto fail; 883b8e80941Smrg } 884848b8605Smrg vmixer->skip_chroma_deint = *(uint8_t*)attribute_values[i]; 885848b8605Smrg vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer); 886848b8605Smrg break; 887848b8605Smrg default: 888b8e80941Smrg ret = VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE; 889b8e80941Smrg goto fail; 890848b8605Smrg } 891848b8605Smrg } 892b8e80941Smrg mtx_unlock(&vmixer->device->mutex); 893848b8605Smrg 894848b8605Smrg return VDP_STATUS_OK; 895b8e80941Smrgfail: 896b8e80941Smrg mtx_unlock(&vmixer->device->mutex); 897b8e80941Smrg return ret; 898848b8605Smrg} 899848b8605Smrg 900848b8605Smrg/** 901848b8605Smrg * Retrieve parameter values given at creation time. 902848b8605Smrg */ 903848b8605SmrgVdpStatus 904848b8605SmrgvlVdpVideoMixerGetParameterValues(VdpVideoMixer mixer, 905848b8605Smrg uint32_t parameter_count, 906848b8605Smrg VdpVideoMixerParameter const *parameters, 907848b8605Smrg void *const *parameter_values) 908848b8605Smrg{ 909848b8605Smrg vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer); 910848b8605Smrg unsigned i; 911848b8605Smrg if (!vmixer) 912848b8605Smrg return VDP_STATUS_INVALID_HANDLE; 913848b8605Smrg 914848b8605Smrg if (!parameter_count) 915848b8605Smrg return VDP_STATUS_OK; 916848b8605Smrg if (!(parameters && parameter_values)) 917848b8605Smrg return VDP_STATUS_INVALID_POINTER; 918848b8605Smrg for (i = 0; i < parameter_count; ++i) { 919848b8605Smrg switch (parameters[i]) { 920848b8605Smrg case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH: 921848b8605Smrg *(uint32_t*)parameter_values[i] = vmixer->video_width; 922848b8605Smrg break; 923848b8605Smrg case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT: 924848b8605Smrg *(uint32_t*)parameter_values[i] = vmixer->video_height; 925848b8605Smrg break; 926848b8605Smrg case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE: 927848b8605Smrg *(VdpChromaType*)parameter_values[i] = PipeToChroma(vmixer->chroma_format); 928848b8605Smrg break; 929848b8605Smrg case VDP_VIDEO_MIXER_PARAMETER_LAYERS: 930848b8605Smrg *(uint32_t*)parameter_values[i] = vmixer->max_layers; 931848b8605Smrg break; 932848b8605Smrg default: 933848b8605Smrg return VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER; 934848b8605Smrg } 935848b8605Smrg } 936848b8605Smrg return VDP_STATUS_OK; 937848b8605Smrg} 938848b8605Smrg 939848b8605Smrg/** 940848b8605Smrg * Retrieve current attribute values. 941848b8605Smrg */ 942848b8605SmrgVdpStatus 943848b8605SmrgvlVdpVideoMixerGetAttributeValues(VdpVideoMixer mixer, 944848b8605Smrg uint32_t attribute_count, 945848b8605Smrg VdpVideoMixerAttribute const *attributes, 946848b8605Smrg void *const *attribute_values) 947848b8605Smrg{ 948848b8605Smrg unsigned i; 949848b8605Smrg VdpCSCMatrix **vdp_csc; 950848b8605Smrg 951848b8605Smrg if (!(attributes && attribute_values)) 952848b8605Smrg return VDP_STATUS_INVALID_POINTER; 953848b8605Smrg 954848b8605Smrg vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer); 955848b8605Smrg if (!vmixer) 956848b8605Smrg return VDP_STATUS_INVALID_HANDLE; 957848b8605Smrg 958b8e80941Smrg mtx_lock(&vmixer->device->mutex); 959848b8605Smrg for (i = 0; i < attribute_count; ++i) { 960848b8605Smrg switch (attributes[i]) { 961848b8605Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR: 962848b8605Smrg vl_compositor_get_clear_color(&vmixer->cstate, attribute_values[i]); 963848b8605Smrg break; 964848b8605Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX: 965848b8605Smrg vdp_csc = attribute_values[i]; 966848b8605Smrg if (!vmixer->custom_csc) { 967848b8605Smrg *vdp_csc = NULL; 968848b8605Smrg break; 969848b8605Smrg } 970848b8605Smrg memcpy(*vdp_csc, vmixer->csc, sizeof(float)*12); 971848b8605Smrg break; 972848b8605Smrg 973848b8605Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL: 974848b8605Smrg *(float*)attribute_values[i] = (float)vmixer->noise_reduction.level / 10.0f; 975848b8605Smrg break; 976848b8605Smrg 977848b8605Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA: 978b8e80941Smrg *(float*)attribute_values[i] = vmixer->luma_key.luma_min; 979848b8605Smrg break; 980848b8605Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA: 981b8e80941Smrg *(float*)attribute_values[i] = vmixer->luma_key.luma_max; 982848b8605Smrg break; 983848b8605Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL: 984848b8605Smrg *(float*)attribute_values[i] = vmixer->sharpness.value; 985848b8605Smrg break; 986848b8605Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE: 987848b8605Smrg *(uint8_t*)attribute_values[i] = vmixer->skip_chroma_deint; 988848b8605Smrg break; 989848b8605Smrg default: 990b8e80941Smrg mtx_unlock(&vmixer->device->mutex); 991848b8605Smrg return VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE; 992848b8605Smrg } 993848b8605Smrg } 994b8e80941Smrg mtx_unlock(&vmixer->device->mutex); 995848b8605Smrg return VDP_STATUS_OK; 996848b8605Smrg} 997848b8605Smrg 998848b8605Smrg/** 999848b8605Smrg * Generate a color space conversion matrix. 1000848b8605Smrg */ 1001848b8605SmrgVdpStatus 1002848b8605SmrgvlVdpGenerateCSCMatrix(VdpProcamp *procamp, 1003848b8605Smrg VdpColorStandard standard, 1004848b8605Smrg VdpCSCMatrix *csc_matrix) 1005848b8605Smrg{ 1006848b8605Smrg enum VL_CSC_COLOR_STANDARD vl_std; 1007848b8605Smrg struct vl_procamp camp; 1008848b8605Smrg 1009848b8605Smrg if (!csc_matrix) 1010848b8605Smrg return VDP_STATUS_INVALID_POINTER; 1011848b8605Smrg 1012848b8605Smrg switch (standard) { 1013848b8605Smrg case VDP_COLOR_STANDARD_ITUR_BT_601: vl_std = VL_CSC_COLOR_STANDARD_BT_601; break; 1014848b8605Smrg case VDP_COLOR_STANDARD_ITUR_BT_709: vl_std = VL_CSC_COLOR_STANDARD_BT_709; break; 1015848b8605Smrg case VDP_COLOR_STANDARD_SMPTE_240M: vl_std = VL_CSC_COLOR_STANDARD_SMPTE_240M; break; 1016848b8605Smrg default: return VDP_STATUS_INVALID_COLOR_STANDARD; 1017848b8605Smrg } 1018848b8605Smrg 1019848b8605Smrg if (procamp) { 1020848b8605Smrg if (procamp->struct_version > VDP_PROCAMP_VERSION) 1021848b8605Smrg return VDP_STATUS_INVALID_STRUCT_VERSION; 1022848b8605Smrg camp.brightness = procamp->brightness; 1023848b8605Smrg camp.contrast = procamp->contrast; 1024848b8605Smrg camp.saturation = procamp->saturation; 1025848b8605Smrg camp.hue = procamp->hue; 1026848b8605Smrg } 1027848b8605Smrg 1028848b8605Smrg vl_csc_get_matrix(vl_std, procamp ? &camp : NULL, true, csc_matrix); 1029848b8605Smrg return VDP_STATUS_OK; 1030848b8605Smrg} 1031