[Mesa-dev,1/2] vl: add motion adaptive deinterlacer

Submitted by Grigori Goronzy on Feb. 13, 2014, 8:32 p.m.

Details

Message ID 1392323550-20477-1-git-send-email-greg@chown.ath.cx
State New
Headers show

Not browsing as part of any series.

Commit Message

Grigori Goronzy Feb. 13, 2014, 8:32 p.m.
---
 src/gallium/auxiliary/Makefile.sources     |   3 +-
 src/gallium/auxiliary/vl/vl_deint_filter.c | 491 +++++++++++++++++++++++++++++
 src/gallium/auxiliary/vl/vl_deint_filter.h |  78 +++++
 3 files changed, 571 insertions(+), 1 deletion(-)
 create mode 100644 src/gallium/auxiliary/vl/vl_deint_filter.c
 create mode 100644 src/gallium/auxiliary/vl/vl_deint_filter.h

Patch hide | download patch | download mbox

diff --git a/src/gallium/auxiliary/Makefile.sources b/src/gallium/auxiliary/Makefile.sources
index c89cbdd..19004e0 100644
--- a/src/gallium/auxiliary/Makefile.sources
+++ b/src/gallium/auxiliary/Makefile.sources
@@ -155,7 +155,8 @@  C_SOURCES := \
         vl/vl_idct.c \
 	vl/vl_mc.c \
         vl/vl_vertex_buffers.c \
-        vl/vl_video_buffer.c
+        vl/vl_video_buffer.c \
+	vl/vl_deint_filter.c
 
 GENERATED_SOURCES := \
 	indices/u_indices_gen.c \
diff --git a/src/gallium/auxiliary/vl/vl_deint_filter.c b/src/gallium/auxiliary/vl/vl_deint_filter.c
new file mode 100644
index 0000000..9b05154
--- /dev/null
+++ b/src/gallium/auxiliary/vl/vl_deint_filter.c
@@ -0,0 +1,491 @@ 
+/**************************************************************************
+ *
+ * Copyright 2013 Grigori Goronzy <greg@chown.ath.cx>.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/*
+ *  References:
+ *
+ *  Lin, S. F., Chang, Y. L., & Chen, L. G. (2003).
+ *  Motion adaptive interpolation with horizontal motion detection for deinterlacing.
+ *  Consumer Electronics, IEEE Transactions on, 49(4), 1256-1265.
+ *
+ *  Pei-Yin, C. H. E. N., & Yao-Hsien, L. A. I. (2007).
+ *  A low-complexity interpolation method for deinterlacing.
+ *  IEICE transactions on information and systems, 90(2), 606-608.
+ *
+ */
+
+#include <stdio.h>
+
+#include "pipe/p_context.h"
+
+#include "tgsi/tgsi_ureg.h"
+
+#include "util/u_draw.h"
+#include "util/u_memory.h"
+#include "util/u_math.h"
+
+#include "vl_types.h"
+#include "vl_video_buffer.h"
+#include "vl_vertex_buffers.h"
+#include "vl_deint_filter.h"
+
+enum VS_OUTPUT
+{
+   VS_O_VPOS = 0,
+   VS_O_VTEX = 0
+};
+
+static void *
+create_vert_shader(struct vl_deint_filter *filter)
+{
+   struct ureg_program *shader;
+   struct ureg_src i_vpos;
+   struct ureg_dst o_vpos, o_vtex;
+
+   shader = ureg_create(TGSI_PROCESSOR_VERTEX);
+   if (!shader)
+      return NULL;
+
+   i_vpos = ureg_DECL_vs_input(shader, 0);
+   o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
+   o_vtex = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX);
+
+   ureg_MOV(shader, o_vpos, i_vpos);
+   ureg_MOV(shader, o_vtex, i_vpos);
+
+   ureg_END(shader);
+
+   return ureg_create_shader_and_destroy(shader, filter->pipe);
+}
+
+static void *
+create_copy_frag_shader(struct vl_deint_filter *filter, unsigned field)
+{
+   struct ureg_program *shader;
+   struct ureg_src i_vtex;
+   struct ureg_src sampler;
+   struct ureg_dst o_fragment;
+   struct ureg_dst t_tex;
+
+   shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
+   if (!shader) {
+      return NULL;
+   }
+   t_tex = ureg_DECL_temporary(shader);
+
+   i_vtex = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX, TGSI_INTERPOLATE_LINEAR);
+   sampler = ureg_DECL_sampler(shader, 2);
+   o_fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
+
+   ureg_MOV(shader, t_tex, i_vtex);
+   if (field) {
+      ureg_MOV(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_ZW),
+               ureg_imm4f(shader, 0, 0, 1.0f, 0));
+   } else {
+      ureg_MOV(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_ZW),
+               ureg_imm1f(shader, 0));
+   }
+
+   ureg_TEX(shader, o_fragment, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_tex), sampler);
+
+   ureg_release_temporary(shader, t_tex);
+   ureg_END(shader);
+
+   return ureg_create_shader_and_destroy(shader, filter->pipe);
+}
+
+static void *
+create_deint_frag_shader(struct vl_deint_filter *filter, unsigned field,
+                         struct vertex2f *sizes, bool spatial_filter)
+{
+   struct ureg_program *shader;
+   struct ureg_src i_vtex;
+   struct ureg_src sampler_cur;
+   struct ureg_src sampler_prevprev;
+   struct ureg_src sampler_prev;
+   struct ureg_src sampler_next;
+   struct ureg_dst o_fragment;
+   struct ureg_dst t_tex;
+   struct ureg_dst t_comp_top, t_comp_bot;
+   struct ureg_dst t_diff;
+   struct ureg_dst t_a, t_b;
+   struct ureg_dst t_weave, t_linear;
+
+   shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
+   if (!shader) {
+      return NULL;
+   }
+
+   t_tex = ureg_DECL_temporary(shader);
+   t_comp_top = ureg_DECL_temporary(shader);
+   t_comp_bot = ureg_DECL_temporary(shader);
+   t_diff = ureg_DECL_temporary(shader);
+   t_a = ureg_DECL_temporary(shader);
+   t_b = ureg_DECL_temporary(shader);
+   t_weave = ureg_DECL_temporary(shader);
+   t_linear = ureg_DECL_temporary(shader);
+
+   i_vtex = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX, TGSI_INTERPOLATE_LINEAR);
+   sampler_prevprev = ureg_DECL_sampler(shader, 0);
+   sampler_prev = ureg_DECL_sampler(shader, 1);
+   sampler_cur = ureg_DECL_sampler(shader, 2);
+   sampler_next = ureg_DECL_sampler(shader, 3);
+   o_fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
+
+   // we don't care about ZW interpolation (allows better optimization)
+   ureg_MOV(shader, t_tex, i_vtex);
+   ureg_MOV(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_ZW),
+            ureg_imm1f(shader, 0));
+
+   // sample between texels for cheap lowpass
+   ureg_ADD(shader, t_comp_top, ureg_src(t_tex),
+            ureg_imm4f(shader, sizes->x * 0.5f, sizes->y * -0.5f, 0, 0));
+   ureg_ADD(shader, t_comp_bot, ureg_src(t_tex),
+            ureg_imm4f(shader, sizes->x * -0.5f, sizes->y * 0.5f, 1.0f, 0));
+
+   if (field == 0) {
+      /* interpolating top field -> current field is a bottom field */
+      // cur vs prev2
+      ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_cur);
+      ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_prevprev);
+      ureg_SUB(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X), ureg_src(t_a), ureg_src(t_b));
+      // prev vs next
+      ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top), sampler_prev);
+      ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top), sampler_next);
+      ureg_SUB(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_Y), ureg_src(t_a), ureg_src(t_b));
+   } else {
+      /* interpolating bottom field -> current field is a top field */
+      // cur vs prev2
+      ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top), sampler_cur);
+      ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top), sampler_prevprev);
+      ureg_SUB(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X), ureg_src(t_a), ureg_src(t_b));
+      // prev vs next
+      ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_prev);
+      ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_next);
+      ureg_SUB(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_Y), ureg_src(t_a), ureg_src(t_b));
+   }
+
+   // absolute maximum of differences
+   ureg_MAX(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X), ureg_abs(ureg_src(t_diff)),
+            ureg_scalar(ureg_abs(ureg_src(t_diff)), TGSI_SWIZZLE_Y));
+
+   if (field == 0) {
+      /* weave with prev top field */
+      ureg_TEX(shader, t_weave, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_tex), sampler_prev);
+      /* get linear interpolation from current bottom field */
+      ureg_ADD(shader, t_comp_top, ureg_src(t_tex), ureg_imm4f(shader, 0, sizes->y * -1.0f, 1.0f, 0));
+      ureg_TEX(shader, t_linear, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top), sampler_cur);
+   } else {
+      /* weave with prev bottom field */
+      ureg_ADD(shader, t_comp_bot, ureg_src(t_tex), ureg_imm4f(shader, 0, 0, 1.0f, 0));
+      ureg_TEX(shader, t_weave, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_prev);
+      /* get linear interpolation from current top field */
+      ureg_ADD(shader, t_comp_bot, ureg_src(t_tex), ureg_imm4f(shader, 0, sizes->y * 1.0f, 0, 0));
+      ureg_TEX(shader, t_linear, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_cur);
+   }
+
+   // mix between weave and linear
+   // fully weave if diff < 6 (0.02353), fully interpolate if diff > 14 (0.05490)
+   ureg_ADD(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X), ureg_src(t_diff),
+            ureg_imm4f(shader, -0.02353f, 0, 0, 0));
+   ureg_MUL(shader, ureg_saturate(ureg_writemask(t_diff, TGSI_WRITEMASK_X)),
+            ureg_src(t_diff), ureg_imm4f(shader, 31.8750f, 0, 0, 0));
+   ureg_LRP(shader, ureg_writemask(o_fragment, TGSI_WRITEMASK_X), ureg_src(t_diff),
+            ureg_src(t_linear), ureg_src(t_weave));
+
+   ureg_release_temporary(shader, t_tex);
+   ureg_release_temporary(shader, t_comp_top);
+   ureg_release_temporary(shader, t_comp_bot);
+   ureg_release_temporary(shader, t_diff);
+   ureg_release_temporary(shader, t_a);
+   ureg_release_temporary(shader, t_b);
+   ureg_release_temporary(shader, t_weave);
+   ureg_release_temporary(shader, t_linear);
+   ureg_END(shader);
+
+   return ureg_create_shader_and_destroy(shader, filter->pipe);
+}
+
+bool
+vl_deint_filter_init(struct vl_deint_filter *filter, struct pipe_context *pipe,
+                     unsigned video_width, unsigned video_height,
+                     bool skip_chroma, bool spatial_filter)
+{
+   struct pipe_rasterizer_state rs_state;
+   struct pipe_blend_state blend;
+   struct pipe_sampler_state sampler;
+   struct pipe_vertex_element ve;
+   struct vertex2f sizes;
+   struct pipe_video_buffer templ;
+
+   assert(filter && pipe);
+   assert(video_width && video_height);
+
+   memset(filter, 0, sizeof(*filter));
+   filter->pipe = pipe;
+   filter->skip_chroma = skip_chroma;
+   filter->video_width = video_width;
+   filter->video_height = video_height;
+
+   /* TODO: handle other than 4:2:0 subsampling */
+   memset(&templ, 0, sizeof(templ));
+   templ.buffer_format = PIPE_FORMAT_YV12;
+   templ.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
+   templ.width = video_width;
+   templ.height = video_height;
+   templ.interlaced = true;
+   filter->video_buffer = vl_video_buffer_create(pipe, &templ);
+   if (!filter->video_buffer)
+      goto error_video_buffer;
+
+   memset(&rs_state, 0, sizeof(rs_state));
+   rs_state.half_pixel_center = true;
+   rs_state.bottom_edge_rule = true;
+   rs_state.depth_clip = 1;
+   filter->rs_state = pipe->create_rasterizer_state(pipe, &rs_state);
+   if (!filter->rs_state)
+      goto error_rs_state;
+
+   memset(&blend, 0, sizeof blend);
+   blend.rt[0].colormask = PIPE_MASK_RGBA;
+   filter->blend = pipe->create_blend_state(pipe, &blend);
+   if (!filter->blend)
+      goto error_blend;
+
+   memset(&sampler, 0, sizeof(sampler));
+   sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
+   sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
+   sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
+   sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
+   sampler.normalized_coords = 1;
+   filter->sampler[0] = pipe->create_sampler_state(pipe, &sampler);
+   filter->sampler[1] = filter->sampler[2] = filter->sampler[3] = filter->sampler[0];
+   if (!filter->sampler[0])
+      goto error_sampler;
+
+   filter->quad = vl_vb_upload_quads(pipe);
+   if(!filter->quad.buffer)
+      goto error_quad;
+
+   memset(&ve, 0, sizeof(ve));
+   ve.src_offset = 0;
+   ve.instance_divisor = 0;
+   ve.vertex_buffer_index = 0;
+   ve.src_format = PIPE_FORMAT_R32G32_FLOAT;
+   filter->ves = pipe->create_vertex_elements_state(pipe, 1, &ve);
+   if (!filter->ves)
+      goto error_ves;
+
+   sizes.x = 1.0f / video_width;
+   sizes.y = 1.0f / video_height;
+
+   filter->vs = create_vert_shader(filter);
+   if (!filter->vs)
+      goto error_vs;
+
+   filter->fs_copy_top = create_copy_frag_shader(filter, 0);
+   if (!filter->fs_copy_top)
+      goto error_fs_copy_top;
+
+   filter->fs_copy_bottom = create_copy_frag_shader(filter, 1);
+   if (!filter->fs_copy_bottom)
+      goto error_fs_copy_bottom;
+
+   filter->fs_deint_top = create_deint_frag_shader(filter, 0, &sizes, spatial_filter);
+   if (!filter->fs_deint_top)
+      goto error_fs_deint_top;
+
+   filter->fs_deint_bottom = create_deint_frag_shader(filter, 1, &sizes, spatial_filter);
+   if (!filter->fs_deint_bottom)
+      goto error_fs_deint_bottom;
+
+   return true;
+
+error_fs_deint_bottom:
+   pipe->delete_fs_state(pipe, filter->fs_deint_top);
+
+error_fs_deint_top:
+   pipe->delete_fs_state(pipe, filter->fs_copy_bottom);
+
+error_fs_copy_bottom:
+   pipe->delete_fs_state(pipe, filter->fs_copy_top);
+
+error_fs_copy_top:
+   pipe->delete_vs_state(pipe, filter->vs);
+
+error_vs:
+   pipe->delete_vertex_elements_state(pipe, filter->ves);
+
+error_ves:
+   pipe_resource_reference(&filter->quad.buffer, NULL);
+
+error_quad:
+   pipe->delete_sampler_state(pipe, filter->sampler);
+
+error_sampler:
+   pipe->delete_blend_state(pipe, filter->blend);
+
+error_blend:
+   pipe->delete_rasterizer_state(pipe, filter->rs_state);
+
+error_rs_state:
+   filter->video_buffer->destroy(filter->video_buffer);
+
+error_video_buffer:
+   return false;
+}
+
+void
+vl_deint_filter_cleanup(struct vl_deint_filter *filter)
+{
+   assert(filter);
+
+   filter->pipe->delete_sampler_state(filter->pipe, filter->sampler[0]);
+   filter->pipe->delete_blend_state(filter->pipe, filter->blend);
+   filter->pipe->delete_rasterizer_state(filter->pipe, filter->rs_state);
+   filter->pipe->delete_vertex_elements_state(filter->pipe, filter->ves);
+   pipe_resource_reference(&filter->quad.buffer, NULL);
+
+   filter->pipe->delete_vs_state(filter->pipe, filter->vs);
+   filter->pipe->delete_fs_state(filter->pipe, filter->fs_copy_top);
+   filter->pipe->delete_fs_state(filter->pipe, filter->fs_copy_bottom);
+   filter->pipe->delete_fs_state(filter->pipe, filter->fs_deint_top);
+   filter->pipe->delete_fs_state(filter->pipe, filter->fs_deint_bottom);
+
+   filter->video_buffer->destroy(filter->video_buffer);
+}
+
+bool
+vl_deint_filter_check_buffers(struct vl_deint_filter *filter,
+                              struct pipe_video_buffer *prevprev,
+                              struct pipe_video_buffer *prev,
+                              struct pipe_video_buffer *cur,
+                              struct pipe_video_buffer *next)
+{
+   int i;
+   struct pipe_video_buffer *bufs[] = { prevprev, prev, cur, next };
+
+   for (i = 0; i < 4; i++) {
+      if (bufs[i]->chroma_format != PIPE_VIDEO_CHROMA_FORMAT_420)
+         return false;
+      if (bufs[i]->width < filter->video_width ||
+          bufs[i]->height < filter->video_height)
+         return false;
+      if (!bufs[i]->interlaced)
+         return false;
+   }
+
+   return true;
+}
+
+void
+vl_deint_filter_render(struct vl_deint_filter *filter,
+                       struct pipe_video_buffer *prevprev,
+                       struct pipe_video_buffer *prev,
+                       struct pipe_video_buffer *cur,
+                       struct pipe_video_buffer *next,
+                       unsigned field)
+{
+   struct pipe_viewport_state viewport;
+   struct pipe_framebuffer_state fb_state;
+   struct pipe_sampler_view **cur_sv;
+   struct pipe_sampler_view **prevprev_sv;
+   struct pipe_sampler_view **prev_sv;
+   struct pipe_sampler_view **next_sv;
+   struct pipe_sampler_view *sampler_views[4];
+   struct pipe_surface **dst_surfaces;
+   int j;
+
+   assert(filter && prevprev && prev && cur && next && field <= 1);
+
+   /* set up destination and source */
+   dst_surfaces = filter->video_buffer->get_surfaces(filter->video_buffer);
+   cur_sv = cur->get_sampler_view_components(cur);
+   prevprev_sv = prevprev->get_sampler_view_components(prevprev);
+   prev_sv = prev->get_sampler_view_components(prev);
+   next_sv = next->get_sampler_view_components(next);
+
+   /* set up pipe state */
+   filter->pipe->bind_rasterizer_state(filter->pipe, filter->rs_state);
+   filter->pipe->bind_blend_state(filter->pipe, filter->blend);
+   filter->pipe->set_vertex_buffers(filter->pipe, 0, 1, &filter->quad);
+   filter->pipe->bind_vertex_elements_state(filter->pipe, filter->ves);
+   filter->pipe->bind_vs_state(filter->pipe, filter->vs);
+   filter->pipe->bind_sampler_states(filter->pipe, PIPE_SHADER_FRAGMENT,
+                                     0, 4, filter->sampler);
+
+   /* prepare viewport */
+   memset(&viewport, 0, sizeof(viewport));
+   viewport.scale[2] = 1;
+   viewport.scale[3] = 1;
+
+   /* prepare framebuffer */
+   memset(&fb_state, 0, sizeof(fb_state));
+   fb_state.nr_cbufs = 1;
+
+   /* process each plane separately */
+   for (j = 0; j < 3; j++) {
+      /* select correct YV12 surfaces */
+      int k = j == 1 ? 2 :
+              j == 2 ? 1 : 0;
+      struct pipe_surface *blit_surf = dst_surfaces[2 * k + field];
+      struct pipe_surface *dst_surf = dst_surfaces[2 * k + 1 - field];
+
+      /* update render target state */
+      viewport.scale[0] = blit_surf->texture->width0;
+      viewport.scale[1] = blit_surf->texture->height0;
+      fb_state.width = blit_surf->texture->width0;
+      fb_state.height = blit_surf->texture->height0;
+
+      /* update sampler view sources  */
+      sampler_views[0] = prevprev_sv[j];
+      sampler_views[1] = prev_sv[j];
+      sampler_views[2] = cur_sv[j];
+      sampler_views[3] = next_sv[j];
+      filter->pipe->set_sampler_views(filter->pipe, PIPE_SHADER_FRAGMENT, 0, 4, sampler_views);
+
+      /* blit current field */
+      fb_state.cbufs[0] = blit_surf;
+      filter->pipe->bind_fs_state(filter->pipe, field ? filter->fs_copy_bottom : filter->fs_copy_top);
+      filter->pipe->set_framebuffer_state(filter->pipe, &fb_state);
+      filter->pipe->set_viewport_states(filter->pipe, 0, 1, &viewport);
+      util_draw_arrays(filter->pipe, PIPE_PRIM_QUADS, 0, 4);
+
+      /* blit or interpolate other field */
+      fb_state.cbufs[0] = dst_surf;
+      filter->pipe->set_framebuffer_state(filter->pipe, &fb_state);
+      if (j > 0 && filter->skip_chroma) {
+         util_draw_arrays(filter->pipe, PIPE_PRIM_QUADS, 0, 4);
+      } else {
+         filter->pipe->bind_fs_state(filter->pipe, field ? filter->fs_deint_top : filter->fs_deint_bottom);
+         util_draw_arrays(filter->pipe, PIPE_PRIM_QUADS, 0, 4);
+      }
+   }
+}
+
diff --git a/src/gallium/auxiliary/vl/vl_deint_filter.h b/src/gallium/auxiliary/vl/vl_deint_filter.h
new file mode 100644
index 0000000..5a21402
--- /dev/null
+++ b/src/gallium/auxiliary/vl/vl_deint_filter.h
@@ -0,0 +1,78 @@ 
+/**************************************************************************
+ *
+ * Copyright 2013 Grigori Goronzy <greg@chown.ath.cx>
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/* motion adaptive deinterlacer implementation */
+
+#ifndef vl_deint_filter_h
+#define vl_deint_filter_h
+
+#include "pipe/p_state.h"
+
+struct vl_deint_filter
+{
+   struct pipe_context *pipe;
+   struct pipe_vertex_buffer quad;
+
+   void *rs_state;
+   void *blend;
+   void *sampler[4];
+   void *ves;
+   void *vs;
+   void *fs_copy_top, *fs_copy_bottom;
+   void *fs_deint_top, *fs_deint_bottom;
+
+   unsigned video_width, video_height;
+   bool skip_chroma;
+
+   struct pipe_video_buffer *video_buffer;
+};
+
+bool
+vl_deint_filter_init(struct vl_deint_filter *filter, struct pipe_context *pipe,
+                     unsigned video_width, unsigned video_height,
+                     bool skip_chroma, bool spatial_filter);
+
+void
+vl_deint_filter_cleanup(struct vl_deint_filter *filter);
+
+bool
+vl_deint_filter_check_buffers(struct vl_deint_filter *filter,
+                              struct pipe_video_buffer *prevprev,
+                              struct pipe_video_buffer *prev,
+                              struct pipe_video_buffer *cur,
+                              struct pipe_video_buffer *next);
+
+void
+vl_deint_filter_render(struct vl_deint_filter *filter,
+                       struct pipe_video_buffer *prevprev,
+                       struct pipe_video_buffer *prev,
+                       struct pipe_video_buffer *cur,
+                       struct pipe_video_buffer *next,
+                       unsigned field);
+
+#endif /* vl_deint_filter_h */
+

