3 #include "deinterlace_effect.h"
4 #include "effect_chain.h"
12 DeinterlaceEffect::DeinterlaceEffect()
13 : enable_spatial_interlacing_check(true),
14 current_field_position(TOP),
17 if (movit_compute_shaders_supported) {
18 compute_effect_owner.reset(new DeinterlaceComputeEffect);
19 compute_effect = compute_effect_owner.get();
21 register_int("enable_spatial_interlacing_check", (int *)&enable_spatial_interlacing_check);
22 register_int("current_field_position", (int *)¤t_field_position);
23 register_uniform_float("num_lines", &num_lines);
24 register_uniform_float("inv_width", &inv_width);
25 register_uniform_float("self_offset", &self_offset);
26 register_uniform_float_array("current_offset", current_offset, 2);
27 register_uniform_float_array("other_offset", other_offset, 3);
31 string DeinterlaceEffect::output_fragment_shader()
34 snprintf(buf, sizeof(buf), "#define YADIF_ENABLE_SPATIAL_INTERLACING_CHECK %d\n",
35 enable_spatial_interlacing_check);
36 string frag_shader = buf;
38 frag_shader += read_file("deinterlace_effect.frag");
42 void DeinterlaceEffect::rewrite_graph(EffectChain *graph, Node *self)
44 if (compute_effect != nullptr) {
45 Node *compute_node = graph->add_node(compute_effect_owner.release());
46 graph->replace_receiver(self, compute_node);
47 graph->replace_sender(self, compute_node);
48 self->disabled = true;
52 bool DeinterlaceEffect::set_int(const std::string &key, int value)
54 if (compute_effect != nullptr) {
55 return compute_effect->set_int(key, value);
57 return Effect::set_int(key, value);
61 void DeinterlaceEffect::inform_input_size(unsigned input_num, unsigned width, unsigned height)
63 assert(input_num >= 0 && input_num < 5);
64 widths[input_num] = width;
65 heights[input_num] = height;
66 num_lines = height * 2;
69 void DeinterlaceEffect::get_output_size(unsigned *width, unsigned *height,
70 unsigned *virtual_width, unsigned *virtual_height) const
72 assert(widths[0] == widths[1]);
73 assert(widths[1] == widths[2]);
74 assert(widths[2] == widths[3]);
75 assert(widths[3] == widths[4]);
76 assert(heights[0] == heights[1]);
77 assert(heights[1] == heights[2]);
78 assert(heights[2] == heights[3]);
79 assert(heights[3] == heights[4]);
80 *width = *virtual_width = widths[0];
81 *height = *virtual_height = heights[0] * 2;
84 void DeinterlaceEffect::set_gl_state(GLuint glsl_program_num, const string &prefix, unsigned *sampler_num)
86 Effect::set_gl_state(glsl_program_num, prefix, sampler_num);
88 inv_width = 1.0 / widths[0];
90 // Texel centers: t = output texel center for top field, b = for bottom field,
91 // x = the input texel. (The same area is two pixels for output, one for input;
92 // thus the stippled line in the middle.)
104 // Note as usual OpenGL's bottom-left convention.
105 if (current_field_position == 0) {
107 self_offset = -0.5 / num_lines;
110 assert(current_field_position == 1);
111 self_offset = 0.5 / num_lines;
114 // Having now established where the texels lie for the uninterpolated samples,
115 // we can use that to figure out where to sample for the interpolation. Drawing
116 // the fields as what lines they represent, here for three-pixel high fields
117 // with current_field_position == 0 (plus an “o” to mark the pixel we're trying
118 // to interpolate, and “c” for corresponding texel in the other field):
128 // Obviously, for sampling in the current field, we are one half-texel off
129 // compared to <self_offset>, so sampling in the current field is easy:
130 current_offset[0] = self_offset - 0.5 / heights[0];
131 current_offset[1] = self_offset + 0.5 / heights[0];
133 // Now to find the texel in the other fields corresponding to the pixel
134 // we're trying to interpolate, let's realign the diagram above:
143 // So obviously for this case, we need to center on the same place as
144 // current_offset[1] (the texel directly above the o; note again the
145 // bottom-left convention). For the case of current_field_position == 1,
146 // the shift in the alignment goes the other way, and what we want
147 // is current_offset[0] (the texel directly below the o).
148 float center_offset = current_offset[1 - current_field_position];
149 other_offset[0] = center_offset - 1.0 / heights[0];
150 other_offset[1] = center_offset;
151 other_offset[2] = center_offset + 1.0 / heights[0];
154 // Implementation of DeinterlaceComputeEffect.
156 DeinterlaceComputeEffect::DeinterlaceComputeEffect()
157 : enable_spatial_interlacing_check(true),
158 current_field_position(TOP)
160 register_int("enable_spatial_interlacing_check", (int *)&enable_spatial_interlacing_check);
161 register_int("current_field_position", (int *)¤t_field_position);
162 register_uniform_float("inv_width", &inv_width);
163 register_uniform_float("inv_height", &inv_height);
164 register_uniform_float("current_field_vertical_offset", ¤t_field_vertical_offset);
167 string DeinterlaceComputeEffect::output_fragment_shader()
170 snprintf(buf, sizeof(buf), "#define YADIF_ENABLE_SPATIAL_INTERLACING_CHECK %d\n",
171 enable_spatial_interlacing_check);
172 string frag_shader = buf;
174 frag_shader += read_file("deinterlace_effect.comp");
178 void DeinterlaceComputeEffect::inform_input_size(unsigned input_num, unsigned width, unsigned height)
180 assert(input_num >= 0 && input_num < 5);
181 widths[input_num] = width;
182 heights[input_num] = height;
185 void DeinterlaceComputeEffect::get_output_size(unsigned *width, unsigned *height,
186 unsigned *virtual_width, unsigned *virtual_height) const
188 assert(widths[0] == widths[1]);
189 assert(widths[1] == widths[2]);
190 assert(widths[2] == widths[3]);
191 assert(widths[3] == widths[4]);
192 assert(heights[0] == heights[1]);
193 assert(heights[1] == heights[2]);
194 assert(heights[2] == heights[3]);
195 assert(heights[3] == heights[4]);
196 *width = *virtual_width = widths[0];
197 *height = *virtual_height = heights[0] * 2;
200 void DeinterlaceComputeEffect::set_gl_state(GLuint glsl_program_num, const string &prefix, unsigned *sampler_num)
202 Effect::set_gl_state(glsl_program_num, prefix, sampler_num);
204 inv_width = 1.0 / widths[0];
205 inv_height = 1.0 / heights[0];
207 // For the compute shader, we need to load a block of pixels. Marking off the
208 // ones we are supposed to interpolate (looking only at one column):
210 // field_pos==0 field_pos==1
227 // So if we are to compute e.g. output samples [2,4), we load input samples
228 // [1,3] for TFF and samples [2,4] for BFF.
229 if (current_field_position == 0) {
230 current_field_vertical_offset = -1.0 / heights[0];
232 current_field_vertical_offset = 0.0 / heights[0];
236 void DeinterlaceComputeEffect::get_compute_dimensions(unsigned output_width, unsigned output_height,
237 unsigned *x, unsigned *y, unsigned *z) const
239 // Each workgroup outputs 8x32 pixels (see GROUP_W and GROUP_H in the shader),
240 // so figure out the number of groups by simply rounding up.
241 *x = (output_width + 7) / 8;
242 *y = (output_height + 31) / 32;