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 = ▭
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