OSDN Git Service

vl/compositor: split shaders and state
[android-x86/external-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 TUNGSTEN GRAPHICS 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_width, max_height, i;
53    enum pipe_video_profile prof = PIPE_VIDEO_PROFILE_UNKNOWN;
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    vmixer->device = dev;
65    vl_compositor_init_state(&vmixer->cstate, dev->context);
66
67    vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, true, vmixer->csc);
68    if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))
69       vl_compositor_set_csc_matrix(&vmixer->cstate, vmixer->csc);
70
71    *mixer = vlAddDataHTAB(vmixer);
72    if (*mixer == 0) {
73       ret = VDP_STATUS_ERROR;
74       goto no_handle;
75    }
76
77    ret = VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
78    for (i = 0; i < feature_count; ++i) {
79       switch (features[i]) {
80       /* they are valid, but we doesn't support them */
81       case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
82       case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
83       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
84       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
85       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
86       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
87       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
88       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
89       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
90       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
91       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
92       case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
93       case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
94          break;
95
96       case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
97          vmixer->sharpness.supported = true;
98          break;
99
100       case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
101          vmixer->noise_reduction.supported = true;
102          break;
103
104       default: goto no_params;
105       }
106    }
107
108    vmixer->chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
109    ret = VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER;
110    for (i = 0; i < parameter_count; ++i) {
111       switch (parameters[i]) {
112       case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH:
113          vmixer->video_width = *(uint32_t*)parameter_values[i];
114          break;
115       case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT:
116          vmixer->video_height = *(uint32_t*)parameter_values[i];
117          break;
118       case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE:
119          vmixer->chroma_format = ChromaToPipe(*(VdpChromaType*)parameter_values[i]);
120          break;
121       case VDP_VIDEO_MIXER_PARAMETER_LAYERS:
122          vmixer->max_layers = *(uint32_t*)parameter_values[i];
123          break;
124       default: goto no_params;
125       }
126    }
127    ret = VDP_STATUS_INVALID_VALUE;
128    if (vmixer->max_layers > 4) {
129       VDPAU_MSG(VDPAU_WARN, "[VDPAU] Max layers > 4 not supported\n", vmixer->max_layers);
130       goto no_params;
131    }
132    max_width = screen->get_video_param(screen, prof, PIPE_VIDEO_CAP_MAX_WIDTH);
133    max_height = screen->get_video_param(screen, prof, PIPE_VIDEO_CAP_MAX_HEIGHT);
134    if (vmixer->video_width < 48 ||
135        vmixer->video_width > max_width) {
136       VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u not valid for width\n", vmixer->video_width, max_width);
137       goto no_params;
138    }
139    if (vmixer->video_height < 48 ||
140        vmixer->video_height > max_height) {
141       VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u  not valid for height\n", vmixer->video_height, max_height);
142       goto no_params;
143    }
144    vmixer->luma_key_min = 0.f;
145    vmixer->luma_key_max = 1.f;
146
147    return VDP_STATUS_OK;
148
149 no_params:
150    vlRemoveDataHTAB(*mixer);
151
152 no_handle:
153    vl_compositor_cleanup_state(&vmixer->cstate);
154    FREE(vmixer);
155    return ret;
156 }
157
158 /**
159  * Destroy a VdpVideoMixer.
160  */
161 VdpStatus
162 vlVdpVideoMixerDestroy(VdpVideoMixer mixer)
163 {
164    vlVdpVideoMixer *vmixer;
165
166    vmixer = vlGetDataHTAB(mixer);
167    if (!vmixer)
168       return VDP_STATUS_INVALID_HANDLE;
169    vlRemoveDataHTAB(mixer);
170
171    vl_compositor_cleanup_state(&vmixer->cstate);
172
173    if (vmixer->noise_reduction.filter) {
174       vl_median_filter_cleanup(vmixer->noise_reduction.filter);
175       FREE(vmixer->noise_reduction.filter);
176    }
177
178    if (vmixer->sharpness.filter) {
179       vl_matrix_filter_cleanup(vmixer->sharpness.filter);
180       FREE(vmixer->sharpness.filter);
181    }
182
183    FREE(vmixer);
184
185    return VDP_STATUS_OK;
186 }
187
188 /**
189  * Perform a video post-processing and compositing operation.
190  */
191 VdpStatus vlVdpVideoMixerRender(VdpVideoMixer mixer,
192                                 VdpOutputSurface background_surface,
193                                 VdpRect const *background_source_rect,
194                                 VdpVideoMixerPictureStructure current_picture_structure,
195                                 uint32_t video_surface_past_count,
196                                 VdpVideoSurface const *video_surface_past,
197                                 VdpVideoSurface video_surface_current,
198                                 uint32_t video_surface_future_count,
199                                 VdpVideoSurface const *video_surface_future,
200                                 VdpRect const *video_source_rect,
201                                 VdpOutputSurface destination_surface,
202                                 VdpRect const *destination_rect,
203                                 VdpRect const *destination_video_rect,
204                                 uint32_t layer_count,
205                                 VdpLayer const *layers)
206 {
207    struct pipe_video_rect src_rect, dst_rect, dst_clip;
208    enum vl_compositor_deinterlace deinterlace;
209    unsigned layer = 0;
210
211    vlVdpVideoMixer *vmixer;
212    vlVdpSurface *surf;
213    vlVdpOutputSurface *dst;
214
215    struct vl_compositor *compositor;
216
217    vmixer = vlGetDataHTAB(mixer);
218    if (!vmixer)
219       return VDP_STATUS_INVALID_HANDLE;
220
221    compositor = &vmixer->device->compositor;
222
223    surf = vlGetDataHTAB(video_surface_current);
224    if (!surf)
225       return VDP_STATUS_INVALID_HANDLE;
226
227    if (surf->device != vmixer->device)
228       return VDP_STATUS_HANDLE_DEVICE_MISMATCH;
229
230    if (vmixer->video_width > surf->video_buffer->width ||
231        vmixer->video_height > surf->video_buffer->height ||
232        vmixer->chroma_format != surf->video_buffer->chroma_format)
233       return VDP_STATUS_INVALID_SIZE;
234
235    if (layer_count > vmixer->max_layers)
236       return VDP_STATUS_INVALID_VALUE;
237
238    dst = vlGetDataHTAB(destination_surface);
239    if (!dst)
240       return VDP_STATUS_INVALID_HANDLE;
241
242    if (background_surface != VDP_INVALID_HANDLE) {
243       vlVdpOutputSurface *bg = vlGetDataHTAB(background_surface);
244       if (!bg)
245          return VDP_STATUS_INVALID_HANDLE;
246       vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer++, bg->sampler_view,
247                                    RectToPipe(background_source_rect, &src_rect), NULL);
248    }
249
250    vl_compositor_clear_layers(&vmixer->cstate);
251
252    switch (current_picture_structure) {
253    case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD:
254       deinterlace = VL_COMPOSITOR_BOB_TOP;
255       break;
256
257    case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD:
258       deinterlace = VL_COMPOSITOR_BOB_BOTTOM;
259       break;
260
261    case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME:
262       deinterlace = VL_COMPOSITOR_WEAVE;
263       break;
264
265    default:
266       return VDP_STATUS_INVALID_VIDEO_MIXER_PICTURE_STRUCTURE;
267    };
268    vl_compositor_set_buffer_layer(&vmixer->cstate, compositor, layer++, surf->video_buffer,
269                                   RectToPipe(video_source_rect, &src_rect), NULL, deinterlace);
270    vl_compositor_set_dst_area(&vmixer->cstate, RectToPipe(destination_video_rect, &dst_rect));
271    vl_compositor_set_dst_clip(&vmixer->cstate, RectToPipe(destination_rect, &dst_clip));
272    vl_compositor_render(&vmixer->cstate, compositor, dst->surface, &dst->dirty_area);
273
274    /* applying the noise reduction after scaling is actually not very
275       clever, but currently we should avoid to copy around the image
276       data once more. */
277    if (vmixer->noise_reduction.filter)
278       vl_median_filter_render(vmixer->noise_reduction.filter,
279                               dst->sampler_view, dst->surface);
280
281    if (vmixer->sharpness.filter)
282       vl_matrix_filter_render(vmixer->sharpness.filter,
283                               dst->sampler_view, dst->surface);
284
285    return VDP_STATUS_OK;
286 }
287
288 /**
289  * Update the noise reduction setting
290  */
291 static void
292 vlVdpVideoMixerUpdateNoiseReductionFilter(vlVdpVideoMixer *vmixer)
293 {
294    assert(vmixer);
295
296    /* if present remove the old filter first */
297    if (vmixer->noise_reduction.filter) {
298       vl_median_filter_cleanup(vmixer->noise_reduction.filter);
299       FREE(vmixer->noise_reduction.filter);
300       vmixer->noise_reduction.filter = NULL;
301    }
302
303    /* and create a new filter as needed */
304    if (vmixer->noise_reduction. enabled && vmixer->noise_reduction.level > 0) {
305       vmixer->noise_reduction.filter = MALLOC(sizeof(struct vl_median_filter));
306       vl_median_filter_init(vmixer->noise_reduction.filter, vmixer->device->context,
307                             vmixer->video_width, vmixer->video_height,
308                             vmixer->noise_reduction.level + 1,
309                             VL_MEDIAN_FILTER_CROSS);
310    }
311 }
312
313 static void
314 vlVdpVideoMixerUpdateSharpnessFilter(vlVdpVideoMixer *vmixer)
315 {
316    assert(vmixer);
317
318    /* if present remove the old filter first */
319    if (vmixer->sharpness.filter) {
320       vl_matrix_filter_cleanup(vmixer->sharpness.filter);
321       FREE(vmixer->sharpness.filter);
322       vmixer->sharpness.filter = NULL;
323    }
324
325    /* and create a new filter as needed */
326    if (vmixer->sharpness.enabled && vmixer->sharpness.value != 0.0f) {
327       float matrix[9];
328       unsigned i;
329
330       if (vmixer->sharpness.value > 0.0f) {
331          matrix[0] = -1.0f; matrix[1] = -1.0f; matrix[2] = -1.0f;
332          matrix[3] = -1.0f; matrix[4] =  8.0f; matrix[5] = -1.0f;
333          matrix[6] = -1.0f; matrix[7] = -1.0f; matrix[8] = -1.0f;
334
335          for (i = 0; i < 9; ++i)
336             matrix[i] *= vmixer->sharpness.value;
337
338          matrix[4] += 1.0f;
339
340       } else {
341          matrix[0] = 1.0f; matrix[1] = 2.0f; matrix[2] = 1.0f;
342          matrix[3] = 2.0f; matrix[4] = 4.0f; matrix[5] = 2.0f;
343          matrix[6] = 1.0f; matrix[7] = 2.0f; matrix[8] = 1.0f;
344
345          for (i = 0; i < 9; ++i)
346                matrix[i] *= fabsf(vmixer->sharpness.value) / 16.0f;
347
348          matrix[4] += 1.0f - fabsf(vmixer->sharpness.value);
349       }
350
351       vmixer->sharpness.filter = MALLOC(sizeof(struct vl_matrix_filter));
352       vl_matrix_filter_init(vmixer->sharpness.filter, vmixer->device->context,
353                             vmixer->video_width, vmixer->video_height,
354                             3, 3, matrix);
355    }
356 }
357
358 /**
359  * Retrieve whether features were requested at creation time.
360  */
361 VdpStatus
362 vlVdpVideoMixerGetFeatureSupport(VdpVideoMixer mixer,
363                                  uint32_t feature_count,
364                                  VdpVideoMixerFeature const *features,
365                                  VdpBool *feature_supports)
366 {
367    vlVdpVideoMixer *vmixer;
368    unsigned i;
369
370    if (!(features && feature_supports))
371       return VDP_STATUS_INVALID_POINTER;
372
373    vmixer = vlGetDataHTAB(mixer);
374    if (!vmixer)
375       return VDP_STATUS_INVALID_HANDLE;
376
377    for (i = 0; i < feature_count; ++i) {
378       switch (features[i]) {
379       /* they are valid, but we doesn't support them */
380       case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
381       case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
382       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
383       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
384       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
385       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
386       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
387       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
388       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
389       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
390       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
391       case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
392       case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
393          feature_supports[i] = false;
394          break;
395
396       case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
397          feature_supports[i] = vmixer->sharpness.supported;
398          break;
399
400       case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
401          feature_supports[i] = vmixer->noise_reduction.supported;
402          break;
403
404       default:
405          return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
406       }
407    }
408
409    return VDP_STATUS_OK;
410 }
411
412 /**
413  * Enable or disable features.
414  */
415 VdpStatus
416 vlVdpVideoMixerSetFeatureEnables(VdpVideoMixer mixer,
417                                  uint32_t feature_count,
418                                  VdpVideoMixerFeature const *features,
419                                  VdpBool const *feature_enables)
420 {
421    vlVdpVideoMixer *vmixer;
422    unsigned i;
423
424    if (!(features && feature_enables))
425       return VDP_STATUS_INVALID_POINTER;
426
427    vmixer = vlGetDataHTAB(mixer);
428    if (!vmixer)
429       return VDP_STATUS_INVALID_HANDLE;
430
431    for (i = 0; i < feature_count; ++i) {
432       switch (features[i]) {
433       /* they are valid, but we doesn't support them */
434       case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
435       case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
436       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
437       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
438       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
439       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
440       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
441       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
442       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
443       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
444       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
445       case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
446       case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
447          break;
448
449       case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
450          vmixer->sharpness.enabled = feature_enables[i];
451          vlVdpVideoMixerUpdateSharpnessFilter(vmixer);
452          break;
453
454       case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
455          vmixer->noise_reduction.enabled = feature_enables[i];
456          vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer);
457          break;
458
459       default:
460          return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
461       }
462    }
463
464    return VDP_STATUS_OK;
465 }
466
467 /**
468  * Retrieve whether features are enabled.
469  */
470 VdpStatus
471 vlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer,
472                                  uint32_t feature_count,
473                                  VdpVideoMixerFeature const *features,
474                                  VdpBool *feature_enables)
475 {
476    vlVdpVideoMixer *vmixer;
477    unsigned i;
478
479    if (!(features && feature_enables))
480       return VDP_STATUS_INVALID_POINTER;
481
482    vmixer = vlGetDataHTAB(mixer);
483    if (!vmixer)
484       return VDP_STATUS_INVALID_HANDLE;
485
486    for (i = 0; i < feature_count; ++i) {
487       switch (features[i]) {
488       /* they are valid, but we doesn't support them */
489       case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
490       case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
491       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
492       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
493       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
494       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
495       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
496       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
497       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
498       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
499       case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
500       case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
501       case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
502          break;
503
504       case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
505          feature_enables[i] = vmixer->sharpness.enabled;
506          break;
507
508       case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
509          feature_enables[i] = vmixer->noise_reduction.enabled;
510          break;
511
512       default:
513          return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
514       }
515    }
516
517    return VDP_STATUS_OK;
518 }
519
520 /**
521  * Set attribute values.
522  */
523 VdpStatus
524 vlVdpVideoMixerSetAttributeValues(VdpVideoMixer mixer,
525                                   uint32_t attribute_count,
526                                   VdpVideoMixerAttribute const *attributes,
527                                   void const *const *attribute_values)
528 {
529    const VdpColor *background_color;
530    union pipe_color_union color;
531    const float *vdp_csc;
532    float val;
533    unsigned i;
534
535    if (!(attributes && attribute_values))
536       return VDP_STATUS_INVALID_POINTER;
537
538    vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
539    if (!vmixer)
540       return VDP_STATUS_INVALID_HANDLE;
541
542    for (i = 0; i < attribute_count; ++i) {
543       switch (attributes[i]) {
544       case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR:
545          background_color = attribute_values[i];
546          color.f[0] = background_color->red;
547          color.f[1] = background_color->green;
548          color.f[2] = background_color->blue;
549          color.f[3] = background_color->alpha;
550          vl_compositor_set_clear_color(&vmixer->cstate, &color);
551          break;
552       case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX:
553          vdp_csc = attribute_values[i];
554          vmixer->custom_csc = !!vdp_csc;
555          if (!vdp_csc)
556             vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, 1, vmixer->csc);
557          else
558             memcpy(vmixer->csc, vdp_csc, sizeof(float)*12);
559          if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))
560             vl_compositor_set_csc_matrix(&vmixer->cstate, vmixer->csc);
561          break;
562
563       case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL:
564
565          val = *(float*)attribute_values[i];
566          if (val < 0.f || val > 1.f)
567             return VDP_STATUS_INVALID_VALUE;
568
569          vmixer->noise_reduction.level = val * 10;
570          vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer);
571          break;
572
573       case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA:
574          val = *(float*)attribute_values[i];
575          if (val < 0.f || val > 1.f)
576             return VDP_STATUS_INVALID_VALUE;
577          vmixer->luma_key_min = val;
578          break;
579       case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA:
580          val = *(float*)attribute_values[i];
581          if (val < 0.f || val > 1.f)
582             return VDP_STATUS_INVALID_VALUE;
583          vmixer->luma_key_max = val;
584          break;
585
586       case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL:
587
588          val = *(float*)attribute_values[i];
589          if (val < -1.f || val > 1.f)
590             return VDP_STATUS_INVALID_VALUE;
591
592          vmixer->sharpness.value = val;
593          vlVdpVideoMixerUpdateSharpnessFilter(vmixer);
594          break;
595
596       case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE:
597          if (*(uint8_t*)attribute_values[i] > 1)
598             return VDP_STATUS_INVALID_VALUE;
599          vmixer->skip_chroma_deint = *(uint8_t*)attribute_values[i];
600          break;
601       default:
602          return VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE;
603       }
604    }
605
606    return VDP_STATUS_OK;
607 }
608
609 /**
610  * Retrieve parameter values given at creation time.
611  */
612 VdpStatus
613 vlVdpVideoMixerGetParameterValues(VdpVideoMixer mixer,
614                                   uint32_t parameter_count,
615                                   VdpVideoMixerParameter const *parameters,
616                                   void *const *parameter_values)
617 {
618    vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
619    unsigned i;
620    if (!vmixer)
621       return VDP_STATUS_INVALID_HANDLE;
622
623    if (!parameter_count)
624       return VDP_STATUS_OK;
625    if (!(parameters && parameter_values))
626       return VDP_STATUS_INVALID_POINTER;
627    for (i = 0; i < parameter_count; ++i) {
628       switch (parameters[i]) {
629       case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH:
630          *(uint32_t*)parameter_values[i] = vmixer->video_width;
631          break;
632       case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT:
633          *(uint32_t*)parameter_values[i] = vmixer->video_height;
634          break;
635       case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE:
636          *(VdpChromaType*)parameter_values[i] = PipeToChroma(vmixer->chroma_format);
637          break;
638       case VDP_VIDEO_MIXER_PARAMETER_LAYERS:
639          *(uint32_t*)parameter_values[i] = vmixer->max_layers;
640          break;
641       default:
642          return VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER;
643       }
644    }
645    return VDP_STATUS_OK;
646 }
647
648 /**
649  * Retrieve current attribute values.
650  */
651 VdpStatus
652 vlVdpVideoMixerGetAttributeValues(VdpVideoMixer mixer,
653                                   uint32_t attribute_count,
654                                   VdpVideoMixerAttribute const *attributes,
655                                   void *const *attribute_values)
656 {
657    unsigned i;
658    VdpCSCMatrix **vdp_csc;
659
660    if (!(attributes && attribute_values))
661       return VDP_STATUS_INVALID_POINTER;
662
663    vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
664    if (!vmixer)
665       return VDP_STATUS_INVALID_HANDLE;
666
667    for (i = 0; i < attribute_count; ++i) {
668       switch (attributes[i]) {
669       case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR:
670          vl_compositor_get_clear_color(&vmixer->cstate, attribute_values[i]);
671          break;
672       case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX:
673          vdp_csc = attribute_values[i];
674          if (!vmixer->custom_csc) {
675              *vdp_csc = NULL;
676             break;
677          }
678          memcpy(*vdp_csc, vmixer->csc, sizeof(float)*12);
679          break;
680
681       case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL:
682          *(float*)attribute_values[i] = (float)vmixer->noise_reduction.level / 10.0f;
683          break;
684
685       case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA:
686          *(float*)attribute_values[i] = vmixer->luma_key_min;
687          break;
688       case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA:
689          *(float*)attribute_values[i] = vmixer->luma_key_max;
690          break;
691       case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL:
692          *(float*)attribute_values[i] = vmixer->sharpness.value;
693          break;
694       case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE:
695          *(uint8_t*)attribute_values[i] = vmixer->skip_chroma_deint;
696          break;
697       default:
698          return VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE;
699       }
700    }
701    return VDP_STATUS_OK;
702 }
703
704 /**
705  * Generate a color space conversion matrix.
706  */
707 VdpStatus
708 vlVdpGenerateCSCMatrix(VdpProcamp *procamp,
709                        VdpColorStandard standard,
710                        VdpCSCMatrix *csc_matrix)
711 {
712    float matrix[16];
713    enum VL_CSC_COLOR_STANDARD vl_std;
714    struct vl_procamp camp;
715
716    if (!(csc_matrix && procamp))
717       return VDP_STATUS_INVALID_POINTER;
718
719    if (procamp->struct_version > VDP_PROCAMP_VERSION)
720       return VDP_STATUS_INVALID_STRUCT_VERSION;
721
722    switch (standard) {
723       case VDP_COLOR_STANDARD_ITUR_BT_601: vl_std = VL_CSC_COLOR_STANDARD_BT_601; break;
724       case VDP_COLOR_STANDARD_ITUR_BT_709: vl_std = VL_CSC_COLOR_STANDARD_BT_709; break;
725       case VDP_COLOR_STANDARD_SMPTE_240M:  vl_std = VL_CSC_COLOR_STANDARD_SMPTE_240M; break;
726       default: return VDP_STATUS_INVALID_COLOR_STANDARD;
727    }
728    camp.brightness = procamp->brightness;
729    camp.contrast = procamp->contrast;
730    camp.saturation = procamp->saturation;
731    camp.hue = procamp->hue;
732    vl_csc_get_matrix(vl_std, &camp, 1, matrix);
733    memcpy(csc_matrix, matrix, sizeof(float)*12);
734    return VDP_STATUS_OK;
735 }