Comments

A really nice piece of work, thx allot.

Both patches reviewed and pushed upstream.

Cheers,
Christian.

Am 13.02.2014 21:32, schrieb Grigori Goronzy:
> ---
>   src/gallium/auxiliary/Makefile.sources     |   3 +-
>   src/gallium/auxiliary/vl/vl_deint_filter.c | 491 +++++++++++++++++++++++++++++
>   src/gallium/auxiliary/vl/vl_deint_filter.h |  78 +++++
>   3 files changed, 571 insertions(+), 1 deletion(-)
>   create mode 100644 src/gallium/auxiliary/vl/vl_deint_filter.c
>   create mode 100644 src/gallium/auxiliary/vl/vl_deint_filter.h
>
> diff --git a/src/gallium/auxiliary/Makefile.sources b/src/gallium/auxiliary/Makefile.sources
> index c89cbdd..19004e0 100644
> --- a/src/gallium/auxiliary/Makefile.sources
> +++ b/src/gallium/auxiliary/Makefile.sources
> @@ -155,7 +155,8 @@ C_SOURCES := \
>           vl/vl_idct.c \
>   	vl/vl_mc.c \
>           vl/vl_vertex_buffers.c \
> -        vl/vl_video_buffer.c
> +        vl/vl_video_buffer.c \
> +	vl/vl_deint_filter.c
>   
>   GENERATED_SOURCES := \
>   	indices/u_indices_gen.c \
> diff --git a/src/gallium/auxiliary/vl/vl_deint_filter.c b/src/gallium/auxiliary/vl/vl_deint_filter.c
> new file mode 100644
> index 0000000..9b05154
> --- /dev/null
> +++ b/src/gallium/auxiliary/vl/vl_deint_filter.c
> @@ -0,0 +1,491 @@
> +/**************************************************************************
> + *
> + * Copyright 2013 Grigori Goronzy <greg@chown.ath.cx>.
> + * All Rights Reserved.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> + * "Software"), to deal in the Software without restriction, including
> + * without limitation the rights to use, copy, modify, merge, publish,
> + * distribute, sub license, and/or sell copies of the Software, and to
> + * permit persons to whom the Software is furnished to do so, subject to
> + * the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the
> + * next paragraph) shall be included in all copies or substantial portions
> + * of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
> + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
> + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
> + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
> + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
> + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
> + *
> + **************************************************************************/
> +
> +/*
> + *  References:
> + *
> + *  Lin, S. F., Chang, Y. L., & Chen, L. G. (2003).
> + *  Motion adaptive interpolation with horizontal motion detection for deinterlacing.
> + *  Consumer Electronics, IEEE Transactions on, 49(4), 1256-1265.
> + *
> + *  Pei-Yin, C. H. E. N., & Yao-Hsien, L. A. I. (2007).
> + *  A low-complexity interpolation method for deinterlacing.
> + *  IEICE transactions on information and systems, 90(2), 606-608.
> + *
> + */
> +
> +#include <stdio.h>
> +
> +#include "pipe/p_context.h"
> +
> +#include "tgsi/tgsi_ureg.h"
> +
> +#include "util/u_draw.h"
> +#include "util/u_memory.h"
> +#include "util/u_math.h"
> +
> +#include "vl_types.h"
> +#include "vl_video_buffer.h"
> +#include "vl_vertex_buffers.h"
> +#include "vl_deint_filter.h"
> +
> +enum VS_OUTPUT
> +{
> +   VS_O_VPOS = 0,
> +   VS_O_VTEX = 0
> +};
> +
> +static void *
> +create_vert_shader(struct vl_deint_filter *filter)
> +{
> +   struct ureg_program *shader;
> +   struct ureg_src i_vpos;
> +   struct ureg_dst o_vpos, o_vtex;
> +
> +   shader = ureg_create(TGSI_PROCESSOR_VERTEX);
> +   if (!shader)
> +      return NULL;
> +
> +   i_vpos = ureg_DECL_vs_input(shader, 0);
> +   o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
> +   o_vtex = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX);
> +
> +   ureg_MOV(shader, o_vpos, i_vpos);
> +   ureg_MOV(shader, o_vtex, i_vpos);
> +
> +   ureg_END(shader);
> +
> +   return ureg_create_shader_and_destroy(shader, filter->pipe);
> +}
> +
> +static void *
> +create_copy_frag_shader(struct vl_deint_filter *filter, unsigned field)
> +{
> +   struct ureg_program *shader;
> +   struct ureg_src i_vtex;
> +   struct ureg_src sampler;
> +   struct ureg_dst o_fragment;
> +   struct ureg_dst t_tex;
> +
> +   shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
> +   if (!shader) {
> +      return NULL;
> +   }
> +   t_tex = ureg_DECL_temporary(shader);
> +
> +   i_vtex = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX, TGSI_INTERPOLATE_LINEAR);
> +   sampler = ureg_DECL_sampler(shader, 2);
> +   o_fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
> +
> +   ureg_MOV(shader, t_tex, i_vtex);
> +   if (field) {
> +      ureg_MOV(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_ZW),
> +               ureg_imm4f(shader, 0, 0, 1.0f, 0));
> +   } else {
> +      ureg_MOV(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_ZW),
> +               ureg_imm1f(shader, 0));
> +   }
> +
> +   ureg_TEX(shader, o_fragment, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_tex), sampler);
> +
> +   ureg_release_temporary(shader, t_tex);
> +   ureg_END(shader);
> +
> +   return ureg_create_shader_and_destroy(shader, filter->pipe);
> +}
> +
> +static void *
> +create_deint_frag_shader(struct vl_deint_filter *filter, unsigned field,
> +                         struct vertex2f *sizes, bool spatial_filter)
> +{
> +   struct ureg_program *shader;
> +   struct ureg_src i_vtex;
> +   struct ureg_src sampler_cur;
> +   struct ureg_src sampler_prevprev;
> +   struct ureg_src sampler_prev;
> +   struct ureg_src sampler_next;
> +   struct ureg_dst o_fragment;
> +   struct ureg_dst t_tex;
> +   struct ureg_dst t_comp_top, t_comp_bot;
> +   struct ureg_dst t_diff;
> +   struct ureg_dst t_a, t_b;
> +   struct ureg_dst t_weave, t_linear;
> +
> +   shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
> +   if (!shader) {
> +      return NULL;
> +   }
> +
> +   t_tex = ureg_DECL_temporary(shader);
> +   t_comp_top = ureg_DECL_temporary(shader);
> +   t_comp_bot = ureg_DECL_temporary(shader);
> +   t_diff = ureg_DECL_temporary(shader);
> +   t_a = ureg_DECL_temporary(shader);
> +   t_b = ureg_DECL_temporary(shader);
> +   t_weave = ureg_DECL_temporary(shader);
> +   t_linear = ureg_DECL_temporary(shader);
> +
> +   i_vtex = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX, TGSI_INTERPOLATE_LINEAR);
> +   sampler_prevprev = ureg_DECL_sampler(shader, 0);
> +   sampler_prev = ureg_DECL_sampler(shader, 1);
> +   sampler_cur = ureg_DECL_sampler(shader, 2);
> +   sampler_next = ureg_DECL_sampler(shader, 3);
> +   o_fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
> +
> +   // we don't care about ZW interpolation (allows better optimization)
> +   ureg_MOV(shader, t_tex, i_vtex);
> +   ureg_MOV(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_ZW),
> +            ureg_imm1f(shader, 0));
> +
> +   // sample between texels for cheap lowpass
> +   ureg_ADD(shader, t_comp_top, ureg_src(t_tex),
> +            ureg_imm4f(shader, sizes->x * 0.5f, sizes->y * -0.5f, 0, 0));
> +   ureg_ADD(shader, t_comp_bot, ureg_src(t_tex),
> +            ureg_imm4f(shader, sizes->x * -0.5f, sizes->y * 0.5f, 1.0f, 0));
> +
> +   if (field == 0) {
> +      /* interpolating top field -> current field is a bottom field */
> +      // cur vs prev2
> +      ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_cur);
> +      ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_prevprev);
> +      ureg_SUB(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X), ureg_src(t_a), ureg_src(t_b));
> +      // prev vs next
> +      ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top), sampler_prev);
> +      ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top), sampler_next);
> +      ureg_SUB(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_Y), ureg_src(t_a), ureg_src(t_b));
> +   } else {
> +      /* interpolating bottom field -> current field is a top field */
> +      // cur vs prev2
> +      ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top), sampler_cur);
> +      ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top), sampler_prevprev);
> +      ureg_SUB(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X), ureg_src(t_a), ureg_src(t_b));
> +      // prev vs next
> +      ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_prev);
> +      ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_next);
> +      ureg_SUB(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_Y), ureg_src(t_a), ureg_src(t_b));
> +   }
> +
> +   // absolute maximum of differences
> +   ureg_MAX(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X), ureg_abs(ureg_src(t_diff)),
> +            ureg_scalar(ureg_abs(ureg_src(t_diff)), TGSI_SWIZZLE_Y));
> +
> +   if (field == 0) {
> +      /* weave with prev top field */
> +      ureg_TEX(shader, t_weave, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_tex), sampler_prev);
> +      /* get linear interpolation from current bottom field */
> +      ureg_ADD(shader, t_comp_top, ureg_src(t_tex), ureg_imm4f(shader, 0, sizes->y * -1.0f, 1.0f, 0));
> +      ureg_TEX(shader, t_linear, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top), sampler_cur);
> +   } else {
> +      /* weave with prev bottom field */
> +      ureg_ADD(shader, t_comp_bot, ureg_src(t_tex), ureg_imm4f(shader, 0, 0, 1.0f, 0));
> +      ureg_TEX(shader, t_weave, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_prev);
> +      /* get linear interpolation from current top field */
> +      ureg_ADD(shader, t_comp_bot, ureg_src(t_tex), ureg_imm4f(shader, 0, sizes->y * 1.0f, 0, 0));
> +      ureg_TEX(shader, t_linear, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_cur);
> +   }
> +
> +   // mix between weave and linear
> +   // fully weave if diff < 6 (0.02353), fully interpolate if diff > 14 (0.05490)
> +   ureg_ADD(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X), ureg_src(t_diff),
> +            ureg_imm4f(shader, -0.02353f, 0, 0, 0));
> +   ureg_MUL(shader, ureg_saturate(ureg_writemask(t_diff, TGSI_WRITEMASK_X)),
> +            ureg_src(t_diff), ureg_imm4f(shader, 31.8750f, 0, 0, 0));
> +   ureg_LRP(shader, ureg_writemask(o_fragment, TGSI_WRITEMASK_X), ureg_src(t_diff),
> +            ureg_src(t_linear), ureg_src(t_weave));
> +
> +   ureg_release_temporary(shader, t_tex);
> +   ureg_release_temporary(shader, t_comp_top);
> +   ureg_release_temporary(shader, t_comp_bot);
> +   ureg_release_temporary(shader, t_diff);
> +   ureg_release_temporary(shader, t_a);
> +   ureg_release_temporary(shader, t_b);
> +   ureg_release_temporary(shader, t_weave);
> +   ureg_release_temporary(shader, t_linear);
> +   ureg_END(shader);
> +
> +   return ureg_create_shader_and_destroy(shader, filter->pipe);
> +}
> +
> +bool
> +vl_deint_filter_init(struct vl_deint_filter *filter, struct pipe_context *pipe,
> +                     unsigned video_width, unsigned video_height,
> +                     bool skip_chroma, bool spatial_filter)
> +{
> +   struct pipe_rasterizer_state rs_state;
> +   struct pipe_blend_state blend;
> +   struct pipe_sampler_state sampler;
> +   struct pipe_vertex_element ve;
> +   struct vertex2f sizes;
> +   struct pipe_video_buffer templ;
> +
> +   assert(filter && pipe);
> +   assert(video_width && video_height);
> +
> +   memset(filter, 0, sizeof(*filter));
> +   filter->pipe = pipe;
> +   filter->skip_chroma = skip_chroma;
> +   filter->video_width = video_width;
> +   filter->video_height = video_height;
> +
> +   /* TODO: handle other than 4:2:0 subsampling */
> +   memset(&templ, 0, sizeof(templ));
> +   templ.buffer_format = PIPE_FORMAT_YV12;
> +   templ.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
> +   templ.width = video_width;
> +   templ.height = video_height;
> +   templ.interlaced = true;
> +   filter->video_buffer = vl_video_buffer_create(pipe, &templ);
> +   if (!filter->video_buffer)
> +      goto error_video_buffer;
> +
> +   memset(&rs_state, 0, sizeof(rs_state));
> +   rs_state.half_pixel_center = true;
> +   rs_state.bottom_edge_rule = true;
> +   rs_state.depth_clip = 1;
> +   filter->rs_state = pipe->create_rasterizer_state(pipe, &rs_state);
> +   if (!filter->rs_state)
> +      goto error_rs_state;
> +
> +   memset(&blend, 0, sizeof blend);
> +   blend.rt[0].colormask = PIPE_MASK_RGBA;
> +   filter->blend = pipe->create_blend_state(pipe, &blend);
> +   if (!filter->blend)
> +      goto error_blend;
> +
> +   memset(&sampler, 0, sizeof(sampler));
> +   sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
> +   sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
> +   sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
> +   sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
> +   sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
> +   sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
> +   sampler.normalized_coords = 1;
> +   filter->sampler[0] = pipe->create_sampler_state(pipe, &sampler);
> +   filter->sampler[1] = filter->sampler[2] = filter->sampler[3] = filter->sampler[0];
> +   if (!filter->sampler[0])
> +      goto error_sampler;
> +
> +   filter->quad = vl_vb_upload_quads(pipe);
> +   if(!filter->quad.buffer)
> +      goto error_quad;
> +
> +   memset(&ve, 0, sizeof(ve));
> +   ve.src_offset = 0;
> +   ve.instance_divisor = 0;
> +   ve.vertex_buffer_index = 0;
> +   ve.src_format = PIPE_FORMAT_R32G32_FLOAT;
> +   filter->ves = pipe->create_vertex_elements_state(pipe, 1, &ve);
> +   if (!filter->ves)
> +      goto error_ves;
> +
> +   sizes.x = 1.0f / video_width;
> +   sizes.y = 1.0f / video_height;
> +
> +   filter->vs = create_vert_shader(filter);
> +   if (!filter->vs)
> +      goto error_vs;
> +
> +   filter->fs_copy_top = create_copy_frag_shader(filter, 0);
> +   if (!filter->fs_copy_top)
> +      goto error_fs_copy_top;
> +
> +   filter->fs_copy_bottom = create_copy_frag_shader(filter, 1);
> +   if (!filter->fs_copy_bottom)
> +      goto error_fs_copy_bottom;
> +
> +   filter->fs_deint_top = create_deint_frag_shader(filter, 0, &sizes, spatial_filter);
> +   if (!filter->fs_deint_top)
> +      goto error_fs_deint_top;
> +
> +   filter->fs_deint_bottom = create_deint_frag_shader(filter, 1, &sizes, spatial_filter);
> +   if (!filter->fs_deint_bottom)
> +      goto error_fs_deint_bottom;
> +
> +   return true;
> +
> +error_fs_deint_bottom:
> +   pipe->delete_fs_state(pipe, filter->fs_deint_top);
> +
> +error_fs_deint_top:
> +   pipe->delete_fs_state(pipe, filter->fs_copy_bottom);
> +
> +error_fs_copy_bottom:
> +   pipe->delete_fs_state(pipe, filter->fs_copy_top);
> +
> +error_fs_copy_top:
> +   pipe->delete_vs_state(pipe, filter->vs);
> +
> +error_vs:
> +   pipe->delete_vertex_elements_state(pipe, filter->ves);
> +
> +error_ves:
> +   pipe_resource_reference(&filter->quad.buffer, NULL);
> +
> +error_quad:
> +   pipe->delete_sampler_state(pipe, filter->sampler);
> +
> +error_sampler:
> +   pipe->delete_blend_state(pipe, filter->blend);
> +
> +error_blend:
> +   pipe->delete_rasterizer_state(pipe, filter->rs_state);
> +
> +error_rs_state:
> +   filter->video_buffer->destroy(filter->video_buffer);
> +
> +error_video_buffer:
> +   return false;
> +}
> +
> +void
> +vl_deint_filter_cleanup(struct vl_deint_filter *filter)
> +{
> +   assert(filter);
> +
> +   filter->pipe->delete_sampler_state(filter->pipe, filter->sampler[0]);
> +   filter->pipe->delete_blend_state(filter->pipe, filter->blend);
> +   filter->pipe->delete_rasterizer_state(filter->pipe, filter->rs_state);
> +   filter->pipe->delete_vertex_elements_state(filter->pipe, filter->ves);
> +   pipe_resource_reference(&filter->quad.buffer, NULL);
> +
> +   filter->pipe->delete_vs_state(filter->pipe, filter->vs);
> +   filter->pipe->delete_fs_state(filter->pipe, filter->fs_copy_top);
> +   filter->pipe->delete_fs_state(filter->pipe, filter->fs_copy_bottom);
> +   filter->pipe->delete_fs_state(filter->pipe, filter->fs_deint_top);
> +   filter->pipe->delete_fs_state(filter->pipe, filter->fs_deint_bottom);
> +
> +   filter->video_buffer->destroy(filter->video_buffer);
> +}
> +
> +bool
> +vl_deint_filter_check_buffers(struct vl_deint_filter *filter,
> +                              struct pipe_video_buffer *prevprev,
> +                              struct pipe_video_buffer *prev,
> +                              struct pipe_video_buffer *cur,
> +                              struct pipe_video_buffer *next)
> +{
> +   int i;
> +   struct pipe_video_buffer *bufs[] = { prevprev, prev, cur, next };
> +
> +   for (i = 0; i < 4; i++) {
> +      if (bufs[i]->chroma_format != PIPE_VIDEO_CHROMA_FORMAT_420)
> +         return false;
> +      if (bufs[i]->width < filter->video_width ||
> +          bufs[i]->height < filter->video_height)
> +         return false;
> +      if (!bufs[i]->interlaced)
> +         return false;
> +   }
> +
> +   return true;
> +}
> +
> +void
> +vl_deint_filter_render(struct vl_deint_filter *filter,
> +                       struct pipe_video_buffer *prevprev,
> +                       struct pipe_video_buffer *prev,
> +                       struct pipe_video_buffer *cur,
> +                       struct pipe_video_buffer *next,
> +                       unsigned field)
> +{
> +   struct pipe_viewport_state viewport;
> +   struct pipe_framebuffer_state fb_state;
> +   struct pipe_sampler_view **cur_sv;
> +   struct pipe_sampler_view **prevprev_sv;
> +   struct pipe_sampler_view **prev_sv;
> +   struct pipe_sampler_view **next_sv;
> +   struct pipe_sampler_view *sampler_views[4];
> +   struct pipe_surface **dst_surfaces;
> +   int j;
> +
> +   assert(filter && prevprev && prev && cur && next && field <= 1);
> +
> +   /* set up destination and source */
> +   dst_surfaces = filter->video_buffer->get_surfaces(filter->video_buffer);
> +   cur_sv = cur->get_sampler_view_components(cur);
> +   prevprev_sv = prevprev->get_sampler_view_components(prevprev);
> +   prev_sv = prev->get_sampler_view_components(prev);
> +   next_sv = next->get_sampler_view_components(next);
> +
> +   /* set up pipe state */
> +   filter->pipe->bind_rasterizer_state(filter->pipe, filter->rs_state);
> +   filter->pipe->bind_blend_state(filter->pipe, filter->blend);
> +   filter->pipe->set_vertex_buffers(filter->pipe, 0, 1, &filter->quad);
> +   filter->pipe->bind_vertex_elements_state(filter->pipe, filter->ves);
> +   filter->pipe->bind_vs_state(filter->pipe, filter->vs);
> +   filter->pipe->bind_sampler_states(filter->pipe, PIPE_SHADER_FRAGMENT,
> +                                     0, 4, filter->sampler);
> +
> +   /* prepare viewport */
> +   memset(&viewport, 0, sizeof(viewport));
> +   viewport.scale[2] = 1;
> +   viewport.scale[3] = 1;
> +
> +   /* prepare framebuffer */
> +   memset(&fb_state, 0, sizeof(fb_state));
> +   fb_state.nr_cbufs = 1;
> +
> +   /* process each plane separately */
> +   for (j = 0; j < 3; j++) {
> +      /* select correct YV12 surfaces */
> +      int k = j == 1 ? 2 :
> +              j == 2 ? 1 : 0;
> +      struct pipe_surface *blit_surf = dst_surfaces[2 * k + field];
> +      struct pipe_surface *dst_surf = dst_surfaces[2 * k + 1 - field];
> +
> +      /* update render target state */
> +      viewport.scale[0] = blit_surf->texture->width0;
> +      viewport.scale[1] = blit_surf->texture->height0;
> +      fb_state.width = blit_surf->texture->width0;
> +      fb_state.height = blit_surf->texture->height0;
> +
> +      /* update sampler view sources  */
> +      sampler_views[0] = prevprev_sv[j];
> +      sampler_views[1] = prev_sv[j];
> +      sampler_views[2] = cur_sv[j];
> +      sampler_views[3] = next_sv[j];
> +      filter->pipe->set_sampler_views(filter->pipe, PIPE_SHADER_FRAGMENT, 0, 4, sampler_views);
> +
> +      /* blit current field */
> +      fb_state.cbufs[0] = blit_surf;
> +      filter->pipe->bind_fs_state(filter->pipe, field ? filter->fs_copy_bottom : filter->fs_copy_top);
> +      filter->pipe->set_framebuffer_state(filter->pipe, &fb_state);
> +      filter->pipe->set_viewport_states(filter->pipe, 0, 1, &viewport);
> +      util_draw_arrays(filter->pipe, PIPE_PRIM_QUADS, 0, 4);
> +
> +      /* blit or interpolate other field */
> +      fb_state.cbufs[0] = dst_surf;
> +      filter->pipe->set_framebuffer_state(filter->pipe, &fb_state);
> +      if (j > 0 && filter->skip_chroma) {
> +         util_draw_arrays(filter->pipe, PIPE_PRIM_QUADS, 0, 4);
> +      } else {
> +         filter->pipe->bind_fs_state(filter->pipe, field ? filter->fs_deint_top : filter->fs_deint_bottom);
> +         util_draw_arrays(filter->pipe, PIPE_PRIM_QUADS, 0, 4);
> +      }
> +   }
> +}
> +
> diff --git a/src/gallium/auxiliary/vl/vl_deint_filter.h b/src/gallium/auxiliary/vl/vl_deint_filter.h
> new file mode 100644
> index 0000000..5a21402
> --- /dev/null
> +++ b/src/gallium/auxiliary/vl/vl_deint_filter.h
> @@ -0,0 +1,78 @@
> +/**************************************************************************
> + *
> + * Copyright 2013 Grigori Goronzy <greg@chown.ath.cx>
> + * All Rights Reserved.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> + * "Software"), to deal in the Software without restriction, including
> + * without limitation the rights to use, copy, modify, merge, publish,
> + * distribute, sub license, and/or sell copies of the Software, and to
> + * permit persons to whom the Software is furnished to do so, subject to
> + * the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the
> + * next paragraph) shall be included in all copies or substantial portions
> + * of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
> + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
> + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
> + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
> + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
> + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
> + *
> + **************************************************************************/
> +
> +/* motion adaptive deinterlacer implementation */
> +
> +#ifndef vl_deint_filter_h
> +#define vl_deint_filter_h
> +
> +#include "pipe/p_state.h"
> +
> +struct vl_deint_filter
> +{
> +   struct pipe_context *pipe;
> +   struct pipe_vertex_buffer quad;
> +
> +   void *rs_state;
> +   void *blend;
> +   void *sampler[4];
> +   void *ves;
> +   void *vs;
> +   void *fs_copy_top, *fs_copy_bottom;
> +   void *fs_deint_top, *fs_deint_bottom;
> +
> +   unsigned video_width, video_height;
> +   bool skip_chroma;
> +
> +   struct pipe_video_buffer *video_buffer;
> +};
> +
> +bool
> +vl_deint_filter_init(struct vl_deint_filter *filter, struct pipe_context *pipe,
> +                     unsigned video_width, unsigned video_height,
> +                     bool skip_chroma, bool spatial_filter);
> +
> +void
> +vl_deint_filter_cleanup(struct vl_deint_filter *filter);
> +
> +bool
> +vl_deint_filter_check_buffers(struct vl_deint_filter *filter,
> +                              struct pipe_video_buffer *prevprev,
> +                              struct pipe_video_buffer *prev,
> +                              struct pipe_video_buffer *cur,
> +                              struct pipe_video_buffer *next);
> +
> +void
> +vl_deint_filter_render(struct vl_deint_filter *filter,
> +                       struct pipe_video_buffer *prevprev,
> +                       struct pipe_video_buffer *prev,
> +                       struct pipe_video_buffer *cur,
> +                       struct pipe_video_buffer *next,
> +                       unsigned field);
> +
> +#endif /* vl_deint_filter_h */
> +
Grigori,

