Cycles: constant folding for RGB/Vector Curves and Color Ramp.
authorAlexander Gavrilov <angavrilov@gmail.com>
Sat, 30 Jul 2016 21:30:36 +0000 (23:30 +0200)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Sun, 31 Jul 2016 00:18:23 +0000 (02:18 +0200)
These are complex nodes, and it's conceivable they may end up constant
in some circumstances within node groups, so folding support is useful.

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D2084

intern/cycles/kernel/CMakeLists.txt
intern/cycles/kernel/shaders/node_ramp_util.h [new file with mode: 0644]
intern/cycles/kernel/shaders/node_rgb_curves.osl
intern/cycles/kernel/shaders/node_rgb_ramp.osl
intern/cycles/kernel/shaders/node_vector_curves.osl
intern/cycles/kernel/svm/svm.h
intern/cycles/kernel/svm/svm_ramp.h
intern/cycles/kernel/svm/svm_ramp_util.h [new file with mode: 0644]
intern/cycles/render/constant_fold.h
intern/cycles/render/nodes.cpp
intern/cycles/render/nodes.h

index 685574e..0d663bb 100644 (file)
@@ -140,6 +140,7 @@ set(SRC_SVM_HEADERS
        svm/svm_noisetex.h
        svm/svm_normal.h
        svm/svm_ramp.h
+       svm/svm_ramp_util.h
        svm/svm_sepcomb_hsv.h
        svm/svm_sepcomb_vector.h
        svm/svm_sky.h
diff --git a/intern/cycles/kernel/shaders/node_ramp_util.h b/intern/cycles/kernel/shaders/node_ramp_util.h
new file mode 100644 (file)
index 0000000..917fb65
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* NOTE: svm_ramp.h, svm_ramp_util.h and node_ramp_util.h must stay consistent */
+
+color rgb_ramp_lookup(color ramp[], float at, int interpolate, int extrapolate)
+{
+       float f = at;
+       int table_size = arraylength(ramp);
+
+       if ((f < 0.0 || f > 1.0) && extrapolate) {
+               color t0, dy;
+               if (f < 0.0) {
+                       t0 = ramp[0];
+                       dy = t0 - ramp[1];
+                       f = -f;
+               }
+               else {
+                       t0 = ramp[table_size - 1];
+                       dy = t0 - ramp[table_size - 2];
+                       f = f - 1.0;
+               }
+               return t0 + dy * f * (table_size - 1);
+       }
+
+       f = clamp(at, 0.0, 1.0) * (table_size - 1);
+
+       /* clamp int as well in case of NaN */
+       int i = (int)f;
+       if (i < 0) i = 0;
+       if (i >= table_size) i = table_size - 1;
+       float t = f - (float)i;
+
+       color result = ramp[i];
+
+       if (interpolate && t > 0.0)
+               result = (1.0 - t) * result + t * ramp[i + 1];
+
+       return result;
+}
+
+float rgb_ramp_lookup(float ramp[], float at, int interpolate, int extrapolate)
+{
+       float f = at;
+       int table_size = arraylength(ramp);
+
+       if ((f < 0.0 || f > 1.0) && extrapolate) {
+               float t0, dy;
+               if (f < 0.0) {
+                       t0 = ramp[0];
+                       dy = t0 - ramp[1];
+                       f = -f;
+               }
+               else {
+                       t0 = ramp[table_size - 1];
+                       dy = t0 - ramp[table_size - 2];
+                       f = f - 1.0;
+               }
+               return t0 + dy * f * (table_size - 1);
+       }
+
+       f = clamp(at, 0.0, 1.0) * (table_size - 1);
+
+       /* clamp int as well in case of NaN */
+       int i = (int)f;
+       if (i < 0) i = 0;
+       if (i >= table_size) i = table_size - 1;
+       float t = f - (float)i;
+
+       float result = ramp[i];
+
+       if (interpolate && t > 0.0)
+               result = (1.0 - t) * result + t * ramp[i + 1];
+       
+       return result;
+}
index 8e208e8..c8e7e4f 100644 (file)
  * limitations under the License.
  */
 
-#include "stdosl.h"
-#include "oslutil.h"
-
-float ramp_lookup(color ramp[], float at, int component)
-{
-       int table_size = arraylength(ramp);
-
-       if (at < 0.0 || at > 1.0) {
-               float t0, dy;
-               if (at < 0.0) {
-                       t0 = ramp[0][component];
-                       dy = t0 - ramp[1][component];
-                       at = -at;
-               }
-               else {
-                       t0 = ramp[table_size - 1][component];
-                       dy = t0 - ramp[table_size - 2][component];
-                       at = at - 1.0;
-               }
-               return t0 + dy * at * (table_size - 1);
-       }
-
-       float f = clamp(at, 0.0, 1.0) * (table_size - 1);
-
-       /* clamp int as well in case of NaN */
-       int i = (int)f;
-       if (i < 0) i = 0;
-       if (i >= table_size) i = table_size - 1;
-       float t = f - (float)i;
-
-       float result = ramp[i][component];
-
-       if (t > 0.0)
-               result = (1.0 - t) * result + t * ramp[i + 1][component];
-       
-       return result;
-}
+#include "node_ramp_util.h"
 
 shader node_rgb_curves(
        color ramp[] = {0.0},
@@ -63,9 +27,13 @@ shader node_rgb_curves(
 {
        color c = (ColorIn - color(min_x, min_x, min_x)) / (max_x - min_x);
 
-       ColorOut[0] = ramp_lookup(ramp, c[0], 0);
-       ColorOut[1] = ramp_lookup(ramp, c[1], 1);
-       ColorOut[2] = ramp_lookup(ramp, c[2], 2);
+       color r = rgb_ramp_lookup(ramp, c[0], 1, 1);
+       color g = rgb_ramp_lookup(ramp, c[0], 1, 1);
+       color b = rgb_ramp_lookup(ramp, c[0], 1, 1);
+
+       ColorOut[0] = r[0];
+       ColorOut[1] = g[1];
+       ColorOut[2] = b[2];
 
        ColorOut = mix(ColorIn, ColorOut, Fac);
 }
index c0ae74d..24b8728 100644 (file)
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#include "stdosl.h"
-#include "oslutil.h"
+#include "node_ramp_util.h"
 
 shader node_rgb_ramp(
        color ramp_color[] = {0.0},
@@ -26,21 +25,7 @@ shader node_rgb_ramp(
        output color Color = 0.0,
        output float Alpha = 1.0)
 {
-       int table_size = arraylength(ramp_color);
-       float f = clamp(Fac, 0.0, 1.0) * (table_size - 1);
-
-       /* clamp int as well in case of NaN */
-       int i = (int)f;
-       if (i < 0) i = 0;
-       if (i >= table_size) i = table_size - 1;
-       float t = f - (float)i;
-
-       Color = ramp_color[i];
-       Alpha = ramp_alpha[i];
-
-       if (interpolate && t > 0.0) {
-               Color = (1.0 - t) * Color + t * ramp_color[i + 1];
-               Alpha = (1.0 - t) * Alpha + t * ramp_alpha[i + 1];
-       }
+       Color = rgb_ramp_lookup(ramp_color, Fac, interpolate, 0);
+       Alpha = rgb_ramp_lookup(ramp_alpha, Fac, interpolate, 0);
 }
 
index cff4efe..d92fa11 100644 (file)
  * limitations under the License.
  */
 
-#include "stdosl.h"
-#include "oslutil.h"
-
-float ramp_lookup(color ramp[], float at, int component)
-{
-       int table_size = arraylength(ramp);
-
-       if (at < 0.0 || at > 1.0) {
-               float t0, dy;
-               if (at < 0.0) {
-                       t0 = ramp[0][component];
-                       dy = t0 - ramp[1][component];
-                       at = -at;
-               }
-               else {
-                       t0 = ramp[table_size - 1][component];
-                       dy = t0 - ramp[table_size - 2][component];
-                       at = at - 1.0;
-               }
-               return t0 + dy * at * (table_size - 1);
-       }
-
-       float f = clamp(at, 0.0, 1.0) * (table_size - 1);
-
-       /* clamp int as well in case of NaN */
-       int i = (int)f;
-       if (i < 0) i = 0;
-       if (i >= table_size) i = table_size - 1;
-       float t = f - (float)i;
-
-       float result = ramp[i][component];
-
-       if (t > 0.0)
-               result = (1.0 - t) * result + t * ramp[i + 1][component];
-       
-       return result;
-}
+#include "node_ramp_util.h"
 
 shader node_vector_curves(
        color ramp[] = {0.0},
@@ -63,9 +27,13 @@ shader node_vector_curves(
 {
        vector c = (VectorIn - vector(min_x, min_x, min_x)) / (max_x - min_x);
 
-       VectorOut[0] = ramp_lookup(ramp, c[0], 0);
-       VectorOut[1] = ramp_lookup(ramp, c[1], 1);
-       VectorOut[2] = ramp_lookup(ramp, c[2], 2);
+       color r = rgb_ramp_lookup(ramp, c[0], 1, 1);
+       color g = rgb_ramp_lookup(ramp, c[0], 1, 1);
+       color b = rgb_ramp_lookup(ramp, c[0], 1, 1);
+
+       VectorOut[0] = r[0];
+       VectorOut[1] = g[1];
+       VectorOut[2] = b[2];
 
        VectorOut = mix(VectorIn, VectorOut, Fac);
 }
index de7e03e..502994e 100644 (file)
@@ -405,10 +405,8 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ccl_a
 
 #if NODES_GROUP(NODE_GROUP_LEVEL_3)
                        case NODE_RGB_CURVES:
-                               svm_node_rgb_curves(kg, sd, stack, node, &offset);
-                               break;
                        case NODE_VECTOR_CURVES:
-                               svm_node_vector_curves(kg, sd, stack, node, &offset);
+                               svm_node_curves(kg, sd, stack, node, &offset);
                                break;
                        case NODE_TANGENT:
                                svm_node_tangent(kg, sd, stack, node);
index 24275d0..f959d90 100644 (file)
@@ -19,6 +19,8 @@
 
 CCL_NAMESPACE_BEGIN
 
+/* NOTE: svm_ramp.h, svm_ramp_util.h and node_ramp_util.h must stay consistent */
+
 ccl_device float4 rgb_ramp_lookup(KernelGlobals *kg,
                                   int offset,
                                   float f,
@@ -75,36 +77,7 @@ ccl_device void svm_node_rgb_ramp(KernelGlobals *kg, ShaderData *sd, float *stac
        *offset += table_size;
 }
 
-ccl_device void svm_node_rgb_curves(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
-{
-       uint fac_offset, color_offset, out_offset;
-       decode_node_uchar4(node.y,
-                          &fac_offset,
-                          &color_offset,
-                          &out_offset,
-                          NULL);
-
-       uint table_size = read_node(kg, offset).x;
-
-       float fac = stack_load_float(stack, fac_offset);
-       float3 color = stack_load_float3(stack, color_offset);
-
-       const float min_x = __int_as_float(node.z),
-                   max_x = __int_as_float(node.w);
-       const float range_x = max_x - min_x;
-       const float3 relpos = (color - make_float3(min_x, min_x, min_x)) / range_x;
-
-       float r = rgb_ramp_lookup(kg, *offset, relpos.x, true, true, table_size).x;
-       float g = rgb_ramp_lookup(kg, *offset, relpos.y, true, true, table_size).y;
-       float b = rgb_ramp_lookup(kg, *offset, relpos.z, true, true, table_size).z;
-
-       color = (1.0f - fac)*color + fac*make_float3(r, g, b);
-       stack_store_float3(stack, out_offset, color);
-
-       *offset += table_size;
-}
-
-ccl_device void svm_node_vector_curves(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
+ccl_device void svm_node_curves(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
 {
        uint fac_offset, color_offset, out_offset;
        decode_node_uchar4(node.y,
diff --git a/intern/cycles/kernel/svm/svm_ramp_util.h b/intern/cycles/kernel/svm/svm_ramp_util.h
new file mode 100644 (file)
index 0000000..495d98c
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SVM_RAMP_UTIL_H__
+#define __SVM_RAMP_UTIL_H__
+
+CCL_NAMESPACE_BEGIN
+
+/* NOTE: svm_ramp.h, svm_ramp_util.h and node_ramp_util.h must stay consistent */
+
+ccl_device float3 rgb_ramp_lookup(const float3 *ramp,
+                                  float f,
+                                  bool interpolate,
+                                  bool extrapolate,
+                                  int table_size)
+{
+       if ((f < 0.0f || f > 1.0f) && extrapolate) {
+               float3 t0, dy;
+               if (f < 0.0f) {
+                       t0 = ramp[0];
+                       dy = t0 - ramp[1],
+                       f = -f;
+               }
+               else {
+                       t0 = ramp[table_size - 1];
+                       dy = t0 - ramp[table_size - 2];
+                       f = f - 1.0f;
+               }
+               return t0 + dy * f * (table_size - 1);
+       }
+
+       f = clamp(f, 0.0f, 1.0f) * (table_size - 1);
+
+       /* clamp int as well in case of NaN */
+       int i = clamp(float_to_int(f), 0, table_size-1);
+       float t = f - (float)i;
+
+       float3 result = ramp[i];
+
+       if (interpolate && t > 0.0f)
+               result = (1.0f - t) * result + t * ramp[i + 1];
+
+       return result;
+}
+
+ccl_device float float_ramp_lookup(const float *ramp,
+                                   float f,
+                                   bool interpolate,
+                                   bool extrapolate,
+                                   int table_size)
+{
+       if ((f < 0.0f || f > 1.0f) && extrapolate) {
+               float t0, dy;
+               if (f < 0.0f) {
+                       t0 = ramp[0];
+                       dy = t0 - ramp[1],
+                       f = -f;
+               }
+               else {
+                       t0 = ramp[table_size - 1];
+                       dy = t0 - ramp[table_size - 2];
+                       f = f - 1.0f;
+               }
+               return t0 + dy * f * (table_size - 1);
+       }
+
+       f = clamp(f, 0.0f, 1.0f) * (table_size - 1);
+
+       /* clamp int as well in case of NaN */
+       int i = clamp(float_to_int(f), 0, table_size-1);
+       float t = f - (float)i;
+
+       float result = ramp[i];
+
+       if (interpolate && t > 0.0f)
+               result = (1.0f - t) * result + t * ramp[i + 1];
+
+       return result;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __SVM_RAMP_UTIL_H__ */
+
index 978c8e5..195e5b1 100644 (file)
@@ -18,6 +18,7 @@
 #define __CONSTANT_FOLD_H__
 
 #include "util_types.h"
+#include "util_vector.h"
 
 CCL_NAMESPACE_BEGIN
 
index 3af6a71..b3b0108 100644 (file)
@@ -20,6 +20,7 @@
 #include "scene.h"
 #include "svm.h"
 #include "svm_color_util.h"
+#include "svm_ramp_util.h"
 #include "svm_math_util.h"
 #include "osl.h"
 #include "constant_fold.h"
@@ -4855,6 +4856,30 @@ CurvesNode::CurvesNode(const NodeType *node_type)
 {
 }
 
+void CurvesNode::constant_fold(const ConstantFolder& folder, ShaderInput *value_in)
+{
+       ShaderInput *fac_in = input("Fac");
+
+       /* remove no-op node */
+       if(!fac_in->link && fac == 0.0f) {
+               folder.bypass(value_in->link);
+       }
+       /* evaluate fully constant node */
+       else if(folder.all_inputs_constant()) {
+               if (curves.size() == 0)
+                       return;
+
+               float3 pos = (value - make_float3(min_x, min_x, min_x)) / (max_x - min_x);
+               float3 result;
+
+               result[0] = rgb_ramp_lookup(curves.data(), pos[0], true, true, curves.size()).x;
+               result[1] = rgb_ramp_lookup(curves.data(), pos[1], true, true, curves.size()).y;
+               result[2] = rgb_ramp_lookup(curves.data(), pos[2], true, true, curves.size()).z;
+
+               folder.make_constant(interp(value, result, fac));
+       }
+}
+
 void CurvesNode::compile(SVMCompiler& compiler, int type, ShaderInput *value_in, ShaderOutput *value_out)
 {
        if(curves.size() == 0)
@@ -4918,6 +4943,11 @@ RGBCurvesNode::RGBCurvesNode()
 {
 }
 
+void RGBCurvesNode::constant_fold(const ConstantFolder& folder)
+{
+       CurvesNode::constant_fold(folder, input("Color"));
+}
+
 void RGBCurvesNode::compile(SVMCompiler& compiler)
 {
        CurvesNode::compile(compiler, NODE_RGB_CURVES, input("Color"), output("Color"));
@@ -4951,6 +4981,11 @@ VectorCurvesNode::VectorCurvesNode()
 {
 }
 
+void VectorCurvesNode::constant_fold(const ConstantFolder& folder)
+{
+       CurvesNode::constant_fold(folder, input("Vector"));
+}
+
 void VectorCurvesNode::compile(SVMCompiler& compiler)
 {
        CurvesNode::compile(compiler, NODE_VECTOR_CURVES, input("Vector"), output("Vector"));
@@ -4984,6 +5019,31 @@ RGBRampNode::RGBRampNode()
 {
 }
 
+void RGBRampNode::constant_fold(const ConstantFolder& folder)
+{
+       if(ramp.size() == 0 || ramp.size() != ramp_alpha.size())
+               return;
+
+       if(folder.all_inputs_constant()) {
+               float f = clamp(fac, 0.0f, 1.0f) * (ramp.size() - 1);
+
+               /* clamp int as well in case of NaN */
+               int i = clamp((int)f, 0, ramp.size()-1);
+               float t = f - (float)i;
+
+               bool use_lerp = interpolate && t > 0.0f;
+
+               if(folder.output == output("Color")) {
+                       float3 color = rgb_ramp_lookup(ramp.data(), fac, use_lerp, false, ramp.size());
+                       folder.make_constant(color);
+               }
+               else if(folder.output == output("Alpha")) {
+                       float alpha = float_ramp_lookup(ramp_alpha.data(), fac, use_lerp, false, ramp_alpha.size());
+                       folder.make_constant(alpha);
+               }
+       }
+}
+
 void RGBRampNode::compile(SVMCompiler& compiler)
 {
        if(ramp.size() == 0 || ramp.size() != ramp_alpha.size())
index 28b40ba..b0eb239 100644 (file)
@@ -889,28 +889,32 @@ public:
 
        virtual int get_group() { return NODE_GROUP_LEVEL_3; }
 
-       bool has_spatial_varying() { return true; }
-       void compile(SVMCompiler& compiler, int type, ShaderInput *value_in, ShaderOutput *value_out);
-       void compile(OSLCompiler& compiler, const char *name);
-
        array<float3> curves;
        float min_x, max_x, fac;
        float3 value;
+
+protected:
+       void constant_fold(const ConstantFolder& folder, ShaderInput *value_in);
+       void compile(SVMCompiler& compiler, int type, ShaderInput *value_in, ShaderOutput *value_out);
+       void compile(OSLCompiler& compiler, const char *name);
 };
 
 class RGBCurvesNode : public CurvesNode {
 public:
        SHADER_NODE_CLASS(RGBCurvesNode)
+       void constant_fold(const ConstantFolder& folder);
 };
 
 class VectorCurvesNode : public CurvesNode {
 public:
        SHADER_NODE_CLASS(VectorCurvesNode)
+       void constant_fold(const ConstantFolder& folder);
 };
 
 class RGBRampNode : public ShaderNode {
 public:
        SHADER_NODE_CLASS(RGBRampNode)
+       void constant_fold(const ConstantFolder& folder);
        virtual int get_group() { return NODE_GROUP_LEVEL_1; }
 
        array<float3> ramp;