Home | History | Annotate | Download | only in vl
      1 /**************************************************************************
      2  *
      3  * Copyright 2013 Grigori Goronzy <greg (at) chown.ath.cx>.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 /*
     29  *  References:
     30  *
     31  *  Lin, S. F., Chang, Y. L., & Chen, L. G. (2003).
     32  *  Motion adaptive interpolation with horizontal motion detection for deinterlacing.
     33  *  Consumer Electronics, IEEE Transactions on, 49(4), 1256-1265.
     34  *
     35  *  Pei-Yin, C. H. E. N., & Yao-Hsien, L. A. I. (2007).
     36  *  A low-complexity interpolation method for deinterlacing.
     37  *  IEICE transactions on information and systems, 90(2), 606-608.
     38  *
     39  */
     40 
     41 #include <stdio.h>
     42 
     43 #include "pipe/p_context.h"
     44 
     45 #include "tgsi/tgsi_ureg.h"
     46 
     47 #include "util/u_draw.h"
     48 #include "util/u_memory.h"
     49 #include "util/u_math.h"
     50 #include "util/u_format.h"
     51 
     52 #include "vl_types.h"
     53 #include "vl_video_buffer.h"
     54 #include "vl_vertex_buffers.h"
     55 #include "vl_deint_filter.h"
     56 
     57 enum VS_OUTPUT
     58 {
     59    VS_O_VPOS = 0,
     60    VS_O_VTEX = 0
     61 };
     62 
     63 static void *
     64 create_vert_shader(struct vl_deint_filter *filter)
     65 {
     66    struct ureg_program *shader;
     67    struct ureg_src i_vpos;
     68    struct ureg_dst o_vpos, o_vtex;
     69 
     70    shader = ureg_create(PIPE_SHADER_VERTEX);
     71    if (!shader)
     72       return NULL;
     73 
     74    i_vpos = ureg_DECL_vs_input(shader, 0);
     75    o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
     76    o_vtex = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX);
     77 
     78    ureg_MOV(shader, o_vpos, i_vpos);
     79    ureg_MOV(shader, o_vtex, i_vpos);
     80 
     81    ureg_END(shader);
     82 
     83    return ureg_create_shader_and_destroy(shader, filter->pipe);
     84 }
     85 
     86 static void *
     87 create_copy_frag_shader(struct vl_deint_filter *filter, unsigned field)
     88 {
     89    struct ureg_program *shader;
     90    struct ureg_src i_vtex;
     91    struct ureg_src sampler;
     92    struct ureg_dst o_fragment;
     93    struct ureg_dst t_tex;
     94 
     95    shader = ureg_create(PIPE_SHADER_FRAGMENT);
     96    if (!shader) {
     97       return NULL;
     98    }
     99    t_tex = ureg_DECL_temporary(shader);
    100 
    101    i_vtex = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX, TGSI_INTERPOLATE_LINEAR);
    102    sampler = ureg_DECL_sampler(shader, 2);
    103    o_fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
    104 
    105    ureg_MOV(shader, t_tex, i_vtex);
    106    if (field) {
    107       ureg_MOV(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_ZW),
    108                ureg_imm4f(shader, 0, 0, 1.0f, 0));
    109    } else {
    110       ureg_MOV(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_ZW),
    111                ureg_imm1f(shader, 0));
    112    }
    113 
    114    ureg_TEX(shader, o_fragment, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_tex), sampler);
    115 
    116    ureg_release_temporary(shader, t_tex);
    117    ureg_END(shader);
    118 
    119    return ureg_create_shader_and_destroy(shader, filter->pipe);
    120 }
    121 
    122 static void *
    123 create_deint_frag_shader(struct vl_deint_filter *filter, unsigned field,
    124                          struct vertex2f *sizes, bool spatial_filter)
    125 {
    126    struct ureg_program *shader;
    127    struct ureg_src i_vtex;
    128    struct ureg_src sampler_cur;
    129    struct ureg_src sampler_prevprev;
    130    struct ureg_src sampler_prev;
    131    struct ureg_src sampler_next;
    132    struct ureg_dst o_fragment;
    133    struct ureg_dst t_tex;
    134    struct ureg_dst t_comp_top, t_comp_bot;
    135    struct ureg_dst t_diff;
    136    struct ureg_dst t_a, t_b;
    137    struct ureg_dst t_weave, t_linear;
    138 
    139    shader = ureg_create(PIPE_SHADER_FRAGMENT);
    140    if (!shader) {
    141       return NULL;
    142    }
    143 
    144    t_tex = ureg_DECL_temporary(shader);
    145    t_comp_top = ureg_DECL_temporary(shader);
    146    t_comp_bot = ureg_DECL_temporary(shader);
    147    t_diff = ureg_DECL_temporary(shader);
    148    t_a = ureg_DECL_temporary(shader);
    149    t_b = ureg_DECL_temporary(shader);
    150    t_weave = ureg_DECL_temporary(shader);
    151    t_linear = ureg_DECL_temporary(shader);
    152 
    153    i_vtex = ureg_DECL_fs_input(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTEX, TGSI_INTERPOLATE_LINEAR);
    154    sampler_prevprev = ureg_DECL_sampler(shader, 0);
    155    sampler_prev = ureg_DECL_sampler(shader, 1);
    156    sampler_cur = ureg_DECL_sampler(shader, 2);
    157    sampler_next = ureg_DECL_sampler(shader, 3);
    158    o_fragment = ureg_DECL_output(shader, TGSI_SEMANTIC_COLOR, 0);
    159 
    160    // we don't care about ZW interpolation (allows better optimization)
    161    ureg_MOV(shader, t_tex, i_vtex);
    162    ureg_MOV(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_ZW),
    163             ureg_imm1f(shader, 0));
    164 
    165    // sample between texels for cheap lowpass
    166    ureg_ADD(shader, t_comp_top, ureg_src(t_tex),
    167             ureg_imm4f(shader, sizes->x * 0.5f, sizes->y * -0.5f, 0, 0));
    168    ureg_ADD(shader, t_comp_bot, ureg_src(t_tex),
    169             ureg_imm4f(shader, sizes->x * -0.5f, sizes->y * 0.5f, 1.0f, 0));
    170 
    171    if (field == 0) {
    172       /* interpolating top field -> current field is a bottom field */
    173       // cur vs prev2
    174       ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_cur);
    175       ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_prevprev);
    176       ureg_ADD(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X), ureg_src(t_a), ureg_negate(ureg_src(t_b)));
    177       // prev vs next
    178       ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top), sampler_prev);
    179       ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top), sampler_next);
    180       ureg_ADD(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_Y), ureg_src(t_a), ureg_negate(ureg_src(t_b)));
    181    } else {
    182       /* interpolating bottom field -> current field is a top field */
    183       // cur vs prev2
    184       ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top), sampler_cur);
    185       ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top), sampler_prevprev);
    186       ureg_ADD(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X), ureg_src(t_a), ureg_negate(ureg_src(t_b)));
    187       // prev vs next
    188       ureg_TEX(shader, t_a, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_prev);
    189       ureg_TEX(shader, t_b, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_next);
    190       ureg_ADD(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_Y), ureg_src(t_a), ureg_negate(ureg_src(t_b)));
    191    }
    192 
    193    // absolute maximum of differences
    194    ureg_MAX(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X), ureg_abs(ureg_src(t_diff)),
    195             ureg_scalar(ureg_abs(ureg_src(t_diff)), TGSI_SWIZZLE_Y));
    196 
    197    if (field == 0) {
    198       /* weave with prev top field */
    199       ureg_TEX(shader, t_weave, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_tex), sampler_prev);
    200       /* get linear interpolation from current bottom field */
    201       ureg_ADD(shader, t_comp_top, ureg_src(t_tex), ureg_imm4f(shader, 0, sizes->y * -1.0f, 1.0f, 0));
    202       ureg_TEX(shader, t_linear, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_top), sampler_cur);
    203    } else {
    204       /* weave with prev bottom field */
    205       ureg_ADD(shader, t_comp_bot, ureg_src(t_tex), ureg_imm4f(shader, 0, 0, 1.0f, 0));
    206       ureg_TEX(shader, t_weave, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_prev);
    207       /* get linear interpolation from current top field */
    208       ureg_ADD(shader, t_comp_bot, ureg_src(t_tex), ureg_imm4f(shader, 0, sizes->y * 1.0f, 0, 0));
    209       ureg_TEX(shader, t_linear, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_comp_bot), sampler_cur);
    210    }
    211 
    212    // mix between weave and linear
    213    // fully weave if diff < 6 (0.02353), fully interpolate if diff > 14 (0.05490)
    214    ureg_ADD(shader, ureg_writemask(t_diff, TGSI_WRITEMASK_X), ureg_src(t_diff),
    215             ureg_imm4f(shader, -0.02353f, 0, 0, 0));
    216    ureg_MUL(shader, ureg_saturate(ureg_writemask(t_diff, TGSI_WRITEMASK_X)),
    217             ureg_src(t_diff), ureg_imm4f(shader, 31.8750f, 0, 0, 0));
    218    ureg_LRP(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_X), ureg_src(t_diff),
    219             ureg_src(t_linear), ureg_src(t_weave));
    220    ureg_MOV(shader, o_fragment, ureg_scalar(ureg_src(t_tex), TGSI_SWIZZLE_X));
    221 
    222    ureg_release_temporary(shader, t_tex);
    223    ureg_release_temporary(shader, t_comp_top);
    224    ureg_release_temporary(shader, t_comp_bot);
    225    ureg_release_temporary(shader, t_diff);
    226    ureg_release_temporary(shader, t_a);
    227    ureg_release_temporary(shader, t_b);
    228    ureg_release_temporary(shader, t_weave);
    229    ureg_release_temporary(shader, t_linear);
    230    ureg_END(shader);
    231 
    232    return ureg_create_shader_and_destroy(shader, filter->pipe);
    233 }
    234 
    235 bool
    236 vl_deint_filter_init(struct vl_deint_filter *filter, struct pipe_context *pipe,
    237                      unsigned video_width, unsigned video_height,
    238                      bool skip_chroma, bool spatial_filter)
    239 {
    240    struct pipe_rasterizer_state rs_state;
    241    struct pipe_blend_state blend;
    242    struct pipe_sampler_state sampler;
    243    struct pipe_vertex_element ve;
    244    struct vertex2f sizes;
    245    struct pipe_video_buffer templ;
    246 
    247    assert(filter && pipe);
    248    assert(video_width && video_height);
    249 
    250    memset(filter, 0, sizeof(*filter));
    251    filter->pipe = pipe;
    252    filter->skip_chroma = skip_chroma;
    253    filter->video_width = video_width;
    254    filter->video_height = video_height;
    255 
    256    /* TODO: handle other than 4:2:0 subsampling */
    257    memset(&templ, 0, sizeof(templ));
    258    templ.buffer_format = pipe->screen->get_video_param
    259    (
    260       pipe->screen,
    261       PIPE_VIDEO_PROFILE_UNKNOWN,
    262       PIPE_VIDEO_ENTRYPOINT_UNKNOWN,
    263       PIPE_VIDEO_CAP_PREFERED_FORMAT
    264    );
    265    templ.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
    266    templ.width = video_width;
    267    templ.height = video_height;
    268    templ.interlaced = true;
    269    filter->video_buffer = vl_video_buffer_create(pipe, &templ);
    270    if (!filter->video_buffer)
    271       goto error_video_buffer;
    272 
    273    memset(&rs_state, 0, sizeof(rs_state));
    274    rs_state.half_pixel_center = true;
    275    rs_state.bottom_edge_rule = true;
    276    rs_state.depth_clip = 1;
    277    filter->rs_state = pipe->create_rasterizer_state(pipe, &rs_state);
    278    if (!filter->rs_state)
    279       goto error_rs_state;
    280 
    281    memset(&blend, 0, sizeof blend);
    282    blend.rt[0].colormask = PIPE_MASK_R;
    283    filter->blend[0] = pipe->create_blend_state(pipe, &blend);
    284    if (!filter->blend[0])
    285       goto error_blendR;
    286 
    287    blend.rt[0].colormask = PIPE_MASK_G;
    288    filter->blend[1] = pipe->create_blend_state(pipe, &blend);
    289    if (!filter->blend[1])
    290       goto error_blendG;
    291 
    292    blend.rt[0].colormask = PIPE_MASK_B;
    293    filter->blend[2] = pipe->create_blend_state(pipe, &blend);
    294    if (!filter->blend[2])
    295       goto error_blendB;
    296 
    297    memset(&sampler, 0, sizeof(sampler));
    298    sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    299    sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    300    sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
    301    sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR;
    302    sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
    303    sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
    304    sampler.normalized_coords = 1;
    305    filter->sampler[0] = pipe->create_sampler_state(pipe, &sampler);
    306    filter->sampler[1] = filter->sampler[2] = filter->sampler[3] = filter->sampler[0];
    307    if (!filter->sampler[0])
    308       goto error_sampler;
    309 
    310    filter->quad = vl_vb_upload_quads(pipe);
    311    if(!filter->quad.buffer)
    312       goto error_quad;
    313 
    314    memset(&ve, 0, sizeof(ve));
    315    ve.src_offset = 0;
    316    ve.instance_divisor = 0;
    317    ve.vertex_buffer_index = 0;
    318    ve.src_format = PIPE_FORMAT_R32G32_FLOAT;
    319    filter->ves = pipe->create_vertex_elements_state(pipe, 1, &ve);
    320    if (!filter->ves)
    321       goto error_ves;
    322 
    323    sizes.x = 1.0f / video_width;
    324    sizes.y = 1.0f / video_height;
    325 
    326    filter->vs = create_vert_shader(filter);
    327    if (!filter->vs)
    328       goto error_vs;
    329 
    330    filter->fs_copy_top = create_copy_frag_shader(filter, 0);
    331    if (!filter->fs_copy_top)
    332       goto error_fs_copy_top;
    333 
    334    filter->fs_copy_bottom = create_copy_frag_shader(filter, 1);
    335    if (!filter->fs_copy_bottom)
    336       goto error_fs_copy_bottom;
    337 
    338    filter->fs_deint_top = create_deint_frag_shader(filter, 0, &sizes, spatial_filter);
    339    if (!filter->fs_deint_top)
    340       goto error_fs_deint_top;
    341 
    342    filter->fs_deint_bottom = create_deint_frag_shader(filter, 1, &sizes, spatial_filter);
    343    if (!filter->fs_deint_bottom)
    344       goto error_fs_deint_bottom;
    345 
    346    return true;
    347 
    348 error_fs_deint_bottom:
    349    pipe->delete_fs_state(pipe, filter->fs_deint_top);
    350 
    351 error_fs_deint_top:
    352    pipe->delete_fs_state(pipe, filter->fs_copy_bottom);
    353 
    354 error_fs_copy_bottom:
    355    pipe->delete_fs_state(pipe, filter->fs_copy_top);
    356 
    357 error_fs_copy_top:
    358    pipe->delete_vs_state(pipe, filter->vs);
    359 
    360 error_vs:
    361    pipe->delete_vertex_elements_state(pipe, filter->ves);
    362 
    363 error_ves:
    364    pipe_resource_reference(&filter->quad.buffer, NULL);
    365 
    366 error_quad:
    367    pipe->delete_sampler_state(pipe, filter->sampler);
    368 
    369 error_sampler:
    370    pipe->delete_blend_state(pipe, filter->blend[2]);
    371 
    372 error_blendB:
    373    pipe->delete_blend_state(pipe, filter->blend[1]);
    374 
    375 error_blendG:
    376    pipe->delete_blend_state(pipe, filter->blend[0]);
    377 
    378 error_blendR:
    379    pipe->delete_rasterizer_state(pipe, filter->rs_state);
    380 
    381 error_rs_state:
    382    filter->video_buffer->destroy(filter->video_buffer);
    383 
    384 error_video_buffer:
    385    return false;
    386 }
    387 
    388 void
    389 vl_deint_filter_cleanup(struct vl_deint_filter *filter)
    390 {
    391    assert(filter);
    392 
    393    filter->pipe->delete_sampler_state(filter->pipe, filter->sampler[0]);
    394    filter->pipe->delete_blend_state(filter->pipe, filter->blend[0]);
    395    filter->pipe->delete_blend_state(filter->pipe, filter->blend[1]);
    396    filter->pipe->delete_blend_state(filter->pipe, filter->blend[2]);
    397    filter->pipe->delete_rasterizer_state(filter->pipe, filter->rs_state);
    398    filter->pipe->delete_vertex_elements_state(filter->pipe, filter->ves);
    399    pipe_resource_reference(&filter->quad.buffer, NULL);
    400 
    401    filter->pipe->delete_vs_state(filter->pipe, filter->vs);
    402    filter->pipe->delete_fs_state(filter->pipe, filter->fs_copy_top);
    403    filter->pipe->delete_fs_state(filter->pipe, filter->fs_copy_bottom);
    404    filter->pipe->delete_fs_state(filter->pipe, filter->fs_deint_top);
    405    filter->pipe->delete_fs_state(filter->pipe, filter->fs_deint_bottom);
    406 
    407    filter->video_buffer->destroy(filter->video_buffer);
    408 }
    409 
    410 bool
    411 vl_deint_filter_check_buffers(struct vl_deint_filter *filter,
    412                               struct pipe_video_buffer *prevprev,
    413                               struct pipe_video_buffer *prev,
    414                               struct pipe_video_buffer *cur,
    415                               struct pipe_video_buffer *next)
    416 {
    417    int i;
    418    struct pipe_video_buffer *bufs[] = { prevprev, prev, cur, next };
    419 
    420    for (i = 0; i < 4; i++) {
    421       if (bufs[i]->chroma_format != PIPE_VIDEO_CHROMA_FORMAT_420)
    422          return false;
    423       if (bufs[i]->width < filter->video_width ||
    424           bufs[i]->height < filter->video_height)
    425          return false;
    426       if (!bufs[i]->interlaced)
    427          return false;
    428    }
    429 
    430    return true;
    431 }
    432 
    433 void
    434 vl_deint_filter_render(struct vl_deint_filter *filter,
    435                        struct pipe_video_buffer *prevprev,
    436                        struct pipe_video_buffer *prev,
    437                        struct pipe_video_buffer *cur,
    438                        struct pipe_video_buffer *next,
    439                        unsigned field)
    440 {
    441    struct pipe_viewport_state viewport;
    442    struct pipe_framebuffer_state fb_state;
    443    struct pipe_sampler_view **cur_sv;
    444    struct pipe_sampler_view **prevprev_sv;
    445    struct pipe_sampler_view **prev_sv;
    446    struct pipe_sampler_view **next_sv;
    447    struct pipe_sampler_view *sampler_views[4];
    448    struct pipe_surface **dst_surfaces;
    449    const unsigned *plane_order;
    450    int i;
    451    unsigned j;
    452 
    453    assert(filter && prevprev && prev && cur && next && field <= 1);
    454 
    455    /* set up destination and source */
    456    dst_surfaces = filter->video_buffer->get_surfaces(filter->video_buffer);
    457    plane_order = vl_video_buffer_plane_order(filter->video_buffer->buffer_format);
    458    cur_sv = cur->get_sampler_view_components(cur);
    459    prevprev_sv = prevprev->get_sampler_view_components(prevprev);
    460    prev_sv = prev->get_sampler_view_components(prev);
    461    next_sv = next->get_sampler_view_components(next);
    462 
    463    /* set up pipe state */
    464    filter->pipe->bind_rasterizer_state(filter->pipe, filter->rs_state);
    465    filter->pipe->set_vertex_buffers(filter->pipe, 0, 1, &filter->quad);
    466    filter->pipe->bind_vertex_elements_state(filter->pipe, filter->ves);
    467    filter->pipe->bind_vs_state(filter->pipe, filter->vs);
    468    filter->pipe->bind_sampler_states(filter->pipe, PIPE_SHADER_FRAGMENT,
    469                                      0, 4, filter->sampler);
    470 
    471    /* prepare viewport */
    472    memset(&viewport, 0, sizeof(viewport));
    473    viewport.scale[2] = 1;
    474 
    475    /* prepare framebuffer */
    476    memset(&fb_state, 0, sizeof(fb_state));
    477    fb_state.nr_cbufs = 1;
    478 
    479    /* process each plane separately */
    480    for (i = 0, j = 0; i < VL_NUM_COMPONENTS; ++i) {
    481       struct pipe_surface *blit_surf = dst_surfaces[field];
    482       struct pipe_surface *dst_surf = dst_surfaces[1 - field];
    483       int k = plane_order[i];
    484 
    485       /* bind blend state for this component in the plane */
    486       filter->pipe->bind_blend_state(filter->pipe, filter->blend[j]);
    487 
    488       /* update render target state */
    489       viewport.scale[0] = blit_surf->texture->width0;
    490       viewport.scale[1] = blit_surf->texture->height0;
    491       fb_state.width = blit_surf->texture->width0;
    492       fb_state.height = blit_surf->texture->height0;
    493 
    494       /* update sampler view sources  */
    495       sampler_views[0] = prevprev_sv[k];
    496       sampler_views[1] = prev_sv[k];
    497       sampler_views[2] = cur_sv[k];
    498       sampler_views[3] = next_sv[k];
    499       filter->pipe->set_sampler_views(filter->pipe, PIPE_SHADER_FRAGMENT, 0, 4, sampler_views);
    500 
    501       /* blit current field */
    502       fb_state.cbufs[0] = blit_surf;
    503       filter->pipe->bind_fs_state(filter->pipe, field ? filter->fs_copy_bottom : filter->fs_copy_top);
    504       filter->pipe->set_framebuffer_state(filter->pipe, &fb_state);
    505       filter->pipe->set_viewport_states(filter->pipe, 0, 1, &viewport);
    506       util_draw_arrays(filter->pipe, PIPE_PRIM_QUADS, 0, 4);
    507 
    508       /* blit or interpolate other field */
    509       fb_state.cbufs[0] = dst_surf;
    510       filter->pipe->set_framebuffer_state(filter->pipe, &fb_state);
    511       if (i > 0 && filter->skip_chroma) {
    512          util_draw_arrays(filter->pipe, PIPE_PRIM_QUADS, 0, 4);
    513       } else {
    514          filter->pipe->bind_fs_state(filter->pipe, field ? filter->fs_deint_top : filter->fs_deint_bottom);
    515          util_draw_arrays(filter->pipe, PIPE_PRIM_QUADS, 0, 4);
    516       }
    517 
    518       if (++j >= util_format_get_nr_components(dst_surf->format)) {
    519          dst_surfaces += 2;
    520          j = 0;
    521       }
    522    }
    523 }
    524