I just tried this out on a few interlaced videos I have, and it works
really quite well! One thing I did notice is that when playing back
content with mplayer (and -vo vdpau:deint=3) in full screen mode, the
black bars are now stale/uninitialized textures. This does not happen
if I don't use deint=3. Is it something that we're doing wrong in
nouveau, or is it an issue in st/vdpau? If it's likely an issue in
nouveau, any hints on what it might be?

  -ilia

On Fri, Feb 14, 2014 at 3:18 AM, Christian König
<deathsimple@vodafone.de> wrote:
> A really nice piece of work, thx allot.
>
> Both patches reviewed and pushed upstream.
>
> Cheers,
> Christian.
>
> Am 13.02.2014 21:32, schrieb Grigori Goronzy:
>
>> ---
>>   src/gallium/auxiliary/Makefile.sources     |   3 +-
>>   src/gallium/auxiliary/vl/vl_deint_filter.c | 491
>> +++++++++++++++++++++++++++++
>>   src/gallium/auxiliary/vl/vl_deint_filter.h |  78 +++++
>>   3 files changed, 571 insertions(+), 1 deletion(-)
>>   create mode 100644 src/gallium/auxiliary/vl/vl_deint_filter.c
>>   create mode 100644 src/gallium/auxiliary/vl/vl_deint_filter.h
>>
>> diff --git a/src/gallium/auxiliary/Makefile.sources
>> b/src/gallium/auxiliary/Makefile.sources
>> index c89cbdd..19004e0 100644
>> --- a/src/gallium/auxiliary/Makefile.sources
>> +++ b/src/gallium/auxiliary/Makefile.sources
>> @@ -155,7 +155,8 @@ C_SOURCES := \
>>           vl/vl_idct.c \
>>         vl/vl_mc.c \
>>           vl/vl_vertex_buffers.c \
>> -        vl/vl_video_buffer.c
>> +        vl/vl_video_buffer.c \
>> +       vl/vl_deint_filter.c
>>     GENERATED_SOURCES := \
>>         indices/u_indices_gen.c \
>> diff --git a/src/gallium/auxiliary/vl/vl_deint_filter.c
>> b/src/gallium/auxiliary/vl/vl_deint_filter.c
>> new file mode 100644
>> index 0000000..9b05154
>> --- /dev/null
>> +++ b/src/gallium/auxiliary/vl/vl_deint_filter.c
>> @@ -0,0 +1,491 @@
>>
>> +/**************************************************************************
>> + *
>> + * Copyright 2013 Grigori Goronzy <greg@chown.ath.cx>.
>> + * All Rights Reserved.
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining
>> a
>> + * copy of this software and associated documentation files (the
>> + * "Software"), to deal in the Software without restriction, including
>> + * without limitation the rights to use, copy, modify, merge, publish,
>> + * distribute, sub license, and/or sell copies of the Software, and to
>> + * permit persons to whom the Software is furnished to do so, subject to
>> + * the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including the
>> + * next paragraph) shall be included in all copies or substantial
>> portions
>> + * of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>> EXPRESS
>> + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>> NON-INFRINGEMENT.
>> + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
>> + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
>> CONTRACT,
>> + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
>> + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
>> + *
>> +
>> **************************************************************************/
>> +
>> +/*
>> + *  References:
>> + *
>> + *  Lin, S. F., Chang, Y. L., & Chen, L. G. (2003).
>> + *  Motion adaptive interpolation with horizontal motion detection for
>> deinterlacing.
>> + *  Consumer Electronics, IEEE Transactions on, 49(4), 1256-1265.
>> + *
>> + *  Pei-Yin, C. H. E. N., & Yao-Hsien, L. A. I. (2007).
>> + *  A low-complexity interpolation method for deinterlacing.
>> + *  IEICE transactions on information and systems, 90(2), 606-608.
>> + *
>> + */
>> +
>> +#include <stdio.h>
>> +
>> +#include "pipe/p_context.h"
>> +
>> +#include "tgsi/tgsi_ureg.h"
>> +
>> +#include "util/u_draw.h"
>> +#include "util/u_memory.h"
>> +#include "util/u_math.h"
>> +
>> +#include "vl_types.h"
>> +#include "vl_video_buffer.h"
>> +#include "vl_vertex_buffers.h"
>> +#include "vl_deint_filter.h"
>> +
>> +enum VS_OUTPUT
>> +{
>> +   VS_O_VPOS = 0,
>> +   VS_O_VTEX = 0
>> +};
>> +
>> +static void *
>> +create_vert_shader(struct vl_deint_filter *filter)
>> +{
>> +   struct ureg_program *shader;
>> +   struct ureg_src i_vpos;
>> +   struct ureg_dst o_vpos, o_vtex;
>> +
>> +   shader = ureg_create(TGSI_PROCESSOR_VERTEX);
>> +   if (!shader)
>> +      return NULL;
>> +
>> +   i_vpos = ureg_DECL_vs_input(shader, 0);
>> +   o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
>> +   o_vtex = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX);
>> +
>> +   ureg_MOV(shader, o_vpos, i_vpos);
>> +   ureg_MOV(shader, o_vtex, i_vpos);
>> +
>> +   ureg_END(shader);
>> +
>> +   return ureg_create_shader_and_destroy(shader, filter->pipe);
>> +}
>> +
>> +static void *
>> +create_copy_frag_shader(struct vl_deint_filter *filter, unsigned field)
>> +{
>> +   struct ureg_program *shader;
>> +   struct ureg_src i_vtex;
>> +   struct ureg_src sampler;
>> +   struct ureg_dst o_fragment;
>> +   struct ureg_dst t_tex;
>> +
>> +   shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
>> +   if (!shader) {
>> +      return NULL;
>> +   }
>> +   t_tex = ureg_DECL_temporary(shader);
>> +
>> +   i_vtex = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX,
>> TGSI_INTERPOLATE_LINEAR);
>> +   sampler = ureg_DECL_sampler(shader, 2);
>> +   o_fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
>> +
>> +   ureg_MOV(shader, t_tex, i_vtex);
>> +   if (field) {
>> +      ureg_MOV(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_ZW),
>> +               ureg_imm4f(shader, 0, 0, 1.0f, 0));
>> +   } else {
>> +      ureg_MOV(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_ZW),
>> +               ureg_imm1f(shader, 0));
>> +   }
>> +
>> +   ureg_TEX(shader, o_fragment, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_tex),
>> sampler);
>> +
>> +   ureg_release_temporary(shader, t_tex);
>> +   ureg_END(shader);
>> +
>> +   return ureg_create_shader_and_destroy(shader, filter->pipe);
>> +}
>> +
>> +static void *
>> +create_deint_frag_shader(struct vl_deint_filter *filter, unsigned field,
>> +                         struct vertex2f *sizes, bool spatial_filter)
>> +{
>> +   struct ureg_program *shader;
>> +   struct ureg_src i_vtex;
>> +   struct ureg_src sampler_cur;
>> +   struct ureg_src sampler_prevprev;
>> +   struct ureg_src sampler_prev;
>> +   struct ureg_src sampler_next;
>> +   struct ureg_dst o_fragment;
>> +   struct ureg_dst t_tex;
>> +   struct ureg_dst t_comp_top, t_comp_bot;
>> +   struct ureg_dst t_diff;
>> +   struct ureg_dst t_a, t_b;
>> +   struct ureg_dst t_weave, t_linear;
>> +
>> +   shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
>> +   if (!shader) {
>> +      return NULL;
>> +   }
>> +
>> +   t_tex = ureg_DECL_temporary(shader);
>> +   t_comp_top = ureg_DECL_temporary(shader);
>> +   t_comp_bot = ureg_DECL_temporary(shader);
>> +   t_diff = ureg_DECL_temporary(shader);
>> +   t_a = ureg_DECL_temporary(shader);
>> +   t_b = ureg_DECL_temporary(shader);
>> +   t_weave = ureg_DECL_temporary(shader);
>> +   t_linear = ureg_DECL_temporary(shader);
>> +
>> +   i_vtex = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX,
>> TGSI_INTERPOLATE_LINEAR);
>> +   sampler_prevprev = ureg_DECL_sampler(shader, 0);
>> +   sampler_prev = ureg_DECL_sampler(shader, 1);
>> +   sampler_cur = ureg_DECL_sampler(shader, 2);
>> +   sampler_next = ureg_DECL_sampler(shader, 3);
>> +   o_fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
>> +
>> +   // we don't care about ZW interpolation (allows better optimization)
>> +   ureg_MOV(shader, t_tex, i_vtex);
>> +   ureg_MOV(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_ZW),
>> +            ureg_imm1f(shader, 0));
>> +
>> +   // sample between texels for cheap lowpass
>> +   ureg_ADD(shader, t_comp_top, ureg_src(t_tex),
>> +            ureg_imm4f(shader, sizes->x * 0.5f, sizes->y * -0.5f, 0, 0));
>> +   ureg_ADD(shader, t_comp_bot, ureg_src(t_tex),
>> +            ureg_imm4f(shader, sizes->x * -0.5f, sizes->y * 0.5f, 1.0f,
>> 0));
>> +
>> +   if (field == 0) {
>> +      /* interpolating top field -> current field is a bottom field */
>> +      // cur vs prev2
>> +      ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot),
>> sampler_cur);
>> +      ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot),
>> sampler_prevprev);
>> +      ureg_SUB(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X),
>> ureg_src(t_a), ureg_src(t_b));
>> +      // prev vs next
>> +      ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top),
>> sampler_prev);
>> +      ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top),
>> sampler_next);
>> +      ureg_SUB(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_Y),
>> ureg_src(t_a), ureg_src(t_b));
>> +   } else {
>> +      /* interpolating bottom field -> current field is a top field */
>> +      // cur vs prev2
>> +      ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top),
>> sampler_cur);
>> +      ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top),
>> sampler_prevprev);
>> +      ureg_SUB(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X),
>> ureg_src(t_a), ureg_src(t_b));
>> +      // prev vs next
>> +      ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot),
>> sampler_prev);
>> +      ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot),
>> sampler_next);
>> +      ureg_SUB(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_Y),
>> ureg_src(t_a), ureg_src(t_b));
>> +   }
>> +
>> +   // absolute maximum of differences
>> +   ureg_MAX(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X),
>> ureg_abs(ureg_src(t_diff)),
>> +            ureg_scalar(ureg_abs(ureg_src(t_diff)), TGSI_SWIZZLE_Y));
>> +
>> +   if (field == 0) {
>> +      /* weave with prev top field */
>> +      ureg_TEX(shader, t_weave, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_tex),
>> sampler_prev);
>> +      /* get linear interpolation from current bottom field */
>> +      ureg_ADD(shader, t_comp_top, ureg_src(t_tex), ureg_imm4f(shader, 0,
>> sizes->y * -1.0f, 1.0f, 0));
>> +      ureg_TEX(shader, t_linear, TGSI_TEXTURE_2D_ARRAY,
>> ureg_src(t_comp_top), sampler_cur);
>> +   } else {
>> +      /* weave with prev bottom field */
>> +      ureg_ADD(shader, t_comp_bot, ureg_src(t_tex), ureg_imm4f(shader, 0,
>> 0, 1.0f, 0));
>> +      ureg_TEX(shader, t_weave, TGSI_TEXTURE_2D_ARRAY,
>> ureg_src(t_comp_bot), sampler_prev);
>> +      /* get linear interpolation from current top field */
>> +      ureg_ADD(shader, t_comp_bot, ureg_src(t_tex), ureg_imm4f(shader, 0,
>> sizes->y * 1.0f, 0, 0));
>> +      ureg_TEX(shader, t_linear, TGSI_TEXTURE_2D_ARRAY,
>> ureg_src(t_comp_bot), sampler_cur);
>> +   }
>> +
>> +   // mix between weave and linear
>> +   // fully weave if diff < 6 (0.02353), fully interpolate if diff > 14
>> (0.05490)
>> +   ureg_ADD(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X),
>> ureg_src(t_diff),
>> +            ureg_imm4f(shader, -0.02353f, 0, 0, 0));
>> +   ureg_MUL(shader, ureg_saturate(ureg_writemask(t_diff,
>> TGSI_WRITEMASK_X)),
>> +            ureg_src(t_diff), ureg_imm4f(shader, 31.8750f, 0, 0, 0));
>> +   ureg_LRP(shader, ureg_writemask(o_fragment, TGSI_WRITEMASK_X),
>> ureg_src(t_diff),
>> +            ureg_src(t_linear), ureg_src(t_weave));
>> +
>> +   ureg_release_temporary(shader, t_tex);
>> +   ureg_release_temporary(shader, t_comp_top);
>> +   ureg_release_temporary(shader, t_comp_bot);
>> +   ureg_release_temporary(shader, t_diff);
>> +   ureg_release_temporary(shader, t_a);
>> +   ureg_release_temporary(shader, t_b);
>> +   ureg_release_temporary(shader, t_weave);
>> +   ureg_release_temporary(shader, t_linear);
>> +   ureg_END(shader);
>> +
>> +   return ureg_create_shader_and_destroy(shader, filter->pipe);
>> +}
>> +
>> +bool
>> +vl_deint_filter_init(struct vl_deint_filter *filter, struct pipe_context
>> *pipe,
>> +                     unsigned video_width, unsigned video_height,
>> +                     bool skip_chroma, bool spatial_filter)
>> +{
>> +   struct pipe_rasterizer_state rs_state;
>> +   struct pipe_blend_state blend;
>> +   struct pipe_sampler_state sampler;
>> +   struct pipe_vertex_element ve;
>> +   struct vertex2f sizes;
>> +   struct pipe_video_buffer templ;
>> +
>> +   assert(filter && pipe);
>> +   assert(video_width && video_height);
>> +
>> +   memset(filter, 0, sizeof(*filter));
>> +   filter->pipe = pipe;
>> +   filter->skip_chroma = skip_chroma;
>> +   filter->video_width = video_width;
>> +   filter->video_height = video_height;
>> +
>> +   /* TODO: handle other than 4:2:0 subsampling */
>> +   memset(&templ, 0, sizeof(templ));
>> +   templ.buffer_format = PIPE_FORMAT_YV12;
>> +   templ.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
>> +   templ.width = video_width;
>> +   templ.height = video_height;
>> +   templ.interlaced = true;
>> +   filter->video_buffer = vl_video_buffer_create(pipe, &templ);
>> +   if (!filter->video_buffer)
>> +      goto error_video_buffer;
>> +
>> +   memset(&rs_state, 0, sizeof(rs_state));
>> +   rs_state.half_pixel_center = true;
>> +   rs_state.bottom_edge_rule = true;
>> +   rs_state.depth_clip = 1;
>> +   filter->rs_state = pipe->create_rasterizer_state(pipe, &rs_state);
>> +   if (!filter->rs_state)
>> +      goto error_rs_state;
>> +
>> +   memset(&blend, 0, sizeof blend);
>> +   blend.rt[0].colormask = PIPE_MASK_RGBA;
>> +   filter->blend = pipe->create_blend_state(pipe, &blend);
>> +   if (!filter->blend)
>> +      goto error_blend;
>> +
>> +   memset(&sampler, 0, sizeof(sampler));
>> +   sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
>> +   sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
>> +   sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
>> +   sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
>> +   sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
>> +   sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
>> +   sampler.normalized_coords = 1;
>> +   filter->sampler[0] = pipe->create_sampler_state(pipe, &sampler);
>> +   filter->sampler[1] = filter->sampler[2] = filter->sampler[3] =
>> filter->sampler[0];
>> +   if (!filter->sampler[0])
>> +      goto error_sampler;
>> +
>> +   filter->quad = vl_vb_upload_quads(pipe);
>> +   if(!filter->quad.buffer)
>> +      goto error_quad;
>> +
>> +   memset(&ve, 0, sizeof(ve));
>> +   ve.src_offset = 0;
>> +   ve.instance_divisor = 0;
>> +   ve.vertex_buffer_index = 0;
>> +   ve.src_format = PIPE_FORMAT_R32G32_FLOAT;
>> +   filter->ves = pipe->create_vertex_elements_state(pipe, 1, &ve);
>> +   if (!filter->ves)
>> +      goto error_ves;
>> +
>> +   sizes.x = 1.0f / video_width;
>> +   sizes.y = 1.0f / video_height;
>> +
>> +   filter->vs = create_vert_shader(filter);
>> +   if (!filter->vs)
>> +      goto error_vs;
>> +
>> +   filter->fs_copy_top = create_copy_frag_shader(filter, 0);
>> +   if (!filter->fs_copy_top)
>> +      goto error_fs_copy_top;
>> +
>> +   filter->fs_copy_bottom = create_copy_frag_shader(filter, 1);
>> +   if (!filter->fs_copy_bottom)
>> +      goto error_fs_copy_bottom;
>> +
>> +   filter->fs_deint_top = create_deint_frag_shader(filter, 0, &sizes,
>> spatial_filter);
>> +   if (!filter->fs_deint_top)
>> +      goto error_fs_deint_top;
>> +
>> +   filter->fs_deint_bottom = create_deint_frag_shader(filter, 1, &sizes,
>> spatial_filter);
>> +   if (!filter->fs_deint_bottom)
>> +      goto error_fs_deint_bottom;
>> +
>> +   return true;
>> +
>> +error_fs_deint_bottom:
>> +   pipe->delete_fs_state(pipe, filter->fs_deint_top);
>> +
>> +error_fs_deint_top:
>> +   pipe->delete_fs_state(pipe, filter->fs_copy_bottom);
>> +
>> +error_fs_copy_bottom:
>> +   pipe->delete_fs_state(pipe, filter->fs_copy_top);
>> +
>> +error_fs_copy_top:
>> +   pipe->delete_vs_state(pipe, filter->vs);
>> +
>> +error_vs:
>> +   pipe->delete_vertex_elements_state(pipe, filter->ves);
>> +
>> +error_ves:
>> +   pipe_resource_reference(&filter->quad.buffer, NULL);
>> +
>> +error_quad:
>> +   pipe->delete_sampler_state(pipe, filter->sampler);
>> +
>> +error_sampler:
>> +   pipe->delete_blend_state(pipe, filter->blend);
>> +
>> +error_blend:
>> +   pipe->delete_rasterizer_state(pipe, filter->rs_state);
>> +
>> +error_rs_state:
>> +   filter->video_buffer->destroy(filter->video_buffer);
>> +
>> +error_video_buffer:
>> +   return false;
>> +}
>> +
>> +void
>> +vl_deint_filter_cleanup(struct vl_deint_filter *filter)
>> +{
>> +   assert(filter);
>> +
>> +   filter->pipe->delete_sampler_state(filter->pipe, filter->sampler[0]);
>> +   filter->pipe->delete_blend_state(filter->pipe, filter->blend);
>> +   filter->pipe->delete_rasterizer_state(filter->pipe, filter->rs_state);
>> +   filter->pipe->delete_vertex_elements_state(filter->pipe, filter->ves);
>> +   pipe_resource_reference(&filter->quad.buffer, NULL);
>> +
>> +   filter->pipe->delete_vs_state(filter->pipe, filter->vs);
>> +   filter->pipe->delete_fs_state(filter->pipe, filter->fs_copy_top);
>> +   filter->pipe->delete_fs_state(filter->pipe, filter->fs_copy_bottom);
>> +   filter->pipe->delete_fs_state(filter->pipe, filter->fs_deint_top);
>> +   filter->pipe->delete_fs_state(filter->pipe, filter->fs_deint_bottom);
>> +
>> +   filter->video_buffer->destroy(filter->video_buffer);
>> +}
>> +
>> +bool
>> +vl_deint_filter_check_buffers(struct vl_deint_filter *filter,
>> +                              struct pipe_video_buffer *prevprev,
>> +                              struct pipe_video_buffer *prev,
>> +                              struct pipe_video_buffer *cur,
>> +                              struct pipe_video_buffer *next)
>> +{
>> +   int i;
>> +   struct pipe_video_buffer *bufs[] = { prevprev, prev, cur, next };
>> +
>> +   for (i = 0; i < 4; i++) {
>> +      if (bufs[i]->chroma_format != PIPE_VIDEO_CHROMA_FORMAT_420)
>> +         return false;
>> +      if (bufs[i]->width < filter->video_width ||
>> +          bufs[i]->height < filter->video_height)
>> +         return false;
>> +      if (!bufs[i]->interlaced)
>> +         return false;
>> +   }
>> +
>> +   return true;
>> +}
>> +
>> +void
>> +vl_deint_filter_render(struct vl_deint_filter *filter,
>> +                       struct pipe_video_buffer *prevprev,
>> +                       struct pipe_video_buffer *prev,
>> +                       struct pipe_video_buffer *cur,
>> +                       struct pipe_video_buffer *next,
>> +                       unsigned field)
>> +{
>> +   struct pipe_viewport_state viewport;
>> +   struct pipe_framebuffer_state fb_state;
>> +   struct pipe_sampler_view **cur_sv;
>> +   struct pipe_sampler_view **prevprev_sv;
>> +   struct pipe_sampler_view **prev_sv;
>> +   struct pipe_sampler_view **next_sv;
>> +   struct pipe_sampler_view *sampler_views[4];
>> +   struct pipe_surface **dst_surfaces;
>> +   int j;
>> +
>> +   assert(filter && prevprev && prev && cur && next && field <= 1);
>> +
>> +   /* set up destination and source */
>> +   dst_surfaces =
>> filter->video_buffer->get_surfaces(filter->video_buffer);
>> +   cur_sv = cur->get_sampler_view_components(cur);
>> +   prevprev_sv = prevprev->get_sampler_view_components(prevprev);
>> +   prev_sv = prev->get_sampler_view_components(prev);
>> +   next_sv = next->get_sampler_view_components(next);
>> +
>> +   /* set up pipe state */
>> +   filter->pipe->bind_rasterizer_state(filter->pipe, filter->rs_state);
>> +   filter->pipe->bind_blend_state(filter->pipe, filter->blend);
>> +   filter->pipe->set_vertex_buffers(filter->pipe, 0, 1, &filter->quad);
>> +   filter->pipe->bind_vertex_elements_state(filter->pipe, filter->ves);
>> +   filter->pipe->bind_vs_state(filter->pipe, filter->vs);
>> +   filter->pipe->bind_sampler_states(filter->pipe, PIPE_SHADER_FRAGMENT,
>> +                                     0, 4, filter->sampler);
>> +
>> +   /* prepare viewport */
>> +   memset(&viewport, 0, sizeof(viewport));
>> +   viewport.scale[2] = 1;
>> +   viewport.scale[3] = 1;
>> +
>> +   /* prepare framebuffer */
>> +   memset(&fb_state, 0, sizeof(fb_state));
>> +   fb_state.nr_cbufs = 1;
>> +
>> +   /* process each plane separately */
>> +   for (j = 0; j < 3; j++) {
>> +      /* select correct YV12 surfaces */
>> +      int k = j == 1 ? 2 :
>> +              j == 2 ? 1 : 0;
>> +      struct pipe_surface *blit_surf = dst_surfaces[2 * k + field];
>> +      struct pipe_surface *dst_surf = dst_surfaces[2 * k + 1 - field];
>> +
>> +      /* update render target state */
>> +      viewport.scale[0] = blit_surf->texture->width0;
>> +      viewport.scale[1] = blit_surf->texture->height0;
>> +      fb_state.width = blit_surf->texture->width0;
>> +      fb_state.height = blit_surf->texture->height0;
>> +
>> +      /* update sampler view sources  */
>> +      sampler_views[0] = prevprev_sv[j];
>> +      sampler_views[1] = prev_sv[j];
>> +      sampler_views[2] = cur_sv[j];
>> +      sampler_views[3] = next_sv[j];
>> +      filter->pipe->set_sampler_views(filter->pipe, PIPE_SHADER_FRAGMENT,
>> 0, 4, sampler_views);
>> +
>> +      /* blit current field */
>> +      fb_state.cbufs[0] = blit_surf;
>> +      filter->pipe->bind_fs_state(filter->pipe, field ?
>> filter->fs_copy_bottom : filter->fs_copy_top);
>> +      filter->pipe->set_framebuffer_state(filter->pipe, &fb_state);
>> +      filter->pipe->set_viewport_states(filter->pipe, 0, 1, &viewport);
>> +      util_draw_arrays(filter->pipe, PIPE_PRIM_QUADS, 0, 4);
>> +
>> +      /* blit or interpolate other field */
>> +      fb_state.cbufs[0] = dst_surf;
>> +      filter->pipe->set_framebuffer_state(filter->pipe, &fb_state);
>> +      if (j > 0 && filter->skip_chroma) {
>> +         util_draw_arrays(filter->pipe, PIPE_PRIM_QUADS, 0, 4);
>> +      } else {
>> +         filter->pipe->bind_fs_state(filter->pipe, field ?
>> filter->fs_deint_top : filter->fs_deint_bottom);
>> +         util_draw_arrays(filter->pipe, PIPE_PRIM_QUADS, 0, 4);
>> +      }
>> +   }
>> +}
>> +
>> diff --git a/src/gallium/auxiliary/vl/vl_deint_filter.h
>> b/src/gallium/auxiliary/vl/vl_deint_filter.h
>> new file mode 100644
>> index 0000000..5a21402
>> --- /dev/null
>> +++ b/src/gallium/auxiliary/vl/vl_deint_filter.h
>> @@ -0,0 +1,78 @@
>>
>> +/**************************************************************************
>> + *
>> + * Copyright 2013 Grigori Goronzy <greg@chown.ath.cx>
>> + * All Rights Reserved.
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining
>> a
>> + * copy of this software and associated documentation files (the
>> + * "Software"), to deal in the Software without restriction, including
>> + * without limitation the rights to use, copy, modify, merge, publish,
>> + * distribute, sub license, and/or sell copies of the Software, and to
>> + * permit persons to whom the Software is furnished to do so, subject to
>> + * the following conditions:
>> + *
>> + * The above copyright notice and this permission notice (including the
>> + * next paragraph) shall be included in all copies or substantial
>> portions
>> + * of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>> EXPRESS
>> + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>> NON-INFRINGEMENT.
>> + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
>> + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
>> CONTRACT,
>> + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
>> + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
>> + *
>> +
>> **************************************************************************/
>> +
>> +/* motion adaptive deinterlacer implementation */
>> +
>> +#ifndef vl_deint_filter_h
>> +#define vl_deint_filter_h
>> +
>> +#include "pipe/p_state.h"
>> +
>> +struct vl_deint_filter
>> +{
>> +   struct pipe_context *pipe;
>> +   struct pipe_vertex_buffer quad;
>> +
>> +   void *rs_state;
>> +   void *blend;
>> +   void *sampler[4];
>> +   void *ves;
>> +   void *vs;
>> +   void *fs_copy_top, *fs_copy_bottom;
>> +   void *fs_deint_top, *fs_deint_bottom;
>> +
>> +   unsigned video_width, video_height;
>> +   bool skip_chroma;
>> +
>> +   struct pipe_video_buffer *video_buffer;
>> +};
>> +
>> +bool
>> +vl_deint_filter_init(struct vl_deint_filter *filter, struct pipe_context
>> *pipe,
>> +                     unsigned video_width, unsigned video_height,
>> +                     bool skip_chroma, bool spatial_filter);
>> +
>> +void
>> +vl_deint_filter_cleanup(struct vl_deint_filter *filter);
>> +
>> +bool
>> +vl_deint_filter_check_buffers(struct vl_deint_filter *filter,
>> +                              struct pipe_video_buffer *prevprev,
>> +                              struct pipe_video_buffer *prev,
>> +                              struct pipe_video_buffer *cur,
>> +                              struct pipe_video_buffer *next);
>> +
>> +void
>> +vl_deint_filter_render(struct vl_deint_filter *filter,
>> +                       struct pipe_video_buffer *prevprev,
>> +                       struct pipe_video_buffer *prev,
>> +                       struct pipe_video_buffer *cur,
>> +                       struct pipe_video_buffer *next,
>> +                       unsigned field);
>> +
>> +#endif /* vl_deint_filter_h */
>> +
>
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
That's most likely an issue with st/vdpau. I implemented a small hack to 
clear the black bars of a surface only once. No idea how exactly it 
happens, but Grigoris patch seems to somehow break the logic there.

