X-Git-Url: https://git.sesse.net/?p=movit;a=blobdiff_plain;f=effect_chain.cpp;h=f79c09a478360b5b59aa158ecae0111702ee9e43;hp=475821585abf7df9967214647711062dc9dd51f2;hb=bbf22bd4cc8c00add6b934f19d30a099241ffd84;hpb=7f7069a0392bf5a5815e2a7452f5879b25959155 diff --git a/effect_chain.cpp b/effect_chain.cpp index 4758215..f79c09a 100644 --- a/effect_chain.cpp +++ b/effect_chain.cpp @@ -229,8 +229,10 @@ Phase *EffectChain::compile_glsl_program( frag_shader += "\n"; } - for (unsigned i = 0; i < effects.size(); ++i) { - Node *node = effects[i]; + std::vector sorted_effects = topological_sort(effects); + + for (unsigned i = 0; i < sorted_effects.size(); ++i) { + Node *node = sorted_effects[i]; if (node->incoming_links.size() == 1) { frag_shader += std::string("#define INPUT ") + node->incoming_links[0]->effect_id + "\n"; @@ -261,13 +263,13 @@ Phase *EffectChain::compile_glsl_program( input_needs_mipmaps |= node->effect->needs_mipmaps(); } - for (unsigned i = 0; i < effects.size(); ++i) { - Node *node = effects[i]; + for (unsigned i = 0; i < sorted_effects.size(); ++i) { + Node *node = sorted_effects[i]; if (node->effect->num_inputs() == 0) { CHECK(node->effect->set_int("needs_mipmaps", input_needs_mipmaps)); } } - frag_shader += std::string("#define INPUT ") + effects.back()->effect_id + "\n"; + frag_shader += std::string("#define INPUT ") + sorted_effects.back()->effect_id + "\n"; frag_shader.append(read_file("footer.frag")); if (movit_debug_level == MOVIT_DEBUG_ON) { @@ -300,7 +302,7 @@ Phase *EffectChain::compile_glsl_program( phase->fragment_shader = fs_obj; phase->input_needs_mipmaps = input_needs_mipmaps; phase->inputs = true_inputs; - phase->effects = effects; + phase->effects = sorted_effects; return phase; } @@ -343,8 +345,12 @@ void EffectChain::construct_glsl_programs(Node *output) Node *node = effects_todo_this_phase.top(); effects_todo_this_phase.pop(); - // This should currently only happen for effects that are phase outputs, - // and we throw those out separately below. + // This should currently only happen for effects that are inputs + // (either true inputs or phase outputs). We special-case inputs, + // and then deduplicate phase outputs in compile_glsl_program(). + if (node->effect->num_inputs() == 0 && completed_effects.count(node)) { + continue; + } assert(completed_effects.count(node) == 0); this_phase_effects.push_back(node); @@ -442,85 +448,46 @@ void EffectChain::output_dot(const char *filename) } fprintf(fp, "digraph G {\n"); + fprintf(fp, " output [shape=box label=\"(output)\"];\n"); for (unsigned i = 0; i < nodes.size(); ++i) { // Find out which phase this event belongs to. - int in_phase = -1; + std::vector in_phases; for (unsigned j = 0; j < phases.size(); ++j) { const Phase* p = phases[j]; if (std::find(p->effects.begin(), p->effects.end(), nodes[i]) != p->effects.end()) { - assert(in_phase == -1); - in_phase = j; + in_phases.push_back(j); } } - if (in_phase == -1) { + if (in_phases.empty()) { fprintf(fp, " n%ld [label=\"%s\"];\n", (long)nodes[i], nodes[i]->effect->effect_type_id().c_str()); - } else { + } else if (in_phases.size() == 1) { fprintf(fp, " n%ld [label=\"%s\" style=\"filled\" fillcolor=\"/accent8/%d\"];\n", (long)nodes[i], nodes[i]->effect->effect_type_id().c_str(), - (in_phase % 8) + 1); + (in_phases[0] % 8) + 1); + } else { + // If we had new enough Graphviz, style="wedged" would probably be ideal here. + // But alas. + fprintf(fp, " n%ld [label=\"%s [in multiple phases]\" style=\"filled\" fillcolor=\"/accent8/%d\"];\n", + (long)nodes[i], nodes[i]->effect->effect_type_id().c_str(), + (in_phases[0] % 8) + 1); } - for (unsigned j = 0; j < nodes[i]->outgoing_links.size(); ++j) { - std::vector labels; - - if (nodes[i]->outgoing_links[j]->effect->needs_texture_bounce()) { - labels.push_back("needs_bounce"); - } - if (nodes[i]->effect->changes_output_size()) { - labels.push_back("resize"); - } - switch (nodes[i]->output_color_space) { - case COLORSPACE_INVALID: - labels.push_back("spc[invalid]"); - break; - case COLORSPACE_REC_601_525: - labels.push_back("spc[rec601-525]"); - break; - case COLORSPACE_REC_601_625: - labels.push_back("spc[rec601-625]"); - break; - default: - break; - } + char from_node_id[256]; + snprintf(from_node_id, 256, "n%ld", (long)nodes[i]); - switch (nodes[i]->output_gamma_curve) { - case GAMMA_INVALID: - labels.push_back("gamma[invalid]"); - break; - case GAMMA_sRGB: - labels.push_back("gamma[sRGB]"); - break; - case GAMMA_REC_601: // and GAMMA_REC_709 - labels.push_back("gamma[rec601/709]"); - break; - default: - break; - } + for (unsigned j = 0; j < nodes[i]->outgoing_links.size(); ++j) { + char to_node_id[256]; + snprintf(to_node_id, 256, "n%ld", (long)nodes[i]->outgoing_links[j]); - switch (nodes[i]->output_alpha_type) { - case ALPHA_INVALID: - labels.push_back("alpha[invalid]"); - break; - case ALPHA_BLANK: - labels.push_back("alpha[blank]"); - break; - case ALPHA_POSTMULTIPLIED: - labels.push_back("alpha[postmult]"); - break; - default: - break; - } + std::vector labels = get_labels_for_edge(nodes[i], nodes[i]->outgoing_links[j]); + output_dot_edge(fp, from_node_id, to_node_id, labels); + } - if (labels.empty()) { - fprintf(fp, " n%ld -> n%ld;\n", (long)nodes[i], (long)nodes[i]->outgoing_links[j]); - } else { - std::string label = labels[0]; - for (unsigned k = 1; k < labels.size(); ++k) { - label += ", " + labels[k]; - } - fprintf(fp, " n%ld -> n%ld [label=\"%s\"];\n", (long)nodes[i], (long)nodes[i]->outgoing_links[j], label.c_str()); - } + if (nodes[i]->outgoing_links.empty() && !nodes[i]->disabled) { + // Output node. + std::vector labels = get_labels_for_edge(nodes[i], NULL); + output_dot_edge(fp, from_node_id, "output", labels); } } fprintf(fp, "}\n"); @@ -528,6 +495,78 @@ void EffectChain::output_dot(const char *filename) fclose(fp); } +std::vector EffectChain::get_labels_for_edge(const Node *from, const Node *to) +{ + std::vector labels; + + if (to != NULL && to->effect->needs_texture_bounce()) { + labels.push_back("needs_bounce"); + } + if (from->effect->changes_output_size()) { + labels.push_back("resize"); + } + + switch (from->output_color_space) { + case COLORSPACE_INVALID: + labels.push_back("spc[invalid]"); + break; + case COLORSPACE_REC_601_525: + labels.push_back("spc[rec601-525]"); + break; + case COLORSPACE_REC_601_625: + labels.push_back("spc[rec601-625]"); + break; + default: + break; + } + + switch (from->output_gamma_curve) { + case GAMMA_INVALID: + labels.push_back("gamma[invalid]"); + break; + case GAMMA_sRGB: + labels.push_back("gamma[sRGB]"); + break; + case GAMMA_REC_601: // and GAMMA_REC_709 + labels.push_back("gamma[rec601/709]"); + break; + default: + break; + } + + switch (from->output_alpha_type) { + case ALPHA_INVALID: + labels.push_back("alpha[invalid]"); + break; + case ALPHA_BLANK: + labels.push_back("alpha[blank]"); + break; + case ALPHA_POSTMULTIPLIED: + labels.push_back("alpha[postmult]"); + break; + default: + break; + } + + return labels; +} + +void EffectChain::output_dot_edge(FILE *fp, + const std::string &from_node_id, + const std::string &to_node_id, + const std::vector &labels) +{ + if (labels.empty()) { + fprintf(fp, " %s -> %s;\n", from_node_id.c_str(), to_node_id.c_str()); + } else { + std::string label = labels[0]; + for (unsigned k = 1; k < labels.size(); ++k) { + label += ", " + labels[k]; + } + fprintf(fp, " %s -> %s [label=\"%s\"];\n", from_node_id.c_str(), to_node_id.c_str(), label.c_str()); + } +} + unsigned EffectChain::fit_rectangle_to_aspect(unsigned width, unsigned height) { if (float(width) * aspect_denom >= float(height) * aspect_nom) { @@ -638,27 +677,30 @@ void EffectChain::find_output_size(Phase *phase) phase->output_height = best_width * aspect_denom / aspect_nom; } -void EffectChain::sort_nodes_topologically() +void EffectChain::sort_all_nodes_topologically() +{ + nodes = topological_sort(nodes); +} + +std::vector EffectChain::topological_sort(const std::vector &nodes) { - std::set visited_nodes; + std::set nodes_left_to_visit(nodes.begin(), nodes.end()); std::vector sorted_list; for (unsigned i = 0; i < nodes.size(); ++i) { - if (nodes[i]->incoming_links.size() == 0) { - topological_sort_visit_node(nodes[i], &visited_nodes, &sorted_list); - } + topological_sort_visit_node(nodes[i], &nodes_left_to_visit, &sorted_list); } reverse(sorted_list.begin(), sorted_list.end()); - nodes = sorted_list; + return sorted_list; } -void EffectChain::topological_sort_visit_node(Node *node, std::set *visited_nodes, std::vector *sorted_list) +void EffectChain::topological_sort_visit_node(Node *node, std::set *nodes_left_to_visit, std::vector *sorted_list) { - if (visited_nodes->count(node) != 0) { + if (nodes_left_to_visit->count(node) == 0) { return; } - visited_nodes->insert(node); + nodes_left_to_visit->erase(node); for (unsigned i = 0; i < node->outgoing_links.size(); ++i) { - topological_sort_visit_node(node->outgoing_links[i], visited_nodes, sorted_list); + topological_sort_visit_node(node->outgoing_links[i], nodes_left_to_visit, sorted_list); } sorted_list->push_back(node); } @@ -690,6 +732,10 @@ void EffectChain::find_color_spaces_for_inputs() default: assert(false); } + + if (node->output_alpha_type == ALPHA_PREMULTIPLIED) { + assert(node->output_gamma_curve == GAMMA_LINEAR); + } } } } @@ -700,7 +746,7 @@ void EffectChain::find_color_spaces_for_inputs() void EffectChain::propagate_gamma_and_color_space() { // We depend on going through the nodes in order. - sort_nodes_topologically(); + sort_all_nodes_topologically(); for (unsigned i = 0; i < nodes.size(); ++i) { Node *node = nodes[i]; @@ -742,7 +788,7 @@ void EffectChain::propagate_gamma_and_color_space() void EffectChain::propagate_alpha() { // We depend on going through the nodes in order. - sort_nodes_topologically(); + sort_all_nodes_topologically(); for (unsigned i = 0; i < nodes.size(); ++i) { Node *node = nodes[i];