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