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/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(TGSI_PROCESSOR_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(TGSI_PROCESSOR_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(TGSI_PROCESSOR_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_SUB(shader
, ureg_writemask(t_diff
, TGSI_WRITEMASK_X
), ureg_src(t_a
), 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_SUB(shader
, ureg_writemask(t_diff
, TGSI_WRITEMASK_Y
), ureg_src(t_a
), 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_SUB(shader
, ureg_writemask(t_diff
, TGSI_WRITEMASK_X
), ureg_src(t_a
), 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_SUB(shader
, ureg_writemask(t_diff
, TGSI_WRITEMASK_Y
), ureg_src(t_a
), 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_FORMAT_YV12
;
259 templ
.chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
260 templ
.width
= video_width
;
261 templ
.height
= video_height
;
262 templ
.interlaced
= true;
263 filter
->video_buffer
= vl_video_buffer_create(pipe
, &templ
);
264 if (!filter
->video_buffer
)
265 goto error_video_buffer
;
267 memset(&rs_state
, 0, sizeof(rs_state
));
268 rs_state
.half_pixel_center
= true;
269 rs_state
.bottom_edge_rule
= true;
270 rs_state
.depth_clip
= 1;
271 filter
->rs_state
= pipe
->create_rasterizer_state(pipe
, &rs_state
);
272 if (!filter
->rs_state
)
275 memset(&blend
, 0, sizeof blend
);
276 blend
.rt
[0].colormask
= PIPE_MASK_R
;
277 filter
->blend
[0] = pipe
->create_blend_state(pipe
, &blend
);
278 if (!filter
->blend
[0])
281 blend
.rt
[0].colormask
= PIPE_MASK_G
;
282 filter
->blend
[1] = pipe
->create_blend_state(pipe
, &blend
);
283 if (!filter
->blend
[1])
286 blend
.rt
[0].colormask
= PIPE_MASK_B
;
287 filter
->blend
[2] = pipe
->create_blend_state(pipe
, &blend
);
288 if (!filter
->blend
[2])
291 memset(&sampler
, 0, sizeof(sampler
));
292 sampler
.wrap_s
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
293 sampler
.wrap_t
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
294 sampler
.wrap_r
= PIPE_TEX_WRAP_CLAMP_TO_EDGE
;
295 sampler
.min_img_filter
= PIPE_TEX_FILTER_LINEAR
;
296 sampler
.min_mip_filter
= PIPE_TEX_MIPFILTER_NONE
;
297 sampler
.mag_img_filter
= PIPE_TEX_FILTER_LINEAR
;
298 sampler
.normalized_coords
= 1;
299 filter
->sampler
[0] = pipe
->create_sampler_state(pipe
, &sampler
);
300 filter
->sampler
[1] = filter
->sampler
[2] = filter
->sampler
[3] = filter
->sampler
[0];
301 if (!filter
->sampler
[0])
304 filter
->quad
= vl_vb_upload_quads(pipe
);
305 if(!filter
->quad
.buffer
)
308 memset(&ve
, 0, sizeof(ve
));
310 ve
.instance_divisor
= 0;
311 ve
.vertex_buffer_index
= 0;
312 ve
.src_format
= PIPE_FORMAT_R32G32_FLOAT
;
313 filter
->ves
= pipe
->create_vertex_elements_state(pipe
, 1, &ve
);
317 sizes
.x
= 1.0f
/ video_width
;
318 sizes
.y
= 1.0f
/ video_height
;
320 filter
->vs
= create_vert_shader(filter
);
324 filter
->fs_copy_top
= create_copy_frag_shader(filter
, 0);
325 if (!filter
->fs_copy_top
)
326 goto error_fs_copy_top
;
328 filter
->fs_copy_bottom
= create_copy_frag_shader(filter
, 1);
329 if (!filter
->fs_copy_bottom
)
330 goto error_fs_copy_bottom
;
332 filter
->fs_deint_top
= create_deint_frag_shader(filter
, 0, &sizes
, spatial_filter
);
333 if (!filter
->fs_deint_top
)
334 goto error_fs_deint_top
;
336 filter
->fs_deint_bottom
= create_deint_frag_shader(filter
, 1, &sizes
, spatial_filter
);
337 if (!filter
->fs_deint_bottom
)
338 goto error_fs_deint_bottom
;
342 error_fs_deint_bottom
:
343 pipe
->delete_fs_state(pipe
, filter
->fs_deint_top
);
346 pipe
->delete_fs_state(pipe
, filter
->fs_copy_bottom
);
348 error_fs_copy_bottom
:
349 pipe
->delete_fs_state(pipe
, filter
->fs_copy_top
);
352 pipe
->delete_vs_state(pipe
, filter
->vs
);
355 pipe
->delete_vertex_elements_state(pipe
, filter
->ves
);
358 pipe_resource_reference(&filter
->quad
.buffer
, NULL
);
361 pipe
->delete_sampler_state(pipe
, filter
->sampler
);
364 pipe
->delete_blend_state(pipe
, filter
->blend
[2]);
367 pipe
->delete_blend_state(pipe
, filter
->blend
[1]);
370 pipe
->delete_blend_state(pipe
, filter
->blend
[0]);
373 pipe
->delete_rasterizer_state(pipe
, filter
->rs_state
);
376 filter
->video_buffer
->destroy(filter
->video_buffer
);
383 vl_deint_filter_cleanup(struct vl_deint_filter
*filter
)
387 filter
->pipe
->delete_sampler_state(filter
->pipe
, filter
->sampler
[0]);
388 filter
->pipe
->delete_blend_state(filter
->pipe
, filter
->blend
[0]);
389 filter
->pipe
->delete_blend_state(filter
->pipe
, filter
->blend
[1]);
390 filter
->pipe
->delete_blend_state(filter
->pipe
, filter
->blend
[2]);
391 filter
->pipe
->delete_rasterizer_state(filter
->pipe
, filter
->rs_state
);
392 filter
->pipe
->delete_vertex_elements_state(filter
->pipe
, filter
->ves
);
393 pipe_resource_reference(&filter
->quad
.buffer
, NULL
);
395 filter
->pipe
->delete_vs_state(filter
->pipe
, filter
->vs
);
396 filter
->pipe
->delete_fs_state(filter
->pipe
, filter
->fs_copy_top
);
397 filter
->pipe
->delete_fs_state(filter
->pipe
, filter
->fs_copy_bottom
);
398 filter
->pipe
->delete_fs_state(filter
->pipe
, filter
->fs_deint_top
);
399 filter
->pipe
->delete_fs_state(filter
->pipe
, filter
->fs_deint_bottom
);
401 filter
->video_buffer
->destroy(filter
->video_buffer
);
405 vl_deint_filter_check_buffers(struct vl_deint_filter
*filter
,
406 struct pipe_video_buffer
*prevprev
,
407 struct pipe_video_buffer
*prev
,
408 struct pipe_video_buffer
*cur
,
409 struct pipe_video_buffer
*next
)
412 struct pipe_video_buffer
*bufs
[] = { prevprev
, prev
, cur
, next
};
414 for (i
= 0; i
< 4; i
++) {
415 if (bufs
[i
]->chroma_format
!= PIPE_VIDEO_CHROMA_FORMAT_420
)
417 if (bufs
[i
]->width
< filter
->video_width
||
418 bufs
[i
]->height
< filter
->video_height
)
420 if (!bufs
[i
]->interlaced
)
428 vl_deint_filter_render(struct vl_deint_filter
*filter
,
429 struct pipe_video_buffer
*prevprev
,
430 struct pipe_video_buffer
*prev
,
431 struct pipe_video_buffer
*cur
,
432 struct pipe_video_buffer
*next
,
435 struct pipe_viewport_state viewport
;
436 struct pipe_framebuffer_state fb_state
;
437 struct pipe_sampler_view
**cur_sv
;
438 struct pipe_sampler_view
**prevprev_sv
;
439 struct pipe_sampler_view
**prev_sv
;
440 struct pipe_sampler_view
**next_sv
;
441 struct pipe_sampler_view
*sampler_views
[4];
442 struct pipe_surface
**dst_surfaces
;
443 const unsigned *plane_order
;
446 assert(filter
&& prevprev
&& prev
&& cur
&& next
&& field
<= 1);
448 /* set up destination and source */
449 dst_surfaces
= filter
->video_buffer
->get_surfaces(filter
->video_buffer
);
450 plane_order
= vl_video_buffer_plane_order(filter
->video_buffer
->buffer_format
);
451 cur_sv
= cur
->get_sampler_view_components(cur
);
452 prevprev_sv
= prevprev
->get_sampler_view_components(prevprev
);
453 prev_sv
= prev
->get_sampler_view_components(prev
);
454 next_sv
= next
->get_sampler_view_components(next
);
456 /* set up pipe state */
457 filter
->pipe
->bind_rasterizer_state(filter
->pipe
, filter
->rs_state
);
458 filter
->pipe
->set_vertex_buffers(filter
->pipe
, 0, 1, &filter
->quad
);
459 filter
->pipe
->bind_vertex_elements_state(filter
->pipe
, filter
->ves
);
460 filter
->pipe
->bind_vs_state(filter
->pipe
, filter
->vs
);
461 filter
->pipe
->bind_sampler_states(filter
->pipe
, PIPE_SHADER_FRAGMENT
,
462 0, 4, filter
->sampler
);
464 /* prepare viewport */
465 memset(&viewport
, 0, sizeof(viewport
));
466 viewport
.scale
[2] = 1;
468 /* prepare framebuffer */
469 memset(&fb_state
, 0, sizeof(fb_state
));
470 fb_state
.nr_cbufs
= 1;
472 /* process each plane separately */
473 for (i
= 0, j
= 0; i
< VL_NUM_COMPONENTS
; ++i
) {
474 struct pipe_surface
*blit_surf
= dst_surfaces
[field
];
475 struct pipe_surface
*dst_surf
= dst_surfaces
[1 - field
];
476 int k
= plane_order
[i
];
478 /* bind blend state for this component in the plane */
479 filter
->pipe
->bind_blend_state(filter
->pipe
, filter
->blend
[j
]);
481 /* update render target state */
482 viewport
.scale
[0] = blit_surf
->texture
->width0
;
483 viewport
.scale
[1] = blit_surf
->texture
->height0
;
484 fb_state
.width
= blit_surf
->texture
->width0
;
485 fb_state
.height
= blit_surf
->texture
->height0
;
487 /* update sampler view sources */
488 sampler_views
[0] = prevprev_sv
[k
];
489 sampler_views
[1] = prev_sv
[k
];
490 sampler_views
[2] = cur_sv
[k
];
491 sampler_views
[3] = next_sv
[k
];
492 filter
->pipe
->set_sampler_views(filter
->pipe
, PIPE_SHADER_FRAGMENT
, 0, 4, sampler_views
);
494 /* blit current field */
495 fb_state
.cbufs
[0] = blit_surf
;
496 filter
->pipe
->bind_fs_state(filter
->pipe
, field
? filter
->fs_copy_bottom
: filter
->fs_copy_top
);
497 filter
->pipe
->set_framebuffer_state(filter
->pipe
, &fb_state
);
498 filter
->pipe
->set_viewport_states(filter
->pipe
, 0, 1, &viewport
);
499 util_draw_arrays(filter
->pipe
, PIPE_PRIM_QUADS
, 0, 4);
501 /* blit or interpolate other field */
502 fb_state
.cbufs
[0] = dst_surf
;
503 filter
->pipe
->set_framebuffer_state(filter
->pipe
, &fb_state
);
504 if (i
> 0 && filter
->skip_chroma
) {
505 util_draw_arrays(filter
->pipe
, PIPE_PRIM_QUADS
, 0, 4);
507 filter
->pipe
->bind_fs_state(filter
->pipe
, field
? filter
->fs_deint_top
: filter
->fs_deint_bottom
);
508 util_draw_arrays(filter
->pipe
, PIPE_PRIM_QUADS
, 0, 4);
511 if (++j
>= util_format_get_nr_components(dst_surf
->format
)) {