[Mesa-dev] [PATCH 1/2] vl: add motion adaptive deinterlacer
Christian König
deathsimple at vodafone.de
Sat Feb 15 02:10:32 PST 2014
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 at 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 at 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 at 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 at lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
More information about the mesa-dev
mailing list