17ec681f3Smrg/************************************************************************** 27ec681f3Smrg * 37ec681f3Smrg * Copyright 2010 Thomas Balling Sørensen. 47ec681f3Smrg * All Rights Reserved. 57ec681f3Smrg * 67ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 77ec681f3Smrg * copy of this software and associated documentation files (the 87ec681f3Smrg * "Software"), to deal in the Software without restriction, including 97ec681f3Smrg * without limitation the rights to use, copy, modify, merge, publish, 107ec681f3Smrg * distribute, sub license, and/or sell copies of the Software, and to 117ec681f3Smrg * permit persons to whom the Software is furnished to do so, subject to 127ec681f3Smrg * the following conditions: 137ec681f3Smrg * 147ec681f3Smrg * The above copyright notice and this permission notice (including the 157ec681f3Smrg * next paragraph) shall be included in all copies or substantial portions 167ec681f3Smrg * of the Software. 177ec681f3Smrg * 187ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 197ec681f3Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 207ec681f3Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 217ec681f3Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 227ec681f3Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 237ec681f3Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 247ec681f3Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 257ec681f3Smrg * 267ec681f3Smrg **************************************************************************/ 277ec681f3Smrg 287ec681f3Smrg#include <vdpau/vdpau.h> 297ec681f3Smrg 307ec681f3Smrg#include "util/u_memory.h" 317ec681f3Smrg#include "util/u_debug.h" 327ec681f3Smrg 337ec681f3Smrg#include "vl/vl_csc.h" 347ec681f3Smrg 357ec681f3Smrg#include "vdpau_private.h" 367ec681f3Smrg 377ec681f3Smrg/** 387ec681f3Smrg * Create a VdpVideoMixer. 397ec681f3Smrg */ 407ec681f3SmrgVdpStatus 417ec681f3SmrgvlVdpVideoMixerCreate(VdpDevice device, 427ec681f3Smrg uint32_t feature_count, 437ec681f3Smrg VdpVideoMixerFeature const *features, 447ec681f3Smrg uint32_t parameter_count, 457ec681f3Smrg VdpVideoMixerParameter const *parameters, 467ec681f3Smrg void const *const *parameter_values, 477ec681f3Smrg VdpVideoMixer *mixer) 487ec681f3Smrg{ 497ec681f3Smrg vlVdpVideoMixer *vmixer = NULL; 507ec681f3Smrg VdpStatus ret; 517ec681f3Smrg struct pipe_screen *screen; 527ec681f3Smrg unsigned max_size, i; 537ec681f3Smrg 547ec681f3Smrg vlVdpDevice *dev = vlGetDataHTAB(device); 557ec681f3Smrg if (!dev) 567ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 577ec681f3Smrg screen = dev->vscreen->pscreen; 587ec681f3Smrg 597ec681f3Smrg vmixer = CALLOC(1, sizeof(vlVdpVideoMixer)); 607ec681f3Smrg if (!vmixer) 617ec681f3Smrg return VDP_STATUS_RESOURCES; 627ec681f3Smrg 637ec681f3Smrg DeviceReference(&vmixer->device, dev); 647ec681f3Smrg 657ec681f3Smrg mtx_lock(&dev->mutex); 667ec681f3Smrg 677ec681f3Smrg if (!vl_compositor_init_state(&vmixer->cstate, dev->context)) { 687ec681f3Smrg ret = VDP_STATUS_ERROR; 697ec681f3Smrg goto no_compositor_state; 707ec681f3Smrg } 717ec681f3Smrg 727ec681f3Smrg vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, true, &vmixer->csc); 737ec681f3Smrg if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) { 747ec681f3Smrg if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 1.0f, 0.0f)) { 757ec681f3Smrg ret = VDP_STATUS_ERROR; 767ec681f3Smrg goto err_csc_matrix; 777ec681f3Smrg } 787ec681f3Smrg } 797ec681f3Smrg 807ec681f3Smrg *mixer = vlAddDataHTAB(vmixer); 817ec681f3Smrg if (*mixer == 0) { 827ec681f3Smrg ret = VDP_STATUS_ERROR; 837ec681f3Smrg goto no_handle; 847ec681f3Smrg } 857ec681f3Smrg 867ec681f3Smrg ret = VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE; 877ec681f3Smrg for (i = 0; i < feature_count; ++i) { 887ec681f3Smrg switch (features[i]) { 897ec681f3Smrg /* they are valid, but we doesn't support them */ 907ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL: 917ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2: 927ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3: 937ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4: 947ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5: 957ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6: 967ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7: 977ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8: 987ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9: 997ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE: 1007ec681f3Smrg break; 1017ec681f3Smrg 1027ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL: 1037ec681f3Smrg vmixer->deint.supported = true; 1047ec681f3Smrg break; 1057ec681f3Smrg 1067ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_SHARPNESS: 1077ec681f3Smrg vmixer->sharpness.supported = true; 1087ec681f3Smrg break; 1097ec681f3Smrg 1107ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION: 1117ec681f3Smrg vmixer->noise_reduction.supported = true; 1127ec681f3Smrg break; 1137ec681f3Smrg 1147ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY: 1157ec681f3Smrg vmixer->luma_key.supported = true; 1167ec681f3Smrg break; 1177ec681f3Smrg 1187ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1: 1197ec681f3Smrg vmixer->bicubic.supported = true; 1207ec681f3Smrg break; 1217ec681f3Smrg default: goto no_params; 1227ec681f3Smrg } 1237ec681f3Smrg } 1247ec681f3Smrg 1257ec681f3Smrg vmixer->chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420; 1267ec681f3Smrg ret = VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER; 1277ec681f3Smrg for (i = 0; i < parameter_count; ++i) { 1287ec681f3Smrg switch (parameters[i]) { 1297ec681f3Smrg case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH: 1307ec681f3Smrg vmixer->video_width = *(uint32_t*)parameter_values[i]; 1317ec681f3Smrg break; 1327ec681f3Smrg case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT: 1337ec681f3Smrg vmixer->video_height = *(uint32_t*)parameter_values[i]; 1347ec681f3Smrg break; 1357ec681f3Smrg case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE: 1367ec681f3Smrg vmixer->chroma_format = ChromaToPipe(*(VdpChromaType*)parameter_values[i]); 1377ec681f3Smrg break; 1387ec681f3Smrg case VDP_VIDEO_MIXER_PARAMETER_LAYERS: 1397ec681f3Smrg vmixer->max_layers = *(uint32_t*)parameter_values[i]; 1407ec681f3Smrg break; 1417ec681f3Smrg default: goto no_params; 1427ec681f3Smrg } 1437ec681f3Smrg } 1447ec681f3Smrg ret = VDP_STATUS_INVALID_VALUE; 1457ec681f3Smrg if (vmixer->max_layers > 4) { 1467ec681f3Smrg VDPAU_MSG(VDPAU_WARN, "[VDPAU] Max layers %u > 4 not supported\n", vmixer->max_layers); 1477ec681f3Smrg goto no_params; 1487ec681f3Smrg } 1497ec681f3Smrg 1507ec681f3Smrg max_size = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_SIZE); 1517ec681f3Smrg if (vmixer->video_width < 48 || vmixer->video_width > max_size) { 1527ec681f3Smrg VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u not valid for width\n", 1537ec681f3Smrg vmixer->video_width, max_size); 1547ec681f3Smrg goto no_params; 1557ec681f3Smrg } 1567ec681f3Smrg if (vmixer->video_height < 48 || vmixer->video_height > max_size) { 1577ec681f3Smrg VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u not valid for height\n", 1587ec681f3Smrg vmixer->video_height, max_size); 1597ec681f3Smrg goto no_params; 1607ec681f3Smrg } 1617ec681f3Smrg vmixer->luma_key.luma_min = 1.0f; 1627ec681f3Smrg vmixer->luma_key.luma_max = 0.0f; 1637ec681f3Smrg mtx_unlock(&dev->mutex); 1647ec681f3Smrg 1657ec681f3Smrg return VDP_STATUS_OK; 1667ec681f3Smrg 1677ec681f3Smrgno_params: 1687ec681f3Smrg vlRemoveDataHTAB(*mixer); 1697ec681f3Smrg 1707ec681f3Smrgno_handle: 1717ec681f3Smrgerr_csc_matrix: 1727ec681f3Smrg vl_compositor_cleanup_state(&vmixer->cstate); 1737ec681f3Smrgno_compositor_state: 1747ec681f3Smrg mtx_unlock(&dev->mutex); 1757ec681f3Smrg DeviceReference(&vmixer->device, NULL); 1767ec681f3Smrg FREE(vmixer); 1777ec681f3Smrg return ret; 1787ec681f3Smrg} 1797ec681f3Smrg 1807ec681f3Smrg/** 1817ec681f3Smrg * Destroy a VdpVideoMixer. 1827ec681f3Smrg */ 1837ec681f3SmrgVdpStatus 1847ec681f3SmrgvlVdpVideoMixerDestroy(VdpVideoMixer mixer) 1857ec681f3Smrg{ 1867ec681f3Smrg vlVdpVideoMixer *vmixer; 1877ec681f3Smrg 1887ec681f3Smrg vmixer = vlGetDataHTAB(mixer); 1897ec681f3Smrg if (!vmixer) 1907ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 1917ec681f3Smrg 1927ec681f3Smrg mtx_lock(&vmixer->device->mutex); 1937ec681f3Smrg 1947ec681f3Smrg vlRemoveDataHTAB(mixer); 1957ec681f3Smrg 1967ec681f3Smrg vl_compositor_cleanup_state(&vmixer->cstate); 1977ec681f3Smrg 1987ec681f3Smrg if (vmixer->deint.filter) { 1997ec681f3Smrg vl_deint_filter_cleanup(vmixer->deint.filter); 2007ec681f3Smrg FREE(vmixer->deint.filter); 2017ec681f3Smrg } 2027ec681f3Smrg 2037ec681f3Smrg if (vmixer->noise_reduction.filter) { 2047ec681f3Smrg vl_median_filter_cleanup(vmixer->noise_reduction.filter); 2057ec681f3Smrg FREE(vmixer->noise_reduction.filter); 2067ec681f3Smrg } 2077ec681f3Smrg 2087ec681f3Smrg if (vmixer->sharpness.filter) { 2097ec681f3Smrg vl_matrix_filter_cleanup(vmixer->sharpness.filter); 2107ec681f3Smrg FREE(vmixer->sharpness.filter); 2117ec681f3Smrg } 2127ec681f3Smrg 2137ec681f3Smrg if (vmixer->bicubic.filter) { 2147ec681f3Smrg vl_bicubic_filter_cleanup(vmixer->bicubic.filter); 2157ec681f3Smrg FREE(vmixer->bicubic.filter); 2167ec681f3Smrg } 2177ec681f3Smrg mtx_unlock(&vmixer->device->mutex); 2187ec681f3Smrg DeviceReference(&vmixer->device, NULL); 2197ec681f3Smrg 2207ec681f3Smrg FREE(vmixer); 2217ec681f3Smrg 2227ec681f3Smrg return VDP_STATUS_OK; 2237ec681f3Smrg} 2247ec681f3Smrg 2257ec681f3Smrg/** 2267ec681f3Smrg * Perform a video post-processing and compositing operation. 2277ec681f3Smrg */ 2287ec681f3SmrgVdpStatus vlVdpVideoMixerRender(VdpVideoMixer mixer, 2297ec681f3Smrg VdpOutputSurface background_surface, 2307ec681f3Smrg VdpRect const *background_source_rect, 2317ec681f3Smrg VdpVideoMixerPictureStructure current_picture_structure, 2327ec681f3Smrg uint32_t video_surface_past_count, 2337ec681f3Smrg VdpVideoSurface const *video_surface_past, 2347ec681f3Smrg VdpVideoSurface video_surface_current, 2357ec681f3Smrg uint32_t video_surface_future_count, 2367ec681f3Smrg VdpVideoSurface const *video_surface_future, 2377ec681f3Smrg VdpRect const *video_source_rect, 2387ec681f3Smrg VdpOutputSurface destination_surface, 2397ec681f3Smrg VdpRect const *destination_rect, 2407ec681f3Smrg VdpRect const *destination_video_rect, 2417ec681f3Smrg uint32_t layer_count, 2427ec681f3Smrg VdpLayer const *layers) 2437ec681f3Smrg{ 2447ec681f3Smrg enum vl_compositor_deinterlace deinterlace; 2457ec681f3Smrg struct u_rect rect, clip, *prect, dirty_area; 2467ec681f3Smrg unsigned i, layer = 0; 2477ec681f3Smrg struct pipe_video_buffer *video_buffer; 2487ec681f3Smrg struct pipe_sampler_view *sampler_view, sv_templ; 2497ec681f3Smrg struct pipe_surface *surface, surf_templ; 2507ec681f3Smrg struct pipe_context *pipe = NULL; 2517ec681f3Smrg struct pipe_resource res_tmpl, *res; 2527ec681f3Smrg 2537ec681f3Smrg vlVdpVideoMixer *vmixer; 2547ec681f3Smrg vlVdpSurface *surf; 2557ec681f3Smrg vlVdpOutputSurface *dst, *bg = NULL; 2567ec681f3Smrg 2577ec681f3Smrg struct vl_compositor *compositor; 2587ec681f3Smrg 2597ec681f3Smrg vmixer = vlGetDataHTAB(mixer); 2607ec681f3Smrg if (!vmixer) 2617ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 2627ec681f3Smrg 2637ec681f3Smrg compositor = &vmixer->device->compositor; 2647ec681f3Smrg 2657ec681f3Smrg surf = vlGetDataHTAB(video_surface_current); 2667ec681f3Smrg if (!surf) 2677ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 2687ec681f3Smrg video_buffer = surf->video_buffer; 2697ec681f3Smrg 2707ec681f3Smrg if (surf->device != vmixer->device) 2717ec681f3Smrg return VDP_STATUS_HANDLE_DEVICE_MISMATCH; 2727ec681f3Smrg 2737ec681f3Smrg if (vmixer->video_width > video_buffer->width || 2747ec681f3Smrg vmixer->video_height > video_buffer->height || 2757ec681f3Smrg vmixer->chroma_format != pipe_format_to_chroma_format(video_buffer->buffer_format)) 2767ec681f3Smrg return VDP_STATUS_INVALID_SIZE; 2777ec681f3Smrg 2787ec681f3Smrg if (layer_count > vmixer->max_layers) 2797ec681f3Smrg return VDP_STATUS_INVALID_VALUE; 2807ec681f3Smrg 2817ec681f3Smrg dst = vlGetDataHTAB(destination_surface); 2827ec681f3Smrg if (!dst) 2837ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 2847ec681f3Smrg 2857ec681f3Smrg if (background_surface != VDP_INVALID_HANDLE) { 2867ec681f3Smrg bg = vlGetDataHTAB(background_surface); 2877ec681f3Smrg if (!bg) 2887ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 2897ec681f3Smrg } 2907ec681f3Smrg 2917ec681f3Smrg mtx_lock(&vmixer->device->mutex); 2927ec681f3Smrg 2937ec681f3Smrg vl_compositor_clear_layers(&vmixer->cstate); 2947ec681f3Smrg 2957ec681f3Smrg if (bg) 2967ec681f3Smrg vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer++, bg->sampler_view, 2977ec681f3Smrg RectToPipe(background_source_rect, &rect), NULL, NULL); 2987ec681f3Smrg 2997ec681f3Smrg switch (current_picture_structure) { 3007ec681f3Smrg case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD: 3017ec681f3Smrg deinterlace = VL_COMPOSITOR_BOB_TOP; 3027ec681f3Smrg break; 3037ec681f3Smrg 3047ec681f3Smrg case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD: 3057ec681f3Smrg deinterlace = VL_COMPOSITOR_BOB_BOTTOM; 3067ec681f3Smrg break; 3077ec681f3Smrg 3087ec681f3Smrg case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME: 3097ec681f3Smrg deinterlace = VL_COMPOSITOR_WEAVE; 3107ec681f3Smrg break; 3117ec681f3Smrg 3127ec681f3Smrg default: 3137ec681f3Smrg mtx_unlock(&vmixer->device->mutex); 3147ec681f3Smrg return VDP_STATUS_INVALID_VIDEO_MIXER_PICTURE_STRUCTURE; 3157ec681f3Smrg } 3167ec681f3Smrg 3177ec681f3Smrg if (deinterlace != VL_COMPOSITOR_WEAVE && vmixer->deint.enabled && 3187ec681f3Smrg video_surface_past_count > 1 && video_surface_future_count > 0) { 3197ec681f3Smrg vlVdpSurface *prevprev = vlGetDataHTAB(video_surface_past[1]); 3207ec681f3Smrg vlVdpSurface *prev = vlGetDataHTAB(video_surface_past[0]); 3217ec681f3Smrg vlVdpSurface *next = vlGetDataHTAB(video_surface_future[0]); 3227ec681f3Smrg if (prevprev && prev && next && 3237ec681f3Smrg vl_deint_filter_check_buffers(vmixer->deint.filter, 3247ec681f3Smrg prevprev->video_buffer, prev->video_buffer, surf->video_buffer, next->video_buffer)) { 3257ec681f3Smrg vl_deint_filter_render(vmixer->deint.filter, prevprev->video_buffer, 3267ec681f3Smrg prev->video_buffer, surf->video_buffer, 3277ec681f3Smrg next->video_buffer, 3287ec681f3Smrg deinterlace == VL_COMPOSITOR_BOB_BOTTOM); 3297ec681f3Smrg deinterlace = VL_COMPOSITOR_WEAVE; 3307ec681f3Smrg video_buffer = vmixer->deint.filter->video_buffer; 3317ec681f3Smrg } 3327ec681f3Smrg } 3337ec681f3Smrg 3347ec681f3Smrg if (!destination_video_rect) 3357ec681f3Smrg destination_video_rect = video_source_rect; 3367ec681f3Smrg 3377ec681f3Smrg prect = RectToPipe(video_source_rect, &rect); 3387ec681f3Smrg if (!prect) { 3397ec681f3Smrg rect.x0 = 0; 3407ec681f3Smrg rect.y0 = 0; 3417ec681f3Smrg rect.x1 = surf->templat.width; 3427ec681f3Smrg rect.y1 = surf->templat.height; 3437ec681f3Smrg prect = ▭ 3447ec681f3Smrg } 3457ec681f3Smrg vl_compositor_set_buffer_layer(&vmixer->cstate, compositor, layer, video_buffer, prect, NULL, deinterlace); 3467ec681f3Smrg 3477ec681f3Smrg if (vmixer->bicubic.filter || vmixer->sharpness.filter || vmixer->noise_reduction.filter) { 3487ec681f3Smrg pipe = vmixer->device->context; 3497ec681f3Smrg memset(&res_tmpl, 0, sizeof(res_tmpl)); 3507ec681f3Smrg 3517ec681f3Smrg res_tmpl.target = PIPE_TEXTURE_2D; 3527ec681f3Smrg res_tmpl.format = dst->sampler_view->format; 3537ec681f3Smrg res_tmpl.depth0 = 1; 3547ec681f3Smrg res_tmpl.array_size = 1; 3557ec681f3Smrg res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; 3567ec681f3Smrg res_tmpl.usage = PIPE_USAGE_DEFAULT; 3577ec681f3Smrg 3587ec681f3Smrg if (!vmixer->bicubic.filter) { 3597ec681f3Smrg res_tmpl.width0 = dst->surface->width; 3607ec681f3Smrg res_tmpl.height0 = dst->surface->height; 3617ec681f3Smrg } else { 3627ec681f3Smrg res_tmpl.width0 = surf->templat.width; 3637ec681f3Smrg res_tmpl.height0 = surf->templat.height; 3647ec681f3Smrg } 3657ec681f3Smrg 3667ec681f3Smrg res = pipe->screen->resource_create(pipe->screen, &res_tmpl); 3677ec681f3Smrg 3687ec681f3Smrg vlVdpDefaultSamplerViewTemplate(&sv_templ, res); 3697ec681f3Smrg sampler_view = pipe->create_sampler_view(pipe, res, &sv_templ); 3707ec681f3Smrg 3717ec681f3Smrg memset(&surf_templ, 0, sizeof(surf_templ)); 3727ec681f3Smrg surf_templ.format = res->format; 3737ec681f3Smrg surface = pipe->create_surface(pipe, res, &surf_templ); 3747ec681f3Smrg 3757ec681f3Smrg vl_compositor_reset_dirty_area(&dirty_area); 3767ec681f3Smrg pipe_resource_reference(&res, NULL); 3777ec681f3Smrg } else { 3787ec681f3Smrg surface = dst->surface; 3797ec681f3Smrg sampler_view = dst->sampler_view; 3807ec681f3Smrg dirty_area = dst->dirty_area; 3817ec681f3Smrg } 3827ec681f3Smrg 3837ec681f3Smrg if (!vmixer->bicubic.filter) { 3847ec681f3Smrg vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(destination_video_rect, &rect)); 3857ec681f3Smrg vl_compositor_set_dst_clip(&vmixer->cstate, RectToPipe(destination_rect, &clip)); 3867ec681f3Smrg } 3877ec681f3Smrg 3887ec681f3Smrg for (i = 0; i < layer_count; ++i) { 3897ec681f3Smrg vlVdpOutputSurface *src = vlGetDataHTAB(layers->source_surface); 3907ec681f3Smrg if (!src) { 3917ec681f3Smrg mtx_unlock(&vmixer->device->mutex); 3927ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 3937ec681f3Smrg } 3947ec681f3Smrg 3957ec681f3Smrg assert(layers->struct_version == VDP_LAYER_VERSION); 3967ec681f3Smrg 3977ec681f3Smrg vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer, src->sampler_view, 3987ec681f3Smrg RectToPipe(layers->source_rect, &rect), NULL, NULL); 3997ec681f3Smrg vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(layers->destination_rect, &rect)); 4007ec681f3Smrg 4017ec681f3Smrg ++layers; 4027ec681f3Smrg } 4037ec681f3Smrg 4047ec681f3Smrg vl_compositor_render(&vmixer->cstate, compositor, surface, &dirty_area, true); 4057ec681f3Smrg 4067ec681f3Smrg if (vmixer->noise_reduction.filter) { 4077ec681f3Smrg if (!vmixer->sharpness.filter && !vmixer->bicubic.filter) { 4087ec681f3Smrg vl_median_filter_render(vmixer->noise_reduction.filter, 4097ec681f3Smrg sampler_view, dst->surface); 4107ec681f3Smrg } else { 4117ec681f3Smrg res = pipe->screen->resource_create(pipe->screen, &res_tmpl); 4127ec681f3Smrg struct pipe_sampler_view *sampler_view_temp = pipe->create_sampler_view(pipe, res, &sv_templ); 4137ec681f3Smrg struct pipe_surface *surface_temp = pipe->create_surface(pipe, res, &surf_templ); 4147ec681f3Smrg pipe_resource_reference(&res, NULL); 4157ec681f3Smrg 4167ec681f3Smrg vl_median_filter_render(vmixer->noise_reduction.filter, 4177ec681f3Smrg sampler_view, surface_temp); 4187ec681f3Smrg 4197ec681f3Smrg pipe_sampler_view_reference(&sampler_view, NULL); 4207ec681f3Smrg pipe_surface_reference(&surface, NULL); 4217ec681f3Smrg 4227ec681f3Smrg sampler_view = sampler_view_temp; 4237ec681f3Smrg surface = surface_temp; 4247ec681f3Smrg } 4257ec681f3Smrg } 4267ec681f3Smrg 4277ec681f3Smrg if (vmixer->sharpness.filter) { 4287ec681f3Smrg if (!vmixer->bicubic.filter) { 4297ec681f3Smrg vl_matrix_filter_render(vmixer->sharpness.filter, 4307ec681f3Smrg sampler_view, dst->surface); 4317ec681f3Smrg } else { 4327ec681f3Smrg res = pipe->screen->resource_create(pipe->screen, &res_tmpl); 4337ec681f3Smrg struct pipe_sampler_view *sampler_view_temp = pipe->create_sampler_view(pipe, res, &sv_templ); 4347ec681f3Smrg struct pipe_surface *surface_temp = pipe->create_surface(pipe, res, &surf_templ); 4357ec681f3Smrg pipe_resource_reference(&res, NULL); 4367ec681f3Smrg 4377ec681f3Smrg vl_matrix_filter_render(vmixer->sharpness.filter, 4387ec681f3Smrg sampler_view, surface_temp); 4397ec681f3Smrg 4407ec681f3Smrg pipe_sampler_view_reference(&sampler_view, NULL); 4417ec681f3Smrg pipe_surface_reference(&surface, NULL); 4427ec681f3Smrg 4437ec681f3Smrg sampler_view = sampler_view_temp; 4447ec681f3Smrg surface = surface_temp; 4457ec681f3Smrg } 4467ec681f3Smrg } 4477ec681f3Smrg 4487ec681f3Smrg if (vmixer->bicubic.filter) 4497ec681f3Smrg vl_bicubic_filter_render(vmixer->bicubic.filter, 4507ec681f3Smrg sampler_view, dst->surface, 4517ec681f3Smrg RectToPipe(destination_video_rect, &rect), 4527ec681f3Smrg RectToPipe(destination_rect, &clip)); 4537ec681f3Smrg 4547ec681f3Smrg if(surface != dst->surface) { 4557ec681f3Smrg pipe_sampler_view_reference(&sampler_view, NULL); 4567ec681f3Smrg pipe_surface_reference(&surface, NULL); 4577ec681f3Smrg } 4587ec681f3Smrg mtx_unlock(&vmixer->device->mutex); 4597ec681f3Smrg 4607ec681f3Smrg return VDP_STATUS_OK; 4617ec681f3Smrg} 4627ec681f3Smrg 4637ec681f3Smrgstatic void 4647ec681f3SmrgvlVdpVideoMixerUpdateDeinterlaceFilter(vlVdpVideoMixer *vmixer) 4657ec681f3Smrg{ 4667ec681f3Smrg struct pipe_context *pipe = vmixer->device->context; 4677ec681f3Smrg assert(vmixer); 4687ec681f3Smrg 4697ec681f3Smrg /* remove existing filter */ 4707ec681f3Smrg if (vmixer->deint.filter) { 4717ec681f3Smrg vl_deint_filter_cleanup(vmixer->deint.filter); 4727ec681f3Smrg FREE(vmixer->deint.filter); 4737ec681f3Smrg vmixer->deint.filter = NULL; 4747ec681f3Smrg } 4757ec681f3Smrg 4767ec681f3Smrg /* create a new filter if requested */ 4777ec681f3Smrg if (vmixer->deint.enabled && vmixer->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) { 4787ec681f3Smrg vmixer->deint.filter = MALLOC(sizeof(struct vl_deint_filter)); 4797ec681f3Smrg vmixer->deint.enabled = vl_deint_filter_init(vmixer->deint.filter, pipe, 4807ec681f3Smrg vmixer->video_width, vmixer->video_height, 4817ec681f3Smrg vmixer->skip_chroma_deint, vmixer->deint.spatial); 4827ec681f3Smrg if (!vmixer->deint.enabled) { 4837ec681f3Smrg FREE(vmixer->deint.filter); 4847ec681f3Smrg } 4857ec681f3Smrg } 4867ec681f3Smrg} 4877ec681f3Smrg 4887ec681f3Smrg/** 4897ec681f3Smrg * Update the noise reduction setting 4907ec681f3Smrg */ 4917ec681f3Smrgstatic void 4927ec681f3SmrgvlVdpVideoMixerUpdateNoiseReductionFilter(vlVdpVideoMixer *vmixer) 4937ec681f3Smrg{ 4947ec681f3Smrg assert(vmixer); 4957ec681f3Smrg 4967ec681f3Smrg /* if present remove the old filter first */ 4977ec681f3Smrg if (vmixer->noise_reduction.filter) { 4987ec681f3Smrg vl_median_filter_cleanup(vmixer->noise_reduction.filter); 4997ec681f3Smrg FREE(vmixer->noise_reduction.filter); 5007ec681f3Smrg vmixer->noise_reduction.filter = NULL; 5017ec681f3Smrg } 5027ec681f3Smrg 5037ec681f3Smrg /* and create a new filter as needed */ 5047ec681f3Smrg if (vmixer->noise_reduction. enabled && vmixer->noise_reduction.level > 0) { 5057ec681f3Smrg vmixer->noise_reduction.filter = MALLOC(sizeof(struct vl_median_filter)); 5067ec681f3Smrg vl_median_filter_init(vmixer->noise_reduction.filter, vmixer->device->context, 5077ec681f3Smrg vmixer->video_width, vmixer->video_height, 5087ec681f3Smrg vmixer->noise_reduction.level + 1, 5097ec681f3Smrg VL_MEDIAN_FILTER_CROSS); 5107ec681f3Smrg } 5117ec681f3Smrg} 5127ec681f3Smrg 5137ec681f3Smrgstatic void 5147ec681f3SmrgvlVdpVideoMixerUpdateSharpnessFilter(vlVdpVideoMixer *vmixer) 5157ec681f3Smrg{ 5167ec681f3Smrg assert(vmixer); 5177ec681f3Smrg 5187ec681f3Smrg /* if present remove the old filter first */ 5197ec681f3Smrg if (vmixer->sharpness.filter) { 5207ec681f3Smrg vl_matrix_filter_cleanup(vmixer->sharpness.filter); 5217ec681f3Smrg FREE(vmixer->sharpness.filter); 5227ec681f3Smrg vmixer->sharpness.filter = NULL; 5237ec681f3Smrg } 5247ec681f3Smrg 5257ec681f3Smrg /* and create a new filter as needed */ 5267ec681f3Smrg if (vmixer->sharpness.enabled && vmixer->sharpness.value != 0.0f) { 5277ec681f3Smrg float matrix[9]; 5287ec681f3Smrg unsigned i; 5297ec681f3Smrg 5307ec681f3Smrg if (vmixer->sharpness.value > 0.0f) { 5317ec681f3Smrg matrix[0] = -1.0f; matrix[1] = -1.0f; matrix[2] = -1.0f; 5327ec681f3Smrg matrix[3] = -1.0f; matrix[4] = 8.0f; matrix[5] = -1.0f; 5337ec681f3Smrg matrix[6] = -1.0f; matrix[7] = -1.0f; matrix[8] = -1.0f; 5347ec681f3Smrg 5357ec681f3Smrg for (i = 0; i < 9; ++i) 5367ec681f3Smrg matrix[i] *= vmixer->sharpness.value; 5377ec681f3Smrg 5387ec681f3Smrg matrix[4] += 1.0f; 5397ec681f3Smrg 5407ec681f3Smrg } else { 5417ec681f3Smrg matrix[0] = 1.0f; matrix[1] = 2.0f; matrix[2] = 1.0f; 5427ec681f3Smrg matrix[3] = 2.0f; matrix[4] = 4.0f; matrix[5] = 2.0f; 5437ec681f3Smrg matrix[6] = 1.0f; matrix[7] = 2.0f; matrix[8] = 1.0f; 5447ec681f3Smrg 5457ec681f3Smrg for (i = 0; i < 9; ++i) 5467ec681f3Smrg matrix[i] *= fabsf(vmixer->sharpness.value) / 16.0f; 5477ec681f3Smrg 5487ec681f3Smrg matrix[4] += 1.0f - fabsf(vmixer->sharpness.value); 5497ec681f3Smrg } 5507ec681f3Smrg 5517ec681f3Smrg vmixer->sharpness.filter = MALLOC(sizeof(struct vl_matrix_filter)); 5527ec681f3Smrg vl_matrix_filter_init(vmixer->sharpness.filter, vmixer->device->context, 5537ec681f3Smrg vmixer->video_width, vmixer->video_height, 5547ec681f3Smrg 3, 3, matrix); 5557ec681f3Smrg } 5567ec681f3Smrg} 5577ec681f3Smrg 5587ec681f3Smrg/** 5597ec681f3Smrg * Update the bicubic filter 5607ec681f3Smrg */ 5617ec681f3Smrgstatic void 5627ec681f3SmrgvlVdpVideoMixerUpdateBicubicFilter(vlVdpVideoMixer *vmixer) 5637ec681f3Smrg{ 5647ec681f3Smrg assert(vmixer); 5657ec681f3Smrg 5667ec681f3Smrg /* if present remove the old filter first */ 5677ec681f3Smrg if (vmixer->bicubic.filter) { 5687ec681f3Smrg vl_bicubic_filter_cleanup(vmixer->bicubic.filter); 5697ec681f3Smrg FREE(vmixer->bicubic.filter); 5707ec681f3Smrg vmixer->bicubic.filter = NULL; 5717ec681f3Smrg } 5727ec681f3Smrg /* and create a new filter as needed */ 5737ec681f3Smrg if (vmixer->bicubic.enabled) { 5747ec681f3Smrg vmixer->bicubic.filter = MALLOC(sizeof(struct vl_bicubic_filter)); 5757ec681f3Smrg vl_bicubic_filter_init(vmixer->bicubic.filter, vmixer->device->context, 5767ec681f3Smrg vmixer->video_width, vmixer->video_height); 5777ec681f3Smrg } 5787ec681f3Smrg} 5797ec681f3Smrg 5807ec681f3Smrg/** 5817ec681f3Smrg * Retrieve whether features were requested at creation time. 5827ec681f3Smrg */ 5837ec681f3SmrgVdpStatus 5847ec681f3SmrgvlVdpVideoMixerGetFeatureSupport(VdpVideoMixer mixer, 5857ec681f3Smrg uint32_t feature_count, 5867ec681f3Smrg VdpVideoMixerFeature const *features, 5877ec681f3Smrg VdpBool *feature_supports) 5887ec681f3Smrg{ 5897ec681f3Smrg vlVdpVideoMixer *vmixer; 5907ec681f3Smrg unsigned i; 5917ec681f3Smrg 5927ec681f3Smrg if (!(features && feature_supports)) 5937ec681f3Smrg return VDP_STATUS_INVALID_POINTER; 5947ec681f3Smrg 5957ec681f3Smrg vmixer = vlGetDataHTAB(mixer); 5967ec681f3Smrg if (!vmixer) 5977ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 5987ec681f3Smrg 5997ec681f3Smrg for (i = 0; i < feature_count; ++i) { 6007ec681f3Smrg switch (features[i]) { 6017ec681f3Smrg /* they are valid, but we doesn't support them */ 6027ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL: 6037ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2: 6047ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3: 6057ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4: 6067ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5: 6077ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6: 6087ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7: 6097ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8: 6107ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9: 6117ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE: 6127ec681f3Smrg feature_supports[i] = false; 6137ec681f3Smrg break; 6147ec681f3Smrg 6157ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL: 6167ec681f3Smrg feature_supports[i] = vmixer->deint.supported; 6177ec681f3Smrg break; 6187ec681f3Smrg 6197ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_SHARPNESS: 6207ec681f3Smrg feature_supports[i] = vmixer->sharpness.supported; 6217ec681f3Smrg break; 6227ec681f3Smrg 6237ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION: 6247ec681f3Smrg feature_supports[i] = vmixer->noise_reduction.supported; 6257ec681f3Smrg break; 6267ec681f3Smrg 6277ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY: 6287ec681f3Smrg feature_supports[i] = vmixer->luma_key.supported; 6297ec681f3Smrg break; 6307ec681f3Smrg 6317ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1: 6327ec681f3Smrg feature_supports[i] = vmixer->bicubic.supported; 6337ec681f3Smrg break; 6347ec681f3Smrg 6357ec681f3Smrg default: 6367ec681f3Smrg return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE; 6377ec681f3Smrg } 6387ec681f3Smrg } 6397ec681f3Smrg 6407ec681f3Smrg return VDP_STATUS_OK; 6417ec681f3Smrg} 6427ec681f3Smrg 6437ec681f3Smrg/** 6447ec681f3Smrg * Enable or disable features. 6457ec681f3Smrg */ 6467ec681f3SmrgVdpStatus 6477ec681f3SmrgvlVdpVideoMixerSetFeatureEnables(VdpVideoMixer mixer, 6487ec681f3Smrg uint32_t feature_count, 6497ec681f3Smrg VdpVideoMixerFeature const *features, 6507ec681f3Smrg VdpBool const *feature_enables) 6517ec681f3Smrg{ 6527ec681f3Smrg vlVdpVideoMixer *vmixer; 6537ec681f3Smrg unsigned i; 6547ec681f3Smrg 6557ec681f3Smrg if (!(features && feature_enables)) 6567ec681f3Smrg return VDP_STATUS_INVALID_POINTER; 6577ec681f3Smrg 6587ec681f3Smrg vmixer = vlGetDataHTAB(mixer); 6597ec681f3Smrg if (!vmixer) 6607ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 6617ec681f3Smrg 6627ec681f3Smrg mtx_lock(&vmixer->device->mutex); 6637ec681f3Smrg for (i = 0; i < feature_count; ++i) { 6647ec681f3Smrg switch (features[i]) { 6657ec681f3Smrg /* they are valid, but we doesn't support them */ 6667ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL: 6677ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2: 6687ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3: 6697ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4: 6707ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5: 6717ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6: 6727ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7: 6737ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8: 6747ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9: 6757ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE: 6767ec681f3Smrg break; 6777ec681f3Smrg 6787ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL: 6797ec681f3Smrg vmixer->deint.enabled = feature_enables[i]; 6807ec681f3Smrg vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer); 6817ec681f3Smrg break; 6827ec681f3Smrg 6837ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_SHARPNESS: 6847ec681f3Smrg vmixer->sharpness.enabled = feature_enables[i]; 6857ec681f3Smrg vlVdpVideoMixerUpdateSharpnessFilter(vmixer); 6867ec681f3Smrg break; 6877ec681f3Smrg 6887ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION: 6897ec681f3Smrg vmixer->noise_reduction.enabled = feature_enables[i]; 6907ec681f3Smrg vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer); 6917ec681f3Smrg break; 6927ec681f3Smrg 6937ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY: 6947ec681f3Smrg vmixer->luma_key.enabled = feature_enables[i]; 6957ec681f3Smrg if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) 6967ec681f3Smrg if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 6977ec681f3Smrg vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) { 6987ec681f3Smrg mtx_unlock(&vmixer->device->mutex); 6997ec681f3Smrg return VDP_STATUS_ERROR; 7007ec681f3Smrg } 7017ec681f3Smrg break; 7027ec681f3Smrg 7037ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1: 7047ec681f3Smrg vmixer->bicubic.enabled = feature_enables[i]; 7057ec681f3Smrg vlVdpVideoMixerUpdateBicubicFilter(vmixer); 7067ec681f3Smrg break; 7077ec681f3Smrg 7087ec681f3Smrg default: 7097ec681f3Smrg mtx_unlock(&vmixer->device->mutex); 7107ec681f3Smrg return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE; 7117ec681f3Smrg } 7127ec681f3Smrg } 7137ec681f3Smrg mtx_unlock(&vmixer->device->mutex); 7147ec681f3Smrg 7157ec681f3Smrg return VDP_STATUS_OK; 7167ec681f3Smrg} 7177ec681f3Smrg 7187ec681f3Smrg/** 7197ec681f3Smrg * Retrieve whether features are enabled. 7207ec681f3Smrg */ 7217ec681f3SmrgVdpStatus 7227ec681f3SmrgvlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer, 7237ec681f3Smrg uint32_t feature_count, 7247ec681f3Smrg VdpVideoMixerFeature const *features, 7257ec681f3Smrg VdpBool *feature_enables) 7267ec681f3Smrg{ 7277ec681f3Smrg vlVdpVideoMixer *vmixer; 7287ec681f3Smrg unsigned i; 7297ec681f3Smrg 7307ec681f3Smrg if (!(features && feature_enables)) 7317ec681f3Smrg return VDP_STATUS_INVALID_POINTER; 7327ec681f3Smrg 7337ec681f3Smrg vmixer = vlGetDataHTAB(mixer); 7347ec681f3Smrg if (!vmixer) 7357ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 7367ec681f3Smrg 7377ec681f3Smrg for (i = 0; i < feature_count; ++i) { 7387ec681f3Smrg switch (features[i]) { 7397ec681f3Smrg /* they are valid, but we doesn't support them */ 7407ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL: 7417ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL: 7427ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2: 7437ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3: 7447ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4: 7457ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5: 7467ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6: 7477ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7: 7487ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8: 7497ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9: 7507ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE: 7517ec681f3Smrg break; 7527ec681f3Smrg 7537ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_SHARPNESS: 7547ec681f3Smrg feature_enables[i] = vmixer->sharpness.enabled; 7557ec681f3Smrg break; 7567ec681f3Smrg 7577ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION: 7587ec681f3Smrg feature_enables[i] = vmixer->noise_reduction.enabled; 7597ec681f3Smrg break; 7607ec681f3Smrg 7617ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY: 7627ec681f3Smrg feature_enables[i] = vmixer->luma_key.enabled; 7637ec681f3Smrg break; 7647ec681f3Smrg 7657ec681f3Smrg case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1: 7667ec681f3Smrg feature_enables[i] = vmixer->bicubic.enabled; 7677ec681f3Smrg break; 7687ec681f3Smrg 7697ec681f3Smrg default: 7707ec681f3Smrg return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE; 7717ec681f3Smrg } 7727ec681f3Smrg } 7737ec681f3Smrg 7747ec681f3Smrg return VDP_STATUS_OK; 7757ec681f3Smrg} 7767ec681f3Smrg 7777ec681f3Smrg/** 7787ec681f3Smrg * Set attribute values. 7797ec681f3Smrg */ 7807ec681f3SmrgVdpStatus 7817ec681f3SmrgvlVdpVideoMixerSetAttributeValues(VdpVideoMixer mixer, 7827ec681f3Smrg uint32_t attribute_count, 7837ec681f3Smrg VdpVideoMixerAttribute const *attributes, 7847ec681f3Smrg void const *const *attribute_values) 7857ec681f3Smrg{ 7867ec681f3Smrg const VdpColor *background_color; 7877ec681f3Smrg union pipe_color_union color; 7887ec681f3Smrg const float *vdp_csc; 7897ec681f3Smrg float val; 7907ec681f3Smrg unsigned i; 7917ec681f3Smrg VdpStatus ret; 7927ec681f3Smrg 7937ec681f3Smrg if (!(attributes && attribute_values)) 7947ec681f3Smrg return VDP_STATUS_INVALID_POINTER; 7957ec681f3Smrg 7967ec681f3Smrg vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer); 7977ec681f3Smrg if (!vmixer) 7987ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 7997ec681f3Smrg 8007ec681f3Smrg mtx_lock(&vmixer->device->mutex); 8017ec681f3Smrg for (i = 0; i < attribute_count; ++i) { 8027ec681f3Smrg switch (attributes[i]) { 8037ec681f3Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR: 8047ec681f3Smrg background_color = attribute_values[i]; 8057ec681f3Smrg color.f[0] = background_color->red; 8067ec681f3Smrg color.f[1] = background_color->green; 8077ec681f3Smrg color.f[2] = background_color->blue; 8087ec681f3Smrg color.f[3] = background_color->alpha; 8097ec681f3Smrg vl_compositor_set_clear_color(&vmixer->cstate, &color); 8107ec681f3Smrg break; 8117ec681f3Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX: 8127ec681f3Smrg vdp_csc = attribute_values[i]; 8137ec681f3Smrg vmixer->custom_csc = !!vdp_csc; 8147ec681f3Smrg if (!vdp_csc) 8157ec681f3Smrg vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, 1, &vmixer->csc); 8167ec681f3Smrg else 8177ec681f3Smrg memcpy(vmixer->csc, vdp_csc, sizeof(vl_csc_matrix)); 8187ec681f3Smrg if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) 8197ec681f3Smrg if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 8207ec681f3Smrg vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) { 8217ec681f3Smrg ret = VDP_STATUS_ERROR; 8227ec681f3Smrg goto fail; 8237ec681f3Smrg } 8247ec681f3Smrg break; 8257ec681f3Smrg 8267ec681f3Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL: 8277ec681f3Smrg 8287ec681f3Smrg val = *(float*)attribute_values[i]; 8297ec681f3Smrg if (val < 0.0f || val > 1.0f) { 8307ec681f3Smrg ret = VDP_STATUS_INVALID_VALUE; 8317ec681f3Smrg goto fail; 8327ec681f3Smrg } 8337ec681f3Smrg 8347ec681f3Smrg vmixer->noise_reduction.level = val * 10; 8357ec681f3Smrg vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer); 8367ec681f3Smrg break; 8377ec681f3Smrg 8387ec681f3Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA: 8397ec681f3Smrg val = *(float*)attribute_values[i]; 8407ec681f3Smrg if (val < 0.0f || val > 1.0f) { 8417ec681f3Smrg ret = VDP_STATUS_INVALID_VALUE; 8427ec681f3Smrg goto fail; 8437ec681f3Smrg } 8447ec681f3Smrg vmixer->luma_key.luma_min = val; 8457ec681f3Smrg if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) 8467ec681f3Smrg if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 8477ec681f3Smrg vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) { 8487ec681f3Smrg ret = VDP_STATUS_ERROR; 8497ec681f3Smrg goto fail; 8507ec681f3Smrg } 8517ec681f3Smrg break; 8527ec681f3Smrg 8537ec681f3Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA: 8547ec681f3Smrg val = *(float*)attribute_values[i]; 8557ec681f3Smrg if (val < 0.0f || val > 1.0f) { 8567ec681f3Smrg ret = VDP_STATUS_INVALID_VALUE; 8577ec681f3Smrg goto fail; 8587ec681f3Smrg } 8597ec681f3Smrg vmixer->luma_key.luma_max = val; 8607ec681f3Smrg if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) 8617ec681f3Smrg if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 8627ec681f3Smrg vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) { 8637ec681f3Smrg ret = VDP_STATUS_ERROR; 8647ec681f3Smrg goto fail; 8657ec681f3Smrg } 8667ec681f3Smrg break; 8677ec681f3Smrg 8687ec681f3Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL: 8697ec681f3Smrg 8707ec681f3Smrg val = *(float*)attribute_values[i]; 8717ec681f3Smrg if (val < -1.0f || val > 1.0f) { 8727ec681f3Smrg ret = VDP_STATUS_INVALID_VALUE; 8737ec681f3Smrg goto fail; 8747ec681f3Smrg } 8757ec681f3Smrg 8767ec681f3Smrg vmixer->sharpness.value = val; 8777ec681f3Smrg vlVdpVideoMixerUpdateSharpnessFilter(vmixer); 8787ec681f3Smrg break; 8797ec681f3Smrg 8807ec681f3Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE: 8817ec681f3Smrg if (*(uint8_t*)attribute_values[i] > 1) { 8827ec681f3Smrg ret = VDP_STATUS_INVALID_VALUE; 8837ec681f3Smrg goto fail; 8847ec681f3Smrg } 8857ec681f3Smrg vmixer->skip_chroma_deint = *(uint8_t*)attribute_values[i]; 8867ec681f3Smrg vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer); 8877ec681f3Smrg break; 8887ec681f3Smrg default: 8897ec681f3Smrg ret = VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE; 8907ec681f3Smrg goto fail; 8917ec681f3Smrg } 8927ec681f3Smrg } 8937ec681f3Smrg mtx_unlock(&vmixer->device->mutex); 8947ec681f3Smrg 8957ec681f3Smrg return VDP_STATUS_OK; 8967ec681f3Smrgfail: 8977ec681f3Smrg mtx_unlock(&vmixer->device->mutex); 8987ec681f3Smrg return ret; 8997ec681f3Smrg} 9007ec681f3Smrg 9017ec681f3Smrg/** 9027ec681f3Smrg * Retrieve parameter values given at creation time. 9037ec681f3Smrg */ 9047ec681f3SmrgVdpStatus 9057ec681f3SmrgvlVdpVideoMixerGetParameterValues(VdpVideoMixer mixer, 9067ec681f3Smrg uint32_t parameter_count, 9077ec681f3Smrg VdpVideoMixerParameter const *parameters, 9087ec681f3Smrg void *const *parameter_values) 9097ec681f3Smrg{ 9107ec681f3Smrg vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer); 9117ec681f3Smrg unsigned i; 9127ec681f3Smrg if (!vmixer) 9137ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 9147ec681f3Smrg 9157ec681f3Smrg if (!parameter_count) 9167ec681f3Smrg return VDP_STATUS_OK; 9177ec681f3Smrg if (!(parameters && parameter_values)) 9187ec681f3Smrg return VDP_STATUS_INVALID_POINTER; 9197ec681f3Smrg for (i = 0; i < parameter_count; ++i) { 9207ec681f3Smrg switch (parameters[i]) { 9217ec681f3Smrg case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH: 9227ec681f3Smrg *(uint32_t*)parameter_values[i] = vmixer->video_width; 9237ec681f3Smrg break; 9247ec681f3Smrg case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT: 9257ec681f3Smrg *(uint32_t*)parameter_values[i] = vmixer->video_height; 9267ec681f3Smrg break; 9277ec681f3Smrg case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE: 9287ec681f3Smrg *(VdpChromaType*)parameter_values[i] = PipeToChroma(vmixer->chroma_format); 9297ec681f3Smrg break; 9307ec681f3Smrg case VDP_VIDEO_MIXER_PARAMETER_LAYERS: 9317ec681f3Smrg *(uint32_t*)parameter_values[i] = vmixer->max_layers; 9327ec681f3Smrg break; 9337ec681f3Smrg default: 9347ec681f3Smrg return VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER; 9357ec681f3Smrg } 9367ec681f3Smrg } 9377ec681f3Smrg return VDP_STATUS_OK; 9387ec681f3Smrg} 9397ec681f3Smrg 9407ec681f3Smrg/** 9417ec681f3Smrg * Retrieve current attribute values. 9427ec681f3Smrg */ 9437ec681f3SmrgVdpStatus 9447ec681f3SmrgvlVdpVideoMixerGetAttributeValues(VdpVideoMixer mixer, 9457ec681f3Smrg uint32_t attribute_count, 9467ec681f3Smrg VdpVideoMixerAttribute const *attributes, 9477ec681f3Smrg void *const *attribute_values) 9487ec681f3Smrg{ 9497ec681f3Smrg unsigned i; 9507ec681f3Smrg VdpCSCMatrix **vdp_csc; 9517ec681f3Smrg 9527ec681f3Smrg if (!(attributes && attribute_values)) 9537ec681f3Smrg return VDP_STATUS_INVALID_POINTER; 9547ec681f3Smrg 9557ec681f3Smrg vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer); 9567ec681f3Smrg if (!vmixer) 9577ec681f3Smrg return VDP_STATUS_INVALID_HANDLE; 9587ec681f3Smrg 9597ec681f3Smrg mtx_lock(&vmixer->device->mutex); 9607ec681f3Smrg for (i = 0; i < attribute_count; ++i) { 9617ec681f3Smrg switch (attributes[i]) { 9627ec681f3Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR: 9637ec681f3Smrg vl_compositor_get_clear_color(&vmixer->cstate, attribute_values[i]); 9647ec681f3Smrg break; 9657ec681f3Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX: 9667ec681f3Smrg vdp_csc = attribute_values[i]; 9677ec681f3Smrg if (!vmixer->custom_csc) { 9687ec681f3Smrg *vdp_csc = NULL; 9697ec681f3Smrg break; 9707ec681f3Smrg } 9717ec681f3Smrg memcpy(*vdp_csc, vmixer->csc, sizeof(float)*12); 9727ec681f3Smrg break; 9737ec681f3Smrg 9747ec681f3Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL: 9757ec681f3Smrg *(float*)attribute_values[i] = (float)vmixer->noise_reduction.level / 10.0f; 9767ec681f3Smrg break; 9777ec681f3Smrg 9787ec681f3Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA: 9797ec681f3Smrg *(float*)attribute_values[i] = vmixer->luma_key.luma_min; 9807ec681f3Smrg break; 9817ec681f3Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA: 9827ec681f3Smrg *(float*)attribute_values[i] = vmixer->luma_key.luma_max; 9837ec681f3Smrg break; 9847ec681f3Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL: 9857ec681f3Smrg *(float*)attribute_values[i] = vmixer->sharpness.value; 9867ec681f3Smrg break; 9877ec681f3Smrg case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE: 9887ec681f3Smrg *(uint8_t*)attribute_values[i] = vmixer->skip_chroma_deint; 9897ec681f3Smrg break; 9907ec681f3Smrg default: 9917ec681f3Smrg mtx_unlock(&vmixer->device->mutex); 9927ec681f3Smrg return VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE; 9937ec681f3Smrg } 9947ec681f3Smrg } 9957ec681f3Smrg mtx_unlock(&vmixer->device->mutex); 9967ec681f3Smrg return VDP_STATUS_OK; 9977ec681f3Smrg} 9987ec681f3Smrg 9997ec681f3Smrg/** 10007ec681f3Smrg * Generate a color space conversion matrix. 10017ec681f3Smrg */ 10027ec681f3SmrgVdpStatus 10037ec681f3SmrgvlVdpGenerateCSCMatrix(VdpProcamp *procamp, 10047ec681f3Smrg VdpColorStandard standard, 10057ec681f3Smrg VdpCSCMatrix *csc_matrix) 10067ec681f3Smrg{ 10077ec681f3Smrg enum VL_CSC_COLOR_STANDARD vl_std; 10087ec681f3Smrg struct vl_procamp camp; 10097ec681f3Smrg 10107ec681f3Smrg if (!csc_matrix) 10117ec681f3Smrg return VDP_STATUS_INVALID_POINTER; 10127ec681f3Smrg 10137ec681f3Smrg switch (standard) { 10147ec681f3Smrg case VDP_COLOR_STANDARD_ITUR_BT_601: vl_std = VL_CSC_COLOR_STANDARD_BT_601; break; 10157ec681f3Smrg case VDP_COLOR_STANDARD_ITUR_BT_709: vl_std = VL_CSC_COLOR_STANDARD_BT_709; break; 10167ec681f3Smrg case VDP_COLOR_STANDARD_SMPTE_240M: vl_std = VL_CSC_COLOR_STANDARD_SMPTE_240M; break; 10177ec681f3Smrg default: return VDP_STATUS_INVALID_COLOR_STANDARD; 10187ec681f3Smrg } 10197ec681f3Smrg 10207ec681f3Smrg if (procamp) { 10217ec681f3Smrg if (procamp->struct_version > VDP_PROCAMP_VERSION) 10227ec681f3Smrg return VDP_STATUS_INVALID_STRUCT_VERSION; 10237ec681f3Smrg camp.brightness = procamp->brightness; 10247ec681f3Smrg camp.contrast = procamp->contrast; 10257ec681f3Smrg camp.saturation = procamp->saturation; 10267ec681f3Smrg camp.hue = procamp->hue; 10277ec681f3Smrg } 10287ec681f3Smrg 10297ec681f3Smrg vl_csc_get_matrix(vl_std, procamp ? &camp : NULL, true, csc_matrix); 10307ec681f3Smrg return VDP_STATUS_OK; 10317ec681f3Smrg} 1032