1 /**************************************************************************
3 * Copyright 2013 Grigori Goronzy <greg@chown.ath.cx>.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
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.
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.
43 #include "pipe/p_context.h"
45 #include "tgsi/tgsi_ureg.h"
47 #include "util/u_draw.h"
48 #include "util/u_memory.h"
49 #include "util/u_math.h"
50 #include "util/format/u_format.h"
53 #include "vl_video_buffer.h"
54 #include "vl_vertex_buffers.h"
55 #include "vl_deint_filter.h"
64 create_vert_shader(struct vl_deint_filter
*filter
)
66 struct ureg_program
*shader
;
67 struct ureg_src i_vpos
;
68 struct ureg_dst o_vpos
, o_vtex
;
70 shader
= ureg_create(PIPE_SHADER_VERTEX
);
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
);
78 ureg_MOV(shader
, o_vpos
, i_vpos
);
79 ureg_MOV(shader
, o_vtex
, i_vpos
);
83 return ureg_create_shader_and_destroy(shader
, filter
->pipe
);
87 create_copy_frag_shader(struct vl_deint_filter
*filter
, unsigned field
)
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
;
95 shader
= ureg_create(PIPE_SHADER_FRAGMENT
);
99 t_tex
= ureg_DECL_temporary(shader
);
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);
105 ureg_MOV(shader
, t_tex
, i_vtex
);
107 ureg_MOV(shader
, ureg_writemask(t_tex
, TGSI_WRITEMASK_ZW
),
108 ureg_imm4f(shader
, 0, 0, 1.0f
, 0));
110 ureg_MOV(shader
, ureg_writemask(t_tex
, TGSI_WRITEMASK_ZW
),
111 ureg_imm1f(shader
, 0));
114 ureg_TEX(shader
, o_fragment
, TGSI_TEXTURE_2D_ARRAY
, ureg_src(t_tex
), sampler
);
116 ureg_release_temporary(shader
, t_tex
);
119 return ureg_create_shader_and_destroy(shader
, filter
->pipe
);
123 create_deint_frag_shader(struct vl_deint_filter
*filter
, unsigned field
,
124 struct vertex2f
*sizes
, bool spatial_filter
)
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
;
139 shader
= ureg_create(PIPE_SHADER_FRAGMENT
);
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
);
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);
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));
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));
172 /* interpolating top field -> current field is a bottom field */
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
)));
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
)));
182 /* interpolating bottom field -> current field is a top field */
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
)));
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
)));
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
));
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
);
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
);
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
));
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
);
232 return ureg_create_shader_and_destroy(shader
, filter
->pipe
);
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
)
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
;
247 assert(filter
&& pipe
);
248 assert(video_width
&& video_height
);
250 memset(filter
, 0, sizeof(*filter
));
252 filter
->skip_chroma
= skip_chroma
;
253 filter
->video_width
= video_width
;
254 filter
->video_height
= video_height
;
256 /* TODO: handle other than 4:2:0 subsampling */
257 memset(&templ
, 0, sizeof(templ
));
258 templ
.buffer_format
= pipe
->screen
->get_video_param
261 PIPE_VIDEO_PROFILE_UNKNOWN
,
262 PIPE_VIDEO_ENTRYPOINT_UNKNOWN
,
263 PIPE_VIDEO_CAP_PREFERED_FORMAT
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
;
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_near
= 1;
277 rs_state
.depth_clip_far
= 1;
279 filter
->rs_state
= pipe
->create_rasterizer_state(pipe
, &rs_state
);
280 if (!filter
->rs_state
)
283 memset(&blend
, 0, sizeof blend
);
284 blend
.rt
[0].colormask
= PIPE_MASK_R
;
285 filter
->blend
[0] = pipe
->create_blend_state(pipe
, &blend
);
286 if (!filter
->blend
[0])
289 blend
.rt
[0].colormask
= PIPE_MASK_G
;
290 filter
->blend
[1] = pipe
->create_blend_state(pipe
, &blend
);
291 if (!filter
->blend
[1])
294 blend
.rt
[0].colormask
= PIPE_MASK_B
;
295 filter
->blend
[2] = pipe
->create_blend_state(pipe
, &blend
);
296 if (!filter
->blend
[2])
299 memset(&sampler
, 0, sizeof(sampler
));
300 sampler
.wrap_s
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
301 sampler
.wrap_t
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
302 sampler
.wrap_r
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
303 sampler
.min_img_filter
= PIPE_TEX_FILTER_LINEAR
;
304 sampler
.min_mip_filter
= PIPE_TEX_MIPFILTER_NONE
;
305 sampler
.mag_img_filter
= PIPE_TEX_FILTER_LINEAR
;
306 sampler
.normalized_coords
= 1;
307 filter
->sampler
[0] = pipe
->create_sampler_state(pipe
, &sampler
);
308 filter
->sampler
[1] = filter
->sampler
[2] = filter
->sampler
[3] = filter
->sampler
[0];
309 if (!filter
->sampler
[0])
312 filter
->quad
= vl_vb_upload_quads(pipe
);
313 if(!filter
->quad
.buffer
.resource
)
316 memset(&ve
, 0, sizeof(ve
));
318 ve
.instance_divisor
= 0;
319 ve
.vertex_buffer_index
= 0;
320 ve
.src_format
= PIPE_FORMAT_R32G32_FLOAT
;
321 filter
->ves
= pipe
->create_vertex_elements_state(pipe
, 1, &ve
);
325 sizes
.x
= 1.0f
/ video_width
;
326 sizes
.y
= 1.0f
/ video_height
;
328 filter
->vs
= create_vert_shader(filter
);
332 filter
->fs_copy_top
= create_copy_frag_shader(filter
, 0);
333 if (!filter
->fs_copy_top
)
334 goto error_fs_copy_top
;
336 filter
->fs_copy_bottom
= create_copy_frag_shader(filter
, 1);
337 if (!filter
->fs_copy_bottom
)
338 goto error_fs_copy_bottom
;
340 filter
->fs_deint_top
= create_deint_frag_shader(filter
, 0, &sizes
, spatial_filter
);
341 if (!filter
->fs_deint_top
)
342 goto error_fs_deint_top
;
344 filter
->fs_deint_bottom
= create_deint_frag_shader(filter
, 1, &sizes
, spatial_filter
);
345 if (!filter
->fs_deint_bottom
)
346 goto error_fs_deint_bottom
;
350 error_fs_deint_bottom
:
351 pipe
->delete_fs_state(pipe
, filter
->fs_deint_top
);
354 pipe
->delete_fs_state(pipe
, filter
->fs_copy_bottom
);
356 error_fs_copy_bottom
:
357 pipe
->delete_fs_state(pipe
, filter
->fs_copy_top
);
360 pipe
->delete_vs_state(pipe
, filter
->vs
);
363 pipe
->delete_vertex_elements_state(pipe
, filter
->ves
);
366 pipe_resource_reference(&filter
->quad
.buffer
.resource
, NULL
);
369 pipe
->delete_sampler_state(pipe
, filter
->sampler
);
372 pipe
->delete_blend_state(pipe
, filter
->blend
[2]);
375 pipe
->delete_blend_state(pipe
, filter
->blend
[1]);
378 pipe
->delete_blend_state(pipe
, filter
->blend
[0]);
381 pipe
->delete_rasterizer_state(pipe
, filter
->rs_state
);
384 filter
->video_buffer
->destroy(filter
->video_buffer
);
391 vl_deint_filter_cleanup(struct vl_deint_filter
*filter
)
395 filter
->pipe
->delete_sampler_state(filter
->pipe
, filter
->sampler
[0]);
396 filter
->pipe
->delete_blend_state(filter
->pipe
, filter
->blend
[0]);
397 filter
->pipe
->delete_blend_state(filter
->pipe
, filter
->blend
[1]);
398 filter
->pipe
->delete_blend_state(filter
->pipe
, filter
->blend
[2]);
399 filter
->pipe
->delete_rasterizer_state(filter
->pipe
, filter
->rs_state
);
400 filter
->pipe
->delete_vertex_elements_state(filter
->pipe
, filter
->ves
);
401 pipe_resource_reference(&filter
->quad
.buffer
.resource
, NULL
);
403 filter
->pipe
->delete_vs_state(filter
->pipe
, filter
->vs
);
404 filter
->pipe
->delete_fs_state(filter
->pipe
, filter
->fs_copy_top
);
405 filter
->pipe
->delete_fs_state(filter
->pipe
, filter
->fs_copy_bottom
);
406 filter
->pipe
->delete_fs_state(filter
->pipe
, filter
->fs_deint_top
);
407 filter
->pipe
->delete_fs_state(filter
->pipe
, filter
->fs_deint_bottom
);
409 filter
->video_buffer
->destroy(filter
->video_buffer
);
413 vl_deint_filter_check_buffers(struct vl_deint_filter
*filter
,
414 struct pipe_video_buffer
*prevprev
,
415 struct pipe_video_buffer
*prev
,
416 struct pipe_video_buffer
*cur
,
417 struct pipe_video_buffer
*next
)
420 struct pipe_video_buffer
*bufs
[] = { prevprev
, prev
, cur
, next
};
422 for (i
= 0; i
< 4; i
++) {
423 if (bufs
[i
]->chroma_format
!= PIPE_VIDEO_CHROMA_FORMAT_420
)
425 if (bufs
[i
]->width
< filter
->video_width
||
426 bufs
[i
]->height
< filter
->video_height
)
428 if (!bufs
[i
]->interlaced
)
436 vl_deint_filter_render(struct vl_deint_filter
*filter
,
437 struct pipe_video_buffer
*prevprev
,
438 struct pipe_video_buffer
*prev
,
439 struct pipe_video_buffer
*cur
,
440 struct pipe_video_buffer
*next
,
443 struct pipe_viewport_state viewport
;
444 struct pipe_framebuffer_state fb_state
;
445 struct pipe_sampler_view
**cur_sv
;
446 struct pipe_sampler_view
**prevprev_sv
;
447 struct pipe_sampler_view
**prev_sv
;
448 struct pipe_sampler_view
**next_sv
;
449 struct pipe_sampler_view
*sampler_views
[4];
450 struct pipe_surface
**dst_surfaces
;
451 const unsigned *plane_order
;
455 assert(filter
&& prevprev
&& prev
&& cur
&& next
&& field
<= 1);
457 /* set up destination and source */
458 dst_surfaces
= filter
->video_buffer
->get_surfaces(filter
->video_buffer
);
459 plane_order
= vl_video_buffer_plane_order(filter
->video_buffer
->buffer_format
);
460 cur_sv
= cur
->get_sampler_view_components(cur
);
461 prevprev_sv
= prevprev
->get_sampler_view_components(prevprev
);
462 prev_sv
= prev
->get_sampler_view_components(prev
);
463 next_sv
= next
->get_sampler_view_components(next
);
465 /* set up pipe state */
466 filter
->pipe
->bind_rasterizer_state(filter
->pipe
, filter
->rs_state
);
467 filter
->pipe
->set_vertex_buffers(filter
->pipe
, 0, 1, &filter
->quad
);
468 filter
->pipe
->bind_vertex_elements_state(filter
->pipe
, filter
->ves
);
469 filter
->pipe
->bind_vs_state(filter
->pipe
, filter
->vs
);
470 filter
->pipe
->bind_sampler_states(filter
->pipe
, PIPE_SHADER_FRAGMENT
,
471 0, 4, filter
->sampler
);
473 /* prepare viewport */
474 memset(&viewport
, 0, sizeof(viewport
));
475 viewport
.scale
[2] = 1;
477 /* prepare framebuffer */
478 memset(&fb_state
, 0, sizeof(fb_state
));
479 fb_state
.nr_cbufs
= 1;
481 /* process each plane separately */
482 for (i
= 0, j
= 0; i
< VL_NUM_COMPONENTS
; ++i
) {
483 struct pipe_surface
*blit_surf
= dst_surfaces
[field
];
484 struct pipe_surface
*dst_surf
= dst_surfaces
[1 - field
];
485 int k
= plane_order
[i
];
487 /* bind blend state for this component in the plane */
488 filter
->pipe
->bind_blend_state(filter
->pipe
, filter
->blend
[j
]);
490 /* update render target state */
491 viewport
.scale
[0] = blit_surf
->texture
->width0
;
492 viewport
.scale
[1] = blit_surf
->texture
->height0
;
493 fb_state
.width
= blit_surf
->texture
->width0
;
494 fb_state
.height
= blit_surf
->texture
->height0
;
496 /* update sampler view sources */
497 sampler_views
[0] = prevprev_sv
[k
];
498 sampler_views
[1] = prev_sv
[k
];
499 sampler_views
[2] = cur_sv
[k
];
500 sampler_views
[3] = next_sv
[k
];
501 filter
->pipe
->set_sampler_views(filter
->pipe
, PIPE_SHADER_FRAGMENT
, 0, 4, sampler_views
);
503 /* blit current field */
504 fb_state
.cbufs
[0] = blit_surf
;
505 filter
->pipe
->bind_fs_state(filter
->pipe
, field
? filter
->fs_copy_bottom
: filter
->fs_copy_top
);
506 filter
->pipe
->set_framebuffer_state(filter
->pipe
, &fb_state
);
507 filter
->pipe
->set_viewport_states(filter
->pipe
, 0, 1, &viewport
);
508 util_draw_arrays(filter
->pipe
, PIPE_PRIM_QUADS
, 0, 4);
510 /* blit or interpolate other field */
511 fb_state
.cbufs
[0] = dst_surf
;
512 filter
->pipe
->set_framebuffer_state(filter
->pipe
, &fb_state
);
513 if (i
> 0 && filter
->skip_chroma
) {
514 util_draw_arrays(filter
->pipe
, PIPE_PRIM_QUADS
, 0, 4);
516 filter
->pipe
->bind_fs_state(filter
->pipe
, field
? filter
->fs_deint_top
: filter
->fs_deint_bottom
);
517 util_draw_arrays(filter
->pipe
, PIPE_PRIM_QUADS
, 0, 4);
520 if (++j
>= util_format_get_nr_components(dst_surf
->format
)) {