X-Git-Url: https://git.sesse.net/?p=movit;a=blobdiff_plain;f=deinterlace_effect.cpp;h=078983afabdf896e63de9fb5579bf0c8e816983a;hp=8d9a96c344b647cb7c9018b51920779c891e2354;hb=4179bef190d88739038233ac5d7e5ffa2ff4282f;hpb=c72cd5445d110b4519ac6af2f747832e38c3b829 diff --git a/deinterlace_effect.cpp b/deinterlace_effect.cpp index 8d9a96c..078983a 100644 --- a/deinterlace_effect.cpp +++ b/deinterlace_effect.cpp @@ -1,6 +1,8 @@ #include #include "deinterlace_effect.h" +#include "effect_chain.h" +#include "init.h" #include "util.h" using namespace std; @@ -12,13 +14,18 @@ DeinterlaceEffect::DeinterlaceEffect() current_field_position(TOP), num_lines(1080) { - register_int("enable_spatial_interlacing_check", (int *)&enable_spatial_interlacing_check); - register_int("current_field_position", (int *)¤t_field_position); - register_uniform_float("num_lines", &num_lines); - register_uniform_float("inv_width", &inv_width); - register_uniform_float("self_offset", &self_offset); - register_uniform_float_array("current_offset", current_offset, 2); - register_uniform_float_array("other_offset", other_offset, 3); + if (movit_compute_shaders_supported) { + compute_effect_owner.reset(new DeinterlaceComputeEffect); + compute_effect = compute_effect_owner.get(); + } else { + register_int("enable_spatial_interlacing_check", (int *)&enable_spatial_interlacing_check); + register_int("current_field_position", (int *)¤t_field_position); + register_uniform_float("num_lines", &num_lines); + register_uniform_float("inv_width", &inv_width); + register_uniform_float("self_offset", &self_offset); + register_uniform_float_array("current_offset", current_offset, 2); + register_uniform_float_array("other_offset", other_offset, 3); + } } string DeinterlaceEffect::output_fragment_shader() @@ -32,6 +39,25 @@ string DeinterlaceEffect::output_fragment_shader() return frag_shader; } +void DeinterlaceEffect::rewrite_graph(EffectChain *graph, Node *self) +{ + if (compute_effect != nullptr) { + Node *compute_node = graph->add_node(compute_effect_owner.release()); + graph->replace_receiver(self, compute_node); + graph->replace_sender(self, compute_node); + self->disabled = true; + } +} + +bool DeinterlaceEffect::set_int(const std::string &key, int value) +{ + if (compute_effect != nullptr) { + return compute_effect->set_int(key, value); + } else { + return Effect::set_int(key, value); + } +} + void DeinterlaceEffect::inform_input_size(unsigned input_num, unsigned width, unsigned height) { assert(input_num >= 0 && input_num < 5); @@ -125,4 +151,96 @@ void DeinterlaceEffect::set_gl_state(GLuint glsl_program_num, const string &pref other_offset[2] = center_offset + 1.0 / heights[0]; } +// Implementation of DeinterlaceComputeEffect. + +DeinterlaceComputeEffect::DeinterlaceComputeEffect() + : enable_spatial_interlacing_check(true), + current_field_position(TOP) +{ + register_int("enable_spatial_interlacing_check", (int *)&enable_spatial_interlacing_check); + register_int("current_field_position", (int *)¤t_field_position); + register_uniform_float("inv_width", &inv_width); + register_uniform_float("inv_height", &inv_height); + register_uniform_float("current_field_vertical_offset", ¤t_field_vertical_offset); +} + +string DeinterlaceComputeEffect::output_fragment_shader() +{ + char buf[256]; + snprintf(buf, sizeof(buf), "#define YADIF_ENABLE_SPATIAL_INTERLACING_CHECK %d\n", + enable_spatial_interlacing_check); + string frag_shader = buf; + + frag_shader += read_file("deinterlace_effect.comp"); + return frag_shader; +} + +void DeinterlaceComputeEffect::inform_input_size(unsigned input_num, unsigned width, unsigned height) +{ + assert(input_num >= 0 && input_num < 5); + widths[input_num] = width; + heights[input_num] = height; +} + +void DeinterlaceComputeEffect::get_output_size(unsigned *width, unsigned *height, + unsigned *virtual_width, unsigned *virtual_height) const +{ + assert(widths[0] == widths[1]); + assert(widths[1] == widths[2]); + assert(widths[2] == widths[3]); + assert(widths[3] == widths[4]); + assert(heights[0] == heights[1]); + assert(heights[1] == heights[2]); + assert(heights[2] == heights[3]); + assert(heights[3] == heights[4]); + *width = *virtual_width = widths[0]; + *height = *virtual_height = heights[0] * 2; +} + +void DeinterlaceComputeEffect::set_gl_state(GLuint glsl_program_num, const string &prefix, unsigned *sampler_num) +{ + Effect::set_gl_state(glsl_program_num, prefix, sampler_num); + + inv_width = 1.0 / widths[0]; + inv_height = 1.0 / heights[0]; + + // For the compute shader, we need to load a block of pixels. Marking off the + // ones we are supposed to interpolate (looking only at one column): + // + // field_pos==0 field_pos==1 + // + // 6 x ↑ 6 . ↑ + // 6 . | 6 x | + // 5 x | 5 . | + // 5 . | 5 x | + // 4 x | 4 . | + // 4 . | 4 x | + // 3 x | y 3 o | y + // 3 o | 3 x | + // 2 x | 2 o | + // 2 o | 2 x | + // 1 x | 1 . | + // 1 . | 1 x | + // 0 x | 0 . | + // 0 . | 0 x | + // + // So if we are to compute e.g. output samples [2,4), we load input samples + // [1,3] for TFF and samples [2,4] for BFF. + if (current_field_position == 0) { + current_field_vertical_offset = -1.0 / heights[0]; + } else { + current_field_vertical_offset = 0.0 / heights[0]; + } +} + +void DeinterlaceComputeEffect::get_compute_dimensions(unsigned output_width, unsigned output_height, + unsigned *x, unsigned *y, unsigned *z) const +{ + // Each workgroup outputs 8x32 pixels (see GROUP_W and GROUP_H in the shader), + // so figure out the number of groups by simply rounding up. + *x = (output_width + 7) / 8; + *y = (output_height + 31) / 32; + *z = 1; +} + } // namespace movit