tu: Implement fallback linear staging blit for CopyImage
[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 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 > 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
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 */
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 prect = RectToPipe(video_source_rect, &rect);
335 if (!prect) {
336 rect.x0 = 0;
337 rect.y0 = 0;
338 rect.x1 = surf->templat.width;
339 rect.y1 = surf->templat.height;
340 prect = &rect;
341 }
342 vl_compositor_set_buffer_layer(&vmixer->cstate, compositor, layer, video_buffer, prect, NULL, deinterlace);
343
344 if (vmixer->bicubic.filter || vmixer->sharpness.filter || vmixer->noise_reduction.filter) {
345 pipe = vmixer->device->context;
346 memset(&res_tmpl, 0, sizeof(res_tmpl));
347
348 res_tmpl.target = PIPE_TEXTURE_2D;
349 res_tmpl.format = dst->sampler_view->format;
350 res_tmpl.depth0 = 1;
351 res_tmpl.array_size = 1;
352 res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
353 res_tmpl.usage = PIPE_USAGE_DEFAULT;
354
355 if (!vmixer->bicubic.filter) {
356 res_tmpl.width0 = dst->surface->width;
357 res_tmpl.height0 = dst->surface->height;
358 } else {
359 res_tmpl.width0 = surf->templat.width;
360 res_tmpl.height0 = surf->templat.height;
361 }
362
363 res = pipe->screen->resource_create(pipe->screen, &res_tmpl);
364
365 vlVdpDefaultSamplerViewTemplate(&sv_templ, res);
366 sampler_view = pipe->create_sampler_view(pipe, res, &sv_templ);
367
368 memset(&surf_templ, 0, sizeof(surf_templ));
369 surf_templ.format = res->format;
370 surface = pipe->create_surface(pipe, res, &surf_templ);
371
372 vl_compositor_reset_dirty_area(&dirty_area);
373 pipe_resource_reference(&res, NULL);
374 } else {
375 surface = dst->surface;
376 sampler_view = dst->sampler_view;
377 dirty_area = dst->dirty_area;
378 }
379
380 if (!vmixer->bicubic.filter) {
381 vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(destination_video_rect, &rect));
382 vl_compositor_set_dst_clip(&vmixer->cstate, RectToPipe(destination_rect, &clip));
383 }
384
385 for (i = 0; i < layer_count; ++i) {
386 vlVdpOutputSurface *src = vlGetDataHTAB(layers->source_surface);
387 if (!src) {
388 mtx_unlock(&vmixer->device->mutex);
389 return VDP_STATUS_INVALID_HANDLE;
390 }
391
392 assert(layers->struct_version == VDP_LAYER_VERSION);
393
394 vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer, src->sampler_view,
395 RectToPipe(layers->source_rect, &rect), NULL, NULL);
396 vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(layers->destination_rect, &rect));
397
398 ++layers;
399 }
400
401 vl_compositor_render(&vmixer->cstate, compositor, surface, &dirty_area, true);
402
403 if (vmixer->noise_reduction.filter) {
404 if (!vmixer->sharpness.filter && !vmixer->bicubic.filter) {
405 vl_median_filter_render(vmixer->noise_reduction.filter,
406 sampler_view, dst->surface);
407 } else {
408 res = pipe->screen->resource_create(pipe->screen, &res_tmpl);
409 struct pipe_sampler_view *sampler_view_temp = pipe->create_sampler_view(pipe, res, &sv_templ);
410 struct pipe_surface *surface_temp = pipe->create_surface(pipe, res, &surf_templ);
411 pipe_resource_reference(&res, NULL);
412
413 vl_median_filter_render(vmixer->noise_reduction.filter,
414 sampler_view, surface_temp);
415
416 pipe_sampler_view_reference(&sampler_view, NULL);
417 pipe_surface_reference(&surface, NULL);
418
419 sampler_view = sampler_view_temp;
420 surface = surface_temp;
421 }
422 }
423
424 if (vmixer->sharpness.filter) {
425 if (!vmixer->bicubic.filter) {
426 vl_matrix_filter_render(vmixer->sharpness.filter,
427 sampler_view, dst->surface);
428 } else {
429 res = pipe->screen->resource_create(pipe->screen, &res_tmpl);
430 struct pipe_sampler_view *sampler_view_temp = pipe->create_sampler_view(pipe, res, &sv_templ);
431 struct pipe_surface *surface_temp = pipe->create_surface(pipe, res, &surf_templ);
432 pipe_resource_reference(&res, NULL);
433
434 vl_matrix_filter_render(vmixer->sharpness.filter,
435 sampler_view, surface_temp);
436
437 pipe_sampler_view_reference(&sampler_view, NULL);
438 pipe_surface_reference(&surface, NULL);
439
440 sampler_view = sampler_view_temp;
441 surface = surface_temp;
442 }
443 }
444
445 if (vmixer->bicubic.filter)
446 vl_bicubic_filter_render(vmixer->bicubic.filter,
447 sampler_view, dst->surface,
448 RectToPipe(destination_video_rect, &rect),
449 RectToPipe(destination_rect, &clip));
450
451 if(surface != dst->surface) {
452 pipe_sampler_view_reference(&sampler_view, NULL);
453 pipe_surface_reference(&surface, NULL);
454 }
455 mtx_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 mtx_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 if (!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 mtx_unlock(&vmixer->device->mutex);
696 return VDP_STATUS_ERROR;
697 }
698 break;
699
700 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
701 vmixer->bicubic.enabled = feature_enables[i];
702 vlVdpVideoMixerUpdateBicubicFilter(vmixer);
703 break;
704
705 default:
706 mtx_unlock(&vmixer->device->mutex);
707 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
708 }
709 }
710 mtx_unlock(&vmixer->device->mutex);
711
712 return VDP_STATUS_OK;
713 }
714
715 /**
716 * Retrieve whether features are enabled.
717 */
718 VdpStatus
719 vlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer,
720 uint32_t feature_count,
721 VdpVideoMixerFeature const *features,
722 VdpBool *feature_enables)
723 {
724 vlVdpVideoMixer *vmixer;
725 unsigned i;
726
727 if (!(features && feature_enables))
728 return VDP_STATUS_INVALID_POINTER;
729
730 vmixer = vlGetDataHTAB(mixer);
731 if (!vmixer)
732 return VDP_STATUS_INVALID_HANDLE;
733
734 for (i = 0; i < feature_count; ++i) {
735 switch (features[i]) {
736 /* they are valid, but we doesn't support them */
737 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
738 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
739 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
740 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
741 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
742 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
743 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
744 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
745 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
746 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
747 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
748 break;
749
750 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
751 feature_enables[i] = vmixer->sharpness.enabled;
752 break;
753
754 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
755 feature_enables[i] = vmixer->noise_reduction.enabled;
756 break;
757
758 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
759 feature_enables[i] = vmixer->luma_key.enabled;
760 break;
761
762 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
763 feature_enables[i] = vmixer->bicubic.enabled;
764 break;
765
766 default:
767 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
768 }
769 }
770
771 return VDP_STATUS_OK;
772 }
773
774 /**
775 * Set attribute values.
776 */
777 VdpStatus
778 vlVdpVideoMixerSetAttributeValues(VdpVideoMixer mixer,
779 uint32_t attribute_count,
780 VdpVideoMixerAttribute const *attributes,
781 void const *const *attribute_values)
782 {
783 const VdpColor *background_color;
784 union pipe_color_union color;
785 const float *vdp_csc;
786 float val;
787 unsigned i;
788 VdpStatus ret;
789
790 if (!(attributes && attribute_values))
791 return VDP_STATUS_INVALID_POINTER;
792
793 vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
794 if (!vmixer)
795 return VDP_STATUS_INVALID_HANDLE;
796
797 mtx_lock(&vmixer->device->mutex);
798 for (i = 0; i < attribute_count; ++i) {
799 switch (attributes[i]) {
800 case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR:
801 background_color = attribute_values[i];
802 color.f[0] = background_color->red;
803 color.f[1] = background_color->green;
804 color.f[2] = background_color->blue;
805 color.f[3] = background_color->alpha;
806 vl_compositor_set_clear_color(&vmixer->cstate, &color);
807 break;
808 case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX:
809 vdp_csc = attribute_values[i];
810 vmixer->custom_csc = !!vdp_csc;
811 if (!vdp_csc)
812 vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, 1, &vmixer->csc);
813 else
814 memcpy(vmixer->csc, vdp_csc, sizeof(vl_csc_matrix));
815 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))
816 if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc,
817 vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) {
818 ret = VDP_STATUS_ERROR;
819 goto fail;
820 }
821 break;
822
823 case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL:
824
825 val = *(float*)attribute_values[i];
826 if (val < 0.0f || val > 1.0f) {
827 ret = VDP_STATUS_INVALID_VALUE;
828 goto fail;
829 }
830
831 vmixer->noise_reduction.level = val * 10;
832 vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer);
833 break;
834
835 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA:
836 val = *(float*)attribute_values[i];
837 if (val < 0.0f || val > 1.0f) {
838 ret = VDP_STATUS_INVALID_VALUE;
839 goto fail;
840 }
841 vmixer->luma_key.luma_min = val;
842 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))
843 if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc,
844 vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) {
845 ret = VDP_STATUS_ERROR;
846 goto fail;
847 }
848 break;
849
850 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA:
851 val = *(float*)attribute_values[i];
852 if (val < 0.0f || val > 1.0f) {
853 ret = VDP_STATUS_INVALID_VALUE;
854 goto fail;
855 }
856 vmixer->luma_key.luma_max = val;
857 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))
858 if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc,
859 vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) {
860 ret = VDP_STATUS_ERROR;
861 goto fail;
862 }
863 break;
864
865 case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL:
866
867 val = *(float*)attribute_values[i];
868 if (val < -1.0f || val > 1.0f) {
869 ret = VDP_STATUS_INVALID_VALUE;
870 goto fail;
871 }
872
873 vmixer->sharpness.value = val;
874 vlVdpVideoMixerUpdateSharpnessFilter(vmixer);
875 break;
876
877 case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE:
878 if (*(uint8_t*)attribute_values[i] > 1) {
879 ret = VDP_STATUS_INVALID_VALUE;
880 goto fail;
881 }
882 vmixer->skip_chroma_deint = *(uint8_t*)attribute_values[i];
883 vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer);
884 break;
885 default:
886 ret = VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE;
887 goto fail;
888 }
889 }
890 mtx_unlock(&vmixer->device->mutex);
891
892 return VDP_STATUS_OK;
893 fail:
894 mtx_unlock(&vmixer->device->mutex);
895 return ret;
896 }
897
898 /**
899 * Retrieve parameter values given at creation time.
900 */
901 VdpStatus
902 vlVdpVideoMixerGetParameterValues(VdpVideoMixer mixer,
903 uint32_t parameter_count,
904 VdpVideoMixerParameter const *parameters,
905 void *const *parameter_values)
906 {
907 vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
908 unsigned i;
909 if (!vmixer)
910 return VDP_STATUS_INVALID_HANDLE;
911
912 if (!parameter_count)
913 return VDP_STATUS_OK;
914 if (!(parameters && parameter_values))
915 return VDP_STATUS_INVALID_POINTER;
916 for (i = 0; i < parameter_count; ++i) {
917 switch (parameters[i]) {
918 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH:
919 *(uint32_t*)parameter_values[i] = vmixer->video_width;
920 break;
921 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT:
922 *(uint32_t*)parameter_values[i] = vmixer->video_height;
923 break;
924 case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE:
925 *(VdpChromaType*)parameter_values[i] = PipeToChroma(vmixer->chroma_format);
926 break;
927 case VDP_VIDEO_MIXER_PARAMETER_LAYERS:
928 *(uint32_t*)parameter_values[i] = vmixer->max_layers;
929 break;
930 default:
931 return VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER;
932 }
933 }
934 return VDP_STATUS_OK;
935 }
936
937 /**
938 * Retrieve current attribute values.
939 */
940 VdpStatus
941 vlVdpVideoMixerGetAttributeValues(VdpVideoMixer mixer,
942 uint32_t attribute_count,
943 VdpVideoMixerAttribute const *attributes,
944 void *const *attribute_values)
945 {
946 unsigned i;
947 VdpCSCMatrix **vdp_csc;
948
949 if (!(attributes && attribute_values))
950 return VDP_STATUS_INVALID_POINTER;
951
952 vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
953 if (!vmixer)
954 return VDP_STATUS_INVALID_HANDLE;
955
956 mtx_lock(&vmixer->device->mutex);
957 for (i = 0; i < attribute_count; ++i) {
958 switch (attributes[i]) {
959 case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR:
960 vl_compositor_get_clear_color(&vmixer->cstate, attribute_values[i]);
961 break;
962 case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX:
963 vdp_csc = attribute_values[i];
964 if (!vmixer->custom_csc) {
965 *vdp_csc = NULL;
966 break;
967 }
968 memcpy(*vdp_csc, vmixer->csc, sizeof(float)*12);
969 break;
970
971 case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL:
972 *(float*)attribute_values[i] = (float)vmixer->noise_reduction.level / 10.0f;
973 break;
974
975 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA:
976 *(float*)attribute_values[i] = vmixer->luma_key.luma_min;
977 break;
978 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA:
979 *(float*)attribute_values[i] = vmixer->luma_key.luma_max;
980 break;
981 case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL:
982 *(float*)attribute_values[i] = vmixer->sharpness.value;
983 break;
984 case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE:
985 *(uint8_t*)attribute_values[i] = vmixer->skip_chroma_deint;
986 break;
987 default:
988 mtx_unlock(&vmixer->device->mutex);
989 return VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE;
990 }
991 }
992 mtx_unlock(&vmixer->device->mutex);
993 return VDP_STATUS_OK;
994 }
995
996 /**
997 * Generate a color space conversion matrix.
998 */
999 VdpStatus
1000 vlVdpGenerateCSCMatrix(VdpProcamp *procamp,
1001 VdpColorStandard standard,
1002 VdpCSCMatrix *csc_matrix)
1003 {
1004 enum VL_CSC_COLOR_STANDARD vl_std;
1005 struct vl_procamp camp;
1006
1007 if (!csc_matrix)
1008 return VDP_STATUS_INVALID_POINTER;
1009
1010 switch (standard) {
1011 case VDP_COLOR_STANDARD_ITUR_BT_601: vl_std = VL_CSC_COLOR_STANDARD_BT_601; break;
1012 case VDP_COLOR_STANDARD_ITUR_BT_709: vl_std = VL_CSC_COLOR_STANDARD_BT_709; break;
1013 case VDP_COLOR_STANDARD_SMPTE_240M: vl_std = VL_CSC_COLOR_STANDARD_SMPTE_240M; break;
1014 default: return VDP_STATUS_INVALID_COLOR_STANDARD;
1015 }
1016
1017 if (procamp) {
1018 if (procamp->struct_version > VDP_PROCAMP_VERSION)
1019 return VDP_STATUS_INVALID_STRUCT_VERSION;
1020 camp.brightness = procamp->brightness;
1021 camp.contrast = procamp->contrast;
1022 camp.saturation = procamp->saturation;
1023 camp.hue = procamp->hue;
1024 }
1025
1026 vl_csc_get_matrix(vl_std, procamp ? &camp : NULL, true, csc_matrix);
1027 return VDP_STATUS_OK;
1028 }