Anyway we need to rework this part when getting DRI3 anyway (much more 
efficiently and cleanly), so I'm not sure if we should bother fixing it.

Christian.

Am 15.02.2014 07:17, schrieb Ilia Mirkin:
> Grigori,
>
> I just tried this out on a few interlaced videos I have, and it works
> really quite well! One thing I did notice is that when playing back
> content with mplayer (and -vo vdpau:deint=3) in full screen mode, the
> black bars are now stale/uninitialized textures. This does not happen
> if I don't use deint=3. Is it something that we're doing wrong in
> nouveau, or is it an issue in st/vdpau? If it's likely an issue in
> nouveau, any hints on what it might be?
>
>    -ilia
>
> On Fri, Feb 14, 2014 at 3:18 AM, Christian König
> <deathsimple@vodafone.de> wrote:
>> A really nice piece of work, thx allot.
>>
>> Both patches reviewed and pushed upstream.
>>
>> Cheers,
>> Christian.
>>
>> Am 13.02.2014 21:32, schrieb Grigori Goronzy:
>>
>>> ---
>>>    src/gallium/auxiliary/Makefile.sources     |   3 +-
>>>    src/gallium/auxiliary/vl/vl_deint_filter.c | 491
>>> +++++++++++++++++++++++++++++
>>>    src/gallium/auxiliary/vl/vl_deint_filter.h |  78 +++++
>>>    3 files changed, 571 insertions(+), 1 deletion(-)
>>>    create mode 100644 src/gallium/auxiliary/vl/vl_deint_filter.c
>>>    create mode 100644 src/gallium/auxiliary/vl/vl_deint_filter.h
>>>
>>> diff --git a/src/gallium/auxiliary/Makefile.sources
>>> b/src/gallium/auxiliary/Makefile.sources
>>> index c89cbdd..19004e0 100644
>>> --- a/src/gallium/auxiliary/Makefile.sources
>>> +++ b/src/gallium/auxiliary/Makefile.sources
>>> @@ -155,7 +155,8 @@ C_SOURCES := \
>>>            vl/vl_idct.c \
>>>          vl/vl_mc.c \
>>>            vl/vl_vertex_buffers.c \
>>> -        vl/vl_video_buffer.c
>>> +        vl/vl_video_buffer.c \
>>> +       vl/vl_deint_filter.c
>>>      GENERATED_SOURCES := \
>>>          indices/u_indices_gen.c \
>>> diff --git a/src/gallium/auxiliary/vl/vl_deint_filter.c
>>> b/src/gallium/auxiliary/vl/vl_deint_filter.c
>>> new file mode 100644
>>> index 0000000..9b05154
>>> --- /dev/null
>>> +++ b/src/gallium/auxiliary/vl/vl_deint_filter.c
>>> @@ -0,0 +1,491 @@
>>>
>>> +/**************************************************************************
>>> + *
>>> + * Copyright 2013 Grigori Goronzy <greg@chown.ath.cx>.
>>> + * All Rights Reserved.
>>> + *
>>> + * Permission is hereby granted, free of charge, to any person obtaining
>>> a
>>> + * copy of this software and associated documentation files (the
>>> + * "Software"), to deal in the Software without restriction, including
>>> + * without limitation the rights to use, copy, modify, merge, publish,
>>> + * distribute, sub license, and/or sell copies of the Software, and to
>>> + * permit persons to whom the Software is furnished to do so, subject to
>>> + * the following conditions:
>>> + *
>>> + * The above copyright notice and this permission notice (including the
>>> + * next paragraph) shall be included in all copies or substantial
>>> portions
>>> + * of the Software.
>>> + *
>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>> EXPRESS
>>> + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>>> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>>> NON-INFRINGEMENT.
>>> + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
>>> + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
>>> CONTRACT,
>>> + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
>>> + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
>>> + *
>>> +
>>> **************************************************************************/
>>> +
>>> +/*
>>> + *  References:
>>> + *
>>> + *  Lin, S. F., Chang, Y. L., & Chen, L. G. (2003).
>>> + *  Motion adaptive interpolation with horizontal motion detection for
>>> deinterlacing.
>>> + *  Consumer Electronics, IEEE Transactions on, 49(4), 1256-1265.
>>> + *
>>> + *  Pei-Yin, C. H. E. N., & Yao-Hsien, L. A. I. (2007).
>>> + *  A low-complexity interpolation method for deinterlacing.
>>> + *  IEICE transactions on information and systems, 90(2), 606-608.
>>> + *
>>> + */
>>> +
>>> +#include <stdio.h>
>>> +
>>> +#include "pipe/p_context.h"
>>> +
>>> +#include "tgsi/tgsi_ureg.h"
>>> +
>>> +#include "util/u_draw.h"
>>> +#include "util/u_memory.h"
>>> +#include "util/u_math.h"
>>> +
>>> +#include "vl_types.h"
>>> +#include "vl_video_buffer.h"
>>> +#include "vl_vertex_buffers.h"
>>> +#include "vl_deint_filter.h"
>>> +
>>> +enum VS_OUTPUT
>>> +{
>>> +   VS_O_VPOS = 0,
>>> +   VS_O_VTEX = 0
>>> +};
>>> +
>>> +static void *
>>> +create_vert_shader(struct vl_deint_filter *filter)
>>> +{
>>> +   struct ureg_program *shader;
>>> +   struct ureg_src i_vpos;
>>> +   struct ureg_dst o_vpos, o_vtex;
>>> +
>>> +   shader = ureg_create(TGSI_PROCESSOR_VERTEX);
>>> +   if (!shader)
>>> +      return NULL;
>>> +
>>> +   i_vpos = ureg_DECL_vs_input(shader, 0);
>>> +   o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
>>> +   o_vtex = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX);
>>> +
>>> +   ureg_MOV(shader, o_vpos, i_vpos);
>>> +   ureg_MOV(shader, o_vtex, i_vpos);
>>> +
>>> +   ureg_END(shader);
>>> +
>>> +   return ureg_create_shader_and_destroy(shader, filter->pipe);
>>> +}
>>> +
>>> +static void *
>>> +create_copy_frag_shader(struct vl_deint_filter *filter, unsigned field)
>>> +{
>>> +   struct ureg_program *shader;
>>> +   struct ureg_src i_vtex;
>>> +   struct ureg_src sampler;
>>> +   struct ureg_dst o_fragment;
>>> +   struct ureg_dst t_tex;
>>> +
>>> +   shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
>>> +   if (!shader) {
>>> +      return NULL;
>>> +   }
>>> +   t_tex = ureg_DECL_temporary(shader);
>>> +
>>> +   i_vtex = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX,
>>> TGSI_INTERPOLATE_LINEAR);
>>> +   sampler = ureg_DECL_sampler(shader, 2);
>>> +   o_fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
>>> +
>>> +   ureg_MOV(shader, t_tex, i_vtex);
>>> +   if (field) {
>>> +      ureg_MOV(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_ZW),
>>> +               ureg_imm4f(shader, 0, 0, 1.0f, 0));
>>> +   } else {
>>> +      ureg_MOV(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_ZW),
>>> +               ureg_imm1f(shader, 0));
>>> +   }
>>> +
>>> +   ureg_TEX(shader, o_fragment, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_tex),
>>> sampler);
>>> +
>>> +   ureg_release_temporary(shader, t_tex);
>>> +   ureg_END(shader);
>>> +
>>> +   return ureg_create_shader_and_destroy(shader, filter->pipe);
>>> +}
>>> +
>>> +static void *
>>> +create_deint_frag_shader(struct vl_deint_filter *filter, unsigned field,
>>> +                         struct vertex2f *sizes, bool spatial_filter)
>>> +{
>>> +   struct ureg_program *shader;
>>> +   struct ureg_src i_vtex;
>>> +   struct ureg_src sampler_cur;
>>> +   struct ureg_src sampler_prevprev;
>>> +   struct ureg_src sampler_prev;
>>> +   struct ureg_src sampler_next;
>>> +   struct ureg_dst o_fragment;
>>> +   struct ureg_dst t_tex;
>>> +   struct ureg_dst t_comp_top, t_comp_bot;
>>> +   struct ureg_dst t_diff;
>>> +   struct ureg_dst t_a, t_b;
>>> +   struct ureg_dst t_weave, t_linear;
>>> +
>>> +   shader = ureg_create(TGSI_PROCESSOR_FRAGMENT);
>>> +   if (!shader) {
>>> +      return NULL;
>>> +   }
>>> +
>>> +   t_tex = ureg_DECL_temporary(shader);
>>> +   t_comp_top = ureg_DECL_temporary(shader);
>>> +   t_comp_bot = ureg_DECL_temporary(shader);
>>> +   t_diff = ureg_DECL_temporary(shader);
>>> +   t_a = ureg_DECL_temporary(shader);
>>> +   t_b = ureg_DECL_temporary(shader);
>>> +   t_weave = ureg_DECL_temporary(shader);
>>> +   t_linear = ureg_DECL_temporary(shader);
>>> +
>>> +   i_vtex = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX,
>>> TGSI_INTERPOLATE_LINEAR);
>>> +   sampler_prevprev = ureg_DECL_sampler(shader, 0);
>>> +   sampler_prev = ureg_DECL_sampler(shader, 1);
>>> +   sampler_cur = ureg_DECL_sampler(shader, 2);
>>> +   sampler_next = ureg_DECL_sampler(shader, 3);
>>> +   o_fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
>>> +
>>> +   // we don't care about ZW interpolation (allows better optimization)
>>> +   ureg_MOV(shader, t_tex, i_vtex);
>>> +   ureg_MOV(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_ZW),
>>> +            ureg_imm1f(shader, 0));
>>> +
>>> +   // sample between texels for cheap lowpass
>>> +   ureg_ADD(shader, t_comp_top, ureg_src(t_tex),
>>> +            ureg_imm4f(shader, sizes->x * 0.5f, sizes->y * -0.5f, 0, 0));
>>> +   ureg_ADD(shader, t_comp_bot, ureg_src(t_tex),
>>> +            ureg_imm4f(shader, sizes->x * -0.5f, sizes->y * 0.5f, 1.0f,
>>> 0));
>>> +
>>> +   if (field == 0) {
>>> +      /* interpolating top field -> current field is a bottom field */
>>> +      // cur vs prev2
>>> +      ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot),
>>> sampler_cur);
>>> +      ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot),
>>> sampler_prevprev);
>>> +      ureg_SUB(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X),
>>> ureg_src(t_a), ureg_src(t_b));
>>> +      // prev vs next
>>> +      ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top),
>>> sampler_prev);
>>> +      ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top),
>>> sampler_next);
>>> +      ureg_SUB(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_Y),
>>> ureg_src(t_a), ureg_src(t_b));
>>> +   } else {
>>> +      /* interpolating bottom field -> current field is a top field */
>>> +      // cur vs prev2
>>> +      ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top),
>>> sampler_cur);
>>> +      ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top),
>>> sampler_prevprev);
>>> +      ureg_SUB(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X),
>>> ureg_src(t_a), ureg_src(t_b));
>>> +      // prev vs next
>>> +      ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot),
>>> sampler_prev);
>>> +      ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot),
>>> sampler_next);
>>> +      ureg_SUB(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_Y),
>>> ureg_src(t_a), ureg_src(t_b));
>>> +   }
>>> +
>>> +   // absolute maximum of differences
>>> +   ureg_MAX(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X),
>>> ureg_abs(ureg_src(t_diff)),
>>> +            ureg_scalar(ureg_abs(ureg_src(t_diff)), TGSI_SWIZZLE_Y));
>>> +
>>> +   if (field == 0) {
>>> +      /* weave with prev top field */
>>> +      ureg_TEX(shader, t_weave, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_tex),
>>> sampler_prev);
>>> +      /* get linear interpolation from current bottom field */
>>> +      ureg_ADD(shader, t_comp_top, ureg_src(t_tex), ureg_imm4f(shader, 0,
>>> sizes->y * -1.0f, 1.0f, 0));
>>> +      ureg_TEX(shader, t_linear, TGSI_TEXTURE_2D_ARRAY,
>>> ureg_src(t_comp_top), sampler_cur);
>>> +   } else {
>>> +      /* weave with prev bottom field */
>>> +      ureg_ADD(shader, t_comp_bot, ureg_src(t_tex), ureg_imm4f(shader, 0,
>>> 0, 1.0f, 0));
>>> +      ureg_TEX(shader, t_weave, TGSI_TEXTURE_2D_ARRAY,
>>> ureg_src(t_comp_bot), sampler_prev);
>>> +      /* get linear interpolation from current top field */
>>> +      ureg_ADD(shader, t_comp_bot, ureg_src(t_tex), ureg_imm4f(shader, 0,
>>> sizes->y * 1.0f, 0, 0));
>>> +      ureg_TEX(shader, t_linear, TGSI_TEXTURE_2D_ARRAY,
>>> ureg_src(t_comp_bot), sampler_cur);
>>> +   }
>>> +
>>> +   // mix between weave and linear
>>> +   // fully weave if diff < 6 (0.02353), fully interpolate if diff > 14
>>> (0.05490)
>>> +   ureg_ADD(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X),
>>> ureg_src(t_diff),
>>> +            ureg_imm4f(shader, -0.02353f, 0, 0, 0));
>>> +   ureg_MUL(shader, ureg_saturate(ureg_writemask(t_diff,
>>> TGSI_WRITEMASK_X)),
>>> +            ureg_src(t_diff), ureg_imm4f(shader, 31.8750f, 0, 0, 0));
>>> +   ureg_LRP(shader, ureg_writemask(o_fragment, TGSI_WRITEMASK_X),
>>> ureg_src(t_diff),
>>> +            ureg_src(t_linear), ureg_src(t_weave));
>>> +
>>> +   ureg_release_temporary(shader, t_tex);
>>> +   ureg_release_temporary(shader, t_comp_top);
>>> +   ureg_release_temporary(shader, t_comp_bot);
>>> +   ureg_release_temporary(shader, t_diff);
>>> +   ureg_release_temporary(shader, t_a);
>>> +   ureg_release_temporary(shader, t_b);
>>> +   ureg_release_temporary(shader, t_weave);
>>> +   ureg_release_temporary(shader, t_linear);
>>> +   ureg_END(shader);
>>> +
>>> +   return ureg_create_shader_and_destroy(shader, filter->pipe);
>>> +}
>>> +
>>> +bool
>>> +vl_deint_filter_init(struct vl_deint_filter *filter, struct pipe_context
>>> *pipe,
>>> +                     unsigned video_width, unsigned video_height,
>>> +                     bool skip_chroma, bool spatial_filter)
>>> +{
>>> +   struct pipe_rasterizer_state rs_state;
>>> +   struct pipe_blend_state blend;
>>> +   struct pipe_sampler_state sampler;
>>> +   struct pipe_vertex_element ve;
>>> +   struct vertex2f sizes;
>>> +   struct pipe_video_buffer templ;
>>> +
>>> +   assert(filter && pipe);
>>> +   assert(video_width && video_height);
>>> +
>>> +   memset(filter, 0, sizeof(*filter));
>>> +   filter->pipe = pipe;
>>> +   filter->skip_chroma = skip_chroma;
>>> +   filter->video_width = video_width;
>>> +   filter->video_height = video_height;
>>> +
>>> +   /* TODO: handle other than 4:2:0 subsampling */
>>> +   memset(&templ, 0, sizeof(templ));
>>> +   templ.buffer_format = PIPE_FORMAT_YV12;
>>> +   templ.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
>>> +   templ.width = video_width;
>>> +   templ.height = video_height;
>>> +   templ.interlaced = true;
>>> +   filter->video_buffer = vl_video_buffer_create(pipe, &templ);
>>> +   if (!filter->video_buffer)
>>> +      goto error_video_buffer;
>>> +
>>> +   memset(&rs_state, 0, sizeof(rs_state));
>>> +   rs_state.half_pixel_center = true;
>>> +   rs_state.bottom_edge_rule = true;
>>> +   rs_state.depth_clip = 1;
>>> +   filter->rs_state = pipe->create_rasterizer_state(pipe, &rs_state);
>>> +   if (!filter->rs_state)
>>> +      goto error_rs_state;
>>> +
>>> +   memset(&blend, 0, sizeof blend);
>>> +   blend.rt[0].colormask = PIPE_MASK_RGBA;
>>> +   filter->blend = pipe->create_blend_state(pipe, &blend);
>>> +   if (!filter->blend)
>>> +      goto error_blend;
>>> +
>>> +   memset(&sampler, 0, sizeof(sampler));
>>> +   sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
>>> +   sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
>>> +   sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
>>> +   sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
>>> +   sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
>>> +   sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
>>> +   sampler.normalized_coords = 1;
>>> +   filter->sampler[0] = pipe->create_sampler_state(pipe, &sampler);
>>> +   filter->sampler[1] = filter->sampler[2] = filter->sampler[3] =
>>> filter->sampler[0];
>>> +   if (!filter->sampler[0])
>>> +      goto error_sampler;
>>> +
>>> +   filter->quad = vl_vb_upload_quads(pipe);
>>> +   if(!filter->quad.buffer)
>>> +      goto error_quad;
>>> +
>>> +   memset(&ve, 0, sizeof(ve));
>>> +   ve.src_offset = 0;
>>> +   ve.instance_divisor = 0;
>>> +   ve.vertex_buffer_index = 0;
>>> +   ve.src_format = PIPE_FORMAT_R32G32_FLOAT;
>>> +   filter->ves = pipe->create_vertex_elements_state(pipe, 1, &ve);
>>> +   if (!filter->ves)
>>> +      goto error_ves;
>>> +
>>> +   sizes.x = 1.0f / video_width;
>>> +   sizes.y = 1.0f / video_height;
>>> +
>>> +   filter->vs = create_vert_shader(filter);
>>> +   if (!filter->vs)
>>> +      goto error_vs;
>>> +
>>> +   filter->fs_copy_top = create_copy_frag_shader(filter, 0);
>>> +   if (!filter->fs_copy_top)
>>> +      goto error_fs_copy_top;
>>> +
>>> +   filter->fs_copy_bottom = create_copy_frag_shader(filter, 1);
>>> +   if (!filter->fs_copy_bottom)
>>> +      goto error_fs_copy_bottom;
>>> +
>>> +   filter->fs_deint_top = create_deint_frag_shader(filter, 0, &sizes,
>>> spatial_filter);
>>> +   if (!filter->fs_deint_top)
>>> +      goto error_fs_deint_top;
>>> +
>>> +   filter->fs_deint_bottom = create_deint_frag_shader(filter, 1, &sizes,
>>> spatial_filter);
>>> +   if (!filter->fs_deint_bottom)
>>> +      goto error_fs_deint_bottom;
>>> +
>>> +   return true;
>>> +
>>> +error_fs_deint_bottom:
>>> +   pipe->delete_fs_state(pipe, filter->fs_deint_top);
>>> +
>>> +error_fs_deint_top:
>>> +   pipe->delete_fs_state(pipe, filter->fs_copy_bottom);
>>> +
>>> +error_fs_copy_bottom:
>>> +   pipe->delete_fs_state(pipe, filter->fs_copy_top);
>>> +
>>> +error_fs_copy_top:
>>> +   pipe->delete_vs_state(pipe, filter->vs);
>>> +
>>> +error_vs:
>>> +   pipe->delete_vertex_elements_state(pipe, filter->ves);
>>> +
>>> +error_ves:
>>> +   pipe_resource_reference(&filter->quad.buffer, NULL);
>>> +
>>> +error_quad:
>>> +   pipe->delete_sampler_state(pipe, filter->sampler);
>>> +
>>> +error_sampler:
>>> +   pipe->delete_blend_state(pipe, filter->blend);
>>> +
>>> +error_blend:
>>> +   pipe->delete_rasterizer_state(pipe, filter->rs_state);
>>> +
>>> +error_rs_state:
>>> +   filter->video_buffer->destroy(filter->video_buffer);
>>> +
>>> +error_video_buffer:
>>> +   return false;
>>> +}
>>> +
>>> +void
>>> +vl_deint_filter_cleanup(struct vl_deint_filter *filter)
>>> +{
>>> +   assert(filter);
>>> +
>>> +   filter->pipe->delete_sampler_state(filter->pipe, filter->sampler[0]);
>>> +   filter->pipe->delete_blend_state(filter->pipe, filter->blend);
>>> +   filter->pipe->delete_rasterizer_state(filter->pipe, filter->rs_state);
>>> +   filter->pipe->delete_vertex_elements_state(filter->pipe, filter->ves);
>>> +   pipe_resource_reference(&filter->quad.buffer, NULL);
>>> +
>>> +   filter->pipe->delete_vs_state(filter->pipe, filter->vs);
>>> +   filter->pipe->delete_fs_state(filter->pipe, filter->fs_copy_top);
>>> +   filter->pipe->delete_fs_state(filter->pipe, filter->fs_copy_bottom);
>>> +   filter->pipe->delete_fs_state(filter->pipe, filter->fs_deint_top);
>>> +   filter->pipe->delete_fs_state(filter->pipe, filter->fs_deint_bottom);
>>> +
>>> +   filter->video_buffer->destroy(filter->video_buffer);
>>> +}
>>> +
>>> +bool
>>> +vl_deint_filter_check_buffers(struct vl_deint_filter *filter,
>>> +                              struct pipe_video_buffer *prevprev,
>>> +                              struct pipe_video_buffer *prev,
>>> +                              struct pipe_video_buffer *cur,
>>> +                              struct pipe_video_buffer *next)
>>> +{
>>> +   int i;
>>> +   struct pipe_video_buffer *bufs[] = { prevprev, prev, cur, next };
>>> +
>>> +   for (i = 0; i < 4; i++) {
>>> +      if (bufs[i]->chroma_format != PIPE_VIDEO_CHROMA_FORMAT_420)
>>> +         return false;
>>> +      if (bufs[i]->width < filter->video_width ||
>>> +          bufs[i]->height < filter->video_height)
>>> +         return false;
>>> +      if (!bufs[i]->interlaced)
>>> +         return false;
>>> +   }
>>> +
>>> +   return true;
>>> +}
>>> +
>>> +void
>>> +vl_deint_filter_render(struct vl_deint_filter *filter,
>>> +                       struct pipe_video_buffer *prevprev,
>>> +                       struct pipe_video_buffer *prev,
>>> +                       struct pipe_video_buffer *cur,
>>> +                       struct pipe_video_buffer *next,
>>> +                       unsigned field)
>>> +{
>>> +   struct pipe_viewport_state viewport;
>>> +   struct pipe_framebuffer_state fb_state;
>>> +   struct pipe_sampler_view **cur_sv;
>>> +   struct pipe_sampler_view **prevprev_sv;
>>> +   struct pipe_sampler_view **prev_sv;
>>> +   struct pipe_sampler_view **next_sv;
>>> +   struct pipe_sampler_view *sampler_views[4];
>>> +   struct pipe_surface **dst_surfaces;
>>> +   int j;
>>> +
>>> +   assert(filter && prevprev && prev && cur && next && field <= 1);
>>> +
>>> +   /* set up destination and source */
>>> +   dst_surfaces =
>>> filter->video_buffer->get_surfaces(filter->video_buffer);
>>> +   cur_sv = cur->get_sampler_view_components(cur);
>>> +   prevprev_sv = prevprev->get_sampler_view_components(prevprev);
>>> +   prev_sv = prev->get_sampler_view_components(prev);
>>> +   next_sv = next->get_sampler_view_components(next);
>>> +
>>> +   /* set up pipe state */
>>> +   filter->pipe->bind_rasterizer_state(filter->pipe, filter->rs_state);
>>> +   filter->pipe->bind_blend_state(filter->pipe, filter->blend);
>>> +   filter->pipe->set_vertex_buffers(filter->pipe, 0, 1, &filter->quad);
>>> +   filter->pipe->bind_vertex_elements_state(filter->pipe, filter->ves);
>>> +   filter->pipe->bind_vs_state(filter->pipe, filter->vs);
>>> +   filter->pipe->bind_sampler_states(filter->pipe, PIPE_SHADER_FRAGMENT,
>>> +                                     0, 4, filter->sampler);
>>> +
>>> +   /* prepare viewport */
>>> +   memset(&viewport, 0, sizeof(viewport));
>>> +   viewport.scale[2] = 1;
>>> +   viewport.scale[3] = 1;
>>> +
>>> +   /* prepare framebuffer */
>>> +   memset(&fb_state, 0, sizeof(fb_state));
>>> +   fb_state.nr_cbufs = 1;
>>> +
>>> +   /* process each plane separately */
>>> +   for (j = 0; j < 3; j++) {
>>> +      /* select correct YV12 surfaces */
>>> +      int k = j == 1 ? 2 :
>>> +              j == 2 ? 1 : 0;
>>> +      struct pipe_surface *blit_surf = dst_surfaces[2 * k + field];
>>> +      struct pipe_surface *dst_surf = dst_surfaces[2 * k + 1 - field];
>>> +
>>> +      /* update render target state */
>>> +      viewport.scale[0] = blit_surf->texture->width0;
>>> +      viewport.scale[1] = blit_surf->texture->height0;
>>> +      fb_state.width = blit_surf->texture->width0;
>>> +      fb_state.height = blit_surf->texture->height0;
>>> +
>>> +      /* update sampler view sources  */
>>> +      sampler_views[0] = prevprev_sv[j];
>>> +      sampler_views[1] = prev_sv[j];
>>> +      sampler_views[2] = cur_sv[j];
>>> +      sampler_views[3] = next_sv[j];
>>> +      filter->pipe->set_sampler_views(filter->pipe, PIPE_SHADER_FRAGMENT,
>>> 0, 4, sampler_views);
>>> +
>>> +      /* blit current field */
>>> +      fb_state.cbufs[0] = blit_surf;
>>> +      filter->pipe->bind_fs_state(filter->pipe, field ?
>>> filter->fs_copy_bottom : filter->fs_copy_top);
>>> +      filter->pipe->set_framebuffer_state(filter->pipe, &fb_state);
>>> +      filter->pipe->set_viewport_states(filter->pipe, 0, 1, &viewport);
>>> +      util_draw_arrays(filter->pipe, PIPE_PRIM_QUADS, 0, 4);
>>> +
>>> +      /* blit or interpolate other field */
>>> +      fb_state.cbufs[0] = dst_surf;
>>> +      filter->pipe->set_framebuffer_state(filter->pipe, &fb_state);
>>> +      if (j > 0 && filter->skip_chroma) {
>>> +         util_draw_arrays(filter->pipe, PIPE_PRIM_QUADS, 0, 4);
>>> +      } else {
>>> +         filter->pipe->bind_fs_state(filter->pipe, field ?
>>> filter->fs_deint_top : filter->fs_deint_bottom);
>>> +         util_draw_arrays(filter->pipe, PIPE_PRIM_QUADS, 0, 4);
>>> +      }
>>> +   }
>>> +}
>>> +
>>> diff --git a/src/gallium/auxiliary/vl/vl_deint_filter.h
>>> b/src/gallium/auxiliary/vl/vl_deint_filter.h
>>> new file mode 100644
>>> index 0000000..5a21402
>>> --- /dev/null
>>> +++ b/src/gallium/auxiliary/vl/vl_deint_filter.h
>>> @@ -0,0 +1,78 @@
>>>
>>> +/**************************************************************************
>>> + *
>>> + * Copyright 2013 Grigori Goronzy <greg@chown.ath.cx>
>>> + * All Rights Reserved.
>>> + *
>>> + * Permission is hereby granted, free of charge, to any person obtaining
>>> a
>>> + * copy of this software and associated documentation files (the
>>> + * "Software"), to deal in the Software without restriction, including
>>> + * without limitation the rights to use, copy, modify, merge, publish,
>>> + * distribute, sub license, and/or sell copies of the Software, and to
>>> + * permit persons to whom the Software is furnished to do so, subject to
>>> + * the following conditions:
>>> + *
>>> + * The above copyright notice and this permission notice (including the
>>> + * next paragraph) shall be included in all copies or substantial
>>> portions
>>> + * of the Software.
>>> + *
>>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>>> EXPRESS
>>> + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>>> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>>> NON-INFRINGEMENT.
>>> + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
>>> + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
>>> CONTRACT,
>>> + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
>>> + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
>>> + *
>>> +
>>> **************************************************************************/
>>> +
>>> +/* motion adaptive deinterlacer implementation */
>>> +
>>> +#ifndef vl_deint_filter_h
>>> +#define vl_deint_filter_h
>>> +
>>> +#include "pipe/p_state.h"
>>> +
>>> +struct vl_deint_filter
>>> +{
>>> +   struct pipe_context *pipe;
>>> +   struct pipe_vertex_buffer quad;
>>> +
>>> +   void *rs_state;
>>> +   void *blend;
>>> +   void *sampler[4];
>>> +   void *ves;
>>> +   void *vs;
>>> +   void *fs_copy_top, *fs_copy_bottom;
>>> +   void *fs_deint_top, *fs_deint_bottom;
>>> +
>>> +   unsigned video_width, video_height;
>>> +   bool skip_chroma;
>>> +
>>> +   struct pipe_video_buffer *video_buffer;
>>> +};
>>> +
>>> +bool
>>> +vl_deint_filter_init(struct vl_deint_filter *filter, struct pipe_context
>>> *pipe,
>>> +                     unsigned video_width, unsigned video_height,
>>> +                     bool skip_chroma, bool spatial_filter);
>>> +
>>> +void
>>> +vl_deint_filter_cleanup(struct vl_deint_filter *filter);
>>> +
>>> +bool
>>> +vl_deint_filter_check_buffers(struct vl_deint_filter *filter,
>>> +                              struct pipe_video_buffer *prevprev,
>>> +                              struct pipe_video_buffer *prev,
>>> +                              struct pipe_video_buffer *cur,
>>> +                              struct pipe_video_buffer *next);
>>> +
>>> +void
>>> +vl_deint_filter_render(struct vl_deint_filter *filter,
>>> +                       struct pipe_video_buffer *prevprev,
>>> +                       struct pipe_video_buffer *prev,
>>> +                       struct pipe_video_buffer *cur,
>>> +                       struct pipe_video_buffer *next,
>>> +                       unsigned field);
>>> +
>>> +#endif /* vl_deint_filter_h */
>>> +
>>
>> _______________________________________________
>> mesa-dev mailing list
>> mesa-dev@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
On Sat, Feb 15, 2014 at 5:10 AM, Christian König
<deathsimple@vodafone.de> wrote:
> That's most likely an issue with st/vdpau. I implemented a small hack to
> clear the black bars of a surface only once. No idea how exactly it happens,
> but Grigoris patch seems to somehow break the logic there.
>
> Anyway we need to rework this part when getting DRI3 anyway (much more
> efficiently and cleanly), so I'm not sure if we should bother fixing it.

