<div dir="ltr"><div class="gmail_quote"><div dir="ltr">Thanks for the review.<br><div class="gmail_extra"><br><div class="gmail_quote"><div><div class="h5">On Wed, Jun 22, 2016 at 1:17 PM, Christian König <span dir="ltr"><<a href="mailto:deathsimple@vodafone.de" target="_blank">deathsimple@vodafone.de</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div><div>Am 21.06.2016 um 21:21 schrieb Nayan Deshmukh:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
use bicubic filtering as high quality scaling L1.<br>
<br>
v2: fix a typo and add a newline to code<br>
<br>
v3: -render the unscaled image on a temporary surface (Christian)<br>
     -apply noise reduction and sharpness filter on<br>
      unscaled surface<br>
     -render the final scaled surface using bicubic<br>
      interpolation<br>
<br>
v4: support high quality scaling<br>
<br>
Signed-off-by: Nayan Deshmukh <<a href="mailto:nayan26deshmukh@gmail.com" target="_blank">nayan26deshmukh@gmail.com</a>><br>
---<br>
  src/gallium/state_trackers/vdpau/mixer.c         | 109 ++++++++++++++++++++---<br>
  src/gallium/state_trackers/vdpau/query.c         |   1 +<br>
  src/gallium/state_trackers/vdpau/vdpau_private.h |   6 ++<br>
  3 files changed, 102 insertions(+), 14 deletions(-)<br>
<br>
diff --git a/src/gallium/state_trackers/vdpau/mixer.c b/src/gallium/state_trackers/vdpau/mixer.c<br>
index 65c3ce2..2a67ac2 100644<br>
--- a/src/gallium/state_trackers/vdpau/mixer.c<br>
+++ b/src/gallium/state_trackers/vdpau/mixer.c<br>
@@ -82,7 +82,6 @@ vlVdpVideoMixerCreate(VdpDevice device,<br>
        switch (features[i]) {<br>
        /* they are valid, but we doesn't support them */<br>
        case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:<br>
-      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:<br>
        case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:<br>
        case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:<br>
        case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:<br>
@@ -110,6 +109,9 @@ vlVdpVideoMixerCreate(VdpDevice device,<br>
           vmixer->luma_key.supported = true;<br>
           break;<br>
  +      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:<br>
+         vmixer->bicubic.supported = true;<br>
+         break;<br>
        default: goto no_params;<br>
        }<br>
     }<br>
@@ -202,6 +204,11 @@ vlVdpVideoMixerDestroy(VdpVideoMixer mixer)<br>
        vl_matrix_filter_cleanup(vmixer->sharpness.filter);<br>
        FREE(vmixer->sharpness.filter);<br>
     }<br>
