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