diff options
-rw-r--r-- | intern/cycles/kernel/svm/svm.h | 9 | ||||
-rw-r--r-- | intern/cycles/kernel/svm/svm_types.h | 3 | ||||
-rw-r--r-- | intern/cycles/render/svm.cpp | 72 |
3 files changed, 72 insertions, 12 deletions
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index 96c7cefbcb2..49351d14443 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -232,8 +232,13 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, Shade case NODE_ADD_CLOSURE: svm_node_add_closure(sd, stack, node.y, node.z, &offset, &randb, &closure_weight); break; - case NODE_JUMP: - offset = node.y; + case NODE_JUMP_IF_ZERO: + if(stack_load_float(stack, node.z) == 0.0f) + offset += node.y; + break; + case NODE_JUMP_IF_ONE: + if(stack_load_float(stack, node.z) == 1.0f) + offset += node.y; break; #ifdef __IMAGE_TEXTURES__ case NODE_TEX_IMAGE: diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index 4381bfe0996..866208106dc 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -36,7 +36,8 @@ typedef enum NodeType { NODE_CLOSURE_SET_WEIGHT, NODE_CLOSURE_WEIGHT, NODE_MIX_CLOSURE, - NODE_JUMP, + NODE_JUMP_IF_ZERO, + NODE_JUMP_IF_ONE, NODE_TEX_IMAGE, NODE_TEX_IMAGE_BOX, NODE_TEX_SKY, diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index c004187a091..8035b0129ca 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -515,11 +515,6 @@ void SVMCompiler::generate_closure(ShaderNode *node, set<ShaderNode*>& done) void SVMCompiler::generate_multi_closure(ShaderNode *node, set<ShaderNode*>& done, set<ShaderNode*>& closure_done) { - /* todo: the weak point here is that unlike the single closure sampling - * we will evaluate all nodes even if they are used as input for closures - * that are unused. it's not clear what would be the best way to skip such - * nodes at runtime, especially if they are tangled up */ - /* only generate once */ if(closure_done.find(node) != closure_done.end()) return; @@ -530,11 +525,70 @@ void SVMCompiler::generate_multi_closure(ShaderNode *node, set<ShaderNode*>& don /* weighting is already taken care of in ShaderGraph::transform_multi_closure */ ShaderInput *cl1in = node->input("Closure1"); ShaderInput *cl2in = node->input("Closure2"); + ShaderInput *facin = node->input("Fac"); + + /* skip empty mix/add closure nodes */ + if(!cl1in->link && !cl2in->link) + return; + + if(facin && facin->link) { + /* mix closure: generate instructions to compute mix weight */ + set<ShaderNode*> dependencies; + find_dependencies(dependencies, done, facin); + generate_svm_nodes(dependencies, done); + + stack_assign(facin); /* XXX unassign? */ + + /* execute shared dependencies. this is needed to allow skipping + * of zero weight closures and their dependencies later, so we + * ensure that they only skip dependencies that are unique to them */ + set<ShaderNode*> cl1deps, cl2deps, shareddeps; + + find_dependencies(cl1deps, done, cl1in); + find_dependencies(cl2deps, done, cl2in); + + set_intersection(cl1deps.begin(), cl1deps.end(), + cl2deps.begin(), cl2deps.end(), + std::inserter(shareddeps, shareddeps.begin())); + + generate_svm_nodes(shareddeps, done); + + /* generate instructions for input closure 1 */ + if(cl1in->link) { + /* add instruction to skip closure and its dependencies if mix weight is zero */ + svm_nodes.push_back(make_int4(NODE_JUMP_IF_ONE, 0, facin->stack_offset, 0)); + int node_jump_skip_index = svm_nodes.size() - 1; - if(cl1in->link) - generate_multi_closure(cl1in->link->parent, done, closure_done); - if(cl2in->link) - generate_multi_closure(cl2in->link->parent, done, closure_done); + generate_multi_closure(cl1in->link->parent, done, closure_done); + + /* fill in jump instruction location to be after closure */ + svm_nodes[node_jump_skip_index].y = svm_nodes.size() - node_jump_skip_index - 1; + } + + /* generate instructions for input closure 2 */ + if(cl2in->link) { + /* add instruction to skip closure and its dependencies if mix weight is zero */ + svm_nodes.push_back(make_int4(NODE_JUMP_IF_ZERO, 0, facin->stack_offset, 0)); + int node_jump_skip_index = svm_nodes.size() - 1; + + generate_multi_closure(cl2in->link->parent, done, closure_done); + + /* fill in jump instruction location to be after closure */ + svm_nodes[node_jump_skip_index].y = svm_nodes.size() - node_jump_skip_index - 1; + } + + /* unassign */ + facin->stack_offset = SVM_STACK_INVALID; // XXX clear? + } + else { + /* execute closures and their dependencies, no runtime checks + * to skip closures here because was already optimized due to + * fixed weight or add closure that always needs both */ + if(cl1in->link) + generate_multi_closure(cl1in->link->parent, done, closure_done); + if(cl2in->link) + generate_multi_closure(cl2in->link->parent, done, closure_done); + } } else { /* execute dependencies for closure */ |