+<br>
+   if (vmixer->bicubic.filter) {<br>
+      vl_bicubic_filter_cleanup(vmixer->bicubic.filter);<br>
+      FREE(vmixer->bicubic.filter);<br>
+   }<br>
     pipe_mutex_unlock(vmixer->device->mutex);<br>
     DeviceReference(&vmixer->device, NULL);<br>
  @@ -230,9 +237,11 @@ VdpStatus vlVdpVideoMixerRender(VdpVideoMixer mixer,<br>
                                  VdpLayer const *layers)<br>
  {<br>
     enum vl_compositor_deinterlace deinterlace;<br>
-   struct u_rect rect, clip, *prect;<br>
+   struct u_rect rect, clip, *prect, *rect_temp, dirty_area, temp;<br>
     unsigned i, layer = 0;<br>
     struct pipe_video_buffer *video_buffer;<br>
+   struct pipe_sampler_view *sampler_view;<br>
+   struct pipe_surface *surface;<br>
       vlVdpVideoMixer *vmixer;<br>
     vlVdpSurface *surf;<br>
@@ -324,8 +333,48 @@ VdpStatus vlVdpVideoMixerRender(VdpVideoMixer mixer,<br>
        rect.y1 = surf->templat.height;<br>
        prect = &rect;<br>
     }<br>
+<br>
+   if(vmixer->bicubic.filter){<br>
+      struct pipe_context *pipe;<br>
+      struct pipe_resource res_tmpl, *res;<br>
+      struct pipe_sampler_view sv_templ;<br>
+      struct pipe_surface surf_templ;<br>
+<br>
+      pipe = vmixer->device->context;<br>
+      memset(&res_tmpl, 0, sizeof(res_tmpl));<br>
+<br>
+      res_tmpl.target = PIPE_TEXTURE_2D;<br>
+      res_tmpl.format = surf->templat.chroma_format;<br>
</blockquote>
<br></div></div>
That is incorrect. The resource format isn't related in any way to the chroma format. Please use the format of the destination surface here.<span><br>
<br></span></blockquote></div></div><div>I should probably use res_tmpl = dst->sampler_view->texture->format; Right?</div><span class=""><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><span>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
+      res_tmpl.width0 = surf->templat.width;<br>
+      res_tmpl.height0 = surf->templat.height;<br>
+      res_tmpl.depth0 = 1;<br>
+      res_tmpl.array_size = 1;<br>
+      res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET |<br>
+                     PIPE_BIND_LINEAR | PIPE_BIND_SHARED;<br>
</blockquote>
<br></span>
No need for PIPE_BIND_LINEAR or PIPE_BIND_SHARED here, we are not going to share the temporary texture with anybody.<span><br>
<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
+      res_tmpl.usage = PIPE_USAGE_DEFAULT;<br>
+<br>
+      res = pipe->screen->resource_create(pipe->screen, &res_tmpl);<br>
+<br>
+      vlVdpDefaultSamplerViewTemplate(&sv_templ, res);<br>
+      sampler_view = pipe->create_sampler_view(pipe, res, &sv_templ);<br>
+<br>
+      memset(&surf_templ, 0, sizeof(surf_templ));<br>
+      surf_templ.format = res->format;<br>
+      surface = pipe->create_surface(pipe, res, &surf_templ);<br>
+<br>
+      vl_compositor_reset_dirty_area(&dirty_area);<br>
+      rect_temp = prect;<br>
</blockquote>
<br></span>
You need to free the resource with pipe_resource_reference(&res, NULL); here, otherwise you will create quite a memory leak.<br>
<br>
Same thing is true for the surface and the sampler view, but you need those and can only free them later on. Easiest way to do this is probably to grab an extra reference in the else case as well.<br>
<br></blockquote></span><div>I can also check in the end if (surface != dst->surface) and then free the surface and sampler_view if it's true.</div><span class=""><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
+   }<br>
+<br>
+   else{<br>
</blockquote>
<br>
Coding style here should be "} else {" if I remember correctly.<span><br>
<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
+       surface = dst->surface;<br>
+       sampler_view = dst->sampler_view;<br>
+       rect_temp = RectToPipe(destination_video_rect, &temp);<br>
+       dirty_area = dst->dirty_area;<br>
+   }<br>
+<br>
     vl_compositor_set_buffer_layer(&vmixer->cstate, compositor, layer, video_buffer, prect, NULL, deinterlace);<br>
-   vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(destination_video_rect, &rect));<br>
+   vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, rect_temp);<br>
       for (i = 0; i < layer_count; ++i) {<br>
        vlVdpOutputSurface *src = vlGetDataHTAB(layers->source_surface);<br>
@@ -343,22 +392,22 @@ VdpStatus vlVdpVideoMixerRender(VdpVideoMixer mixer,<br>
        ++layers;<br>
     }<br>
  -   vl_compositor_set_dst_clip(&vmixer->cstate, RectToPipe(destination_rect, &clip));<br>
</blockquote>
<br></span>
That probably needs to be moved into the true case of the if and the clip handled by the bicubic filter as well.<br>
<br>
Same is true for the destination video rectangle as well.<br>
<br>
</blockquote><div><br></div></span><div>if the bicubic scaling is off then we need to set dst_area and dst_clip in vl_compositor, but if bicubic scaling is on then </div><div>dst_area and dst_clip should be set in bicubic_filter.</div><div><br></div><div>Regards,</div><div>Nayan.</div><div><div class="h5"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">Regards,<br>
Christian.<div><div><br>
<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">
-   if (!vmixer->noise_reduction.filter && !vmixer->sharpness.filter)<br>
+   if (!vmixer->noise_reduction.filter && !vmixer->sharpness.filter && !vmixer->bicubic.filter)<br>
        vlVdpSave4DelayedRendering(vmixer->device, destination_surface, &vmixer->cstate);<br>
     else {<br>
-      vl_compositor_render(&vmixer->cstate, compositor, dst->surface, &dst->dirty_area, true);<br>
+      vl_compositor_render(&vmixer->cstate, compositor, surface, &dirty_area, true);<br>
  -      /* applying the noise reduction after scaling is actually not very<br>
-         clever, but currently we should avoid to copy around the image<br>
-         data once more. */<br>
        if (vmixer->noise_reduction.filter)<br>
           vl_median_filter_render(vmixer->noise_reduction.filter,<br>
-                                 dst->sampler_view, dst->surface);<br>
+                                 sampler_view, surface);<br>
          if (vmixer->sharpness.filter)<br>
           vl_matrix_filter_render(vmixer->sharpness.filter,<br>
-                                 dst->sampler_view, dst->surface);<br>
+                                 sampler_view, surface);<br>
+<br>
+      if (vmixer->bicubic.filter)<br>
+         vl_bicubic_filter_render(vmixer->bicubic.filter,<br>
+                                 sampler_view, dst->surface);<br>
     }<br>
     pipe_mutex_unlock(vmixer->device->mutex);<br>
  @@ -461,6 +510,28 @@ vlVdpVideoMixerUpdateSharpnessFilter(vlVdpVideoMixer *vmixer)<br>
  }<br>
    /**<br>
+ * Update the bicubic filter<br>
+ */<br>
+static void<br>
+vlVdpVideoMixerUpdateBicubicFilter(vlVdpVideoMixer *vmixer)<br>
+{<br>
+   assert(vmixer);<br>
+<br>
+   /* if present remove the old filter first */<br>
+   if (vmixer->bicubic.filter) {<br>
+      vl_bicubic_filter_cleanup(vmixer->bicubic.filter);<br>
+      FREE(vmixer->bicubic.filter);<br>
+      vmixer->bicubic.filter = NULL;<br>
+   }<br>
+   /* and create a new filter as needed */<br>
+   if (vmixer->bicubic.enabled) {<br>
+      vmixer->bicubic.filter = MALLOC(sizeof(struct vl_bicubic_filter));<br>
+      vl_bicubic_filter_init(vmixer->bicubic.filter, vmixer->device->context,<br>
+                            vmixer->video_width, vmixer->video_height);<br>
+   }<br>
+}<br>
+<br>
+/**<br>
   * Retrieve whether features were requested at creation time.<br>
   */<br>
  VdpStatus<br>
