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"
52 #include "vl_video_buffer.h"
53 #include "vl_vertex_buffers.h"
54 #include "vl_deint_filter.h"
63 create_vert_shader(struct vl_deint_filter
*filter
)
65 struct ureg_program
*shader
;
66 struct ureg_src i_vpos
;
67 struct ureg_dst o_vpos
, o_vtex
;
69 shader
= ureg_create(TGSI_PROCESSOR_VERTEX
);
73 i_vpos
= ureg_DECL_vs_input(shader
, 0);
74 o_vpos
= ureg_DECL_output(shader
, TGSI_SEMANTIC_POSITION
, VS_O_VPOS
);
75 o_vtex
= ureg_DECL_output(shader
, TGSI_SEMANTIC_GENERIC
, VS_O_VTEX
);
77 ureg_MOV(shader
, o_vpos
, i_vpos
);
78 ureg_MOV(shader
, o_vtex
, i_vpos
);
82 return ureg_create_shader_and_destroy(shader
, filter
->pipe
);
86 create_copy_frag_shader(struct vl_deint_filter
*filter
, unsigned field
)
88 struct ureg_program
*shader
;
89 struct ureg_src i_vtex
;
90 struct ureg_src sampler
;
91 struct ureg_dst o_fragment
;
92 struct ureg_dst t_tex
;
94 shader
= ureg_create(TGSI_PROCESSOR_FRAGMENT
);
98 t_tex
= ureg_DECL_temporary(shader
);
100 i_vtex
= ureg_DECL_fs_input(shader
, TGSI_SEMANTIC_GENERIC
, VS_O_VTEX
, TGSI_INTERPOLATE_LINEAR
);
101 sampler
= ureg_DECL_sampler(shader
, 2);
102 o_fragment
= ureg_DECL_output(shader
, TGSI_SEMANTIC_COLOR
, 0);
104 ureg_MOV(shader
, t_tex
, i_vtex
);
106 ureg_MOV(shader
, ureg_writemask(t_tex
, TGSI_WRITEMASK_ZW
),
107 ureg_imm4f(shader
, 0, 0, 1.0f
, 0));
109 ureg_MOV(shader
, ureg_writemask(t_tex
, TGSI_WRITEMASK_ZW
),
110 ureg_imm1f(shader
, 0));
113 ureg_TEX(shader
, o_fragment
, TGSI_TEXTURE_2D_ARRAY
, ureg_src(t_tex
), sampler
);
115 ureg_release_temporary(shader
, t_tex
);
118 return ureg_create_shader_and_destroy(shader
, filter
->pipe
);
122 create_deint_frag_shader(struct vl_deint_filter
*filter
, unsigned field
,
123 struct vertex2f
*sizes
, bool spatial_filter
)
125 struct ureg_program
*shader
;
126 struct ureg_src i_vtex
;
127 struct ureg_src sampler_cur
;
128 struct ureg_src sampler_prevprev
;
129 struct ureg_src sampler_prev
;
130 struct ureg_src sampler_next
;
131 struct ureg_dst o_fragment
;
132 struct ureg_dst t_tex
;
133 struct ureg_dst t_comp_top
, t_comp_bot
;
134 struct ureg_dst t_diff
;
135 struct ureg_dst t_a
, t_b
;
136 struct ureg_dst t_weave
, t_linear
;
138 shader
= ureg_create(TGSI_PROCESSOR_FRAGMENT
);
143 t_tex
= ureg_DECL_temporary(shader
);
144 t_comp_top
= ureg_DECL_temporary(shader
);
145 t_comp_bot
= ureg_DECL_temporary(shader
);
146 t_diff
= ureg_DECL_temporary(shader
);
147 t_a
= ureg_DECL_temporary(shader
);
148 t_b
= ureg_DECL_temporary(shader
);
149 t_weave
= ureg_DECL_temporary(shader
);
150 t_linear
= ureg_DECL_temporary(shader
);
152 i_vtex
= ureg_DECL_fs_input(shader
, TGSI_SEMANTIC_GENERIC
, VS_O_VTEX
, TGSI_INTERPOLATE_LINEAR
);
153 sampler_prevprev
= ureg_DECL_sampler(shader
, 0);
154 sampler_prev
= ureg_DECL_sampler(shader
, 1);
155 sampler_cur
= ureg_DECL_sampler(shader
, 2);
156 sampler_next
= ureg_DECL_sampler(shader
, 3);
157 o_fragment
= ureg_DECL_output(shader
, TGSI_SEMANTIC_COLOR
, 0);
159 // we don't care about ZW interpolation (allows better optimization)
160 ureg_MOV(shader
, t_tex
, i_vtex
);
161 ureg_MOV(shader
, ureg_writemask(t_tex
, TGSI_WRITEMASK_ZW
),
162 ureg_imm1f(shader
, 0));
164 // sample between texels for cheap lowpass
165 ureg_ADD(shader
, t_comp_top
, ureg_src(t_tex
),
166 ureg_imm4f(shader
, sizes
->x
* 0.5f
, sizes
->y
* -0.5f
, 0, 0));
167 ureg_ADD(shader
, t_comp_bot
, ureg_src(t_tex
),
168 ureg_imm4f(shader
, sizes
->x
* -0.5f
, sizes
->y
* 0.5f
, 1.0f
, 0));
171 /* interpolating top field -> current field is a bottom field */
173 ureg_TEX(shader
, t_a
, TGSI_TEXTURE_2D_ARRAY
, ureg_src(t_comp_bot
), sampler_cur
);
174 ureg_TEX(shader
, t_b
, TGSI_TEXTURE_2D_ARRAY
, ureg_src(t_comp_bot
), sampler_prevprev
);
175 ureg_SUB(shader
, ureg_writemask(t_diff
, TGSI_WRITEMASK_X
), ureg_src(t_a
), ureg_src(t_b
));
177 ureg_TEX(shader
, t_a
, TGSI_TEXTURE_2D_ARRAY
, ureg_src(t_comp_top
), sampler_prev
);
178 ureg_TEX(shader
, t_b
, TGSI_TEXTURE_2D_ARRAY
, ureg_src(t_comp_top
), sampler_next
);
179 ureg_SUB(shader
, ureg_writemask(t_diff
, TGSI_WRITEMASK_Y
), ureg_src(t_a
), ureg_src(t_b
));
181 /* interpolating bottom field -> current field is a top field */
183 ureg_TEX(shader
, t_a
, TGSI_TEXTURE_2D_ARRAY
, ureg_src(t_comp_top
), sampler_cur
);
184 ureg_TEX(shader
, t_b
, TGSI_TEXTURE_2D_ARRAY
, ureg_src(t_comp_top
), sampler_prevprev
);
185 ureg_SUB(shader
, ureg_writemask(t_diff
, TGSI_WRITEMASK_X
), ureg_src(t_a
), ureg_src(t_b
));
187 ureg_TEX(shader
, t_a
, TGSI_TEXTURE_2D_ARRAY
, ureg_src(t_comp_bot
), sampler_prev
);
188 ureg_TEX(shader
, t_b
, TGSI_TEXTURE_2D_ARRAY
, ureg_src(t_comp_bot
), sampler_next
);
189 ureg_SUB(shader
, ureg_writemask(t_diff
, TGSI_WRITEMASK_Y
), ureg_src(t_a
), ureg_src(t_b
));
192 // absolute maximum of differences
193 ureg_MAX(shader
, ureg_writemask(t_diff
, TGSI_WRITEMASK_X
), ureg_abs(ureg_src(t_diff
)),
194 ureg_scalar(ureg_abs(ureg_src(t_diff
)), TGSI_SWIZZLE_Y
));
197 /* weave with prev top field */
198 ureg_TEX(shader
, t_weave
, TGSI_TEXTURE_2D_ARRAY
, ureg_src(t_tex
), sampler_prev
);
199 /* get linear interpolation from current bottom field */
200 ureg_ADD(shader
, t_comp_top
, ureg_src(t_tex
), ureg_imm4f(shader
, 0, sizes
->y
* -1.0f
, 1.0f
, 0));
201 ureg_TEX(shader
, t_linear
, TGSI_TEXTURE_2D_ARRAY
, ureg_src(t_comp_top
), sampler_cur
);
203 /* weave with prev bottom field */
204 ureg_ADD(shader
, t_comp_bot
, ureg_src(t_tex
), ureg_imm4f(shader
, 0, 0, 1.0f
, 0));
205 ureg_TEX(shader
, t_weave
, TGSI_TEXTURE_2D_ARRAY
, ureg_src(t_comp_bot
), sampler_prev
);
206 /* get linear interpolation from current top field */
207 ureg_ADD(shader
, t_comp_bot
, ureg_src(t_tex
), ureg_imm4f(shader
, 0, sizes
->y
* 1.0f
, 0, 0));
208 ureg_TEX(shader
, t_linear
, TGSI_TEXTURE_2D_ARRAY
, ureg_src(t_comp_bot
), sampler_cur
);
211 // mix between weave and linear
212 // fully weave if diff < 6 (0.02353), fully interpolate if diff > 14 (0.05490)
213 ureg_ADD(shader
, ureg_writemask(t_diff
, TGSI_WRITEMASK_X
), ureg_src(t_diff
),
214 ureg_imm4f(shader
, -0.02353f
, 0, 0, 0));
215 ureg_MUL(shader
, ureg_saturate(ureg_writemask(t_diff
, TGSI_WRITEMASK_X
)),
216 ureg_src(t_diff
), ureg_imm4f(shader
, 31.8750f
, 0, 0, 0));
217 ureg_LRP(shader
, ureg_writemask(o_fragment
, TGSI_WRITEMASK_X
), ureg_src(t_diff
),
218 ureg_src(t_linear
), ureg_src(t_weave
));
220 ureg_release_temporary(shader
, t_tex
);
221 ureg_release_temporary(shader
, t_comp_top
);
222 ureg_release_temporary(shader
, t_comp_bot
);
223 ureg_release_temporary(shader
, t_diff
);
224 ureg_release_temporary(shader
, t_a
);
225 ureg_release_temporary(shader
, t_b
);
226 ureg_release_temporary(shader
, t_weave
);
227 ureg_release_temporary(shader
, t_linear
);
230 return ureg_create_shader_and_destroy(shader
, filter
->pipe
);
234 vl_deint_filter_init(struct vl_deint_filter
*filter
, struct pipe_context
*pipe
,
235 unsigned video_width
, unsigned video_height
,
236 bool skip_chroma
, bool spatial_filter
)
238 struct pipe_rasterizer_state rs_state
;
239 struct pipe_blend_state blend
;
240 struct pipe_sampler_state sampler
;
241 struct pipe_vertex_element ve
;
242 struct vertex2f sizes
;
243 struct pipe_video_buffer templ
;
245 assert(filter
&& pipe
);
246 assert(video_width
&& video_height
);
248 memset(filter
, 0, sizeof(*filter
));
250 filter
->skip_chroma
= skip_chroma
;
251 filter
->video_width
= video_width
;
252 filter
->video_height
= video_height
;
254 /* TODO: handle other than 4:2:0 subsampling */
255 memset(&templ
, 0, sizeof(templ
));
256 templ
.buffer_format
= PIPE_FORMAT_YV12
;
257 templ
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
258 templ
.width
= video_width
;
259 templ
.height
= video_height
;
260 templ
.interlaced
= true;
261 filter
->video_buffer
= vl_video_buffer_create(pipe
, &templ
);
262 if (!filter
->video_buffer
)
263 goto error_video_buffer
;
265 memset(&rs_state
, 0, sizeof(rs_state
));
266 rs_state
.half_pixel_center
= true;
267 rs_state
.bottom_edge_rule
= true;
268 rs_state
.depth_clip
= 1;
269 filter
->rs_state
= pipe
->create_rasterizer_state(pipe
, &rs_state
);
270 if (!filter
->rs_state
)
273 memset(&blend
, 0, sizeof blend
);
274 blend
.rt
[0].colormask
= PIPE_MASK_RGBA
;
275 filter
->blend
= pipe
->create_blend_state(pipe
, &blend
);
279 memset(&sampler
, 0, sizeof(sampler
));
280 sampler
.wrap_s
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
281 sampler
.wrap_t
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
282 sampler
.wrap_r
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
283 sampler
.min_img_filter
= PIPE_TEX_FILTER_LINEAR
;
284 sampler
.min_mip_filter
= PIPE_TEX_MIPFILTER_NONE
;
285 sampler
.mag_img_filter
= PIPE_TEX_FILTER_LINEAR
;
286 sampler
.normalized_coords
= 1;
287 filter
->sampler
[0] = pipe
->create_sampler_state(pipe
, &sampler
);
288 filter
->sampler
[1] = filter
->sampler
[2] = filter
->sampler
[3] = filter
->sampler
[0];
289 if (!filter
->sampler
[0])
292 filter
->quad
= vl_vb_upload_quads(pipe
);
293 if(!filter
->quad
.buffer
)
296 memset(&ve
, 0, sizeof(ve
));
298 ve
.instance_divisor
= 0;
299 ve
.vertex_buffer_index
= 0;
300 ve
.src_format
= PIPE_FORMAT_R32G32_FLOAT
;
301 filter
->ves
= pipe
->create_vertex_elements_state(pipe
, 1, &ve
);
305 sizes
.x
= 1.0f
/ video_width
;
306 sizes
.y
= 1.0f
/ video_height
;
308 filter
->vs
= create_vert_shader(filter
);
312 filter
->fs_copy_top
= create_copy_frag_shader(filter
, 0);
313 if (!filter
->fs_copy_top
)
314 goto error_fs_copy_top
;
316 filter
->fs_copy_bottom
= create_copy_frag_shader(filter
, 1);
317 if (!filter
->fs_copy_bottom
)
318 goto error_fs_copy_bottom
;
320 filter
->fs_deint_top
= create_deint_frag_shader(filter
, 0, &sizes
, spatial_filter
);
321 if (!filter
->fs_deint_top
)
322 goto error_fs_deint_top
;
324 filter
->fs_deint_bottom
= create_deint_frag_shader(filter
, 1, &sizes
, spatial_filter
);
325 if (!filter
->fs_deint_bottom
)
326 goto error_fs_deint_bottom
;
330 error_fs_deint_bottom
:
331 pipe
->delete_fs_state(pipe
, filter
->fs_deint_top
);
334 pipe
->delete_fs_state(pipe
, filter
->fs_copy_bottom
);
336 error_fs_copy_bottom
:
337 pipe
->delete_fs_state(pipe
, filter
->fs_copy_top
);
340 pipe
->delete_vs_state(pipe
, filter
->vs
);
343 pipe
->delete_vertex_elements_state(pipe
, filter
->ves
);
346 pipe_resource_reference(&filter
->quad
.buffer
, NULL
);
349 pipe
->delete_sampler_state(pipe
, filter
->sampler
);
352 pipe
->delete_blend_state(pipe
, filter
->blend
);
355 pipe
->delete_rasterizer_state(pipe
, filter
->rs_state
);
358 filter
->video_buffer
->destroy(filter
->video_buffer
);
365 vl_deint_filter_cleanup(struct vl_deint_filter
*filter
)
369 filter
->pipe
->delete_sampler_state(filter
->pipe
, filter
->sampler
[0]);
370 filter
->pipe
->delete_blend_state(filter
->pipe
, filter
->blend
);
371 filter
->pipe
->delete_rasterizer_state(filter
->pipe
, filter
->rs_state
);
372 filter
->pipe
->delete_vertex_elements_state(filter
->pipe
, filter
->ves
);
373 pipe_resource_reference(&filter
->quad
.buffer
, NULL
);
375 filter
->pipe
->delete_vs_state(filter
->pipe
, filter
->vs
);
376 filter
->pipe
->delete_fs_state(filter
->pipe
, filter
->fs_copy_top
);
377 filter
->pipe
->delete_fs_state(filter
->pipe
, filter
->fs_copy_bottom
);
378 filter
->pipe
->delete_fs_state(filter
->pipe
, filter
->fs_deint_top
);
379 filter
->pipe
->delete_fs_state(filter
->pipe
, filter
->fs_deint_bottom
);
381 filter
->video_buffer
->destroy(filter
->video_buffer
);
385 vl_deint_filter_check_buffers(struct vl_deint_filter
*filter
,
386 struct pipe_video_buffer
*prevprev
,
387 struct pipe_video_buffer
*prev
,
388 struct pipe_video_buffer
*cur
,
389 struct pipe_video_buffer
*next
)
392 struct pipe_video_buffer
*bufs
[] = { prevprev
, prev
, cur
, next
};
394 for (i
= 0; i
< 4; i
++) {
395 if (bufs
[i
]->chroma_format
!= PIPE_VIDEO_CHROMA_FORMAT_420
)
397 if (bufs
[i
]->width
< filter
->video_width
||
398 bufs
[i
]->height
< filter
->video_height
)
400 if (!bufs
[i
]->interlaced
)
408 vl_deint_filter_render(struct vl_deint_filter
*filter
,
409 struct pipe_video_buffer
*prevprev
,
410 struct pipe_video_buffer
*prev
,
411 struct pipe_video_buffer
*cur
,
412 struct pipe_video_buffer
*next
,
415 struct pipe_viewport_state viewport
;
416 struct pipe_framebuffer_state fb_state
;
417 struct pipe_sampler_view
**cur_sv
;
418 struct pipe_sampler_view
**prevprev_sv
;
419 struct pipe_sampler_view
**prev_sv
;
420 struct pipe_sampler_view
**next_sv
;
421 struct pipe_sampler_view
*sampler_views
[4];
422 struct pipe_surface
**dst_surfaces
;
425 assert(filter
&& prevprev
&& prev
&& cur
&& next
&& field
<= 1);
427 /* set up destination and source */
428 dst_surfaces
= filter
->video_buffer
->get_surfaces(filter
->video_buffer
);
429 cur_sv
= cur
->get_sampler_view_components(cur
);
430 prevprev_sv
= prevprev
->get_sampler_view_components(prevprev
);
431 prev_sv
= prev
->get_sampler_view_components(prev
);
432 next_sv
= next
->get_sampler_view_components(next
);
434 /* set up pipe state */
435 filter
->pipe
->bind_rasterizer_state(filter
->pipe
, filter
->rs_state
);
436 filter
->pipe
->bind_blend_state(filter
->pipe
, filter
->blend
);
437 filter
->pipe
->set_vertex_buffers(filter
->pipe
, 0, 1, &filter
->quad
);
438 filter
->pipe
->bind_vertex_elements_state(filter
->pipe
, filter
->ves
);
439 filter
->pipe
->bind_vs_state(filter
->pipe
, filter
->vs
);
440 filter
->pipe
->bind_sampler_states(filter
->pipe
, PIPE_SHADER_FRAGMENT
,
441 0, 4, filter
->sampler
);
443 /* prepare viewport */
444 memset(&viewport
, 0, sizeof(viewport
));
445 viewport
.scale
[2] = 1;
447 /* prepare framebuffer */
448 memset(&fb_state
, 0, sizeof(fb_state
));
449 fb_state
.nr_cbufs
= 1;
451 /* process each plane separately */
452 for (j
= 0; j
< 3; j
++) {
453 /* select correct YV12 surfaces */
456 struct pipe_surface
*blit_surf
= dst_surfaces
[2 * k
+ field
];
457 struct pipe_surface
*dst_surf
= dst_surfaces
[2 * k
+ 1 - field
];
459 /* update render target state */
460 viewport
.scale
[0] = blit_surf
->texture
->width0
;
461 viewport
.scale
[1] = blit_surf
->texture
->height0
;
462 fb_state
.width
= blit_surf
->texture
->width0
;
463 fb_state
.height
= blit_surf
->texture
->height0
;
465 /* update sampler view sources */
466 sampler_views
[0] = prevprev_sv
[j
];
467 sampler_views
[1] = prev_sv
[j
];
468 sampler_views
[2] = cur_sv
[j
];
469 sampler_views
[3] = next_sv
[j
];
470 filter
->pipe
->set_sampler_views(filter
->pipe
, PIPE_SHADER_FRAGMENT
, 0, 4, sampler_views
);
472 /* blit current field */
473 fb_state
.cbufs
[0] = blit_surf
;
474 filter
->pipe
->bind_fs_state(filter
->pipe
, field
? filter
->fs_copy_bottom
: filter
->fs_copy_top
);
475 filter
->pipe
->set_framebuffer_state(filter
->pipe
, &fb_state
);
476 filter
->pipe
->set_viewport_states(filter
->pipe
, 0, 1, &viewport
);
477 util_draw_arrays(filter
->pipe
, PIPE_PRIM_QUADS
, 0, 4);
479 /* blit or interpolate other field */
480 fb_state
.cbufs
[0] = dst_surf
;
481 filter
->pipe
->set_framebuffer_state(filter
->pipe
, &fb_state
);
482 if (j
> 0 && filter
->skip_chroma
) {
483 util_draw_arrays(filter
->pipe
, PIPE_PRIM_QUADS
, 0, 4);
485 filter
->pipe
->bind_fs_state(filter
->pipe
, field
? filter
->fs_deint_top
: filter
->fs_deint_bottom
);
486 util_draw_arrays(filter
->pipe
, PIPE_PRIM_QUADS
, 0, 4);