Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@gmail.com>2014-04-18 15:40:30 +0400
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2014-04-18 16:40:19 +0400
commit2a9ef256b1e6cea833855d9517916b9656527672 (patch)
treedd91b03941b78eb8b4af33f8b72029441195c287 /intern/cycles/render
parent2d7b53331c80e878d48e3c2a6bdc81fef9a1a6e0 (diff)
Cycles: SVM optimization for mix shaders, to skip more code when the mix weight
for one of the input shaders is zero. This gives about 5% speedup for koro_final.blend. In general this is important so you can design shaders that run faster for shadows, diffuse bounces, etc, for example by skipping procedural textures or even using a single fixed color.
Diffstat (limited to 'intern/cycles/render')
-rw-r--r--intern/cycles/render/svm.cpp72
1 files changed, 63 insertions, 9 deletions
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 */