OK. Well, until then, the deinterlacing filter is largely unusable --
you end up with flickering textures in the bars (I guess each frame
extends all the way out, and they end up with different junk data).
Which is a shame, since the filter works really well. But at the same
time I'm not volunteering to figure out what's going on :)

  -ilia
Ilia Mirkin wrote:
> On Sat, Feb 15, 2014 at 5:10 AM, Christian König
> <deathsimple@vodafone.de> wrote:
>> That's most likely an issue with st/vdpau. I implemented a small hack to
>> clear the black bars of a surface only once. No idea how exactly it happens,
>> but Grigoris patch seems to somehow break the logic there.
>>
>> Anyway we need to rework this part when getting DRI3 anyway (much more
>> efficiently and cleanly), so I'm not sure if we should bother fixing it.
>
> OK. Well, until then, the deinterlacing filter is largely unusable --
> you end up with flickering textures in the bars (I guess each frame
> extends all the way out, and they end up with different junk data).
> Which is a shame, since the filter works really well. But at the same
> time I'm not volunteering to figure out what's going on :)

Can't reproduce that on my rv790 testing with recentish svn mplayer.

Tried 4/3 -> 16/9 fullscreen side bars are black.

Tried forcing -aspect 2.85 on 16/9 source again top/bottom bars are black.
Andy Furniss wrote:
> Ilia Mirkin wrote:
>> On Sat, Feb 15, 2014 at 5:10 AM, Christian König
>> <deathsimple@vodafone.de> wrote:
>>> That's most likely an issue with st/vdpau. I implemented a small
>>> hack to clear the black bars of a surface only once. No idea how
>>> exactly it happens, but Grigoris patch seems to somehow break the
>>> logic there.
>>>
>>> Anyway we need to rework this part when getting DRI3 anyway (much
>>> more efficiently and cleanly), so I'm not sure if we should
>>> bother fixing it.
>>
>> OK. Well, until then, the deinterlacing filter is largely unusable
>> -- you end up with flickering textures in the bars (I guess each
>> frame extends all the way out, and they end up with different junk
>> data). Which is a shame, since the filter works really well. But at
>> the same time I'm not volunteering to figure out what's going on
>> :)
>
> Can't reproduce that on my rv790 testing with recentish svn mplayer.
>
> Tried 4/3 -> 16/9 fullscreen side bars are black.
>
> Tried forcing -aspect 2.85 on 16/9 source again top/bottom bars are
> black.

