+ // Find all the effects that use this one as a direct input.
+ if (outgoing_links.count(node) == 0) {
+ // End of the line; output.
+ phases.push_back(compile_glsl_program(this_phase_inputs, this_phase_effects));
+ return;
+ }
+
+ std::vector<Effect *> next = outgoing_links[node];
+ assert(!next.empty());
+ if (next.size() > 1) {
+ // More than one effect uses this as the input.
+ // The easiest thing to do (and probably also the safest
+ // performance-wise in most cases) is to bounce it to a texture
+ // and then let the next passes read from that.
+ if (node != NULL) {
+ phases.push_back(compile_glsl_program(this_phase_inputs, this_phase_effects));
+ }
+
+ // Start phases for all the effects that need us (in arbitrary order).
+ for (unsigned i = 0; i < next.size(); ++i) {
+ construct_glsl_programs(next[i], completed_effects);
+ }
+ return;
+ }
+
+ // OK, only one effect uses this as the input. Keep iterating,
+ // but first see if it requires a texture bounce; if so, give it
+ // one by starting a new phase.
+ node = next[0];
+ if (node->needs_texture_bounce()) {
+ phases.push_back(compile_glsl_program(this_phase_inputs, this_phase_effects));
+ this_phase_inputs.clear();
+ this_phase_effects.clear();
+ }
+ }
+}
+
+void EffectChain::finalize()
+{
+ // Add normalizers to get the output format right.
+ assert(output_gamma_curve.count(last_added_effect()) != 0);
+ assert(output_color_space.count(last_added_effect()) != 0);
+ ColorSpace current_color_space = output_color_space[last_added_effect()]; // FIXME
+ if (current_color_space != output_format.color_space) {
+ ColorSpaceConversionEffect *colorspace_conversion = new ColorSpaceConversionEffect();
+ colorspace_conversion->set_int("source_space", current_color_space);
+ colorspace_conversion->set_int("destination_space", output_format.color_space);
+ std::vector<Effect *> inputs;
+ inputs.push_back(last_added_effect());
+ colorspace_conversion->add_self_to_effect_chain(this, inputs);
+ output_color_space[colorspace_conversion] = output_format.color_space;
+ }
+ GammaCurve current_gamma_curve = output_gamma_curve[last_added_effect()]; // FIXME
+ if (current_gamma_curve != output_format.gamma_curve) {
+ if (current_gamma_curve != GAMMA_LINEAR) {
+ normalize_to_linear_gamma(last_added_effect()); // FIXME
+ }
+ assert(current_gamma_curve == GAMMA_LINEAR);
+ GammaCompressionEffect *gamma_conversion = new GammaCompressionEffect();
+ gamma_conversion->set_int("destination_curve", output_format.gamma_curve);
+ std::vector<Effect *> inputs;
+ inputs.push_back(last_added_effect());
+ gamma_conversion->add_self_to_effect_chain(this, inputs);
+ output_gamma_curve[gamma_conversion] = output_format.gamma_curve;
+ }