Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/render/graph.cpp
| Show First 20 Lines • Show All 417 Lines • ▼ Show 20 Lines | foreach(ShaderInput *input, node->inputs) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Graph simplification */ | /* Graph simplification */ | ||||
| /* ******************** */ | /* ******************** */ | ||||
| /* Step 1: Remove proxy nodes. | /* Remove proxy nodes. | ||||
| * | |||||
| * These only exists temporarily when exporting groups, and we must remove them | * These only exists temporarily when exporting groups, and we must remove them | ||||
| * early so that node->attributes() and default links do not see them. | * early so that node->attributes() and default links do not see them. | ||||
| */ | */ | ||||
| void ShaderGraph::remove_proxy_nodes() | void ShaderGraph::remove_proxy_nodes() | ||||
| { | { | ||||
| vector<bool> removed(num_node_ids, false); | vector<bool> removed(num_node_ids, false); | ||||
| bool any_node_removed = false; | bool any_node_removed = false; | ||||
| ▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | foreach(ShaderNode *node, nodes) { | ||||
| else | else | ||||
| delete node; | delete node; | ||||
| } | } | ||||
| nodes = newnodes; | nodes = newnodes; | ||||
| } | } | ||||
| } | } | ||||
| /* Step 2: Constant folding. | /* Constant folding. | ||||
| * | |||||
| * Try to constant fold some nodes, and pipe result directly to | * Try to constant fold some nodes, and pipe result directly to | ||||
| * the input socket of connected nodes. | * the input socket of connected nodes. | ||||
| */ | */ | ||||
| void ShaderGraph::constant_fold() | void ShaderGraph::constant_fold() | ||||
| { | { | ||||
| ShaderNodeSet done, scheduled; | ShaderNodeSet done, scheduled; | ||||
| queue<ShaderNode*> traverse_queue; | queue<ShaderNode*> traverse_queue; | ||||
| ▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | void ShaderGraph::constant_fold() | ||||
| if(has_displacement && !output()->input("Displacement")->link) { | if(has_displacement && !output()->input("Displacement")->link) { | ||||
| ValueNode *value = (ValueNode*)add(new ValueNode()); | ValueNode *value = (ValueNode*)add(new ValueNode()); | ||||
| value->value = output()->displacement; | value->value = output()->displacement; | ||||
| connect(value->output("Value"), output()->input("Displacement")); | connect(value->output("Value"), output()->input("Displacement")); | ||||
| } | } | ||||
| } | } | ||||
| /* Step 3: Simplification. */ | /* Simplification. */ | ||||
| void ShaderGraph::simplify_settings(Scene *scene) | void ShaderGraph::simplify_settings(Scene *scene) | ||||
| { | { | ||||
| foreach(ShaderNode *node, nodes) { | foreach(ShaderNode *node, nodes) { | ||||
| node->simplify_settings(scene); | node->simplify_settings(scene); | ||||
| } | } | ||||
| } | } | ||||
| /* Step 4: Deduplicate nodes with same settings. */ | /* Deduplicate nodes with same settings. */ | ||||
| void ShaderGraph::deduplicate_nodes() | void ShaderGraph::deduplicate_nodes() | ||||
| { | { | ||||
| /* NOTES: | /* NOTES: | ||||
| * - Deduplication happens for nodes which has same exact settings and same | * - Deduplication happens for nodes which has same exact settings and same | ||||
| * exact input links configuration (either connected to same output or has | * exact input links configuration (either connected to same output or has | ||||
| * the same exact default value). | * the same exact default value). | ||||
| * - Deduplication happens in the bottom-top manner, so we know for fact that | * - Deduplication happens in the bottom-top manner, so we know for fact that | ||||
| * all traversed nodes are either can not be deduplicated at all or were | * all traversed nodes are either can not be deduplicated at all or were | ||||
| ▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | while(!traverse_queue.empty()) { | ||||
| } | } | ||||
| } | } | ||||
| if(num_deduplicated > 0) { | if(num_deduplicated > 0) { | ||||
| VLOG(1) << "Deduplicated " << num_deduplicated << " nodes."; | VLOG(1) << "Deduplicated " << num_deduplicated << " nodes."; | ||||
| } | } | ||||
| } | } | ||||
| /* Check whether volume output has meaningful nodes, otherwise | |||||
| * disconnect the output. | |||||
| */ | |||||
| void ShaderGraph::verify_volume_output() | |||||
| { | |||||
| /* Check whether we can optimize the whole volume graph out. */ | |||||
| ShaderInput *volume_in = output()->input("Volume"); | |||||
| if(volume_in->link == NULL) { | |||||
| return; | |||||
| } | |||||
| bool has_valid_volume = false; | |||||
| ShaderNodeSet scheduled; | |||||
| queue<ShaderNode*> traverse_queue; | |||||
| /* Schedule volume output. */ | |||||
| traverse_queue.push(volume_in->link->parent); | |||||
| scheduled.insert(volume_in->link->parent); | |||||
| /* Traverse down the tree. */ | |||||
| while(!traverse_queue.empty()) { | |||||
| ShaderNode *node = traverse_queue.front(); | |||||
| traverse_queue.pop(); | |||||
| /* Node is fully valid for volume, can't optimize anything out. */ | |||||
| if(node->has_volume_support()) { | |||||
| has_valid_volume = true; | |||||
| break; | |||||
| } | |||||
| foreach(ShaderInput *input, node->inputs) { | |||||
| if(input->link == NULL) { | |||||
| continue; | |||||
| } | |||||
| if(scheduled.find(input->link->parent) != scheduled.end()) { | |||||
| continue; | |||||
| } | |||||
| traverse_queue.push(input->link->parent); | |||||
| scheduled.insert(input->link->parent); | |||||
| } | |||||
| } | |||||
| if(!has_valid_volume) { | |||||
| VLOG(1) << "Disconnect meaningless volume output."; | |||||
| disconnect(volume_in->link); | |||||
| } | |||||
| } | |||||
| void ShaderGraph::break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack) | void ShaderGraph::break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack) | ||||
| { | { | ||||
| visited[node->id] = true; | visited[node->id] = true; | ||||
| on_stack[node->id] = true; | on_stack[node->id] = true; | ||||
| foreach(ShaderInput *input, node->inputs) { | foreach(ShaderInput *input, node->inputs) { | ||||
| if(input->link) { | if(input->link) { | ||||
| ShaderNode *depnode = input->link->parent; | ShaderNode *depnode = input->link->parent; | ||||
| Show All 12 Lines | void ShaderGraph::break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack) | ||||
| on_stack[node->id] = false; | on_stack[node->id] = false; | ||||
| } | } | ||||
| void ShaderGraph::clean(Scene *scene) | void ShaderGraph::clean(Scene *scene) | ||||
| { | { | ||||
| /* Graph simplification */ | /* Graph simplification */ | ||||
| /* 1: Remove proxy nodes was already done. */ | /* NOTE: Remove proxy nodes was already done. */ | ||||
| /* 2: Constant folding. */ | |||||
| constant_fold(); | constant_fold(); | ||||
| /* 3: Simplification. */ | |||||
| simplify_settings(scene); | simplify_settings(scene); | ||||
| /* 4: De-duplication. */ | |||||
| deduplicate_nodes(); | deduplicate_nodes(); | ||||
| verify_volume_output(); | |||||
brecht: I think this should happen before or as part of constant folding, so that mix/add nodes can get… | |||||
Not Done Inline ActionsHrm, not sure it fits in constant folding: as far as i know, you'll need to recurse into Volume input of material output node. and do the same logic as here. Otherwise you don't know whether you can remove Diffuse BSDF or not, because it can be used for both Surface and Volume, so you cant' configure constant folder to do special folding for volume output. sergey: Hrm, not sure it fits in constant folding: as far as i know, you'll need to recurse into Volume… | |||||
| /* we do two things here: find cycles and break them, and remove unused | /* we do two things here: find cycles and break them, and remove unused | ||||
| * nodes that don't feed into the output. how cycles are broken is | * nodes that don't feed into the output. how cycles are broken is | ||||
| * undefined, they are invalid input, the important thing is to not crash */ | * undefined, they are invalid input, the important thing is to not crash */ | ||||
| vector<bool> visited(num_node_ids, false); | vector<bool> visited(num_node_ids, false); | ||||
| vector<bool> on_stack(num_node_ids, false); | vector<bool> on_stack(num_node_ids, false); | ||||
| ▲ Show 20 Lines • Show All 395 Lines • Show Last 20 Lines | |||||
I think this should happen before or as part of constant folding, so that mix/add nodes can get removed as well?