I should also add -

Thanks Grigori for doing this - looks really good on HD stuff I've
tested and of course is easily fast enough, unlike anything on the CPU
at high res.

Any plans for the future?

Pre-filtered bicubic HQ scaling would be nice :-)

Below not specific to the deinterlacer, but I would be interested if
others see these as my card is not UVD so I have to patch to get the
deinterlacer to work - I know this breaks decode, but that's no problem
for me.

So I set  PIPE_VIDEO_CAP_PREFERS_INTERLACED
PIPE_VIDEO_CAP_SUPPORTS_INTERLACED to true.

I saw in the code comment that 422 isn't supported, so tested - roughly
works but can have issues depending on source - but unsupported is not
the issue.

I noticed that the weave shader also has issues with 422 - I didn't
expect this as using the progressive (for me unpatched mesa) looks OK -
so is 422 supposed to be supported by weave?

At the start or when I press f on mplayer to toggle between full/window
I see a frame of old/uninitialised video mem - does this happen on nvidia?

TIA

Andy.
On Sat, Feb 15, 2014 at 7:14 AM, Andy Furniss <adf.lists@gmail.com> wrote:
> At the start or when I press f on mplayer to toggle between full/window
> I see a frame of old/uninitialised video mem - does this happen on nvidia?

I definitely see something funny. It seemed like the deinterlace was
essentially "turned off" for a frame or two, not stale video mem. But
it was fast, I could be wrong. (Not sure why that would happen,
presumably the deinterlace is happening on the unscaled video and
_then_ scaled up rather than the other way around, but I didn't try to
understand the code.)

  -ilia
