X-Git-Url: https://git.sesse.net/?p=movit;a=blobdiff_plain;f=effect_chain.cpp;h=13f46344af85a07fb79376afa01a3d45e305b88d;hp=b1dea4b9391b62375919e2bbfa6401668769014a;hb=9dcbd93164611ea111cc29519c18193d4f571ac1;hpb=5aae6761385e1d64cb21b8c902f6b47b4f22690a diff --git a/effect_chain.cpp b/effect_chain.cpp index b1dea4b..13f4634 100644 --- a/effect_chain.cpp +++ b/effect_chain.cpp @@ -16,16 +16,7 @@ #include "effect_chain.h" #include "gamma_expansion_effect.h" #include "gamma_compression_effect.h" -#include "lift_gamma_gain_effect.h" #include "colorspace_conversion_effect.h" -#include "sandbox_effect.h" -#include "saturation_effect.h" -#include "mirror_effect.h" -#include "vignette_effect.h" -#include "blur_effect.h" -#include "diffusion_effect.h" -#include "glow_effect.h" -#include "mix_effect.h" #include "input.h" EffectChain::EffectChain(unsigned width, unsigned height) @@ -33,16 +24,15 @@ EffectChain::EffectChain(unsigned width, unsigned height) height(height), finalized(false) {} -Input *EffectChain::add_input(const ImageFormat &format) +Input *EffectChain::add_input(Input *input) { char eff_id[256]; - sprintf(eff_id, "src_image%d", inputs.size()); + sprintf(eff_id, "src_image%u", (unsigned)inputs.size()); - Input *input = new Input(format, width, height); effects.push_back(input); inputs.push_back(input); - output_color_space.insert(std::make_pair(input, format.color_space)); - output_gamma_curve.insert(std::make_pair(input, format.gamma_curve)); + output_color_space.insert(std::make_pair(input, input->get_color_space())); + output_gamma_curve.insert(std::make_pair(input, input->get_gamma_curve())); effect_ids.insert(std::make_pair(input, eff_id)); incoming_links.insert(std::make_pair(input, std::vector())); return input; @@ -70,79 +60,70 @@ void EffectChain::add_effect_raw(Effect *effect, const std::vector &in output_color_space[effect] = output_color_space[last_added_effect()]; } -Effect *instantiate_effect(EffectId effect) -{ - switch (effect) { - case EFFECT_GAMMA_EXPANSION: - return new GammaExpansionEffect(); - case EFFECT_GAMMA_COMPRESSION: - return new GammaCompressionEffect(); - case EFFECT_COLOR_SPACE_CONVERSION: - return new ColorSpaceConversionEffect(); - case EFFECT_SANDBOX: - return new SandboxEffect(); - case EFFECT_LIFT_GAMMA_GAIN: - return new LiftGammaGainEffect(); - case EFFECT_SATURATION: - return new SaturationEffect(); - case EFFECT_MIRROR: - return new MirrorEffect(); - case EFFECT_VIGNETTE: - return new VignetteEffect(); - case EFFECT_BLUR: - return new BlurEffect(); - case EFFECT_DIFFUSION: - return new DiffusionEffect(); - case EFFECT_GLOW: - return new GlowEffect(); - case EFFECT_MIX: - return new MixEffect(); - } - assert(false); -} - -// Set the "use_srgb_texture_format" option on all inputs that feed into this node, -// and update the output_gamma_curve[] map as we go. -// -// NOTE: We assume that the only way we could actually get GAMMA_sRGB from an -// effect (except from GammaCompressionCurve, which should never be inserted -// into a chain when this is called) is by pass-through from a texture. -// Thus, we can simply feed the flag up towards all inputs. -void EffectChain::set_use_srgb_texture_format(Effect *effect) +void EffectChain::find_all_nonlinear_inputs(Effect *effect, + std::vector *nonlinear_inputs, + std::vector *intermediates) { assert(output_gamma_curve.count(effect) != 0); - assert(output_gamma_curve[effect] == GAMMA_sRGB); + if (output_gamma_curve[effect] == GAMMA_LINEAR) { + return; + } if (effect->num_inputs() == 0) { - effect->set_int("use_srgb_texture_format", 1); + nonlinear_inputs->push_back(static_cast(effect)); } else { + intermediates->push_back(effect); + assert(incoming_links.count(effect) == 1); std::vector deps = incoming_links[effect]; assert(effect->num_inputs() == deps.size()); for (unsigned i = 0; i < deps.size(); ++i) { - set_use_srgb_texture_format(deps[i]); - assert(output_gamma_curve[deps[i]] == GAMMA_LINEAR); + find_all_nonlinear_inputs(deps[i], nonlinear_inputs, intermediates); } } - output_gamma_curve[effect] = GAMMA_LINEAR; } Effect *EffectChain::normalize_to_linear_gamma(Effect *input) { - assert(output_gamma_curve.count(input) != 0); - if (output_gamma_curve[input] == GAMMA_sRGB) { - // TODO: check if the extension exists - set_use_srgb_texture_format(input); - output_gamma_curve[input] = GAMMA_LINEAR; + // Find out if all the inputs can be set to deliver sRGB inputs. + // If so, we can just ask them to do that instead of inserting a + // (possibly expensive) conversion operation. + // + // NOTE: We assume that effects generally don't mess with the gamma + // curve (except GammaCompressionEffect, which should never be + // inserted into a chain when this is called), so that we can just + // update the output gamma as we go. + // + // TODO: Setting this flag for one source might confuse a different + // part of the pipeline using the same source. + std::vector nonlinear_inputs; + std::vector intermediates; + find_all_nonlinear_inputs(input, &nonlinear_inputs, &intermediates); + + bool all_ok = true; + for (unsigned i = 0; i < nonlinear_inputs.size(); ++i) { + all_ok &= nonlinear_inputs[i]->can_output_linear_gamma(); + } + + if (all_ok) { + for (unsigned i = 0; i < nonlinear_inputs.size(); ++i) { + bool ok = nonlinear_inputs[i]->set_int("output_linear_gamma", 1); + assert(ok); + output_gamma_curve[nonlinear_inputs[i]] = GAMMA_LINEAR; + } + for (unsigned i = 0; i < intermediates.size(); ++i) { + output_gamma_curve[intermediates[i]] = GAMMA_LINEAR; + } return input; - } else { - GammaExpansionEffect *gamma_conversion = new GammaExpansionEffect(); - gamma_conversion->set_int("source_curve", output_gamma_curve[input]); - std::vector inputs; - inputs.push_back(input); - gamma_conversion->add_self_to_effect_chain(this, inputs); - output_gamma_curve[gamma_conversion] = GAMMA_LINEAR; - return gamma_conversion; } + + // OK, that didn't work. Insert a conversion effect. + GammaExpansionEffect *gamma_conversion = new GammaExpansionEffect(); + gamma_conversion->set_int("source_curve", output_gamma_curve[input]); + std::vector inputs; + inputs.push_back(input); + gamma_conversion->add_self_to_effect_chain(this, inputs); + output_gamma_curve[gamma_conversion] = GAMMA_LINEAR; + return gamma_conversion; } Effect *EffectChain::normalize_to_srgb(Effect *input) @@ -160,10 +141,8 @@ Effect *EffectChain::normalize_to_srgb(Effect *input) return colorspace_conversion; } -Effect *EffectChain::add_effect(EffectId effect_id, const std::vector &inputs) +Effect *EffectChain::add_effect(Effect *effect, const std::vector &inputs) { - Effect *effect = instantiate_effect(effect_id); - assert(inputs.size() == effect->num_inputs()); std::vector normalized_inputs = inputs;