@@ -483,7 +554,6 @@ vlVdpVideoMixerGetFeatureSupport(VdpVideoMixer mixer,<br>
        switch (features[i]) {<br>
        /* they are valid, but we doesn't support them */<br>
        case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:<br>
-      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:<br>
        case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:<br>
        case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:<br>
        case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:<br>
@@ -512,6 +582,10 @@ vlVdpVideoMixerGetFeatureSupport(VdpVideoMixer mixer,<br>
           feature_supports[i] = vmixer->luma_key.supported;<br>
           break;<br>
  +      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:<br>
+         feature_supports[i] = vmixer->bicubic.supported;<br>
+         break;<br>
+<br>
        default:<br>
           return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;<br>
        }<br>
@@ -544,7 +618,6 @@ vlVdpVideoMixerSetFeatureEnables(VdpVideoMixer mixer,<br>
        switch (features[i]) {<br>
        /* they are valid, but we doesn't support them */<br>
        case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:<br>
-      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:<br>
        case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:<br>
        case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:<br>
        case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:<br>
@@ -578,6 +651,11 @@ vlVdpVideoMixerSetFeatureEnables(VdpVideoMixer mixer,<br>
                                           vmixer->luma_key.luma_min, vmixer->luma_key.luma_max);<br>
           break;<br>
  +      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:<br>
+         vmixer->bicubic.enabled = feature_enables[i];<br>
+         vlVdpVideoMixerUpdateBicubicFilter(vmixer);<br>
+         break;<br>
+<br>
        default:<br>
           pipe_mutex_unlock(vmixer->device->mutex);<br>
           return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;<br>
@@ -612,7 +690,6 @@ vlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer,<br>
        /* they are valid, but we doesn't support them */<br>
        case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:<br>
        case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:<br>
-      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:<br>
        case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:<br>
        case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:<br>
        case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:<br>
@@ -636,6 +713,10 @@ vlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer,<br>
           feature_enables[i] = vmixer->luma_key.enabled;<br>
           break;<br>
  +      case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:<br>
+         feature_enables[i] = vmixer->bicubic.enabled;<br>
+         break;<br>
+<br>
        default:<br>
           return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;<br>
        }<br>
diff --git a/src/gallium/state_trackers/vdpau/query.c b/src/gallium/state_trackers/vdpau/query.c<br>
index c3decc0..e69c9b1 100644<br>
--- a/src/gallium/state_trackers/vdpau/query.c<br>
+++ b/src/gallium/state_trackers/vdpau/query.c<br>
@@ -471,6 +471,7 @@ vlVdpVideoMixerQueryFeatureSupport(VdpDevice device, VdpVideoMixerFeature featur<br>
     case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:<br>
     case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:<br>
     case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:<br>
+   case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:<br>
        *is_supported = VDP_TRUE;<br>
        break;<br>
     default:<br>
diff --git a/src/gallium/state_trackers/vdpau/vdpau_private.h b/src/gallium/state_trackers/vdpau/vdpau_private.h<br>
index 8673c6a..bcd4bb1 100644<br>
--- a/src/gallium/state_trackers/vdpau/vdpau_private.h<br>
+++ b/src/gallium/state_trackers/vdpau/vdpau_private.h<br>
@@ -45,6 +45,7 @@<br>
  #include "os/os_thread.h"<br>
    #include "vl/vl_video_buffer.h"<br>
+#include "vl/vl_bicubic_filter.h"<br>
  #include "vl/vl_compositor.h"<br>
  #include "vl/vl_csc.h"<br>
  #include "vl/vl_deint_filter.h"<br>
@@ -373,6 +374,11 @@ typedef struct<br>
     } deint;<br>
       struct {<br>
+         bool supported, enabled;<br>
+         struct vl_bicubic_filter *filter;<br>
+   } bicubic;<br>
+<br>
+   struct {<br>
        bool supported, enabled;<br>
        unsigned level;<br>
        struct vl_median_filter *filter;<br>
</blockquote>
<br>
</div></div></blockquote></div></div></div><br></div></div>
</div><br></div>