[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [52533] trunk/blender/intern/cycles/render : Fix #33152: cycles SVM crash with certain shader nodes setups where closures would
Brecht Van Lommel
brechtvanlommel at pandora.be
Sat Nov 24 15:50:22 CET 2012
Revision: 52533
http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=52533
Author: blendix
Date: 2012-11-24 14:50:21 +0000 (Sat, 24 Nov 2012)
Log Message:
-----------
Fix #33152: cycles SVM crash with certain shader nodes setups where closures would
appear multiple times after flattening the mix/add shader part of the graph into a
tree structure.
Modified Paths:
--------------
trunk/blender/intern/cycles/render/svm.cpp
trunk/blender/intern/cycles/render/svm.h
Modified: trunk/blender/intern/cycles/render/svm.cpp
===================================================================
--- trunk/blender/intern/cycles/render/svm.cpp 2012-11-24 14:19:21 UTC (rev 52532)
+++ trunk/blender/intern/cycles/render/svm.cpp 2012-11-24 14:50:21 UTC (rev 52533)
@@ -487,8 +487,40 @@
}
}
-void SVMCompiler::generate_multi_closure(ShaderNode *node, set<ShaderNode*>& done, uint in_offset)
+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)
+{
/* 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
@@ -524,21 +556,37 @@
out2_offset = in_offset;
}
- if(cl1in->link) {
- generate_multi_closure(cl1in->link->parent, done, out1_offset);
+ if(cl1in->link)
+ generate_multi_closure(cl1in->link->parent, done, closure_data, out1_offset);
- if(fin)
- stack_clear_offset(SHADER_SOCKET_FLOAT, out1_offset);
+ 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);
+ }
+ 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);
- if(cl2in->link) {
- generate_multi_closure(cl2in->link->parent, done, out2_offset);
+ stack_clear_offset(SHADER_SOCKET_FLOAT, in_offset);
+ }
- if(fin)
- stack_clear_offset(SHADER_SOCKET_FLOAT, out2_offset);
- }
- }
- else {
+ 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) {
@@ -548,7 +596,7 @@
}
}
- mix_weight_offset = in_offset;
+ mix_weight_offset = data.stack_offset;
/* compile closure itself */
node->compile(*this);
@@ -563,6 +611,9 @@
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);
}
}
@@ -634,8 +685,12 @@
if(generate) {
set<ShaderNode*> done;
- if(use_multi_closure)
- generate_multi_closure(clin->link->parent, done, SVM_STACK_INVALID);
+ 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);
+ }
else
generate_closure(clin->link->parent, done);
}
Modified: trunk/blender/intern/cycles/render/svm.h
===================================================================
--- trunk/blender/intern/cycles/render/svm.h 2012-11-24 14:19:21 UTC (rev 52532)
+++ trunk/blender/intern/cycles/render/svm.h 2012-11-24 14:50:21 UTC (rev 52533)
@@ -81,6 +81,7 @@
bool background;
protected:
+ /* stack */
struct Stack {
Stack() { memset(users, 0, sizeof(users)); }
Stack(const Stack& other) { memcpy(users, other.users, sizeof(users)); }
@@ -123,11 +124,22 @@
bool node_skip_input(ShaderNode *node, ShaderInput *input);
+ /* single closure */
void find_dependencies(set<ShaderNode*>& dependencies, const set<ShaderNode*>& done, ShaderInput *input);
void generate_svm_nodes(const set<ShaderNode*>& nodes, set<ShaderNode*>& done);
void generate_closure(ShaderNode *node, set<ShaderNode*>& done);
- void generate_multi_closure(ShaderNode *node, set<ShaderNode*>& done, uint in_offset);
+ /* multi closure */
+ struct MultiClosureData {
+ int stack_offset;
+ int users;
+ };
+
+ void generate_multi_closure(ShaderNode *node, set<ShaderNode*>& done,
+ map<ShaderNode*,MultiClosureData>& closure_data, uint in_offset);
+ void count_closure_users(ShaderNode *node, map<ShaderNode*, MultiClosureData>& closure_data);
+
+ /* compile */
void compile_type(Shader *shader, ShaderGraph *graph, ShaderType type);
vector<int4> svm_nodes;
More information about the Bf-blender-cvs
mailing list