On 15.02.2014 13:14, Andy Furniss wrote:
> Thanks Grigori for doing this - looks really good on HD stuff I've
> tested and of course is easily fast enough, unlike anything on the CPU
> at high res.
>
> Any plans for the future?
>

Well, adding edge-guided spatial interpolation for the temporal-spatial 
mode of VDPAU, I have preliminary shader code for this already. Also, 
motion detection isn't quite perfect, and should be improved.

> Pre-filtered bicubic HQ scaling would be nice :-)
>

Can you describe in more detail what you mean? Better quality scaling is 
possible, but that would be applied *after* deinterlacing.

> Below not specific to the deinterlacer, but I would be interested if
> others see these as my card is not UVD so I have to patch to get the
> deinterlacer to work - I know this breaks decode, but that's no problem
> for me.
>
> So I set  PIPE_VIDEO_CAP_PREFERS_INTERLACED
> PIPE_VIDEO_CAP_SUPPORTS_INTERLACED to true.
>
> I saw in the code comment that 422 isn't supported, so tested - roughly
> works but can have issues depending on source - but unsupported is not
> the issue.
>

The deinterlacer currently always renders into a 420 surface, so even if 
you get some output, the chroma won't be correct. :)

> I noticed that the weave shader also has issues with 422 - I didn't
> expect this as using the progressive (for me unpatched mesa) looks OK -
> so is 422 supposed to be supported by weave?
>
> At the start or when I press f on mplayer to toggle between full/window
> I see a frame of old/uninitialised video mem - does this happen on nvidia?
>

