void EffectChain::find_all_nonlinear_inputs(Node *node, std::vector<Node *> *nonlinear_inputs)
{
- if (node->output_gamma_curve == GAMMA_LINEAR) {
+ if (node->output_gamma_curve == GAMMA_LINEAR &&
+ node->effect->effect_type_id() != "GammaCompressionEffect") {
return;
}
if (node->effect->num_inputs() == 0) {
}
}
+// Propagate input texture sizes throughout, and inform effects downstream.
+// (Like a lot of other code, we depend on effects being in topological order.)
+void EffectChain::inform_input_sizes(Phase *phase)
+{
+ // All effects that have a defined size (inputs and RTT inputs)
+ // get that. Reset all others.
+ for (unsigned i = 0; i < phase->effects.size(); ++i) {
+ Node *node = phase->effects[i];
+ if (node->effect->num_inputs() == 0) {
+ Input *input = static_cast<Input *>(node->effect);
+ node->output_width = input->get_width();
+ node->output_height = input->get_height();
+ assert(node->output_width != 0);
+ assert(node->output_height != 0);
+ } else {
+ node->output_width = node->output_height = 0;
+ }
+ }
+ for (unsigned i = 0; i < phase->inputs.size(); ++i) {
+ Node *input = phase->inputs[i];
+ input->output_width = input->phase->output_width;
+ input->output_height = input->phase->output_height;
+ assert(input->output_width != 0);
+ assert(input->output_height != 0);
+ }
+
+ // Now propagate from the inputs towards the end, and inform as we go.
+ // The rules are simple:
+ //
+ // 1. Don't touch effects that already have given sizes (ie., inputs).
+ // 2. If all of your inputs have the same size, that will be your output size.
+ // 3. Otherwise, your output size is 0x0.
+ for (unsigned i = 0; i < phase->effects.size(); ++i) {
+ Node *node = phase->effects[i];
+ if (node->effect->num_inputs() == 0) {
+ continue;
+ }
+ unsigned this_output_width = 0;
+ unsigned this_output_height = 0;
+ for (unsigned j = 0; j < node->incoming_links.size(); ++j) {
+ Node *input = node->incoming_links[j];
+ node->effect->inform_input_size(j, input->output_width, input->output_height);
+ if (j == 0) {
+ this_output_width = input->output_width;
+ this_output_height = input->output_height;
+ } else if (input->output_width != this_output_width || input->output_height != this_output_height) {
+ // Inputs disagree.
+ this_output_width = 0;
+ this_output_height = 0;
+ }
+ }
+ node->output_width = this_output_width;
+ node->output_height = this_output_height;
+ }
+}
+
+// Note: You should call inform_input_sizes() before this, as the last effect's
+// desired output size might change based on the inputs.
void EffectChain::find_output_size(Phase *phase)
{
Node *output_node = phase->effects.back();
- // If the last effect explicitly sets an output size,
- // use that.
+ // If the last effect explicitly sets an output size, use that.
if (output_node->effect->changes_output_size()) {
output_node->effect->get_output_size(&phase->output_width, &phase->output_height);
return;
// See if all inputs can give us linear gamma. If not, leave it.
std::vector<Node *> nonlinear_inputs;
find_all_nonlinear_inputs(node, &nonlinear_inputs);
+ assert(!nonlinear_inputs.empty());
bool all_ok = true;
for (unsigned i = 0; i < nonlinear_inputs.size(); ++i) {
continue;
}
Node *conversion = add_node(new GammaExpansionEffect());
- conversion->effect->set_int("destination_curve", GAMMA_LINEAR);
+ conversion->effect->set_int("source_curve", input->output_gamma_curve);
conversion->output_gamma_curve = GAMMA_LINEAR;
insert_node_between(input, conversion, node);
}
fix_internal_gamma_by_asking_inputs(5);
fix_internal_gamma_by_inserting_nodes(6);
fix_output_gamma();
- output_dot("step8-output-gammafix.dot");
- fix_internal_gamma_by_asking_inputs(9);
- fix_internal_gamma_by_inserting_nodes(10);
+ output_dot("step7-output-gammafix.dot");
+ fix_internal_gamma_by_asking_inputs(8);
+ fix_internal_gamma_by_inserting_nodes(9);
- output_dot("step11-final.dot");
+ output_dot("step10-final.dot");
// Construct all needed GLSL programs, starting at the output.
construct_glsl_programs(find_output_node());
glGenFramebuffers(1, &fbo);
for (unsigned i = 0; i < phases.size() - 1; ++i) {
+ inform_input_sizes(phases[i]);
find_output_size(phases[i]);
Node *output_node = phases[i]->effects.back();
output_node->output_texture_width = phases[i]->output_width;
output_node->output_texture_height = phases[i]->output_height;
}
+ inform_input_sizes(phases.back());
}
for (unsigned i = 0; i < inputs.size(); ++i) {
for (unsigned phase = 0; phase < phases.size(); ++phase) {
// See if the requested output size has changed. If so, we need to recreate
// the texture (and before we start setting up inputs).
+ inform_input_sizes(phases[phase]);
if (phase != phases.size() - 1) {
find_output_size(phases[phase]);