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.
This commit is contained in:
@@ -487,7 +487,39 @@ void SVMCompiler::generate_closure(ShaderNode *node, set<ShaderNode*>& done)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
/* 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
|
* we will evaluate all nodes even if they are used as input for closures
|
||||||
@@ -524,21 +556,37 @@ void SVMCompiler::generate_multi_closure(ShaderNode *node, set<ShaderNode*>& don
|
|||||||
out2_offset = in_offset;
|
out2_offset = in_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cl1in->link) {
|
if(cl1in->link)
|
||||||
generate_multi_closure(cl1in->link->parent, done, out1_offset);
|
generate_multi_closure(cl1in->link->parent, done, closure_data, out1_offset);
|
||||||
|
|
||||||
if(fin)
|
if(cl2in->link)
|
||||||
stack_clear_offset(SHADER_SOCKET_FLOAT, out1_offset);
|
generate_multi_closure(cl2in->link->parent, done, closure_data, out2_offset);
|
||||||
}
|
|
||||||
|
|
||||||
if(cl2in->link) {
|
if(in_offset != SVM_STACK_INVALID)
|
||||||
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 {
|
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 */
|
/* 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) {
|
||||||
@@ -548,7 +596,7 @@ void SVMCompiler::generate_multi_closure(ShaderNode *node, set<ShaderNode*>& don
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mix_weight_offset = in_offset;
|
mix_weight_offset = data.stack_offset;
|
||||||
|
|
||||||
/* compile closure itself */
|
/* compile closure itself */
|
||||||
node->compile(*this);
|
node->compile(*this);
|
||||||
@@ -563,6 +611,9 @@ void SVMCompiler::generate_multi_closure(ShaderNode *node, set<ShaderNode*>& don
|
|||||||
current_shader->has_surface_transparent = true;
|
current_shader->has_surface_transparent = true;
|
||||||
|
|
||||||
/* end node is added outside of this */
|
/* 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 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
|
|||||||
if(generate) {
|
if(generate) {
|
||||||
set<ShaderNode*> done;
|
set<ShaderNode*> done;
|
||||||
|
|
||||||
if(use_multi_closure)
|
if(use_multi_closure) {
|
||||||
generate_multi_closure(clin->link->parent, done, SVM_STACK_INVALID);
|
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
|
else
|
||||||
generate_closure(clin->link->parent, done);
|
generate_closure(clin->link->parent, done);
|
||||||
}
|
}
|
||||||
|
@@ -81,6 +81,7 @@ public:
|
|||||||
bool background;
|
bool background;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
/* stack */
|
||||||
struct Stack {
|
struct Stack {
|
||||||
Stack() { memset(users, 0, sizeof(users)); }
|
Stack() { memset(users, 0, sizeof(users)); }
|
||||||
Stack(const Stack& other) { memcpy(users, other.users, sizeof(users)); }
|
Stack(const Stack& other) { memcpy(users, other.users, sizeof(users)); }
|
||||||
@@ -123,11 +124,22 @@ protected:
|
|||||||
|
|
||||||
bool node_skip_input(ShaderNode *node, ShaderInput *input);
|
bool node_skip_input(ShaderNode *node, ShaderInput *input);
|
||||||
|
|
||||||
|
/* single closure */
|
||||||
void find_dependencies(set<ShaderNode*>& dependencies, const set<ShaderNode*>& done, ShaderInput *input);
|
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_svm_nodes(const set<ShaderNode*>& nodes, set<ShaderNode*>& done);
|
||||||
void generate_closure(ShaderNode *node, 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);
|
void compile_type(Shader *shader, ShaderGraph *graph, ShaderType type);
|
||||||
|
|
||||||
vector<int4> svm_nodes;
|
vector<int4> svm_nodes;
|
||||||
|
Reference in New Issue
Block a user