Fix issues with node deduplication in Cycles shader graph.

It is not possible to use a set split by name as valid input to
check_node_input_traversed - it needs a complete set of all nodes visited so
far. On the other hand, the merge comparison loop should only check nodes that
were not just visited, but found unique. This means that there should really be
two separate data structures.

Without the fix, check_node_input_traversed actually never returns true, so
only nodes without any inputs are processed.
This commit is contained in:
Alexander Gavrilov 2016-06-19 16:51:10 +03:00 committed by Brecht Van Lommel
parent 98547e8817
commit 81e391a727
1 changed files with 17 additions and 10 deletions

View File

@ -558,8 +558,8 @@ void ShaderGraph::deduplicate_nodes()
* already deduplicated.
*/
ShaderNodeSet scheduled;
map<ustring, ShaderNodeSet> done;
ShaderNodeSet scheduled, done;
map<ustring, ShaderNodeSet> candidates;
queue<ShaderNode*> traverse_queue;
/* Schedule nodes which doesn't have any dependencies. */
@ -573,7 +573,7 @@ void ShaderGraph::deduplicate_nodes()
while(!traverse_queue.empty()) {
ShaderNode *node = traverse_queue.front();
traverse_queue.pop();
done[node->name].insert(node);
done.insert(node);
/* Schedule the nodes which were depending on the current node. */
foreach(ShaderOutput *output, node->outputs) {
foreach(ShaderInput *input, output->links) {
@ -584,21 +584,28 @@ void ShaderGraph::deduplicate_nodes()
continue;
}
/* Schedule node if its inputs are fully done. */
if(check_node_inputs_traversed(input->parent, done[input->parent->name])) {
if(check_node_inputs_traversed(input->parent, done)) {
traverse_queue.push(input->parent);
scheduled.insert(input->parent);
}
}
}
/* Try to merge this node with another one. */
foreach(ShaderNode *other_node, done[node->name]) {
ShaderNode *merge_with = NULL;
foreach(ShaderNode *other_node, candidates[node->type->name]) {
if (node != other_node && node->equals(*other_node)) {
/* TODO(sergey): Consider making it an utility function. */
for(int i = 0; i < node->outputs.size(); ++i) {
relink(node, node->outputs[i], other_node->outputs[i]);
}
merge_with = other_node;
break;
}
break;
}
/* If found an equivalent, merge; otherwise keep node for later merges */
if (merge_with != NULL) {
for(int i = 0; i < node->outputs.size(); ++i) {
relink(node, node->outputs[i], merge_with->outputs[i]);
}
}
else {
candidates[node->type->name].insert(node);
}
}
}