Path: blob/21.2-virgl/src/gallium/frontends/vdpau/mixer.c
4565 views
/**************************************************************************1*2* Copyright 2010 Thomas Balling Sørensen.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/2627#include <vdpau/vdpau.h>2829#include "util/u_memory.h"30#include "util/u_debug.h"3132#include "vl/vl_csc.h"3334#include "vdpau_private.h"3536/**37* Create a VdpVideoMixer.38*/39VdpStatus40vlVdpVideoMixerCreate(VdpDevice device,41uint32_t feature_count,42VdpVideoMixerFeature const *features,43uint32_t parameter_count,44VdpVideoMixerParameter const *parameters,45void const *const *parameter_values,46VdpVideoMixer *mixer)47{48vlVdpVideoMixer *vmixer = NULL;49VdpStatus ret;50struct pipe_screen *screen;51unsigned max_size, i;5253vlVdpDevice *dev = vlGetDataHTAB(device);54if (!dev)55return VDP_STATUS_INVALID_HANDLE;56screen = dev->vscreen->pscreen;5758vmixer = CALLOC(1, sizeof(vlVdpVideoMixer));59if (!vmixer)60return VDP_STATUS_RESOURCES;6162DeviceReference(&vmixer->device, dev);6364mtx_lock(&dev->mutex);6566if (!vl_compositor_init_state(&vmixer->cstate, dev->context)) {67ret = VDP_STATUS_ERROR;68goto no_compositor_state;69}7071vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, true, &vmixer->csc);72if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) {73if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 1.0f, 0.0f)) {74ret = VDP_STATUS_ERROR;75goto err_csc_matrix;76}77}7879*mixer = vlAddDataHTAB(vmixer);80if (*mixer == 0) {81ret = VDP_STATUS_ERROR;82goto no_handle;83}8485ret = VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;86for (i = 0; i < feature_count; ++i) {87switch (features[i]) {88/* they are valid, but we doesn't support them */89case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:90case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:91case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:92case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:93case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:94case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:95case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:96case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:97case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:98case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:99break;100101case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:102vmixer->deint.supported = true;103break;104105case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:106vmixer->sharpness.supported = true;107break;108109case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:110vmixer->noise_reduction.supported = true;111break;112113case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:114vmixer->luma_key.supported = true;115break;116117case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:118vmixer->bicubic.supported = true;119break;120default: goto no_params;121}122}123124vmixer->chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;125ret = VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER;126for (i = 0; i < parameter_count; ++i) {127switch (parameters[i]) {128case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH:129vmixer->video_width = *(uint32_t*)parameter_values[i];130break;131case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT:132vmixer->video_height = *(uint32_t*)parameter_values[i];133break;134case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE:135vmixer->chroma_format = ChromaToPipe(*(VdpChromaType*)parameter_values[i]);136break;137case VDP_VIDEO_MIXER_PARAMETER_LAYERS:138vmixer->max_layers = *(uint32_t*)parameter_values[i];139break;140default: goto no_params;141}142}143ret = VDP_STATUS_INVALID_VALUE;144if (vmixer->max_layers > 4) {145VDPAU_MSG(VDPAU_WARN, "[VDPAU] Max layers %u > 4 not supported\n", vmixer->max_layers);146goto no_params;147}148149max_size = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_SIZE);150if (vmixer->video_width < 48 || vmixer->video_width > max_size) {151VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u not valid for width\n",152vmixer->video_width, max_size);153goto no_params;154}155if (vmixer->video_height < 48 || vmixer->video_height > max_size) {156VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u not valid for height\n",157vmixer->video_height, max_size);158goto no_params;159}160vmixer->luma_key.luma_min = 1.0f;161vmixer->luma_key.luma_max = 0.0f;162mtx_unlock(&dev->mutex);163164return VDP_STATUS_OK;165166no_params:167vlRemoveDataHTAB(*mixer);168169no_handle:170err_csc_matrix:171vl_compositor_cleanup_state(&vmixer->cstate);172no_compositor_state:173mtx_unlock(&dev->mutex);174DeviceReference(&vmixer->device, NULL);175FREE(vmixer);176return ret;177}178179/**180* Destroy a VdpVideoMixer.181*/182VdpStatus183vlVdpVideoMixerDestroy(VdpVideoMixer mixer)184{185vlVdpVideoMixer *vmixer;186187vmixer = vlGetDataHTAB(mixer);188if (!vmixer)189return VDP_STATUS_INVALID_HANDLE;190191mtx_lock(&vmixer->device->mutex);192193vlRemoveDataHTAB(mixer);194195vl_compositor_cleanup_state(&vmixer->cstate);196197if (vmixer->deint.filter) {198vl_deint_filter_cleanup(vmixer->deint.filter);199FREE(vmixer->deint.filter);200}201202if (vmixer->noise_reduction.filter) {203vl_median_filter_cleanup(vmixer->noise_reduction.filter);204FREE(vmixer->noise_reduction.filter);205}206207if (vmixer->sharpness.filter) {208vl_matrix_filter_cleanup(vmixer->sharpness.filter);209FREE(vmixer->sharpness.filter);210}211212if (vmixer->bicubic.filter) {213vl_bicubic_filter_cleanup(vmixer->bicubic.filter);214FREE(vmixer->bicubic.filter);215}216mtx_unlock(&vmixer->device->mutex);217DeviceReference(&vmixer->device, NULL);218219FREE(vmixer);220221return VDP_STATUS_OK;222}223224/**225* Perform a video post-processing and compositing operation.226*/227VdpStatus vlVdpVideoMixerRender(VdpVideoMixer mixer,228VdpOutputSurface background_surface,229VdpRect const *background_source_rect,230VdpVideoMixerPictureStructure current_picture_structure,231uint32_t video_surface_past_count,232VdpVideoSurface const *video_surface_past,233VdpVideoSurface video_surface_current,234uint32_t video_surface_future_count,235VdpVideoSurface const *video_surface_future,236VdpRect const *video_source_rect,237VdpOutputSurface destination_surface,238VdpRect const *destination_rect,239VdpRect const *destination_video_rect,240uint32_t layer_count,241VdpLayer const *layers)242{243enum vl_compositor_deinterlace deinterlace;244struct u_rect rect, clip, *prect, dirty_area;245unsigned i, layer = 0;246struct pipe_video_buffer *video_buffer;247struct pipe_sampler_view *sampler_view, sv_templ;248struct pipe_surface *surface, surf_templ;249struct pipe_context *pipe = NULL;250struct pipe_resource res_tmpl, *res;251252vlVdpVideoMixer *vmixer;253vlVdpSurface *surf;254vlVdpOutputSurface *dst, *bg = NULL;255256struct vl_compositor *compositor;257258vmixer = vlGetDataHTAB(mixer);259if (!vmixer)260return VDP_STATUS_INVALID_HANDLE;261262compositor = &vmixer->device->compositor;263264surf = vlGetDataHTAB(video_surface_current);265if (!surf)266return VDP_STATUS_INVALID_HANDLE;267video_buffer = surf->video_buffer;268269if (surf->device != vmixer->device)270return VDP_STATUS_HANDLE_DEVICE_MISMATCH;271272if (vmixer->video_width > video_buffer->width ||273vmixer->video_height > video_buffer->height ||274vmixer->chroma_format != pipe_format_to_chroma_format(video_buffer->buffer_format))275return VDP_STATUS_INVALID_SIZE;276277if (layer_count > vmixer->max_layers)278return VDP_STATUS_INVALID_VALUE;279280dst = vlGetDataHTAB(destination_surface);281if (!dst)282return VDP_STATUS_INVALID_HANDLE;283284if (background_surface != VDP_INVALID_HANDLE) {285bg = vlGetDataHTAB(background_surface);286if (!bg)287return VDP_STATUS_INVALID_HANDLE;288}289290mtx_lock(&vmixer->device->mutex);291292vl_compositor_clear_layers(&vmixer->cstate);293294if (bg)295vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer++, bg->sampler_view,296RectToPipe(background_source_rect, &rect), NULL, NULL);297298switch (current_picture_structure) {299case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD:300deinterlace = VL_COMPOSITOR_BOB_TOP;301break;302303case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD:304deinterlace = VL_COMPOSITOR_BOB_BOTTOM;305break;306307case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME:308deinterlace = VL_COMPOSITOR_WEAVE;309break;310311default:312mtx_unlock(&vmixer->device->mutex);313return VDP_STATUS_INVALID_VIDEO_MIXER_PICTURE_STRUCTURE;314}315316if (deinterlace != VL_COMPOSITOR_WEAVE && vmixer->deint.enabled &&317video_surface_past_count > 1 && video_surface_future_count > 0) {318vlVdpSurface *prevprev = vlGetDataHTAB(video_surface_past[1]);319vlVdpSurface *prev = vlGetDataHTAB(video_surface_past[0]);320vlVdpSurface *next = vlGetDataHTAB(video_surface_future[0]);321if (prevprev && prev && next &&322vl_deint_filter_check_buffers(vmixer->deint.filter,323prevprev->video_buffer, prev->video_buffer, surf->video_buffer, next->video_buffer)) {324vl_deint_filter_render(vmixer->deint.filter, prevprev->video_buffer,325prev->video_buffer, surf->video_buffer,326next->video_buffer,327deinterlace == VL_COMPOSITOR_BOB_BOTTOM);328deinterlace = VL_COMPOSITOR_WEAVE;329video_buffer = vmixer->deint.filter->video_buffer;330}331}332333if (!destination_video_rect)334destination_video_rect = video_source_rect;335336prect = RectToPipe(video_source_rect, &rect);337if (!prect) {338rect.x0 = 0;339rect.y0 = 0;340rect.x1 = surf->templat.width;341rect.y1 = surf->templat.height;342prect = ▭343}344vl_compositor_set_buffer_layer(&vmixer->cstate, compositor, layer, video_buffer, prect, NULL, deinterlace);345346if (vmixer->bicubic.filter || vmixer->sharpness.filter || vmixer->noise_reduction.filter) {347pipe = vmixer->device->context;348memset(&res_tmpl, 0, sizeof(res_tmpl));349350res_tmpl.target = PIPE_TEXTURE_2D;351res_tmpl.format = dst->sampler_view->format;352res_tmpl.depth0 = 1;353res_tmpl.array_size = 1;354res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;355res_tmpl.usage = PIPE_USAGE_DEFAULT;356357if (!vmixer->bicubic.filter) {358res_tmpl.width0 = dst->surface->width;359res_tmpl.height0 = dst->surface->height;360} else {361res_tmpl.width0 = surf->templat.width;362res_tmpl.height0 = surf->templat.height;363}364365res = pipe->screen->resource_create(pipe->screen, &res_tmpl);366367vlVdpDefaultSamplerViewTemplate(&sv_templ, res);368sampler_view = pipe->create_sampler_view(pipe, res, &sv_templ);369370memset(&surf_templ, 0, sizeof(surf_templ));371surf_templ.format = res->format;372surface = pipe->create_surface(pipe, res, &surf_templ);373374vl_compositor_reset_dirty_area(&dirty_area);375pipe_resource_reference(&res, NULL);376} else {377surface = dst->surface;378sampler_view = dst->sampler_view;379dirty_area = dst->dirty_area;380}381382if (!vmixer->bicubic.filter) {383vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(destination_video_rect, &rect));384vl_compositor_set_dst_clip(&vmixer->cstate, RectToPipe(destination_rect, &clip));385}386387for (i = 0; i < layer_count; ++i) {388vlVdpOutputSurface *src = vlGetDataHTAB(layers->source_surface);389if (!src) {390mtx_unlock(&vmixer->device->mutex);391return VDP_STATUS_INVALID_HANDLE;392}393394assert(layers->struct_version == VDP_LAYER_VERSION);395396vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer, src->sampler_view,397RectToPipe(layers->source_rect, &rect), NULL, NULL);398vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(layers->destination_rect, &rect));399400++layers;401}402403vl_compositor_render(&vmixer->cstate, compositor, surface, &dirty_area, true);404405if (vmixer->noise_reduction.filter) {406if (!vmixer->sharpness.filter && !vmixer->bicubic.filter) {407vl_median_filter_render(vmixer->noise_reduction.filter,408sampler_view, dst->surface);409} else {410res = pipe->screen->resource_create(pipe->screen, &res_tmpl);411struct pipe_sampler_view *sampler_view_temp = pipe->create_sampler_view(pipe, res, &sv_templ);412struct pipe_surface *surface_temp = pipe->create_surface(pipe, res, &surf_templ);413pipe_resource_reference(&res, NULL);414415vl_median_filter_render(vmixer->noise_reduction.filter,416sampler_view, surface_temp);417418pipe_sampler_view_reference(&sampler_view, NULL);419pipe_surface_reference(&surface, NULL);420421sampler_view = sampler_view_temp;422surface = surface_temp;423}424}425426if (vmixer->sharpness.filter) {427if (!vmixer->bicubic.filter) {428vl_matrix_filter_render(vmixer->sharpness.filter,429sampler_view, dst->surface);430} else {431res = pipe->screen->resource_create(pipe->screen, &res_tmpl);432struct pipe_sampler_view *sampler_view_temp = pipe->create_sampler_view(pipe, res, &sv_templ);433struct pipe_surface *surface_temp = pipe->create_surface(pipe, res, &surf_templ);434pipe_resource_reference(&res, NULL);435436vl_matrix_filter_render(vmixer->sharpness.filter,437sampler_view, surface_temp);438439pipe_sampler_view_reference(&sampler_view, NULL);440pipe_surface_reference(&surface, NULL);441442sampler_view = sampler_view_temp;443surface = surface_temp;444}445}446447if (vmixer->bicubic.filter)448vl_bicubic_filter_render(vmixer->bicubic.filter,449sampler_view, dst->surface,450RectToPipe(destination_video_rect, &rect),451RectToPipe(destination_rect, &clip));452453if(surface != dst->surface) {454pipe_sampler_view_reference(&sampler_view, NULL);455pipe_surface_reference(&surface, NULL);456}457mtx_unlock(&vmixer->device->mutex);458459return VDP_STATUS_OK;460}461462static void463vlVdpVideoMixerUpdateDeinterlaceFilter(vlVdpVideoMixer *vmixer)464{465struct pipe_context *pipe = vmixer->device->context;466assert(vmixer);467468/* remove existing filter */469if (vmixer->deint.filter) {470vl_deint_filter_cleanup(vmixer->deint.filter);471FREE(vmixer->deint.filter);472vmixer->deint.filter = NULL;473}474475/* create a new filter if requested */476if (vmixer->deint.enabled && vmixer->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) {477vmixer->deint.filter = MALLOC(sizeof(struct vl_deint_filter));478vmixer->deint.enabled = vl_deint_filter_init(vmixer->deint.filter, pipe,479vmixer->video_width, vmixer->video_height,480vmixer->skip_chroma_deint, vmixer->deint.spatial);481if (!vmixer->deint.enabled) {482FREE(vmixer->deint.filter);483}484}485}486487/**488* Update the noise reduction setting489*/490static void491vlVdpVideoMixerUpdateNoiseReductionFilter(vlVdpVideoMixer *vmixer)492{493assert(vmixer);494495/* if present remove the old filter first */496if (vmixer->noise_reduction.filter) {497vl_median_filter_cleanup(vmixer->noise_reduction.filter);498FREE(vmixer->noise_reduction.filter);499vmixer->noise_reduction.filter = NULL;500}501502/* and create a new filter as needed */503if (vmixer->noise_reduction. enabled && vmixer->noise_reduction.level > 0) {504vmixer->noise_reduction.filter = MALLOC(sizeof(struct vl_median_filter));505vl_median_filter_init(vmixer->noise_reduction.filter, vmixer->device->context,506vmixer->video_width, vmixer->video_height,507vmixer->noise_reduction.level + 1,508VL_MEDIAN_FILTER_CROSS);509}510}511512static void513vlVdpVideoMixerUpdateSharpnessFilter(vlVdpVideoMixer *vmixer)514{515assert(vmixer);516517/* if present remove the old filter first */518if (vmixer->sharpness.filter) {519vl_matrix_filter_cleanup(vmixer->sharpness.filter);520FREE(vmixer->sharpness.filter);521vmixer->sharpness.filter = NULL;522}523524/* and create a new filter as needed */525if (vmixer->sharpness.enabled && vmixer->sharpness.value != 0.0f) {526float matrix[9];527unsigned i;528529if (vmixer->sharpness.value > 0.0f) {530matrix[0] = -1.0f; matrix[1] = -1.0f; matrix[2] = -1.0f;531matrix[3] = -1.0f; matrix[4] = 8.0f; matrix[5] = -1.0f;532matrix[6] = -1.0f; matrix[7] = -1.0f; matrix[8] = -1.0f;533534for (i = 0; i < 9; ++i)535matrix[i] *= vmixer->sharpness.value;536537matrix[4] += 1.0f;538539} else {540matrix[0] = 1.0f; matrix[1] = 2.0f; matrix[2] = 1.0f;541matrix[3] = 2.0f; matrix[4] = 4.0f; matrix[5] = 2.0f;542matrix[6] = 1.0f; matrix[7] = 2.0f; matrix[8] = 1.0f;543544for (i = 0; i < 9; ++i)545matrix[i] *= fabsf(vmixer->sharpness.value) / 16.0f;546547matrix[4] += 1.0f - fabsf(vmixer->sharpness.value);548}549550vmixer->sharpness.filter = MALLOC(sizeof(struct vl_matrix_filter));551vl_matrix_filter_init(vmixer->sharpness.filter, vmixer->device->context,552vmixer->video_width, vmixer->video_height,5533, 3, matrix);554}555}556557/**558* Update the bicubic filter559*/560static void561vlVdpVideoMixerUpdateBicubicFilter(vlVdpVideoMixer *vmixer)562{563assert(vmixer);564565/* if present remove the old filter first */566if (vmixer->bicubic.filter) {567vl_bicubic_filter_cleanup(vmixer->bicubic.filter);568FREE(vmixer->bicubic.filter);569vmixer->bicubic.filter = NULL;570}571/* and create a new filter as needed */572if (vmixer->bicubic.enabled) {573vmixer->bicubic.filter = MALLOC(sizeof(struct vl_bicubic_filter));574vl_bicubic_filter_init(vmixer->bicubic.filter, vmixer->device->context,575vmixer->video_width, vmixer->video_height);576}577}578579/**580* Retrieve whether features were requested at creation time.581*/582VdpStatus583vlVdpVideoMixerGetFeatureSupport(VdpVideoMixer mixer,584uint32_t feature_count,585VdpVideoMixerFeature const *features,586VdpBool *feature_supports)587{588vlVdpVideoMixer *vmixer;589unsigned i;590591if (!(features && feature_supports))592return VDP_STATUS_INVALID_POINTER;593594vmixer = vlGetDataHTAB(mixer);595if (!vmixer)596return VDP_STATUS_INVALID_HANDLE;597598for (i = 0; i < feature_count; ++i) {599switch (features[i]) {600/* they are valid, but we doesn't support them */601case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:602case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:603case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:604case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:605case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:606case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:607case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:608case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:609case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:610case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:611feature_supports[i] = false;612break;613614case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:615feature_supports[i] = vmixer->deint.supported;616break;617618case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:619feature_supports[i] = vmixer->sharpness.supported;620break;621622case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:623feature_supports[i] = vmixer->noise_reduction.supported;624break;625626case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:627feature_supports[i] = vmixer->luma_key.supported;628break;629630case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:631feature_supports[i] = vmixer->bicubic.supported;632break;633634default:635return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;636}637}638639return VDP_STATUS_OK;640}641642/**643* Enable or disable features.644*/645VdpStatus646vlVdpVideoMixerSetFeatureEnables(VdpVideoMixer mixer,647uint32_t feature_count,648VdpVideoMixerFeature const *features,649VdpBool const *feature_enables)650{651vlVdpVideoMixer *vmixer;652unsigned i;653654if (!(features && feature_enables))655return VDP_STATUS_INVALID_POINTER;656657vmixer = vlGetDataHTAB(mixer);658if (!vmixer)659return VDP_STATUS_INVALID_HANDLE;660661mtx_lock(&vmixer->device->mutex);662for (i = 0; i < feature_count; ++i) {663switch (features[i]) {664/* they are valid, but we doesn't support them */665case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:666case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:667case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:668case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:669case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:670case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:671case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:672case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:673case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:674case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:675break;676677case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:678vmixer->deint.enabled = feature_enables[i];679vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer);680break;681682case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:683vmixer->sharpness.enabled = feature_enables[i];684vlVdpVideoMixerUpdateSharpnessFilter(vmixer);685break;686687case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:688vmixer->noise_reduction.enabled = feature_enables[i];689vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer);690break;691692case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:693vmixer->luma_key.enabled = feature_enables[i];694if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))695if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc,696vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) {697mtx_unlock(&vmixer->device->mutex);698return VDP_STATUS_ERROR;699}700break;701702case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:703vmixer->bicubic.enabled = feature_enables[i];704vlVdpVideoMixerUpdateBicubicFilter(vmixer);705break;706707default:708mtx_unlock(&vmixer->device->mutex);709return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;710}711}712mtx_unlock(&vmixer->device->mutex);713714return VDP_STATUS_OK;715}716717/**718* Retrieve whether features are enabled.719*/720VdpStatus721vlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer,722uint32_t feature_count,723VdpVideoMixerFeature const *features,724VdpBool *feature_enables)725{726vlVdpVideoMixer *vmixer;727unsigned i;728729if (!(features && feature_enables))730return VDP_STATUS_INVALID_POINTER;731732vmixer = vlGetDataHTAB(mixer);733if (!vmixer)734return VDP_STATUS_INVALID_HANDLE;735736for (i = 0; i < feature_count; ++i) {737switch (features[i]) {738/* they are valid, but we doesn't support them */739case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:740case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:741case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:742case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:743case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:744case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:745case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:746case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:747case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:748case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:749case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:750break;751752case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:753feature_enables[i] = vmixer->sharpness.enabled;754break;755756case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:757feature_enables[i] = vmixer->noise_reduction.enabled;758break;759760case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:761feature_enables[i] = vmixer->luma_key.enabled;762break;763764case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:765feature_enables[i] = vmixer->bicubic.enabled;766break;767768default:769return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;770}771}772773return VDP_STATUS_OK;774}775776/**777* Set attribute values.778*/779VdpStatus780vlVdpVideoMixerSetAttributeValues(VdpVideoMixer mixer,781uint32_t attribute_count,782VdpVideoMixerAttribute const *attributes,783void const *const *attribute_values)784{785const VdpColor *background_color;786union pipe_color_union color;787const float *vdp_csc;788float val;789unsigned i;790VdpStatus ret;791792if (!(attributes && attribute_values))793return VDP_STATUS_INVALID_POINTER;794795vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);796if (!vmixer)797return VDP_STATUS_INVALID_HANDLE;798799mtx_lock(&vmixer->device->mutex);800for (i = 0; i < attribute_count; ++i) {801switch (attributes[i]) {802case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR:803background_color = attribute_values[i];804color.f[0] = background_color->red;805color.f[1] = background_color->green;806color.f[2] = background_color->blue;807color.f[3] = background_color->alpha;808vl_compositor_set_clear_color(&vmixer->cstate, &color);809break;810case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX:811vdp_csc = attribute_values[i];812vmixer->custom_csc = !!vdp_csc;813if (!vdp_csc)814vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, 1, &vmixer->csc);815else816memcpy(vmixer->csc, vdp_csc, sizeof(vl_csc_matrix));817if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))818if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc,819vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) {820ret = VDP_STATUS_ERROR;821goto fail;822}823break;824825case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL:826827val = *(float*)attribute_values[i];828if (val < 0.0f || val > 1.0f) {829ret = VDP_STATUS_INVALID_VALUE;830goto fail;831}832833vmixer->noise_reduction.level = val * 10;834vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer);835break;836837case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA:838val = *(float*)attribute_values[i];839if (val < 0.0f || val > 1.0f) {840ret = VDP_STATUS_INVALID_VALUE;841goto fail;842}843vmixer->luma_key.luma_min = val;844if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))845if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc,846vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) {847ret = VDP_STATUS_ERROR;848goto fail;849}850break;851852case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA:853val = *(float*)attribute_values[i];854if (val < 0.0f || val > 1.0f) {855ret = VDP_STATUS_INVALID_VALUE;856goto fail;857}858vmixer->luma_key.luma_max = val;859if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))860if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc,861vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) {862ret = VDP_STATUS_ERROR;863goto fail;864}865break;866867case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL:868869val = *(float*)attribute_values[i];870if (val < -1.0f || val > 1.0f) {871ret = VDP_STATUS_INVALID_VALUE;872goto fail;873}874875vmixer->sharpness.value = val;876vlVdpVideoMixerUpdateSharpnessFilter(vmixer);877break;878879case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE:880if (*(uint8_t*)attribute_values[i] > 1) {881ret = VDP_STATUS_INVALID_VALUE;882goto fail;883}884vmixer->skip_chroma_deint = *(uint8_t*)attribute_values[i];885vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer);886break;887default:888ret = VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE;889goto fail;890}891}892mtx_unlock(&vmixer->device->mutex);893894return VDP_STATUS_OK;895fail:896mtx_unlock(&vmixer->device->mutex);897return ret;898}899900/**901* Retrieve parameter values given at creation time.902*/903VdpStatus904vlVdpVideoMixerGetParameterValues(VdpVideoMixer mixer,905uint32_t parameter_count,906VdpVideoMixerParameter const *parameters,907void *const *parameter_values)908{909vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);910unsigned i;911if (!vmixer)912return VDP_STATUS_INVALID_HANDLE;913914if (!parameter_count)915return VDP_STATUS_OK;916if (!(parameters && parameter_values))917return VDP_STATUS_INVALID_POINTER;918for (i = 0; i < parameter_count; ++i) {919switch (parameters[i]) {920case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH:921*(uint32_t*)parameter_values[i] = vmixer->video_width;922break;923case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT:924*(uint32_t*)parameter_values[i] = vmixer->video_height;925break;926case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE:927*(VdpChromaType*)parameter_values[i] = PipeToChroma(vmixer->chroma_format);928break;929case VDP_VIDEO_MIXER_PARAMETER_LAYERS:930*(uint32_t*)parameter_values[i] = vmixer->max_layers;931break;932default:933return VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER;934}935}936return VDP_STATUS_OK;937}938939/**940* Retrieve current attribute values.941*/942VdpStatus943vlVdpVideoMixerGetAttributeValues(VdpVideoMixer mixer,944uint32_t attribute_count,945VdpVideoMixerAttribute const *attributes,946void *const *attribute_values)947{948unsigned i;949VdpCSCMatrix **vdp_csc;950951if (!(attributes && attribute_values))952return VDP_STATUS_INVALID_POINTER;953954vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);955if (!vmixer)956return VDP_STATUS_INVALID_HANDLE;957958mtx_lock(&vmixer->device->mutex);959for (i = 0; i < attribute_count; ++i) {960switch (attributes[i]) {961case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR:962vl_compositor_get_clear_color(&vmixer->cstate, attribute_values[i]);963break;964case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX:965vdp_csc = attribute_values[i];966if (!vmixer->custom_csc) {967*vdp_csc = NULL;968break;969}970memcpy(*vdp_csc, vmixer->csc, sizeof(float)*12);971break;972973case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL:974*(float*)attribute_values[i] = (float)vmixer->noise_reduction.level / 10.0f;975break;976977case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA:978*(float*)attribute_values[i] = vmixer->luma_key.luma_min;979break;980case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA:981*(float*)attribute_values[i] = vmixer->luma_key.luma_max;982break;983case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL:984*(float*)attribute_values[i] = vmixer->sharpness.value;985break;986case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE:987*(uint8_t*)attribute_values[i] = vmixer->skip_chroma_deint;988break;989default:990mtx_unlock(&vmixer->device->mutex);991return VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE;992}993}994mtx_unlock(&vmixer->device->mutex);995return VDP_STATUS_OK;996}997998/**999* Generate a color space conversion matrix.1000*/1001VdpStatus1002vlVdpGenerateCSCMatrix(VdpProcamp *procamp,1003VdpColorStandard standard,1004VdpCSCMatrix *csc_matrix)1005{1006enum VL_CSC_COLOR_STANDARD vl_std;1007struct vl_procamp camp;10081009if (!csc_matrix)1010return VDP_STATUS_INVALID_POINTER;10111012switch (standard) {1013case VDP_COLOR_STANDARD_ITUR_BT_601: vl_std = VL_CSC_COLOR_STANDARD_BT_601; break;1014case VDP_COLOR_STANDARD_ITUR_BT_709: vl_std = VL_CSC_COLOR_STANDARD_BT_709; break;1015case VDP_COLOR_STANDARD_SMPTE_240M: vl_std = VL_CSC_COLOR_STANDARD_SMPTE_240M; break;1016default: return VDP_STATUS_INVALID_COLOR_STANDARD;1017}10181019if (procamp) {1020if (procamp->struct_version > VDP_PROCAMP_VERSION)1021return VDP_STATUS_INVALID_STRUCT_VERSION;1022camp.brightness = procamp->brightness;1023camp.contrast = procamp->contrast;1024camp.saturation = procamp->saturation;1025camp.hue = procamp->hue;1026}10271028vl_csc_get_matrix(vl_std, procamp ? &camp : NULL, true, csc_matrix);1029return VDP_STATUS_OK;1030}103110321033