Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Dinges <blender@dingto.org>2015-11-25 15:52:39 +0300
committerThomas Dinges <blender@dingto.org>2015-11-25 15:57:54 +0300
commite796581655ed9a36c263a20e7ed97856fc0f1070 (patch)
tree6e946a9e683c9fb82911eb01f9380b8df1276e26 /intern/cycles/render
parent415b5a43690b3b823506871335281df717309f72 (diff)
Cycles: Refactor of constant fold.
* Move constant folding from nodes to the shader graph. This way it's part of our (later) 4-step optimization process. * Instead of only doing a one level constant fold, we can now do a recursive constant fold, allowing us to simplify shaders much further. Constant folding is implemented for Blackbody, Math and VectorMath nodes. Example (the highlighted nodes are removed before rendering): Before: http://archive.dingto.org/2015/blender/code/one_level_constant_fold.jpg Now: http://archive.dingto.org/2015/blender/code/multi_level_constant_fold.jpg Thanks to Sergey and Brecht for Review! Differential Revision: https://developer.blender.org/D1626
Diffstat (limited to 'intern/cycles/render')
-rw-r--r--intern/cycles/render/graph.cpp44
-rw-r--r--intern/cycles/render/graph.h13
-rw-r--r--intern/cycles/render/nodes.cpp116
-rw-r--r--intern/cycles/render/nodes.h9
4 files changed, 127 insertions, 55 deletions
diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp
index e888cb37137..8468690841d 100644
--- a/intern/cycles/render/graph.cpp
+++ b/intern/cycles/render/graph.cpp
@@ -297,7 +297,7 @@ void ShaderGraph::finalize(Scene *scene,
finalized = true;
}
else if(do_simplify) {
- simplify_nodes(scene);
+ simplify_settings(scene);
}
}
@@ -562,11 +562,44 @@ void ShaderGraph::remove_unneeded_nodes()
}
}
+/* Step 2: Constant folding.
+ * Try to constant fold some nodes, and pipe result directly to
+ * the input socket of connected nodes.
+ */
+void ShaderGraph::constant_fold(set<ShaderNode*>& done, ShaderNode *node)
+{
+ /* Only fold each node once. */
+ if(done.find(node) != done.end())
+ return;
+
+ done.insert(node);
+
+ /* Fold nodes connected to inputs first. */
+ foreach(ShaderInput *in, node->inputs) {
+ if(in->link) {
+ constant_fold(done, in->link->parent);
+ }
+ }
+
+ /* Then fold self. */
+ foreach(ShaderOutput *sock, node->outputs) {
+ float3 optimized_value = make_float3(0.0f, 0.0f, 0.0f);
+
+ if(node->constant_fold(sock, &optimized_value)) {
+ /* Apply optimized value to connected sockets */
+ foreach(ShaderInput *in, sock->links) {
+ in->value = optimized_value;
+ disconnect(in);
+ }
+ }
+ }
+}
+
/* Step 3: Simplification.*/
-void ShaderGraph::simplify_nodes(Scene *scene)
+void ShaderGraph::simplify_settings(Scene *scene)
{
foreach(ShaderNode *node, nodes) {
- node->optimize(scene);
+ node->simplify_settings(scene);
}
}
@@ -607,10 +640,11 @@ void ShaderGraph::clean(Scene *scene)
remove_unneeded_nodes();
/* 2: Constant folding. */
- /* TODO(dingto): Implement */
+ set<ShaderNode*> done;
+ constant_fold(done, output());
/* 3: Simplification. */
- simplify_nodes(scene);
+ simplify_settings(scene);
/* 4: De-duplication. */
/* TODO(dingto): Implement */
diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h
index 6ad40720d4c..17fb75d459f 100644
--- a/intern/cycles/render/graph.h
+++ b/intern/cycles/render/graph.h
@@ -197,7 +197,15 @@ public:
virtual void attributes(Shader *shader, AttributeRequestSet *attributes);
virtual void compile(SVMCompiler& compiler) = 0;
virtual void compile(OSLCompiler& compiler) = 0;
- virtual void optimize(Scene * /*scene*/) {};
+
+ /* ** Node optimization ** */
+ /* Check whether the node can be replaced with single constant. */
+ virtual bool constant_fold(ShaderOutput * /*socket*/, float3 * /*optimized_value*/) { return false; }
+
+ /* Simplify settings used by artists to the ones which are simpler to
+ * evaluate in the kernel but keep the final result unchanged.
+ */
+ virtual void simplify_settings(Scene * /*scene*/) {};
virtual bool has_surface_emission() { return false; }
virtual bool has_surface_transparent() { return false; }
@@ -307,7 +315,8 @@ protected:
void break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack);
void clean(Scene *scene);
- void simplify_nodes(Scene *scene);
+ void simplify_settings(Scene *scene);
+ void constant_fold(set<ShaderNode*>& visited, ShaderNode *node);
void bump_from_displacement();
void refine_bump_nodes();
void default_inputs(bool do_osl);
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index d89e74837c7..2bca8605a90 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -1881,7 +1881,7 @@ GlossyBsdfNode::GlossyBsdfNode()
add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f);
}
-void GlossyBsdfNode::optimize(Scene *scene)
+void GlossyBsdfNode::simplify_settings(Scene *scene)
{
if(distribution_orig == "") {
distribution_orig = distribution;
@@ -1950,7 +1950,7 @@ GlassBsdfNode::GlassBsdfNode()
add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f);
}
-void GlassBsdfNode::optimize(Scene *scene)
+void GlassBsdfNode::simplify_settings(Scene *scene)
{
if(distribution_orig == "") {
distribution_orig = distribution;
@@ -2019,7 +2019,7 @@ RefractionBsdfNode::RefractionBsdfNode()
add_input("IOR", SHADER_SOCKET_FLOAT, 0.3f);
}
-void RefractionBsdfNode::optimize(Scene *scene)
+void RefractionBsdfNode::simplify_settings(Scene *scene)
{
if(distribution_orig == "") {
distribution_orig = distribution;
@@ -3955,6 +3955,21 @@ BlackbodyNode::BlackbodyNode()
add_output("Color", SHADER_SOCKET_COLOR);
}
+bool BlackbodyNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
+{
+ ShaderInput *temperature_in = input("Temperature");
+
+ if(socket == output("Color")) {
+ if(temperature_in->link == NULL) {
+ *optimized_value = svm_math_blackbody_color(temperature_in->value.x);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
void BlackbodyNode::compile(SVMCompiler& compiler)
{
ShaderInput *temperature_in = input("Temperature");
@@ -3962,15 +3977,8 @@ void BlackbodyNode::compile(SVMCompiler& compiler)
compiler.stack_assign(color_out);
- if(temperature_in->link == NULL) {
- float3 color = svm_math_blackbody_color(temperature_in->value.x);
- compiler.add_node(NODE_VALUE_V, color_out->stack_offset);
- compiler.add_node(NODE_VALUE_V, color);
- }
- else {
- compiler.stack_assign(temperature_in);
- compiler.add_node(NODE_BLACKBODY, temperature_in->stack_offset, color_out->stack_offset);
- }
+ compiler.stack_assign(temperature_in);
+ compiler.add_node(NODE_BLACKBODY, temperature_in->stack_offset, color_out->stack_offset);
}
void BlackbodyNode::compile(OSLCompiler& compiler)
@@ -4054,28 +4062,36 @@ static ShaderEnum math_type_init()
ShaderEnum MathNode::type_enum = math_type_init();
-void MathNode::compile(SVMCompiler& compiler)
+bool MathNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
{
ShaderInput *value1_in = input("Value1");
ShaderInput *value2_in = input("Value2");
- ShaderOutput *value_out = output("Value");
- compiler.stack_assign(value_out);
+ if(socket == output("Value")) {
+ /* Optimize math node without links to a single value. */
+ if(value1_in->link == NULL && value2_in->link == NULL) {
+ optimized_value->x = svm_math((NodeMath)type_enum[type],
+ value1_in->value.x,
+ value2_in->value.x);
+
+ if(use_clamp) {
+ optimized_value->x = saturate(optimized_value->x);
+ }
- /* Optimize math node without links to a single value node. */
- if(value1_in->link == NULL && value2_in->link == NULL) {
- float optimized_value = svm_math((NodeMath)type_enum[type],
- value1_in->value.x,
- value2_in->value.x);
- if(use_clamp) {
- optimized_value = saturate(optimized_value);
+ return true;
}
- compiler.add_node(NODE_VALUE_F,
- __float_as_int(optimized_value),
- value_out->stack_offset);
- return;
}
+ return false;
+}
+
+void MathNode::compile(SVMCompiler& compiler)
+{
+ ShaderInput *value1_in = input("Value1");
+ ShaderInput *value2_in = input("Value2");
+ ShaderOutput *value_out = output("Value");
+
+ compiler.stack_assign(value_out);
compiler.stack_assign(value1_in);
compiler.stack_assign(value2_in);
@@ -4124,6 +4140,35 @@ static ShaderEnum vector_math_type_init()
ShaderEnum VectorMathNode::type_enum = vector_math_type_init();
+bool VectorMathNode::constant_fold(ShaderOutput *socket, float3 *optimized_value)
+{
+ ShaderInput *vector1_in = input("Vector1");
+ ShaderInput *vector2_in = input("Vector2");
+
+ float value;
+ float3 vector;
+
+ /* Optimize vector math node without links to a single value node. */
+ if(vector1_in->link == NULL && vector2_in->link == NULL) {
+ svm_vector_math(&value,
+ &vector,
+ (NodeVectorMath)type_enum[type],
+ vector1_in->value,
+ vector2_in->value);
+
+ if(socket == output("Value")) {
+ optimized_value->x = value;
+ return true;
+ }
+ else if (socket == output("Vector")) {
+ *optimized_value = vector;
+ return true;
+ }
+ }
+
+ return false;
+}
+
void VectorMathNode::compile(SVMCompiler& compiler)
{
ShaderInput *vector1_in = input("Vector1");
@@ -4134,25 +4179,6 @@ void VectorMathNode::compile(SVMCompiler& compiler)
compiler.stack_assign(value_out);
compiler.stack_assign(vector_out);
- /* Optimize vector math node without links to a single value node. */
- if(vector1_in->link == NULL && vector2_in->link == NULL) {
- float optimized_value;
- float3 optimized_vector;
- svm_vector_math(&optimized_value,
- &optimized_vector,
- (NodeVectorMath)type_enum[type],
- vector1_in->value,
- vector2_in->value);
-
- compiler.add_node(NODE_VALUE_F,
- __float_as_int(optimized_value),
- value_out->stack_offset);
-
- compiler.add_node(NODE_VALUE_V, vector_out->stack_offset);
- compiler.add_node(NODE_VALUE_V, optimized_vector);
- return;
- }
-
compiler.stack_assign(vector1_in);
compiler.stack_assign(vector2_in);
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 4f4061286cb..259936c0b7c 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -311,7 +311,7 @@ class GlossyBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(GlossyBsdfNode)
- void optimize(Scene *scene);
+ void simplify_settings(Scene *scene);
bool has_integrator_dependency();
ustring distribution, distribution_orig;
@@ -322,7 +322,7 @@ class GlassBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(GlassBsdfNode)
- void optimize(Scene *scene);
+ void simplify_settings(Scene *scene);
bool has_integrator_dependency();
ustring distribution, distribution_orig;
@@ -333,7 +333,7 @@ class RefractionBsdfNode : public BsdfNode {
public:
SHADER_NODE_CLASS(RefractionBsdfNode)
- void optimize(Scene *scene);
+ void simplify_settings(Scene *scene);
bool has_integrator_dependency();
ustring distribution, distribution_orig;
@@ -636,6 +636,7 @@ public:
class BlackbodyNode : public ShaderNode {
public:
SHADER_NODE_CLASS(BlackbodyNode)
+ bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
virtual int get_group() { return NODE_GROUP_LEVEL_3; }
};
@@ -644,6 +645,7 @@ class MathNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MathNode)
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+ bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
bool use_clamp;
@@ -663,6 +665,7 @@ class VectorMathNode : public ShaderNode {
public:
SHADER_NODE_CLASS(VectorMathNode)
virtual int get_group() { return NODE_GROUP_LEVEL_1; }
+ bool constant_fold(ShaderOutput *socket, float3 *optimized_value);
ustring type;
static ShaderEnum type_enum;