diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2012-11-27 01:59:41 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2012-11-27 01:59:41 +0400 |
commit | ceed3ef640bb40e1232feeb409220fe19011bc43 (patch) | |
tree | 48ad960f483ad185718b14bbc605b6182732f56c /intern/cycles/render/svm.cpp | |
parent | eab58bf994323a53311543d7d706b0be87ffe197 (diff) |
Fix #32907: failure rendering a complex node setup, hitting fixed max number
of closures limit. Optimized the code now so it can handle more.
Change SVM mix/add closure handling, now we transform the node graph so that
the mix weights are fed into the closure nodes directly.
Diffstat (limited to 'intern/cycles/render/svm.cpp')
-rw-r--r-- | intern/cycles/render/svm.cpp | 124 |
1 files changed, 24 insertions, 100 deletions
diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index 73904eac41d..50b3bb59ed4 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -487,106 +487,30 @@ void SVMCompiler::generate_closure(ShaderNode *node, set<ShaderNode*>& done) } } -void SVMCompiler::count_closure_users(ShaderNode *node, map<ShaderNode*, MultiClosureData>& closure_data) -{ - /* here we count the number of times each closure node is used, so that - * the last time we encounter it we can run the actually code with the - * weights from all other places added together */ - - if(node->name == ustring("mix_closure") || node->name == ustring("add_closure")) { - ShaderInput *cl1in = node->input("Closure1"); - ShaderInput *cl2in = node->input("Closure2"); - - if(cl1in->link) - count_closure_users(cl1in->link->parent, closure_data); - if(cl2in->link) - count_closure_users(cl2in->link->parent, closure_data); - } - else { - MultiClosureData data; - - if(closure_data.find(node) == closure_data.end()) { - data.stack_offset = SVM_STACK_INVALID; - data.users = 1; - } - else { - data = closure_data[node]; - data.users++; - } - - closure_data[node] = data; - } -} - -void SVMCompiler::generate_multi_closure(ShaderNode *node, set<ShaderNode*>& done, - map<ShaderNode*, MultiClosureData>& closure_data, uint in_offset) +void SVMCompiler::generate_multi_closure(ShaderNode *node, set<ShaderNode*>& done) { /* todo: the weaks 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(done.find(node) != done.end()) + return; + + done.insert(node); if(node->name == ustring("mix_closure") || node->name == ustring("add_closure")) { - ShaderInput *fin = node->input("Fac"); + /* weighting is already taken care of in ShaderGraph::transform_multi_closure */ ShaderInput *cl1in = node->input("Closure1"); ShaderInput *cl2in = node->input("Closure2"); - uint out1_offset = SVM_STACK_INVALID; - uint out2_offset = SVM_STACK_INVALID; - - if(fin) { - /* mix closure */ - set<ShaderNode*> dependencies; - find_dependencies(dependencies, done, fin); - generate_svm_nodes(dependencies, done); - - stack_assign(fin); - - if(cl1in->link) - out1_offset = stack_find_offset(SHADER_SOCKET_FLOAT); - if(cl2in->link) - out2_offset = stack_find_offset(SHADER_SOCKET_FLOAT); - - add_node(NODE_MIX_CLOSURE, - encode_uchar4(fin->stack_offset, in_offset, out1_offset, out2_offset)); - } - else { - /* add closure */ - out1_offset = in_offset; - out2_offset = in_offset; - } - if(cl1in->link) - generate_multi_closure(cl1in->link->parent, done, closure_data, out1_offset); - + generate_multi_closure(cl1in->link->parent, done); if(cl2in->link) - generate_multi_closure(cl2in->link->parent, done, closure_data, out2_offset); - - if(in_offset != SVM_STACK_INVALID) - stack_clear_offset(SHADER_SOCKET_FLOAT, in_offset); + generate_multi_closure(cl2in->link->parent, done); } else { - MultiClosureData data = closure_data[node]; - - if(data.stack_offset == SVM_STACK_INVALID) { - /* first time using closure, use stack position for weight */ - data.stack_offset = in_offset; - } - else { - /* not first time using, add weights together */ - add_node(NODE_MATH, NODE_MATH_ADD, data.stack_offset, in_offset); - add_node(NODE_MATH, data.stack_offset); - - stack_clear_offset(SHADER_SOCKET_FLOAT, in_offset); - } - - data.users--; - closure_data[node] = data; - - /* still users coming? skip generating closure code */ - if(data.users > 0) - return; - /* execute dependencies for closure */ foreach(ShaderInput *in, node->inputs) { if(!node_skip_input(node, in) && in->link) { @@ -596,7 +520,16 @@ void SVMCompiler::generate_multi_closure(ShaderNode *node, set<ShaderNode*>& don } } - mix_weight_offset = data.stack_offset; + /* closure mix weight */ + const char *weight_name = (current_type == SHADER_TYPE_VOLUME)? "VolumeMixWeight": "SurfaceMixWeight"; + ShaderInput *weight_in = node->input(weight_name); + + if(weight_in && (weight_in->link || weight_in->value.x != 1.0f)) { + stack_assign(weight_in); + mix_weight_offset = weight_in->stack_offset; + } + else + mix_weight_offset = SVM_STACK_INVALID; /* compile closure itself */ node->compile(*this); @@ -609,11 +542,6 @@ void SVMCompiler::generate_multi_closure(ShaderNode *node, set<ShaderNode*>& don current_shader->has_surface_emission = true; if(node->name == ustring("transparent")) current_shader->has_surface_transparent = true; - - /* end node is added outside of this */ - - if(data.stack_offset != SVM_STACK_INVALID) - stack_clear_offset(SHADER_SOCKET_FLOAT, data.stack_offset); } } @@ -685,12 +613,8 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty if(generate) { set<ShaderNode*> done; - if(use_multi_closure) { - map<ShaderNode*, MultiClosureData> closure_data; - - count_closure_users(clin->link->parent, closure_data); - generate_multi_closure(clin->link->parent, done, closure_data, SVM_STACK_INVALID); - } + if(use_multi_closure) + generate_multi_closure(clin->link->parent, done); else generate_closure(clin->link->parent, done); } @@ -713,9 +637,9 @@ void SVMCompiler::compile(Shader *shader, vector<int4>& global_svm_nodes, int in shader->graph_bump = shader->graph->copy(); /* finalize */ - shader->graph->finalize(false, false); + shader->graph->finalize(false, false, use_multi_closure); if(shader->graph_bump) - shader->graph_bump->finalize(true, false); + shader->graph_bump->finalize(true, false, use_multi_closure); current_shader = shader; |