1848b8605Smrg/**************************************************************************
2848b8605Smrg *
3848b8605Smrg * Copyright 2010 Thomas Balling Sørensen.
4848b8605Smrg * All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the
8848b8605Smrg * "Software"), to deal in the Software without restriction, including
9848b8605Smrg * without limitation the rights to use, copy, modify, merge, publish,
10848b8605Smrg * distribute, sub license, and/or sell copies of the Software, and to
11848b8605Smrg * permit persons to whom the Software is furnished to do so, subject to
12848b8605Smrg * the following conditions:
13848b8605Smrg *
14848b8605Smrg * The above copyright notice and this permission notice (including the
15848b8605Smrg * next paragraph) shall be included in all copies or substantial portions
16848b8605Smrg * of the Software.
17848b8605Smrg *
18848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21848b8605Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22848b8605Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23848b8605Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24848b8605Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25848b8605Smrg *
26848b8605Smrg **************************************************************************/
27848b8605Smrg
28848b8605Smrg#include <vdpau/vdpau.h>
29848b8605Smrg
30848b8605Smrg#include "util/u_memory.h"
31848b8605Smrg#include "util/u_debug.h"
32848b8605Smrg
33848b8605Smrg#include "vl/vl_csc.h"
34848b8605Smrg
35848b8605Smrg#include "vdpau_private.h"
36848b8605Smrg
37848b8605Smrg/**
38848b8605Smrg * Create a VdpVideoMixer.
39848b8605Smrg */
40848b8605SmrgVdpStatus
41848b8605SmrgvlVdpVideoMixerCreate(VdpDevice device,
42848b8605Smrg                      uint32_t feature_count,
43848b8605Smrg                      VdpVideoMixerFeature const *features,
44848b8605Smrg                      uint32_t parameter_count,
45848b8605Smrg                      VdpVideoMixerParameter const *parameters,
46848b8605Smrg                      void const *const *parameter_values,
47848b8605Smrg                      VdpVideoMixer *mixer)
48848b8605Smrg{
49848b8605Smrg   vlVdpVideoMixer *vmixer = NULL;
50848b8605Smrg   VdpStatus ret;
51848b8605Smrg   struct pipe_screen *screen;
52b8e80941Smrg   uint32_t max_2d_texture_level;
53b8e80941Smrg   unsigned max_size, i;
54848b8605Smrg
55848b8605Smrg   vlVdpDevice *dev = vlGetDataHTAB(device);
56848b8605Smrg   if (!dev)
57848b8605Smrg      return VDP_STATUS_INVALID_HANDLE;
58848b8605Smrg   screen = dev->vscreen->pscreen;
59848b8605Smrg
60848b8605Smrg   vmixer = CALLOC(1, sizeof(vlVdpVideoMixer));
61848b8605Smrg   if (!vmixer)
62848b8605Smrg      return VDP_STATUS_RESOURCES;
63848b8605Smrg
64848b8605Smrg   DeviceReference(&vmixer->device, dev);
65848b8605Smrg
66b8e80941Smrg   mtx_lock(&dev->mutex);
67848b8605Smrg
68b8e80941Smrg   if (!vl_compositor_init_state(&vmixer->cstate, dev->context)) {
69b8e80941Smrg      ret = VDP_STATUS_ERROR;
70b8e80941Smrg      goto no_compositor_state;
71b8e80941Smrg   }
72848b8605Smrg
73848b8605Smrg   vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, true, &vmixer->csc);
74b8e80941Smrg   if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) {
75b8e80941Smrg      if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 1.0f, 0.0f)) {
76b8e80941Smrg         ret = VDP_STATUS_ERROR;
77b8e80941Smrg         goto err_csc_matrix;
78b8e80941Smrg      }
79b8e80941Smrg   }
80848b8605Smrg
81848b8605Smrg   *mixer = vlAddDataHTAB(vmixer);
82848b8605Smrg   if (*mixer == 0) {
83848b8605Smrg      ret = VDP_STATUS_ERROR;
84848b8605Smrg      goto no_handle;
85848b8605Smrg   }
86848b8605Smrg
87848b8605Smrg   ret = VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
88848b8605Smrg   for (i = 0; i < feature_count; ++i) {
89848b8605Smrg      switch (features[i]) {
90848b8605Smrg      /* they are valid, but we doesn't support them */
91848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
92848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
93848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
94848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
95848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
96848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
97848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
98848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
99848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
100848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
101848b8605Smrg         break;
102848b8605Smrg
103848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
104848b8605Smrg         vmixer->deint.supported = true;
105848b8605Smrg         break;
106848b8605Smrg
107848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
108848b8605Smrg         vmixer->sharpness.supported = true;
109848b8605Smrg         break;
110848b8605Smrg
111848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
112848b8605Smrg         vmixer->noise_reduction.supported = true;
113848b8605Smrg         break;
114848b8605Smrg
115b8e80941Smrg      case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
116b8e80941Smrg         vmixer->luma_key.supported = true;
117b8e80941Smrg         break;
118b8e80941Smrg
119b8e80941Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
120b8e80941Smrg         vmixer->bicubic.supported = true;
121b8e80941Smrg         break;
122848b8605Smrg      default: goto no_params;
123848b8605Smrg      }
124848b8605Smrg   }
125848b8605Smrg
126848b8605Smrg   vmixer->chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
127848b8605Smrg   ret = VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER;
128848b8605Smrg   for (i = 0; i < parameter_count; ++i) {
129848b8605Smrg      switch (parameters[i]) {
130848b8605Smrg      case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH:
131848b8605Smrg         vmixer->video_width = *(uint32_t*)parameter_values[i];
132848b8605Smrg         break;
133848b8605Smrg      case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT:
134848b8605Smrg         vmixer->video_height = *(uint32_t*)parameter_values[i];
135848b8605Smrg         break;
136848b8605Smrg      case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE:
137848b8605Smrg         vmixer->chroma_format = ChromaToPipe(*(VdpChromaType*)parameter_values[i]);
138848b8605Smrg         break;
139848b8605Smrg      case VDP_VIDEO_MIXER_PARAMETER_LAYERS:
140848b8605Smrg         vmixer->max_layers = *(uint32_t*)parameter_values[i];
141848b8605Smrg         break;
142848b8605Smrg      default: goto no_params;
143848b8605Smrg      }
144848b8605Smrg   }
145848b8605Smrg   ret = VDP_STATUS_INVALID_VALUE;
146848b8605Smrg   if (vmixer->max_layers > 4) {
147848b8605Smrg      VDPAU_MSG(VDPAU_WARN, "[VDPAU] Max layers > 4 not supported\n", vmixer->max_layers);
148848b8605Smrg      goto no_params;
149848b8605Smrg   }
150b8e80941Smrg
151b8e80941Smrg   max_2d_texture_level = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
152b8e80941Smrg   max_size = pow(2, max_2d_texture_level-1);
153b8e80941Smrg   if (vmixer->video_width < 48 || vmixer->video_width > max_size) {
154b8e80941Smrg      VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u not valid for width\n",
155b8e80941Smrg                vmixer->video_width, max_size);
156848b8605Smrg      goto no_params;
157848b8605Smrg   }
158b8e80941Smrg   if (vmixer->video_height < 48 || vmixer->video_height > max_size) {
159b8e80941Smrg      VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u  not valid for height\n",
160b8e80941Smrg                vmixer->video_height, max_size);
161848b8605Smrg      goto no_params;
162848b8605Smrg   }
163b8e80941Smrg   vmixer->luma_key.luma_min = 1.0f;
164b8e80941Smrg   vmixer->luma_key.luma_max = 0.0f;
165b8e80941Smrg   mtx_unlock(&dev->mutex);
166848b8605Smrg
167848b8605Smrg   return VDP_STATUS_OK;
168848b8605Smrg
169848b8605Smrgno_params:
170848b8605Smrg   vlRemoveDataHTAB(*mixer);
171848b8605Smrg
172848b8605Smrgno_handle:
173b8e80941Smrgerr_csc_matrix:
174848b8605Smrg   vl_compositor_cleanup_state(&vmixer->cstate);
175b8e80941Smrgno_compositor_state:
176b8e80941Smrg   mtx_unlock(&dev->mutex);
177848b8605Smrg   DeviceReference(&vmixer->device, NULL);
178848b8605Smrg   FREE(vmixer);
179848b8605Smrg   return ret;
180848b8605Smrg}
181848b8605Smrg
182848b8605Smrg/**
183848b8605Smrg * Destroy a VdpVideoMixer.
184848b8605Smrg */
185848b8605SmrgVdpStatus
186848b8605SmrgvlVdpVideoMixerDestroy(VdpVideoMixer mixer)
187848b8605Smrg{
188848b8605Smrg   vlVdpVideoMixer *vmixer;
189848b8605Smrg
190848b8605Smrg   vmixer = vlGetDataHTAB(mixer);
191848b8605Smrg   if (!vmixer)
192848b8605Smrg      return VDP_STATUS_INVALID_HANDLE;
193848b8605Smrg
194b8e80941Smrg   mtx_lock(&vmixer->device->mutex);
195848b8605Smrg
196848b8605Smrg   vlRemoveDataHTAB(mixer);
197848b8605Smrg
198848b8605Smrg   vl_compositor_cleanup_state(&vmixer->cstate);
199848b8605Smrg
200848b8605Smrg   if (vmixer->deint.filter) {
201848b8605Smrg      vl_deint_filter_cleanup(vmixer->deint.filter);
202848b8605Smrg      FREE(vmixer->deint.filter);
203848b8605Smrg   }
204848b8605Smrg
205848b8605Smrg   if (vmixer->noise_reduction.filter) {
206848b8605Smrg      vl_median_filter_cleanup(vmixer->noise_reduction.filter);
207848b8605Smrg      FREE(vmixer->noise_reduction.filter);
208848b8605Smrg   }
209848b8605Smrg
210848b8605Smrg   if (vmixer->sharpness.filter) {
211848b8605Smrg      vl_matrix_filter_cleanup(vmixer->sharpness.filter);
212848b8605Smrg      FREE(vmixer->sharpness.filter);
213848b8605Smrg   }
214b8e80941Smrg
215b8e80941Smrg   if (vmixer->bicubic.filter) {
216b8e80941Smrg      vl_bicubic_filter_cleanup(vmixer->bicubic.filter);
217b8e80941Smrg      FREE(vmixer->bicubic.filter);
218b8e80941Smrg   }
219b8e80941Smrg   mtx_unlock(&vmixer->device->mutex);
220848b8605Smrg   DeviceReference(&vmixer->device, NULL);
221848b8605Smrg
222848b8605Smrg   FREE(vmixer);
223848b8605Smrg
224848b8605Smrg   return VDP_STATUS_OK;
225848b8605Smrg}
226848b8605Smrg
227848b8605Smrg/**
228848b8605Smrg * Perform a video post-processing and compositing operation.
229848b8605Smrg */
230848b8605SmrgVdpStatus vlVdpVideoMixerRender(VdpVideoMixer mixer,
231848b8605Smrg                                VdpOutputSurface background_surface,
232848b8605Smrg                                VdpRect const *background_source_rect,
233848b8605Smrg                                VdpVideoMixerPictureStructure current_picture_structure,
234848b8605Smrg                                uint32_t video_surface_past_count,
235848b8605Smrg                                VdpVideoSurface const *video_surface_past,
236848b8605Smrg                                VdpVideoSurface video_surface_current,
237848b8605Smrg                                uint32_t video_surface_future_count,
238848b8605Smrg                                VdpVideoSurface const *video_surface_future,
239848b8605Smrg                                VdpRect const *video_source_rect,
240848b8605Smrg                                VdpOutputSurface destination_surface,
241848b8605Smrg                                VdpRect const *destination_rect,
242848b8605Smrg                                VdpRect const *destination_video_rect,
243848b8605Smrg                                uint32_t layer_count,
244848b8605Smrg                                VdpLayer const *layers)
245848b8605Smrg{
246848b8605Smrg   enum vl_compositor_deinterlace deinterlace;
247b8e80941Smrg   struct u_rect rect, clip, *prect, dirty_area;
248848b8605Smrg   unsigned i, layer = 0;
249848b8605Smrg   struct pipe_video_buffer *video_buffer;
250b8e80941Smrg   struct pipe_sampler_view *sampler_view, sv_templ;
251b8e80941Smrg   struct pipe_surface *surface, surf_templ;
252b8e80941Smrg   struct pipe_context *pipe = NULL;
253b8e80941Smrg   struct pipe_resource res_tmpl, *res;
254848b8605Smrg
255848b8605Smrg   vlVdpVideoMixer *vmixer;
256848b8605Smrg   vlVdpSurface *surf;
257848b8605Smrg   vlVdpOutputSurface *dst, *bg = NULL;
258848b8605Smrg
259848b8605Smrg   struct vl_compositor *compositor;
260848b8605Smrg
261848b8605Smrg   vmixer = vlGetDataHTAB(mixer);
262848b8605Smrg   if (!vmixer)
263848b8605Smrg      return VDP_STATUS_INVALID_HANDLE;
264848b8605Smrg
265848b8605Smrg   compositor = &vmixer->device->compositor;
266848b8605Smrg
267848b8605Smrg   surf = vlGetDataHTAB(video_surface_current);
268848b8605Smrg   if (!surf)
269848b8605Smrg      return VDP_STATUS_INVALID_HANDLE;
270848b8605Smrg   video_buffer = surf->video_buffer;
271848b8605Smrg
272848b8605Smrg   if (surf->device != vmixer->device)
273848b8605Smrg      return VDP_STATUS_HANDLE_DEVICE_MISMATCH;
274848b8605Smrg
275848b8605Smrg   if (vmixer->video_width > video_buffer->width ||
276848b8605Smrg       vmixer->video_height > video_buffer->height ||
277848b8605Smrg       vmixer->chroma_format != video_buffer->chroma_format)
278848b8605Smrg      return VDP_STATUS_INVALID_SIZE;
279848b8605Smrg
280848b8605Smrg   if (layer_count > vmixer->max_layers)
281848b8605Smrg      return VDP_STATUS_INVALID_VALUE;
282848b8605Smrg
283848b8605Smrg   dst = vlGetDataHTAB(destination_surface);
284848b8605Smrg   if (!dst)
285848b8605Smrg      return VDP_STATUS_INVALID_HANDLE;
286848b8605Smrg
287848b8605Smrg   if (background_surface != VDP_INVALID_HANDLE) {
288848b8605Smrg      bg = vlGetDataHTAB(background_surface);
289848b8605Smrg      if (!bg)
290848b8605Smrg         return VDP_STATUS_INVALID_HANDLE;
291848b8605Smrg   }
292848b8605Smrg
293b8e80941Smrg   mtx_lock(&vmixer->device->mutex);
294848b8605Smrg
295848b8605Smrg   vl_compositor_clear_layers(&vmixer->cstate);
296848b8605Smrg
297848b8605Smrg   if (bg)
298848b8605Smrg      vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer++, bg->sampler_view,
299848b8605Smrg                                   RectToPipe(background_source_rect, &rect), NULL, NULL);
300848b8605Smrg
301848b8605Smrg   switch (current_picture_structure) {
302848b8605Smrg   case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD:
303848b8605Smrg      deinterlace = VL_COMPOSITOR_BOB_TOP;
304848b8605Smrg      break;
305848b8605Smrg
306848b8605Smrg   case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD:
307848b8605Smrg      deinterlace = VL_COMPOSITOR_BOB_BOTTOM;
308848b8605Smrg      break;
309848b8605Smrg
310848b8605Smrg   case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME:
311848b8605Smrg      deinterlace = VL_COMPOSITOR_WEAVE;
312848b8605Smrg      break;
313848b8605Smrg
314848b8605Smrg   default:
315b8e80941Smrg      mtx_unlock(&vmixer->device->mutex);
316848b8605Smrg      return VDP_STATUS_INVALID_VIDEO_MIXER_PICTURE_STRUCTURE;
317b8e80941Smrg   }
318848b8605Smrg
319848b8605Smrg   if (deinterlace != VL_COMPOSITOR_WEAVE && vmixer->deint.enabled &&
320848b8605Smrg       video_surface_past_count > 1 && video_surface_future_count > 0) {
321848b8605Smrg      vlVdpSurface *prevprev = vlGetDataHTAB(video_surface_past[1]);
322848b8605Smrg      vlVdpSurface *prev = vlGetDataHTAB(video_surface_past[0]);
323848b8605Smrg      vlVdpSurface *next = vlGetDataHTAB(video_surface_future[0]);
324848b8605Smrg      if (prevprev && prev && next &&
325848b8605Smrg          vl_deint_filter_check_buffers(vmixer->deint.filter,
326848b8605Smrg          prevprev->video_buffer, prev->video_buffer, surf->video_buffer, next->video_buffer)) {
327848b8605Smrg         vl_deint_filter_render(vmixer->deint.filter, prevprev->video_buffer,
328848b8605Smrg                                prev->video_buffer, surf->video_buffer,
329848b8605Smrg                                next->video_buffer,
330848b8605Smrg                                deinterlace == VL_COMPOSITOR_BOB_BOTTOM);
331848b8605Smrg         deinterlace = VL_COMPOSITOR_WEAVE;
332848b8605Smrg         video_buffer = vmixer->deint.filter->video_buffer;
333848b8605Smrg      }
334848b8605Smrg   }
335848b8605Smrg
336848b8605Smrg   prect = RectToPipe(video_source_rect, &rect);
337848b8605Smrg   if (!prect) {
338848b8605Smrg      rect.x0 = 0;
339848b8605Smrg      rect.y0 = 0;
340848b8605Smrg      rect.x1 = surf->templat.width;
341848b8605Smrg      rect.y1 = surf->templat.height;
342848b8605Smrg      prect = &rect;
343848b8605Smrg   }
344848b8605Smrg   vl_compositor_set_buffer_layer(&vmixer->cstate, compositor, layer, video_buffer, prect, NULL, deinterlace);
345b8e80941Smrg
346b8e80941Smrg   if (vmixer->bicubic.filter || vmixer->sharpness.filter || vmixer->noise_reduction.filter) {
347b8e80941Smrg      pipe = vmixer->device->context;
348b8e80941Smrg      memset(&res_tmpl, 0, sizeof(res_tmpl));
349b8e80941Smrg
350b8e80941Smrg      res_tmpl.target = PIPE_TEXTURE_2D;
351b8e80941Smrg      res_tmpl.format = dst->sampler_view->format;
352b8e80941Smrg      res_tmpl.depth0 = 1;
353b8e80941Smrg      res_tmpl.array_size = 1;
354b8e80941Smrg      res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
355b8e80941Smrg      res_tmpl.usage = PIPE_USAGE_DEFAULT;
356b8e80941Smrg
357b8e80941Smrg      if (!vmixer->bicubic.filter) {
358b8e80941Smrg         res_tmpl.width0 = dst->surface->width;
359b8e80941Smrg         res_tmpl.height0 = dst->surface->height;
360b8e80941Smrg      } else {
361b8e80941Smrg         res_tmpl.width0 = surf->templat.width;
362b8e80941Smrg         res_tmpl.height0 = surf->templat.height;
363b8e80941Smrg      }
364b8e80941Smrg
365b8e80941Smrg      res = pipe->screen->resource_create(pipe->screen, &res_tmpl);
366b8e80941Smrg
367b8e80941Smrg      vlVdpDefaultSamplerViewTemplate(&sv_templ, res);
368b8e80941Smrg      sampler_view = pipe->create_sampler_view(pipe, res, &sv_templ);
369b8e80941Smrg
370b8e80941Smrg      memset(&surf_templ, 0, sizeof(surf_templ));
371b8e80941Smrg      surf_templ.format = res->format;
372b8e80941Smrg      surface = pipe->create_surface(pipe, res, &surf_templ);
373b8e80941Smrg
374b8e80941Smrg      vl_compositor_reset_dirty_area(&dirty_area);
375b8e80941Smrg      pipe_resource_reference(&res, NULL);
376b8e80941Smrg   } else {
377b8e80941Smrg      surface = dst->surface;
378b8e80941Smrg      sampler_view = dst->sampler_view;
379b8e80941Smrg      dirty_area = dst->dirty_area;
380b8e80941Smrg   }
381b8e80941Smrg
382b8e80941Smrg   if (!vmixer->bicubic.filter) {
383b8e80941Smrg      vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(destination_video_rect, &rect));
384b8e80941Smrg      vl_compositor_set_dst_clip(&vmixer->cstate, RectToPipe(destination_rect, &clip));
385b8e80941Smrg   }
386848b8605Smrg
387848b8605Smrg   for (i = 0; i < layer_count; ++i) {
388848b8605Smrg      vlVdpOutputSurface *src = vlGetDataHTAB(layers->source_surface);
389848b8605Smrg      if (!src) {
390b8e80941Smrg         mtx_unlock(&vmixer->device->mutex);
391848b8605Smrg         return VDP_STATUS_INVALID_HANDLE;
392848b8605Smrg      }
393848b8605Smrg
394848b8605Smrg      assert(layers->struct_version == VDP_LAYER_VERSION);
395848b8605Smrg
396848b8605Smrg      vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer, src->sampler_view,
397848b8605Smrg                                   RectToPipe(layers->source_rect, &rect), NULL, NULL);
398848b8605Smrg      vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(layers->destination_rect, &rect));
399848b8605Smrg
400848b8605Smrg      ++layers;
401848b8605Smrg   }
402848b8605Smrg
403b8e80941Smrg   vl_compositor_render(&vmixer->cstate, compositor, surface, &dirty_area, true);
404b8e80941Smrg
405b8e80941Smrg   if (vmixer->noise_reduction.filter) {
406b8e80941Smrg      if (!vmixer->sharpness.filter && !vmixer->bicubic.filter) {
407b8e80941Smrg         vl_median_filter_render(vmixer->noise_reduction.filter,
408b8e80941Smrg                                 sampler_view, dst->surface);
409b8e80941Smrg      } else {
410b8e80941Smrg         res = pipe->screen->resource_create(pipe->screen, &res_tmpl);
411b8e80941Smrg         struct pipe_sampler_view *sampler_view_temp = pipe->create_sampler_view(pipe, res, &sv_templ);
412b8e80941Smrg         struct pipe_surface *surface_temp = pipe->create_surface(pipe, res, &surf_templ);
413b8e80941Smrg         pipe_resource_reference(&res, NULL);
414848b8605Smrg
415848b8605Smrg         vl_median_filter_render(vmixer->noise_reduction.filter,
416b8e80941Smrg                                 sampler_view, surface_temp);
417b8e80941Smrg
418b8e80941Smrg         pipe_sampler_view_reference(&sampler_view, NULL);
419b8e80941Smrg         pipe_surface_reference(&surface, NULL);
420b8e80941Smrg
421b8e80941Smrg         sampler_view = sampler_view_temp;
422b8e80941Smrg         surface = surface_temp;
423b8e80941Smrg      }
424b8e80941Smrg   }
425b8e80941Smrg
426b8e80941Smrg   if (vmixer->sharpness.filter) {
427b8e80941Smrg      if (!vmixer->bicubic.filter) {
428b8e80941Smrg         vl_matrix_filter_render(vmixer->sharpness.filter,
429b8e80941Smrg                                 sampler_view, dst->surface);
430b8e80941Smrg      } else {
431b8e80941Smrg         res = pipe->screen->resource_create(pipe->screen, &res_tmpl);
432b8e80941Smrg         struct pipe_sampler_view *sampler_view_temp = pipe->create_sampler_view(pipe, res, &sv_templ);
433b8e80941Smrg         struct pipe_surface *surface_temp = pipe->create_surface(pipe, res, &surf_templ);
434b8e80941Smrg         pipe_resource_reference(&res, NULL);
435848b8605Smrg
436848b8605Smrg         vl_matrix_filter_render(vmixer->sharpness.filter,
437b8e80941Smrg                                 sampler_view, surface_temp);
438b8e80941Smrg
439b8e80941Smrg         pipe_sampler_view_reference(&sampler_view, NULL);
440b8e80941Smrg         pipe_surface_reference(&surface, NULL);
441b8e80941Smrg
442b8e80941Smrg         sampler_view = sampler_view_temp;
443b8e80941Smrg         surface = surface_temp;
444b8e80941Smrg      }
445848b8605Smrg   }
446b8e80941Smrg
447b8e80941Smrg   if (vmixer->bicubic.filter)
448b8e80941Smrg      vl_bicubic_filter_render(vmixer->bicubic.filter,
449b8e80941Smrg                               sampler_view, dst->surface,
450b8e80941Smrg                               RectToPipe(destination_video_rect, &rect),
451b8e80941Smrg                               RectToPipe(destination_rect, &clip));
452b8e80941Smrg
453b8e80941Smrg   if(surface != dst->surface) {
454b8e80941Smrg      pipe_sampler_view_reference(&sampler_view, NULL);
455b8e80941Smrg      pipe_surface_reference(&surface, NULL);
456b8e80941Smrg   }
457b8e80941Smrg   mtx_unlock(&vmixer->device->mutex);
458848b8605Smrg
459848b8605Smrg   return VDP_STATUS_OK;
460848b8605Smrg}
461848b8605Smrg
462848b8605Smrgstatic void
463848b8605SmrgvlVdpVideoMixerUpdateDeinterlaceFilter(vlVdpVideoMixer *vmixer)
464848b8605Smrg{
465848b8605Smrg   struct pipe_context *pipe = vmixer->device->context;
466848b8605Smrg   assert(vmixer);
467848b8605Smrg
468848b8605Smrg   /* remove existing filter */
469848b8605Smrg   if (vmixer->deint.filter) {
470848b8605Smrg      vl_deint_filter_cleanup(vmixer->deint.filter);
471848b8605Smrg      FREE(vmixer->deint.filter);
472848b8605Smrg      vmixer->deint.filter = NULL;
473848b8605Smrg   }
474848b8605Smrg
475848b8605Smrg   /* create a new filter if requested */
476848b8605Smrg   if (vmixer->deint.enabled && vmixer->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) {
477848b8605Smrg      vmixer->deint.filter = MALLOC(sizeof(struct vl_deint_filter));
478848b8605Smrg      vmixer->deint.enabled = vl_deint_filter_init(vmixer->deint.filter, pipe,
479848b8605Smrg            vmixer->video_width, vmixer->video_height,
480848b8605Smrg            vmixer->skip_chroma_deint, vmixer->deint.spatial);
481848b8605Smrg      if (!vmixer->deint.enabled) {
482848b8605Smrg         FREE(vmixer->deint.filter);
483848b8605Smrg      }
484848b8605Smrg   }
485848b8605Smrg}
486848b8605Smrg
487848b8605Smrg/**
488848b8605Smrg * Update the noise reduction setting
489848b8605Smrg */
490848b8605Smrgstatic void
491848b8605SmrgvlVdpVideoMixerUpdateNoiseReductionFilter(vlVdpVideoMixer *vmixer)
492848b8605Smrg{
493848b8605Smrg   assert(vmixer);
494848b8605Smrg
495848b8605Smrg   /* if present remove the old filter first */
496848b8605Smrg   if (vmixer->noise_reduction.filter) {
497848b8605Smrg      vl_median_filter_cleanup(vmixer->noise_reduction.filter);
498848b8605Smrg      FREE(vmixer->noise_reduction.filter);
499848b8605Smrg      vmixer->noise_reduction.filter = NULL;
500848b8605Smrg   }
501848b8605Smrg
502848b8605Smrg   /* and create a new filter as needed */
503848b8605Smrg   if (vmixer->noise_reduction. enabled && vmixer->noise_reduction.level > 0) {
504848b8605Smrg      vmixer->noise_reduction.filter = MALLOC(sizeof(struct vl_median_filter));
505848b8605Smrg      vl_median_filter_init(vmixer->noise_reduction.filter, vmixer->device->context,
506848b8605Smrg                            vmixer->video_width, vmixer->video_height,
507848b8605Smrg                            vmixer->noise_reduction.level + 1,
508848b8605Smrg                            VL_MEDIAN_FILTER_CROSS);
509848b8605Smrg   }
510848b8605Smrg}
511848b8605Smrg
512848b8605Smrgstatic void
513848b8605SmrgvlVdpVideoMixerUpdateSharpnessFilter(vlVdpVideoMixer *vmixer)
514848b8605Smrg{
515848b8605Smrg   assert(vmixer);
516848b8605Smrg
517848b8605Smrg   /* if present remove the old filter first */
518848b8605Smrg   if (vmixer->sharpness.filter) {
519848b8605Smrg      vl_matrix_filter_cleanup(vmixer->sharpness.filter);
520848b8605Smrg      FREE(vmixer->sharpness.filter);
521848b8605Smrg      vmixer->sharpness.filter = NULL;
522848b8605Smrg   }
523848b8605Smrg
524848b8605Smrg   /* and create a new filter as needed */
525848b8605Smrg   if (vmixer->sharpness.enabled && vmixer->sharpness.value != 0.0f) {
526848b8605Smrg      float matrix[9];
527848b8605Smrg      unsigned i;
528848b8605Smrg
529848b8605Smrg      if (vmixer->sharpness.value > 0.0f) {
530848b8605Smrg         matrix[0] = -1.0f; matrix[1] = -1.0f; matrix[2] = -1.0f;
531848b8605Smrg         matrix[3] = -1.0f; matrix[4] =  8.0f; matrix[5] = -1.0f;
532848b8605Smrg         matrix[6] = -1.0f; matrix[7] = -1.0f; matrix[8] = -1.0f;
533848b8605Smrg
534848b8605Smrg         for (i = 0; i < 9; ++i)
535848b8605Smrg            matrix[i] *= vmixer->sharpness.value;
536848b8605Smrg
537848b8605Smrg         matrix[4] += 1.0f;
538848b8605Smrg
539848b8605Smrg      } else {
540848b8605Smrg         matrix[0] = 1.0f; matrix[1] = 2.0f; matrix[2] = 1.0f;
541848b8605Smrg         matrix[3] = 2.0f; matrix[4] = 4.0f; matrix[5] = 2.0f;
542848b8605Smrg         matrix[6] = 1.0f; matrix[7] = 2.0f; matrix[8] = 1.0f;
543848b8605Smrg
544848b8605Smrg         for (i = 0; i < 9; ++i)
545848b8605Smrg               matrix[i] *= fabsf(vmixer->sharpness.value) / 16.0f;
546848b8605Smrg
547848b8605Smrg         matrix[4] += 1.0f - fabsf(vmixer->sharpness.value);
548848b8605Smrg      }
549848b8605Smrg
550848b8605Smrg      vmixer->sharpness.filter = MALLOC(sizeof(struct vl_matrix_filter));
551848b8605Smrg      vl_matrix_filter_init(vmixer->sharpness.filter, vmixer->device->context,
552848b8605Smrg                            vmixer->video_width, vmixer->video_height,
553848b8605Smrg                            3, 3, matrix);
554848b8605Smrg   }
555848b8605Smrg}
556848b8605Smrg
557b8e80941Smrg/**
558b8e80941Smrg * Update the bicubic filter
559b8e80941Smrg */
560b8e80941Smrgstatic void
561b8e80941SmrgvlVdpVideoMixerUpdateBicubicFilter(vlVdpVideoMixer *vmixer)
562b8e80941Smrg{
563b8e80941Smrg   assert(vmixer);
564b8e80941Smrg
565b8e80941Smrg   /* if present remove the old filter first */
566b8e80941Smrg   if (vmixer->bicubic.filter) {
567b8e80941Smrg      vl_bicubic_filter_cleanup(vmixer->bicubic.filter);
568b8e80941Smrg      FREE(vmixer->bicubic.filter);
569b8e80941Smrg      vmixer->bicubic.filter = NULL;
570b8e80941Smrg   }
571b8e80941Smrg   /* and create a new filter as needed */
572b8e80941Smrg   if (vmixer->bicubic.enabled) {
573b8e80941Smrg      vmixer->bicubic.filter = MALLOC(sizeof(struct vl_bicubic_filter));
574b8e80941Smrg      vl_bicubic_filter_init(vmixer->bicubic.filter, vmixer->device->context,
575b8e80941Smrg                            vmixer->video_width, vmixer->video_height);
576b8e80941Smrg   }
577b8e80941Smrg}
578b8e80941Smrg
579848b8605Smrg/**
580848b8605Smrg * Retrieve whether features were requested at creation time.
581848b8605Smrg */
582848b8605SmrgVdpStatus
583848b8605SmrgvlVdpVideoMixerGetFeatureSupport(VdpVideoMixer mixer,
584848b8605Smrg                                 uint32_t feature_count,
585848b8605Smrg                                 VdpVideoMixerFeature const *features,
586848b8605Smrg                                 VdpBool *feature_supports)
587848b8605Smrg{
588848b8605Smrg   vlVdpVideoMixer *vmixer;
589848b8605Smrg   unsigned i;
590848b8605Smrg
591848b8605Smrg   if (!(features && feature_supports))
592848b8605Smrg      return VDP_STATUS_INVALID_POINTER;
593848b8605Smrg
594848b8605Smrg   vmixer = vlGetDataHTAB(mixer);
595848b8605Smrg   if (!vmixer)
596848b8605Smrg      return VDP_STATUS_INVALID_HANDLE;
597848b8605Smrg
598848b8605Smrg   for (i = 0; i < feature_count; ++i) {
599848b8605Smrg      switch (features[i]) {
600848b8605Smrg      /* they are valid, but we doesn't support them */
601848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
602848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
603848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
604848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
605848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
606848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
607848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
608848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
609848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
610848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
611848b8605Smrg         feature_supports[i] = false;
612848b8605Smrg         break;
613848b8605Smrg
614848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
615848b8605Smrg         feature_supports[i] = vmixer->deint.supported;
616848b8605Smrg         break;
617848b8605Smrg
618848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
619848b8605Smrg         feature_supports[i] = vmixer->sharpness.supported;
620848b8605Smrg         break;
621848b8605Smrg
622848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
623848b8605Smrg         feature_supports[i] = vmixer->noise_reduction.supported;
624848b8605Smrg         break;
625848b8605Smrg
626b8e80941Smrg      case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
627b8e80941Smrg         feature_supports[i] = vmixer->luma_key.supported;
628b8e80941Smrg         break;
629b8e80941Smrg
630b8e80941Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
631b8e80941Smrg         feature_supports[i] = vmixer->bicubic.supported;
632b8e80941Smrg         break;
633b8e80941Smrg
634848b8605Smrg      default:
635848b8605Smrg         return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
636848b8605Smrg      }
637848b8605Smrg   }
638848b8605Smrg
639848b8605Smrg   return VDP_STATUS_OK;
640848b8605Smrg}
641848b8605Smrg
642848b8605Smrg/**
643848b8605Smrg * Enable or disable features.
644848b8605Smrg */
645848b8605SmrgVdpStatus
646848b8605SmrgvlVdpVideoMixerSetFeatureEnables(VdpVideoMixer mixer,
647848b8605Smrg                                 uint32_t feature_count,
648848b8605Smrg                                 VdpVideoMixerFeature const *features,
649848b8605Smrg                                 VdpBool const *feature_enables)
650848b8605Smrg{
651848b8605Smrg   vlVdpVideoMixer *vmixer;
652848b8605Smrg   unsigned i;
653848b8605Smrg
654848b8605Smrg   if (!(features && feature_enables))
655848b8605Smrg      return VDP_STATUS_INVALID_POINTER;
656848b8605Smrg
657848b8605Smrg   vmixer = vlGetDataHTAB(mixer);
658848b8605Smrg   if (!vmixer)
659848b8605Smrg      return VDP_STATUS_INVALID_HANDLE;
660848b8605Smrg
661b8e80941Smrg   mtx_lock(&vmixer->device->mutex);
662848b8605Smrg   for (i = 0; i < feature_count; ++i) {
663848b8605Smrg      switch (features[i]) {
664848b8605Smrg      /* they are valid, but we doesn't support them */
665848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
666848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
667848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
668848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
669848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
670848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
671848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
672848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
673848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
674848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
675848b8605Smrg         break;
676848b8605Smrg
677848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
678848b8605Smrg         vmixer->deint.enabled = feature_enables[i];
679848b8605Smrg         vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer);
680848b8605Smrg         break;
681848b8605Smrg
682848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
683848b8605Smrg         vmixer->sharpness.enabled = feature_enables[i];
684848b8605Smrg         vlVdpVideoMixerUpdateSharpnessFilter(vmixer);
685848b8605Smrg         break;
686848b8605Smrg
687848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
688848b8605Smrg         vmixer->noise_reduction.enabled = feature_enables[i];
689848b8605Smrg         vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer);
690848b8605Smrg         break;
691848b8605Smrg
692b8e80941Smrg      case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
693b8e80941Smrg         vmixer->luma_key.enabled = feature_enables[i];
694b8e80941Smrg         if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))
695b8e80941Smrg            if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc,
696b8e80941Smrg                        vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) {
697b8e80941Smrg               mtx_unlock(&vmixer->device->mutex);
698b8e80941Smrg               return VDP_STATUS_ERROR;
699b8e80941Smrg            }
700b8e80941Smrg         break;
701b8e80941Smrg
702b8e80941Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
703b8e80941Smrg         vmixer->bicubic.enabled = feature_enables[i];
704b8e80941Smrg         vlVdpVideoMixerUpdateBicubicFilter(vmixer);
705b8e80941Smrg         break;
706b8e80941Smrg
707848b8605Smrg      default:
708b8e80941Smrg         mtx_unlock(&vmixer->device->mutex);
709848b8605Smrg         return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
710848b8605Smrg      }
711848b8605Smrg   }
712b8e80941Smrg   mtx_unlock(&vmixer->device->mutex);
713848b8605Smrg
714848b8605Smrg   return VDP_STATUS_OK;
715848b8605Smrg}
716848b8605Smrg
717848b8605Smrg/**
718848b8605Smrg * Retrieve whether features are enabled.
719848b8605Smrg */
720848b8605SmrgVdpStatus
721848b8605SmrgvlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer,
722848b8605Smrg                                 uint32_t feature_count,
723848b8605Smrg                                 VdpVideoMixerFeature const *features,
724848b8605Smrg                                 VdpBool *feature_enables)
725848b8605Smrg{
726848b8605Smrg   vlVdpVideoMixer *vmixer;
727848b8605Smrg   unsigned i;
728848b8605Smrg
729848b8605Smrg   if (!(features && feature_enables))
730848b8605Smrg      return VDP_STATUS_INVALID_POINTER;
731848b8605Smrg
732848b8605Smrg   vmixer = vlGetDataHTAB(mixer);
733848b8605Smrg   if (!vmixer)
734848b8605Smrg      return VDP_STATUS_INVALID_HANDLE;
735848b8605Smrg
736848b8605Smrg   for (i = 0; i < feature_count; ++i) {
737848b8605Smrg      switch (features[i]) {
738848b8605Smrg      /* they are valid, but we doesn't support them */
739848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
740848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
741848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
742848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
743848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
744848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
745848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
746848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
747848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
748848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
749848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
750848b8605Smrg         break;
751848b8605Smrg
752848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
753848b8605Smrg         feature_enables[i] = vmixer->sharpness.enabled;
754848b8605Smrg         break;
755848b8605Smrg
756848b8605Smrg      case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
757848b8605Smrg         feature_enables[i] = vmixer->noise_reduction.enabled;
758848b8605Smrg         break;
759848b8605Smrg
760b8e80941Smrg      case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
761b8e80941Smrg         feature_enables[i] = vmixer->luma_key.enabled;
762b8e80941Smrg         break;
763b8e80941Smrg
764b8e80941Smrg      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
765b8e80941Smrg         feature_enables[i] = vmixer->bicubic.enabled;
766b8e80941Smrg         break;
767b8e80941Smrg
768848b8605Smrg      default:
769848b8605Smrg         return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
770848b8605Smrg      }
771848b8605Smrg   }
772848b8605Smrg
773848b8605Smrg   return VDP_STATUS_OK;
774848b8605Smrg}
775848b8605Smrg
776848b8605Smrg/**
777848b8605Smrg * Set attribute values.
778848b8605Smrg */
779848b8605SmrgVdpStatus
780848b8605SmrgvlVdpVideoMixerSetAttributeValues(VdpVideoMixer mixer,
781848b8605Smrg                                  uint32_t attribute_count,
782848b8605Smrg                                  VdpVideoMixerAttribute const *attributes,
783848b8605Smrg                                  void const *const *attribute_values)
784848b8605Smrg{
785848b8605Smrg   const VdpColor *background_color;
786848b8605Smrg   union pipe_color_union color;
787848b8605Smrg   const float *vdp_csc;
788848b8605Smrg   float val;
789848b8605Smrg   unsigned i;
790b8e80941Smrg   VdpStatus ret;
791848b8605Smrg
792848b8605Smrg   if (!(attributes && attribute_values))
793848b8605Smrg      return VDP_STATUS_INVALID_POINTER;
794848b8605Smrg
795848b8605Smrg   vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
796848b8605Smrg   if (!vmixer)
797848b8605Smrg      return VDP_STATUS_INVALID_HANDLE;
798848b8605Smrg
799b8e80941Smrg   mtx_lock(&vmixer->device->mutex);
800848b8605Smrg   for (i = 0; i < attribute_count; ++i) {
801848b8605Smrg      switch (attributes[i]) {
802848b8605Smrg      case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR:
803848b8605Smrg         background_color = attribute_values[i];
804848b8605Smrg         color.f[0] = background_color->red;
805848b8605Smrg         color.f[1] = background_color->green;
806848b8605Smrg         color.f[2] = background_color->blue;
807848b8605Smrg         color.f[3] = background_color->alpha;
808848b8605Smrg         vl_compositor_set_clear_color(&vmixer->cstate, &color);
809848b8605Smrg         break;
810848b8605Smrg      case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX:
811848b8605Smrg         vdp_csc = attribute_values[i];
812848b8605Smrg         vmixer->custom_csc = !!vdp_csc;
813848b8605Smrg         if (!vdp_csc)
814848b8605Smrg            vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, 1, &vmixer->csc);
815848b8605Smrg         else
816848b8605Smrg            memcpy(vmixer->csc, vdp_csc, sizeof(vl_csc_matrix));
817848b8605Smrg         if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))
818b8e80941Smrg            if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc,
819b8e80941Smrg                                         vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) {
820b8e80941Smrg               ret = VDP_STATUS_ERROR;
821b8e80941Smrg               goto fail;
822b8e80941Smrg            }
823848b8605Smrg         break;
824848b8605Smrg
825848b8605Smrg      case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL:
826848b8605Smrg
827848b8605Smrg         val = *(float*)attribute_values[i];
828b8e80941Smrg         if (val < 0.0f || val > 1.0f) {
829b8e80941Smrg            ret = VDP_STATUS_INVALID_VALUE;
830b8e80941Smrg            goto fail;
831b8e80941Smrg         }
832848b8605Smrg
833848b8605Smrg         vmixer->noise_reduction.level = val * 10;
834848b8605Smrg         vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer);
835848b8605Smrg         break;
836848b8605Smrg
837848b8605Smrg      case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA:
838848b8605Smrg         val = *(float*)attribute_values[i];
839b8e80941Smrg         if (val < 0.0f || val > 1.0f) {
840b8e80941Smrg            ret = VDP_STATUS_INVALID_VALUE;
841b8e80941Smrg            goto fail;
842b8e80941Smrg         }
843b8e80941Smrg         vmixer->luma_key.luma_min = val;
844b8e80941Smrg         if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))
845b8e80941Smrg            if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc,
846b8e80941Smrg                        vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) {
847b8e80941Smrg               ret = VDP_STATUS_ERROR;
848b8e80941Smrg               goto fail;
849b8e80941Smrg            }
850848b8605Smrg         break;
851b8e80941Smrg
852848b8605Smrg      case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA:
853848b8605Smrg         val = *(float*)attribute_values[i];
854b8e80941Smrg         if (val < 0.0f || val > 1.0f) {
855b8e80941Smrg            ret = VDP_STATUS_INVALID_VALUE;
856b8e80941Smrg            goto fail;
857b8e80941Smrg         }
858b8e80941Smrg         vmixer->luma_key.luma_max = val;
859b8e80941Smrg         if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))
860b8e80941Smrg            if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc,
861b8e80941Smrg                        vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) {
862b8e80941Smrg               ret = VDP_STATUS_ERROR;
863b8e80941Smrg               goto fail;
864b8e80941Smrg            }
865848b8605Smrg         break;
866848b8605Smrg
867848b8605Smrg      case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL:
868848b8605Smrg
869848b8605Smrg         val = *(float*)attribute_values[i];
870b8e80941Smrg         if (val < -1.0f || val > 1.0f) {
871b8e80941Smrg            ret = VDP_STATUS_INVALID_VALUE;
872b8e80941Smrg            goto fail;
873b8e80941Smrg         }
874848b8605Smrg
875848b8605Smrg         vmixer->sharpness.value = val;
876848b8605Smrg         vlVdpVideoMixerUpdateSharpnessFilter(vmixer);
877848b8605Smrg         break;
878848b8605Smrg
879848b8605Smrg      case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE:
880b8e80941Smrg         if (*(uint8_t*)attribute_values[i] > 1) {
881b8e80941Smrg            ret = VDP_STATUS_INVALID_VALUE;
882b8e80941Smrg            goto fail;
883b8e80941Smrg         }
884848b8605Smrg         vmixer->skip_chroma_deint = *(uint8_t*)attribute_values[i];
885848b8605Smrg         vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer);
886848b8605Smrg         break;
887848b8605Smrg      default:
888b8e80941Smrg         ret = VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE;
889b8e80941Smrg         goto fail;
890848b8605Smrg      }
891848b8605Smrg   }
892b8e80941Smrg   mtx_unlock(&vmixer->device->mutex);
893848b8605Smrg
894848b8605Smrg   return VDP_STATUS_OK;
895b8e80941Smrgfail:
896b8e80941Smrg   mtx_unlock(&vmixer->device->mutex);
897b8e80941Smrg   return ret;
898848b8605Smrg}
899848b8605Smrg
900848b8605Smrg/**
901848b8605Smrg * Retrieve parameter values given at creation time.
902848b8605Smrg */
903848b8605SmrgVdpStatus
904848b8605SmrgvlVdpVideoMixerGetParameterValues(VdpVideoMixer mixer,
905848b8605Smrg                                  uint32_t parameter_count,
906848b8605Smrg                                  VdpVideoMixerParameter const *parameters,
907848b8605Smrg                                  void *const *parameter_values)
908848b8605Smrg{
909848b8605Smrg   vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
910848b8605Smrg   unsigned i;
911848b8605Smrg   if (!vmixer)
912848b8605Smrg      return VDP_STATUS_INVALID_HANDLE;
913848b8605Smrg
914848b8605Smrg   if (!parameter_count)
915848b8605Smrg      return VDP_STATUS_OK;
916848b8605Smrg   if (!(parameters && parameter_values))
917848b8605Smrg      return VDP_STATUS_INVALID_POINTER;
918848b8605Smrg   for (i = 0; i < parameter_count; ++i) {
919848b8605Smrg      switch (parameters[i]) {
920848b8605Smrg      case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH:
921848b8605Smrg         *(uint32_t*)parameter_values[i] = vmixer->video_width;
922848b8605Smrg         break;
923848b8605Smrg      case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT:
924848b8605Smrg         *(uint32_t*)parameter_values[i] = vmixer->video_height;
925848b8605Smrg         break;
926848b8605Smrg      case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE:
927848b8605Smrg         *(VdpChromaType*)parameter_values[i] = PipeToChroma(vmixer->chroma_format);
928848b8605Smrg         break;
929848b8605Smrg      case VDP_VIDEO_MIXER_PARAMETER_LAYERS:
930848b8605Smrg         *(uint32_t*)parameter_values[i] = vmixer->max_layers;
931848b8605Smrg         break;
932848b8605Smrg      default:
933848b8605Smrg         return VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER;
934848b8605Smrg      }
935848b8605Smrg   }
936848b8605Smrg   return VDP_STATUS_OK;
937848b8605Smrg}
938848b8605Smrg
939848b8605Smrg/**
940848b8605Smrg * Retrieve current attribute values.
941848b8605Smrg */
942848b8605SmrgVdpStatus
943848b8605SmrgvlVdpVideoMixerGetAttributeValues(VdpVideoMixer mixer,
944848b8605Smrg                                  uint32_t attribute_count,
945848b8605Smrg                                  VdpVideoMixerAttribute const *attributes,
946848b8605Smrg                                  void *const *attribute_values)
947848b8605Smrg{
948848b8605Smrg   unsigned i;
949848b8605Smrg   VdpCSCMatrix **vdp_csc;
950848b8605Smrg
951848b8605Smrg   if (!(attributes && attribute_values))
952848b8605Smrg      return VDP_STATUS_INVALID_POINTER;
953848b8605Smrg
954848b8605Smrg   vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
955848b8605Smrg   if (!vmixer)
956848b8605Smrg      return VDP_STATUS_INVALID_HANDLE;
957848b8605Smrg
958b8e80941Smrg   mtx_lock(&vmixer->device->mutex);
959848b8605Smrg   for (i = 0; i < attribute_count; ++i) {
960848b8605Smrg      switch (attributes[i]) {
961848b8605Smrg      case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR:
962848b8605Smrg         vl_compositor_get_clear_color(&vmixer->cstate, attribute_values[i]);
963848b8605Smrg         break;
964848b8605Smrg      case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX:
965848b8605Smrg         vdp_csc = attribute_values[i];
966848b8605Smrg         if (!vmixer->custom_csc) {
967848b8605Smrg             *vdp_csc = NULL;
968848b8605Smrg            break;
969848b8605Smrg         }
970848b8605Smrg         memcpy(*vdp_csc, vmixer->csc, sizeof(float)*12);
971848b8605Smrg         break;
972848b8605Smrg
973848b8605Smrg      case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL:
974848b8605Smrg         *(float*)attribute_values[i] = (float)vmixer->noise_reduction.level / 10.0f;
975848b8605Smrg         break;
976848b8605Smrg
977848b8605Smrg      case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA:
978b8e80941Smrg         *(float*)attribute_values[i] = vmixer->luma_key.luma_min;
979848b8605Smrg         break;
980848b8605Smrg      case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA:
981b8e80941Smrg         *(float*)attribute_values[i] = vmixer->luma_key.luma_max;
982848b8605Smrg         break;
983848b8605Smrg      case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL:
984848b8605Smrg         *(float*)attribute_values[i] = vmixer->sharpness.value;
985848b8605Smrg         break;
986848b8605Smrg      case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE:
987848b8605Smrg         *(uint8_t*)attribute_values[i] = vmixer->skip_chroma_deint;
988848b8605Smrg         break;
989848b8605Smrg      default:
990b8e80941Smrg         mtx_unlock(&vmixer->device->mutex);
991848b8605Smrg         return VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE;
992848b8605Smrg      }
993848b8605Smrg   }
994b8e80941Smrg   mtx_unlock(&vmixer->device->mutex);
995848b8605Smrg   return VDP_STATUS_OK;
996848b8605Smrg}
997848b8605Smrg
998848b8605Smrg/**
999848b8605Smrg * Generate a color space conversion matrix.
1000848b8605Smrg */
1001848b8605SmrgVdpStatus
1002848b8605SmrgvlVdpGenerateCSCMatrix(VdpProcamp *procamp,
1003848b8605Smrg                       VdpColorStandard standard,
1004848b8605Smrg                       VdpCSCMatrix *csc_matrix)
1005848b8605Smrg{
1006848b8605Smrg   enum VL_CSC_COLOR_STANDARD vl_std;
1007848b8605Smrg   struct vl_procamp camp;
1008848b8605Smrg
1009848b8605Smrg   if (!csc_matrix)
1010848b8605Smrg      return VDP_STATUS_INVALID_POINTER;
1011848b8605Smrg
1012848b8605Smrg   switch (standard) {
1013848b8605Smrg      case VDP_COLOR_STANDARD_ITUR_BT_601: vl_std = VL_CSC_COLOR_STANDARD_BT_601; break;
1014848b8605Smrg      case VDP_COLOR_STANDARD_ITUR_BT_709: vl_std = VL_CSC_COLOR_STANDARD_BT_709; break;
1015848b8605Smrg      case VDP_COLOR_STANDARD_SMPTE_240M:  vl_std = VL_CSC_COLOR_STANDARD_SMPTE_240M; break;
1016848b8605Smrg      default: return VDP_STATUS_INVALID_COLOR_STANDARD;
1017848b8605Smrg   }
1018848b8605Smrg
1019848b8605Smrg   if (procamp) {
1020848b8605Smrg      if (procamp->struct_version > VDP_PROCAMP_VERSION)
1021848b8605Smrg         return VDP_STATUS_INVALID_STRUCT_VERSION;
1022848b8605Smrg      camp.brightness = procamp->brightness;
1023848b8605Smrg      camp.contrast = procamp->contrast;
1024848b8605Smrg      camp.saturation = procamp->saturation;
1025848b8605Smrg      camp.hue = procamp->hue;
1026848b8605Smrg   }
1027848b8605Smrg
1028848b8605Smrg   vl_csc_get_matrix(vl_std, procamp ? &camp : NULL, true, csc_matrix);
1029848b8605Smrg   return VDP_STATUS_OK;
1030848b8605Smrg}
1031