diff --git a/intern/cycles/render/constant_fold.cpp b/intern/cycles/render/constant_fold.cpp index 13e12229e85..473560b560d 100644 --- a/intern/cycles/render/constant_fold.cpp +++ b/intern/cycles/render/constant_fold.cpp @@ -64,7 +64,7 @@ void ConstantFolder::make_constant_clamp(float value, bool clamp) const void ConstantFolder::make_constant_clamp(float3 value, bool clamp) const { - if (clamp) { + if(clamp) { value.x = saturate(value.x); value.y = saturate(value.y); value.z = saturate(value.z); @@ -73,6 +73,19 @@ void ConstantFolder::make_constant_clamp(float3 value, bool clamp) const make_constant(value); } +void ConstantFolder::make_zero() const +{ + if(output->type() == SocketType::FLOAT) { + make_constant(0.0f); + } + else if(SocketType::is_float3(output->type())) { + make_constant(make_float3(0.0f, 0.0f, 0.0f)); + } + else { + assert(0); + } +} + void ConstantFolder::bypass(ShaderOutput *new_output) const { assert(new_output); @@ -99,7 +112,7 @@ void ConstantFolder::bypass_or_discard(ShaderInput *input) const { assert(input->type() == SocketType::CLOSURE); - if (input->link) { + if(input->link) { bypass(input->link); } else { @@ -107,11 +120,20 @@ void ConstantFolder::bypass_or_discard(ShaderInput *input) const } } -bool ConstantFolder::try_bypass_or_make_constant(ShaderInput *input, float3 input_value, bool clamp) const +bool ConstantFolder::try_bypass_or_make_constant(ShaderInput *input, bool clamp) const { - if(!input->link) { - make_constant_clamp(input_value, clamp); - return true; + if(input->type() != output->type()) { + return false; + } + else if(!input->link) { + if(input->type() == SocketType::FLOAT) { + make_constant_clamp(node->get_float(input->socket_type), clamp); + return true; + } + else if(SocketType::is_float3(input->type())) { + make_constant_clamp(node->get_float3(input->socket_type), clamp); + return true; + } } else if(!clamp) { bypass(input->link); @@ -121,4 +143,212 @@ bool ConstantFolder::try_bypass_or_make_constant(ShaderInput *input, float3 inpu return false; } +bool ConstantFolder::is_zero(ShaderInput *input) const +{ + if(!input->link) { + if(input->type() == SocketType::FLOAT) { + return node->get_float(input->socket_type) == 0.0f; + } + else if(SocketType::is_float3(input->type())) { + return node->get_float3(input->socket_type) == + make_float3(0.0f, 0.0f, 0.0f); + } + } + + return false; +} + +bool ConstantFolder::is_one(ShaderInput *input) const +{ + if(!input->link) { + if(input->type() == SocketType::FLOAT) { + return node->get_float(input->socket_type) == 1.0f; + } + else if(SocketType::is_float3(input->type())) { + return node->get_float3(input->socket_type) == + make_float3(1.0f, 1.0f, 1.0f); + } + } + + return false; +} + +/* Specific nodes */ + +void ConstantFolder::fold_mix(NodeMix type, bool clamp) const +{ + ShaderInput *fac_in = node->input("Fac"); + ShaderInput *color1_in = node->input("Color1"); + ShaderInput *color2_in = node->input("Color2"); + + float fac = saturate(node->get_float(fac_in->socket_type)); + bool fac_is_zero = !fac_in->link && fac == 0.0f; + bool fac_is_one = !fac_in->link && fac == 1.0f; + + /* remove no-op node when factor is 0.0 */ + if(fac_is_zero) { + /* note that some of the modes will clamp out of bounds values even without use_clamp */ + if(!(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN)) { + if(try_bypass_or_make_constant(color1_in, clamp)) { + return; + } + } + } + + switch(type) { + case NODE_MIX_BLEND: + /* remove useless mix colors nodes */ + if(color1_in->link && color2_in->link) { + if(color1_in->link == color2_in->link) { + try_bypass_or_make_constant(color1_in, clamp); + break; + } + } + else if(!color1_in->link && !color2_in->link) { + float3 color1 = node->get_float3(color1_in->socket_type); + float3 color2 = node->get_float3(color2_in->socket_type); + if(color1 == color2) { + try_bypass_or_make_constant(color1_in, clamp); + break; + } + } + /* remove no-op mix color node when factor is 1.0 */ + if(fac_is_one) { + try_bypass_or_make_constant(color2_in, clamp); + break; + } + break; + case NODE_MIX_ADD: + /* 0 + X (fac 1) == X */ + if(is_zero(color1_in) && fac_is_one) { + try_bypass_or_make_constant(color2_in, clamp); + } + /* X + 0 (fac ?) == X */ + else if(is_zero(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + break; + case NODE_MIX_SUB: + /* X - 0 (fac ?) == X */ + if(is_zero(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + /* X - X (fac 1) == 0 */ + else if(color1_in->link && color1_in->link == color2_in->link && fac_is_one) { + make_zero(); + } + break; + case NODE_MIX_MUL: + /* X * 1 (fac ?) == X, 1 * X (fac 1) == X */ + if(is_one(color1_in) && fac_is_one) { + try_bypass_or_make_constant(color2_in, clamp); + } + else if(is_one(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + /* 0 * ? (fac ?) == 0, ? * 0 (fac 1) == 0 */ + else if(is_zero(color1_in) && fac_is_one) { + make_zero(); + } + else if(is_zero(color2_in)) { + make_zero(); + } + break; + case NODE_MIX_DIV: + /* X / 1 (fac ?) == X */ + if(is_one(color2_in)) { + try_bypass_or_make_constant(color1_in, clamp); + } + /* 0 / ? (fac ?) == 0 */ + else if(is_zero(color1_in)) { + make_zero(); + } + break; + default: + break; + } +} + +void ConstantFolder::fold_math(NodeMath type, bool clamp) const +{ + ShaderInput *value1_in = node->input("Value1"); + ShaderInput *value2_in = node->input("Value2"); + + switch(type) { + case NODE_MATH_ADD: + /* X + 0 == 0 + X == X */ + if(is_zero(value1_in)) { + try_bypass_or_make_constant(value2_in, clamp); + } + else if(is_zero(value2_in)) { + try_bypass_or_make_constant(value1_in, clamp); + } + break; + case NODE_MATH_SUBTRACT: + /* X - 0 == X */ + if(is_zero(value2_in)) { + try_bypass_or_make_constant(value1_in, clamp); + } + break; + case NODE_MATH_MULTIPLY: + /* X * 1 == 1 * X == X */ + if(is_one(value1_in)) { + try_bypass_or_make_constant(value2_in, clamp); + } + else if(is_one(value2_in)) { + try_bypass_or_make_constant(value1_in, clamp); + } + /* X * 0 == 0 * X == 0 */ + else if(is_zero(value1_in) || is_zero(value2_in)) { + make_zero(); + } + break; + case NODE_MATH_DIVIDE: + /* X / 1 == X */ + if(is_one(value2_in)) { + try_bypass_or_make_constant(value1_in, clamp); + } + /* 0 / X == 0 */ + else if(is_zero(value1_in)) { + make_zero(); + } + break; + default: + break; + } +} + +void ConstantFolder::fold_vector_math(NodeVectorMath type) const +{ + ShaderInput *vector1_in = node->input("Vector1"); + ShaderInput *vector2_in = node->input("Vector2"); + + switch(type) { + case NODE_VECTOR_MATH_ADD: + /* X + 0 == 0 + X == X */ + if(is_zero(vector1_in)) { + try_bypass_or_make_constant(vector2_in); + } + else if(is_zero(vector2_in)) { + try_bypass_or_make_constant(vector1_in); + } + break; + case NODE_VECTOR_MATH_SUBTRACT: + /* X - 0 == X */ + if(is_zero(vector2_in)) { + try_bypass_or_make_constant(vector1_in); + } + break; + case NODE_VECTOR_MATH_DOT_PRODUCT: + case NODE_VECTOR_MATH_CROSS_PRODUCT: + /* X * 0 == 0 * X == 0 */ + if(is_zero(vector1_in) || is_zero(vector2_in)) { + make_zero(); + } + break; + default: + break; + } +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/constant_fold.h b/intern/cycles/render/constant_fold.h index 195e5b127e8..2b31c2a5887 100644 --- a/intern/cycles/render/constant_fold.h +++ b/intern/cycles/render/constant_fold.h @@ -18,7 +18,7 @@ #define __CONSTANT_FOLD_H__ #include "util_types.h" -#include "util_vector.h" +#include "svm_types.h" CCL_NAMESPACE_BEGIN @@ -37,11 +37,12 @@ public: bool all_inputs_constant() const; - /* Constant folding helpers, always return true for convenience. */ + /* Constant folding helpers */ void make_constant(float value) const; void make_constant(float3 value) const; void make_constant_clamp(float value, bool clamp) const; void make_constant_clamp(float3 value, bool clamp) const; + void make_zero() const; /* Bypass node, relinking to another output socket. */ void bypass(ShaderOutput *output) const; @@ -51,7 +52,16 @@ public: void bypass_or_discard(ShaderInput *input) const; /* Bypass or make constant, unless we can't due to clamp being true. */ - bool try_bypass_or_make_constant(ShaderInput *input, float3 input_value, bool clamp) const; + bool try_bypass_or_make_constant(ShaderInput *input, bool clamp = false) const; + + /* Test if shader inputs of the current nodes have fixed values. */ + bool is_zero(ShaderInput *input) const; + bool is_one(ShaderInput *input) const; + + /* Specific nodes. */ + void fold_mix(NodeMix type, bool clamp) const; + void fold_math(NodeMath type, bool clamp) const; + void fold_vector_math(NodeVectorMath type) const; }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index b3b010841e9..9009d71da2f 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -3701,44 +3701,11 @@ void MixNode::compile(OSLCompiler& compiler) void MixNode::constant_fold(const ConstantFolder& folder) { - ShaderInput *fac_in = input("Fac"); - ShaderInput *color1_in = input("Color1"); - ShaderInput *color2_in = input("Color2"); - - /* evaluate fully constant node */ if(folder.all_inputs_constant()) { folder.make_constant_clamp(svm_mix(type, fac, color1, color2), use_clamp); - return; } - - /* remove no-op node when factor is 0.0 */ - if(!fac_in->link && fac <= 0.0f) { - /* note that some of the modes will clamp out of bounds values even without use_clamp */ - if(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN) { - if(!color1_in->link) { - folder.make_constant_clamp(svm_mix(type, 0.0f, color1, color1), use_clamp); - return; - } - } - else if(folder.try_bypass_or_make_constant(color1_in, color1, use_clamp)) { - return; - } - } - - if(type == NODE_MIX_BLEND) { - /* remove useless mix colors nodes */ - if(color1_in->link ? (color1_in->link == color2_in->link) : (!color2_in->link && color1 == color2)) { - if(folder.try_bypass_or_make_constant(color1_in, color1, use_clamp)) { - return; - } - } - - /* remove no-op mix color node when factor is 1.0 */ - if(!fac_in->link && fac >= 1.0f) { - if(folder.try_bypass_or_make_constant(color2_in, color2, use_clamp)) { - return; - } - } + else { + folder.fold_mix(type, use_clamp); } } @@ -4624,6 +4591,9 @@ void MathNode::constant_fold(const ConstantFolder& folder) if(folder.all_inputs_constant()) { folder.make_constant_clamp(svm_math(type, value1, value2), use_clamp); } + else { + folder.fold_math(type, use_clamp); + } } void MathNode::compile(SVMCompiler& compiler) @@ -4696,6 +4666,9 @@ void VectorMathNode::constant_fold(const ConstantFolder& folder) folder.make_constant(vector); } } + else { + folder.fold_vector_math(type); + } } void VectorMathNode::compile(SVMCompiler& compiler)