Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/render/svm.cpp
| Show First 20 Lines • Show All 174 Lines • ▼ Show 20 Lines | |||||
| void SVMCompiler::stack_clear_offset(ShaderSocketType type, int offset) | void SVMCompiler::stack_clear_offset(ShaderSocketType type, int offset) | ||||
| { | { | ||||
| int size = stack_size(type); | int size = stack_size(type); | ||||
| for(int i = 0; i < size; i++) | for(int i = 0; i < size; i++) | ||||
| active_stack.users[offset + i]--; | active_stack.users[offset + i]--; | ||||
| } | } | ||||
| void SVMCompiler::stack_backup(StackBackup& backup, set<ShaderNode*>& done) | void SVMCompiler::stack_backup(StackBackup& backup, ShaderNodeSet& done) | ||||
| { | { | ||||
| backup.done = done; | backup.done = done; | ||||
| backup.stack = active_stack; | backup.stack = active_stack; | ||||
| foreach(ShaderNode *node, current_graph->nodes) { | foreach(ShaderNode *node, current_graph->nodes) { | ||||
| foreach(ShaderInput *input, node->inputs) | foreach(ShaderInput *input, node->inputs) | ||||
| backup.offsets.push_back(input->stack_offset); | backup.offsets.push_back(input->stack_offset); | ||||
| foreach(ShaderOutput *output, node->outputs) | foreach(ShaderOutput *output, node->outputs) | ||||
| backup.offsets.push_back(output->stack_offset); | backup.offsets.push_back(output->stack_offset); | ||||
| } | } | ||||
| } | } | ||||
| void SVMCompiler::stack_restore(StackBackup& backup, set<ShaderNode*>& done) | void SVMCompiler::stack_restore(StackBackup& backup, ShaderNodeSet& done) | ||||
| { | { | ||||
| int i = 0; | int i = 0; | ||||
| done = backup.done; | done = backup.done; | ||||
| active_stack = backup.stack; | active_stack = backup.stack; | ||||
| foreach(ShaderNode *node, current_graph->nodes) { | foreach(ShaderNode *node, current_graph->nodes) { | ||||
| foreach(ShaderInput *input, node->inputs) | foreach(ShaderInput *input, node->inputs) | ||||
| ▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | if(output->stack_offset == SVM_STACK_INVALID) { | ||||
| int size = stack_size(output->type); | int size = stack_size(output->type); | ||||
| for(int i = 0; i < size; i++) | for(int i = 0; i < size; i++) | ||||
| active_stack.users[output->stack_offset + i]++; | active_stack.users[output->stack_offset + i]++; | ||||
| } | } | ||||
| } | } | ||||
| void SVMCompiler::stack_clear_users(ShaderNode *node, set<ShaderNode*>& done) | void SVMCompiler::stack_clear_users(ShaderNode *node, ShaderNodeSet& done) | ||||
| { | { | ||||
| /* optimization we should add: | /* optimization we should add: | ||||
| * find and lower user counts for outputs for which all inputs are done. | * find and lower user counts for outputs for which all inputs are done. | ||||
| * this is done before the node is compiled, under the assumption that the | * this is done before the node is compiled, under the assumption that the | ||||
| * node will first load all inputs from the stack and then writes its | * node will first load all inputs from the stack and then writes its | ||||
| * outputs. this used to work, but was disabled because it gave trouble | * outputs. this used to work, but was disabled because it gave trouble | ||||
| * with inputs getting stack positions assigned */ | * with inputs getting stack positions assigned */ | ||||
| ▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| /* nasty exception .. */ | /* nasty exception .. */ | ||||
| if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->name == ustring("bump")) | if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->name == ustring("bump")) | ||||
| return true; | return true; | ||||
| return false; | return false; | ||||
| } | } | ||||
| void SVMCompiler::find_dependencies(set<ShaderNode*>& dependencies, | void SVMCompiler::find_dependencies(ShaderNodeSet& dependencies, | ||||
| const set<ShaderNode*>& done, | const ShaderNodeSet& done, | ||||
| ShaderInput *input, | ShaderInput *input, | ||||
| ShaderNode *skip_node) | ShaderNode *skip_node) | ||||
| { | { | ||||
| ShaderNode *node = (input->link)? input->link->parent: NULL; | ShaderNode *node = (input->link)? input->link->parent: NULL; | ||||
| if(node && done.find(node) == done.end() && node != skip_node) { | if(node && done.find(node) == done.end() && node != skip_node) { | ||||
| foreach(ShaderInput *in, node->inputs) | foreach(ShaderInput *in, node->inputs) | ||||
| if(!node_skip_input(node, in)) | if(!node_skip_input(node, in)) | ||||
| find_dependencies(dependencies, done, in, skip_node); | find_dependencies(dependencies, done, in, skip_node); | ||||
| dependencies.insert(node); | dependencies.insert(node); | ||||
| } | } | ||||
| } | } | ||||
| void SVMCompiler::generate_node(ShaderNode *node, set<ShaderNode*>& done) | void SVMCompiler::generate_node(ShaderNode *node, ShaderNodeSet& done) | ||||
| { | { | ||||
| node->compile(*this); | node->compile(*this); | ||||
| stack_clear_users(node, done); | stack_clear_users(node, done); | ||||
| stack_clear_temporary(node); | stack_clear_temporary(node); | ||||
| if(current_type == SHADER_TYPE_VOLUME) { | if(current_type == SHADER_TYPE_VOLUME) { | ||||
| if(node->has_spatial_varying()) | if(node->has_spatial_varying()) | ||||
| current_shader->has_heterogeneous_volume = true; | current_shader->has_heterogeneous_volume = true; | ||||
| } | } | ||||
| if(node->has_object_dependency()) { | if(node->has_object_dependency()) { | ||||
| current_shader->has_object_dependency = true; | current_shader->has_object_dependency = true; | ||||
| } | } | ||||
| if(node->has_integrator_dependency()) { | if(node->has_integrator_dependency()) { | ||||
| current_shader->has_integrator_dependency = true; | current_shader->has_integrator_dependency = true; | ||||
| } | } | ||||
| } | } | ||||
| void SVMCompiler::generate_svm_nodes(const set<ShaderNode*>& nodes, set<ShaderNode*>& done) | void SVMCompiler::generate_svm_nodes(const ShaderNodeSet& nodes, ShaderNodeSet& done) | ||||
| { | { | ||||
| bool nodes_done; | bool nodes_done; | ||||
| do { | do { | ||||
| nodes_done = true; | nodes_done = true; | ||||
| foreach(ShaderNode *node, nodes) { | foreach(ShaderNode *node, nodes) { | ||||
| if(done.find(node) == done.end()) { | if(done.find(node) == done.end()) { | ||||
| Show All 10 Lines | foreach(ShaderNode *node, nodes) { | ||||
| } | } | ||||
| else | else | ||||
| nodes_done = false; | nodes_done = false; | ||||
| } | } | ||||
| } | } | ||||
| } while(!nodes_done); | } while(!nodes_done); | ||||
| } | } | ||||
| void SVMCompiler::generate_closure_node(ShaderNode *node, set<ShaderNode*>& done) | void SVMCompiler::generate_closure_node(ShaderNode *node, ShaderNodeSet& done) | ||||
| { | { | ||||
| /* execute dependencies for closure */ | /* execute dependencies for closure */ | ||||
| foreach(ShaderInput *in, node->inputs) { | foreach(ShaderInput *in, node->inputs) { | ||||
| if(!node_skip_input(node, in) && in->link) { | if(!node_skip_input(node, in) && in->link) { | ||||
| set<ShaderNode*> dependencies; | ShaderNodeSet dependencies; | ||||
| find_dependencies(dependencies, done, in); | find_dependencies(dependencies, done, in); | ||||
| generate_svm_nodes(dependencies, done); | generate_svm_nodes(dependencies, done); | ||||
| } | } | ||||
| } | } | ||||
| /* closure mix weight */ | /* closure mix weight */ | ||||
| const char *weight_name = (current_type == SHADER_TYPE_VOLUME)? "VolumeMixWeight": "SurfaceMixWeight"; | const char *weight_name = (current_type == SHADER_TYPE_VOLUME)? "VolumeMixWeight": "SurfaceMixWeight"; | ||||
| ShaderInput *weight_in = node->input(weight_name); | ShaderInput *weight_in = node->input(weight_name); | ||||
| Show All 20 Lines | if(node->has_surface_bssrdf()) { | ||||
| if(node->has_bssrdf_bump()) | if(node->has_bssrdf_bump()) | ||||
| current_shader->has_bssrdf_bump = true; | current_shader->has_bssrdf_bump = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node, | void SVMCompiler::generated_shared_closure_nodes(ShaderNode *root_node, | ||||
| ShaderNode *node, | ShaderNode *node, | ||||
| set<ShaderNode*>& done, | ShaderNodeSet& done, | ||||
| set<ShaderNode*>& closure_done, | ShaderNodeSet& closure_done, | ||||
| const set<ShaderNode*>& shared) | const ShaderNodeSet& shared) | ||||
| { | { | ||||
| if(shared.find(node) != shared.end()) { | if(shared.find(node) != shared.end()) { | ||||
| generate_multi_closure(root_node, node, done, closure_done); | generate_multi_closure(root_node, node, done, closure_done); | ||||
| } | } | ||||
| else { | else { | ||||
| foreach(ShaderInput *in, node->inputs) { | foreach(ShaderInput *in, node->inputs) { | ||||
| if(in->type == SHADER_SOCKET_CLOSURE && in->link) | if(in->type == SHADER_SOCKET_CLOSURE && in->link) | ||||
| generated_shared_closure_nodes(root_node, in->link->parent, | generated_shared_closure_nodes(root_node, in->link->parent, | ||||
| done, closure_done, shared); | done, closure_done, shared); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void SVMCompiler::generate_multi_closure(ShaderNode *root_node, | void SVMCompiler::generate_multi_closure(ShaderNode *root_node, | ||||
| ShaderNode *node, | ShaderNode *node, | ||||
| set<ShaderNode*>& done, | ShaderNodeSet& done, | ||||
| set<ShaderNode*>& closure_done) | ShaderNodeSet& closure_done) | ||||
| { | { | ||||
| /* only generate once */ | /* only generate once */ | ||||
| if(closure_done.find(node) != closure_done.end()) | if(closure_done.find(node) != closure_done.end()) | ||||
| return; | return; | ||||
| closure_done.insert(node); | closure_done.insert(node); | ||||
| if(node->name == ustring("mix_closure") || node->name == ustring("add_closure")) { | if(node->name == ustring("mix_closure") || node->name == ustring("add_closure")) { | ||||
| /* weighting is already taken care of in ShaderGraph::transform_multi_closure */ | /* weighting is already taken care of in ShaderGraph::transform_multi_closure */ | ||||
| ShaderInput *cl1in = node->input("Closure1"); | ShaderInput *cl1in = node->input("Closure1"); | ||||
| ShaderInput *cl2in = node->input("Closure2"); | ShaderInput *cl2in = node->input("Closure2"); | ||||
| ShaderInput *facin = node->input("Fac"); | ShaderInput *facin = node->input("Fac"); | ||||
| /* skip empty mix/add closure nodes */ | /* skip empty mix/add closure nodes */ | ||||
| if(!cl1in->link && !cl2in->link) | if(!cl1in->link && !cl2in->link) | ||||
| return; | return; | ||||
| if(facin && facin->link) { | if(facin && facin->link) { | ||||
| /* mix closure: generate instructions to compute mix weight */ | /* mix closure: generate instructions to compute mix weight */ | ||||
| set<ShaderNode*> dependencies; | ShaderNodeSet dependencies; | ||||
| find_dependencies(dependencies, done, facin); | find_dependencies(dependencies, done, facin); | ||||
| generate_svm_nodes(dependencies, done); | generate_svm_nodes(dependencies, done); | ||||
| stack_assign(facin); | stack_assign(facin); | ||||
| /* execute shared dependencies. this is needed to allow skipping | /* execute shared dependencies. this is needed to allow skipping | ||||
| * of zero weight closures and their dependencies later, so we | * of zero weight closures and their dependencies later, so we | ||||
| * ensure that they only skip dependencies that are unique to them */ | * ensure that they only skip dependencies that are unique to them */ | ||||
| set<ShaderNode*> cl1deps, cl2deps, shareddeps; | ShaderNodeSet cl1deps, cl2deps, shareddeps; | ||||
| find_dependencies(cl1deps, done, cl1in); | find_dependencies(cl1deps, done, cl1in); | ||||
| find_dependencies(cl2deps, done, cl2in); | find_dependencies(cl2deps, done, cl2in); | ||||
| set_intersection(cl1deps.begin(), cl1deps.end(), | set_intersection(cl1deps.begin(), cl1deps.end(), | ||||
| cl2deps.begin(), cl2deps.end(), | cl2deps.begin(), cl2deps.end(), | ||||
| std::inserter(shareddeps, shareddeps.begin())); | std::inserter(shareddeps, shareddeps.begin())); | ||||
| /* it's possible some nodes are not shared between this mix node | /* it's possible some nodes are not shared between this mix node | ||||
| * inputs, but still needed to be always executed, this mainly | * inputs, but still needed to be always executed, this mainly | ||||
| * happens when a node of current subbranch is used by a parent | * happens when a node of current subbranch is used by a parent | ||||
| * node or so */ | * node or so */ | ||||
| if(root_node != node) { | if(root_node != node) { | ||||
| foreach(ShaderInput *in, root_node->inputs) { | foreach(ShaderInput *in, root_node->inputs) { | ||||
| set<ShaderNode*> rootdeps; | ShaderNodeSet rootdeps; | ||||
| find_dependencies(rootdeps, done, in, node); | find_dependencies(rootdeps, done, in, node); | ||||
| set_intersection(rootdeps.begin(), rootdeps.end(), | set_intersection(rootdeps.begin(), rootdeps.end(), | ||||
| cl1deps.begin(), cl1deps.end(), | cl1deps.begin(), cl1deps.end(), | ||||
| std::inserter(shareddeps, shareddeps.begin())); | std::inserter(shareddeps, shareddeps.begin())); | ||||
| set_intersection(rootdeps.begin(), rootdeps.end(), | set_intersection(rootdeps.begin(), rootdeps.end(), | ||||
| cl2deps.begin(), cl2deps.end(), | cl2deps.begin(), cl2deps.end(), | ||||
| std::inserter(shareddeps, shareddeps.begin())); | std::inserter(shareddeps, shareddeps.begin())); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | if(clin->link) { | ||||
| generate = true; | generate = true; | ||||
| shader->has_displacement = true; | shader->has_displacement = true; | ||||
| break; | break; | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| if(generate) { | if(generate) { | ||||
| set<ShaderNode*> done, closure_done; | ShaderNodeSet done, closure_done; | ||||
| generate_multi_closure(clin->link->parent, clin->link->parent, | generate_multi_closure(clin->link->parent, clin->link->parent, | ||||
| done, closure_done); | done, closure_done); | ||||
| } | } | ||||
| } | } | ||||
| /* compile output node */ | /* compile output node */ | ||||
| node->compile(*this); | node->compile(*this); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 74 Lines • Show Last 20 Lines | |||||