Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5564 | serge | 1 | /************************************************************************** |
2 | * |
||
3 | * Copyright 2013 Grigori Goronzy |
||
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 |
||
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 | |||
51 | #include "vl_types.h" |
||
52 | #include "vl_video_buffer.h" |
||
53 | #include "vl_vertex_buffers.h" |
||
54 | #include "vl_deint_filter.h" |
||
55 | |||
56 | enum VS_OUTPUT |
||
57 | { |
||
58 | VS_O_VPOS = 0, |
||
59 | VS_O_VTEX = 0 |
||
60 | }; |
||
61 | |||
62 | static void * |
||
63 | create_vert_shader(struct vl_deint_filter *filter) |
||
64 | { |
||
65 | struct ureg_program *shader; |
||
66 | struct ureg_src i_vpos; |
||
67 | struct ureg_dst o_vpos, o_vtex; |
||
68 | |||
69 | shader = ureg_create(TGSI_PROCESSOR_VERTEX); |
||
70 | if (!shader) |
||
71 | return NULL; |
||
72 | |||
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); |
||
76 | |||
77 | ureg_MOV(shader, o_vpos, i_vpos); |
||
78 | ureg_MOV(shader, o_vtex, i_vpos); |
||
79 | |||
80 | ureg_END(shader); |
||
81 | |||
82 | return ureg_create_shader_and_destroy(shader, filter->pipe); |
||
83 | } |
||
84 | |||
85 | static void * |
||
86 | create_copy_frag_shader(struct vl_deint_filter *filter, unsigned field) |
||
87 | { |
||
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; |
||
93 | |||
94 | shader = ureg_create(TGSI_PROCESSOR_FRAGMENT); |
||
95 | if (!shader) { |
||
96 | return NULL; |
||
97 | } |
||
98 | t_tex = ureg_DECL_temporary(shader); |
||
99 | |||
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); |
||
103 | |||
104 | ureg_MOV(shader, t_tex, i_vtex); |
||
105 | if (field) { |
||
106 | ureg_MOV(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_ZW), |
||
107 | ureg_imm4f(shader, 0, 0, 1.0f, 0)); |
||
108 | } else { |
||
109 | ureg_MOV(shader, ureg_writemask(t_tex, TGSI_WRITEMASK_ZW), |
||
110 | ureg_imm1f(shader, 0)); |
||
111 | } |
||
112 | |||
113 | ureg_TEX(shader, o_fragment, TGSI_TEXTURE_2D_ARRAY, ureg_src(t_tex), sampler); |
||
114 | |||
115 | ureg_release_temporary(shader, t_tex); |
||
116 | ureg_END(shader); |
||
117 | |||
118 | return ureg_create_shader_and_destroy(shader, filter->pipe); |
||
119 | } |
||
120 | |||
121 | static void * |
||
122 | create_deint_frag_shader(struct vl_deint_filter *filter, unsigned field, |
||
123 | struct vertex2f *sizes, bool spatial_filter) |
||
124 | { |
||
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; |
||
137 | |||
138 | shader = ureg_create(TGSI_PROCESSOR_FRAGMENT); |
||
139 | if (!shader) { |
||
140 | return NULL; |
||
141 | } |
||
142 | |||
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); |
||
151 | |||
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); |
||
158 | |||
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)); |
||
163 | |||
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)); |
||
169 | |||
170 | if (field == 0) { |
||
171 | /* interpolating top field -> current field is a bottom field */ |
||
172 | // cur vs prev2 |
||
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)); |
||
176 | // prev vs next |
||
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)); |
||
180 | } else { |
||
181 | /* interpolating bottom field -> current field is a top field */ |
||
182 | // cur vs prev2 |
||
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)); |
||
186 | // prev vs next |
||
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)); |
||
190 | } |
||
191 | |||
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)); |
||
195 | |||
196 | if (field == 0) { |
||
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); |
||
202 | } else { |
||
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); |
||
209 | } |
||
210 | |||
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)); |
||
219 | |||
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); |
||
228 | ureg_END(shader); |
||
229 | |||
230 | return ureg_create_shader_and_destroy(shader, filter->pipe); |
||
231 | } |
||
232 | |||
233 | bool |
||
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) |
||
237 | { |
||
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; |
||
244 | |||
245 | assert(filter && pipe); |
||
246 | assert(video_width && video_height); |
||
247 | |||
248 | memset(filter, 0, sizeof(*filter)); |
||
249 | filter->pipe = pipe; |
||
250 | filter->skip_chroma = skip_chroma; |
||
251 | filter->video_width = video_width; |
||
252 | filter->video_height = video_height; |
||
253 | |||
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; |
||
264 | |||
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) |
||
271 | goto error_rs_state; |
||
272 | |||
273 | memset(&blend, 0, sizeof blend); |
||
274 | blend.rt[0].colormask = PIPE_MASK_RGBA; |
||
275 | filter->blend = pipe->create_blend_state(pipe, &blend); |
||
276 | if (!filter->blend) |
||
277 | goto error_blend; |
||
278 | |||
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]) |
||
290 | goto error_sampler; |
||
291 | |||
292 | filter->quad = vl_vb_upload_quads(pipe); |
||
293 | if(!filter->quad.buffer) |
||
294 | goto error_quad; |
||
295 | |||
296 | memset(&ve, 0, sizeof(ve)); |
||
297 | ve.src_offset = 0; |
||
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); |
||
302 | if (!filter->ves) |
||
303 | goto error_ves; |
||
304 | |||
305 | sizes.x = 1.0f / video_width; |
||
306 | sizes.y = 1.0f / video_height; |
||
307 | |||
308 | filter->vs = create_vert_shader(filter); |
||
309 | if (!filter->vs) |
||
310 | goto error_vs; |
||
311 | |||
312 | filter->fs_copy_top = create_copy_frag_shader(filter, 0); |
||
313 | if (!filter->fs_copy_top) |
||
314 | goto error_fs_copy_top; |
||
315 | |||
316 | filter->fs_copy_bottom = create_copy_frag_shader(filter, 1); |
||
317 | if (!filter->fs_copy_bottom) |
||
318 | goto error_fs_copy_bottom; |
||
319 | |||
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; |
||
323 | |||
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; |
||
327 | |||
328 | return true; |
||
329 | |||
330 | error_fs_deint_bottom: |
||
331 | pipe->delete_fs_state(pipe, filter->fs_deint_top); |
||
332 | |||
333 | error_fs_deint_top: |
||
334 | pipe->delete_fs_state(pipe, filter->fs_copy_bottom); |
||
335 | |||
336 | error_fs_copy_bottom: |
||
337 | pipe->delete_fs_state(pipe, filter->fs_copy_top); |
||
338 | |||
339 | error_fs_copy_top: |
||
340 | pipe->delete_vs_state(pipe, filter->vs); |
||
341 | |||
342 | error_vs: |
||
343 | pipe->delete_vertex_elements_state(pipe, filter->ves); |
||
344 | |||
345 | error_ves: |
||
346 | pipe_resource_reference(&filter->quad.buffer, NULL); |
||
347 | |||
348 | error_quad: |
||
349 | pipe->delete_sampler_state(pipe, filter->sampler); |
||
350 | |||
351 | error_sampler: |
||
352 | pipe->delete_blend_state(pipe, filter->blend); |
||
353 | |||
354 | error_blend: |
||
355 | pipe->delete_rasterizer_state(pipe, filter->rs_state); |
||
356 | |||
357 | error_rs_state: |
||
358 | filter->video_buffer->destroy(filter->video_buffer); |
||
359 | |||
360 | error_video_buffer: |
||
361 | return false; |
||
362 | } |
||
363 | |||
364 | void |
||
365 | vl_deint_filter_cleanup(struct vl_deint_filter *filter) |
||
366 | { |
||
367 | assert(filter); |
||
368 | |||
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); |
||
374 | |||
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); |
||
380 | |||
381 | filter->video_buffer->destroy(filter->video_buffer); |
||
382 | } |
||
383 | |||
384 | bool |
||
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) |
||
390 | { |
||
391 | int i; |
||
392 | struct pipe_video_buffer *bufs[] = { prevprev, prev, cur, next }; |
||
393 | |||
394 | for (i = 0; i < 4; i++) { |
||
395 | if (bufs[i]->chroma_format != PIPE_VIDEO_CHROMA_FORMAT_420) |
||
396 | return false; |
||
397 | if (bufs[i]->width < filter->video_width || |
||
398 | bufs[i]->height < filter->video_height) |
||
399 | return false; |
||
400 | if (!bufs[i]->interlaced) |
||
401 | return false; |
||
402 | } |
||
403 | |||
404 | return true; |
||
405 | } |
||
406 | |||
407 | void |
||
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, |
||
413 | unsigned field) |
||
414 | { |
||
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; |
||
423 | int j; |
||
424 | |||
425 | assert(filter && prevprev && prev && cur && next && field <= 1); |
||
426 | |||
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); |
||
433 | |||
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); |
||
442 | |||
443 | /* prepare viewport */ |
||
444 | memset(&viewport, 0, sizeof(viewport)); |
||
445 | viewport.scale[2] = 1; |
||
446 | |||
447 | /* prepare framebuffer */ |
||
448 | memset(&fb_state, 0, sizeof(fb_state)); |
||
449 | fb_state.nr_cbufs = 1; |
||
450 | |||
451 | /* process each plane separately */ |
||
452 | for (j = 0; j < 3; j++) { |
||
453 | /* select correct YV12 surfaces */ |
||
454 | int k = j == 1 ? 2 : |
||
455 | j == 2 ? 1 : 0; |
||
456 | struct pipe_surface *blit_surf = dst_surfaces[2 * k + field]; |
||
457 | struct pipe_surface *dst_surf = dst_surfaces[2 * k + 1 - field]; |
||
458 | |||
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; |
||
464 | |||
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); |
||
471 | |||
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); |
||
478 | |||
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); |
||
484 | } else { |
||
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); |
||
487 | } |
||
488 | } |
||
489 | }>=>>>>> |