MPlayer can be quite flawed. Have you tried mpv?

Best regards
Grigori
Grigori Goronzy wrote:
> On 15.02.2014 13:14, Andy Furniss wrote:
>> Thanks Grigori for doing this - looks really good on HD stuff I've
>> tested and of course is easily fast enough, unlike anything on the
>> CPU at high res.
>>
>> Any plans for the future?
>>
>
> Well, adding edge-guided spatial interpolation for the
> temporal-spatial mode of VDPAU, I have preliminary shader code for
> this already. Also, motion detection isn't quite perfect, and should
> be improved.

OK, from a user point of view the main obvious artifacts that I see
currently are jaggies on diagonals on SD material. If the above
addresses that then perfect. When I say SD I expect HD is the same but
having HD monitors/TV means that SD gets scaled up so amplifying them.
This is nothing to do with me mentioning HQ scaling below. Of course
there are other artifacts, but I guess ones you need to pause/slow-mo to
see don't really count.

>> Pre-filtered bicubic HQ scaling would be nice :-)
>
> Can you describe in more detail what you mean? Better quality scaling
> is possible, but that would be applied *after* deinterlacing.

Yea, I wasn't really thinking about it WRT deinterlacing - more just a
cheeky future project feature request because mesa vdpau has the
parameter but there is no implementation.

The pre-filtered bicubic was because I recalled coming across some
papers some time ago that praised the quality of that type of scaling
and others that mentioned GPU - now I've re-found and looked I am not so
sure they are applicable as they use cuda.

FWIW one was -

http://bigwww.epfl.ch/publications/ruijters1201.pdf

and another you will find by searching for

"Efficient Cubic B-spline Image Interpolation on a GPU"

> The deinterlacer currently always renders into a 420 surface, so even
> if you get some output, the chroma won't be correct. :)

OK, I was suprised by how good most looked some luck involved there I think.

>> I noticed that the weave shader also has issues with 422 - I
>> didn't expect this as using the progressive (for me unpatched mesa)
>> looks OK - so is 422 supposed to be supported by weave?

Nothing to do with the deinterlacer as such, but I am still curious
about the weave shader vs progressive, unless it's an mplayer issue.

>>
>> At the start or when I press f on mplayer to toggle between
>> full/window I see a frame of old/uninitialised video mem - does
>> this happen on nvidia?
>>
>
> MPlayer can be quite flawed. Have you tried mpv?

You are right, I just got mpv and the issue is gone - slightly strange
WRT mplayer being wrong as I thought nvidia effectively did their
implementation.