forked from bartvdbraak/blender
Cycles: constant fold add/mul type nodes with known 0 and 1 arguments.
These values often either turn the node into a no-op, or even make it evaluate to 0 no matter what the other input value is, thus allowing deletion of a branch of the node graph that otherwise is not constant. Reviewed By: brecht Differential Revision: https://developer.blender.org/D2085
This commit is contained in:
parent
ea2ebf7a00
commit
1776f75c3b
@ -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,12 +120,21 @@ 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);
|
||||
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);
|
||||
return true;
|
||||
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user