X-Git-Url: https://git.sesse.net/?p=movit;a=blobdiff_plain;f=effect_chain.cpp;h=519cb2c6b9ea1c5816ead123b05260904519f96e;hp=d33cdaeb4a42e6aab680b62c684ccf8dbac2bf4e;hb=82071a94aaff95d2d29d077338085a8fb27e76d1;hpb=9faecb6aed1b84c71286b30b6600ef5e4ee76537 diff --git a/effect_chain.cpp b/effect_chain.cpp index d33cdae..519cb2c 100644 --- a/effect_chain.cpp +++ b/effect_chain.cpp @@ -89,6 +89,7 @@ Node *EffectChain::add_node(Effect *effect) node->output_gamma_curve = GAMMA_INVALID; node->output_alpha_type = ALPHA_INVALID; node->needs_mipmaps = false; + node->one_to_one_sampling = false; nodes.push_back(node); node_map[effect] = node; @@ -289,8 +290,8 @@ void EffectChain::compile_glsl_program(Phase *phase) // Construct GLSL programs, starting at the given effect and following // the chain from there. We end a program every time we come to an effect // marked as "needs texture bounce", one that is used by multiple other -// effects, every time an effect wants to change the output size, -// and of course at the end. +// effects, every time we need to bounce due to output size change +// (not all size changes require ending), and of course at the end. // // We follow a quite simple depth-first search from the output, although // without recursing explicitly within each phase. @@ -303,6 +304,13 @@ Phase *EffectChain::construct_phase(Node *output, map *complete Phase *phase = new Phase; phase->output_node = output; + // If the output effect has one-to-one sampling, we try to trace this + // status down through the dependency chain. This is important in case + // we hit an effect that changes output size (and not sets a virtual + // output size); if we have one-to-one sampling, we don't have to break + // the phase. + output->one_to_one_sampling = output->effect->one_to_one_sampling(); + // Effects that we have yet to calculate, but that we know should // be in the current phase. stack effects_todo_this_phase; @@ -380,7 +388,14 @@ Phase *EffectChain::construct_phase(Node *output, map *complete } } - if (deps[i]->effect->changes_output_size()) { + if (deps[i]->effect->sets_virtual_output_size()) { + assert(deps[i]->effect->changes_output_size()); + // If the next effect sets a virtual size to rely on OpenGL's + // bilinear sampling, we'll really need to break the phase here. + start_new_phase = true; + } else if (deps[i]->effect->changes_output_size() && !node->one_to_one_sampling) { + // If the next effect changes size and we don't have one-to-one sampling, + // we also need to break here. start_new_phase = true; } @@ -388,6 +403,10 @@ Phase *EffectChain::construct_phase(Node *output, map *complete phase->inputs.push_back(construct_phase(deps[i], completed_effects)); } else { effects_todo_this_phase.push(deps[i]); + + // Propagate the one-to-one status down through the dependency. + deps[i]->one_to_one_sampling = node->one_to_one_sampling && + deps[i]->effect->one_to_one_sampling(); } } } @@ -419,6 +438,14 @@ Phase *EffectChain::construct_phase(Node *output, map *complete } } + // Tell each node which phase it ended up in, so that the unit test + // can check that the phases were split in the right place. + // Note that this ignores that effects may be part of multiple phases; + // if the unit tests need to test such cases, we'll reconsider. + for (unsigned i = 0; i < phase->effects.size(); ++i) { + phase->effects[i]->containing_phase = phase; + } + // Actually make the shader for this phase. compile_glsl_program(phase); @@ -623,7 +650,8 @@ void EffectChain::inform_input_sizes(Phase *phase) // 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). + // 1. Don't touch effects that already have given sizes (ie., inputs + // or effects that change the output size). // 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) { @@ -645,8 +673,19 @@ void EffectChain::inform_input_sizes(Phase *phase) this_output_height = 0; } } - node->output_width = this_output_width; - node->output_height = this_output_height; + if (node->effect->changes_output_size()) { + // We cannot call get_output_size() before we've done inform_input_size() + // on all inputs. + unsigned real_width, real_height; + node->effect->get_output_size(&real_width, &real_height, + &node->output_width, &node->output_height); + assert(node->effect->sets_virtual_output_size() || + (real_width == node->output_width && + real_height == node->output_height)); + } else { + node->output_width = this_output_width; + node->output_height = this_output_height; + } } } @@ -660,6 +699,9 @@ void EffectChain::find_output_size(Phase *phase) if (output_node->effect->changes_output_size()) { output_node->effect->get_output_size(&phase->output_width, &phase->output_height, &phase->virtual_output_width, &phase->virtual_output_height); + assert(output_node->effect->sets_virtual_output_size() || + (phase->output_width == phase->virtual_output_width && + phase->output_height == phase->virtual_output_height)); return; } @@ -1598,10 +1640,9 @@ void EffectChain::execute_phase(Phase *phase, bool last_phase, map