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