[Bf-blender-cvs] [e796581] master: Cycles: Refactor of constant fold.

Thomas Dinges noreply at git.blender.org
Wed Nov 25 13:59:02 CET 2015


Commit: e796581655ed9a36c263a20e7ed97856fc0f1070
Author: Thomas Dinges
Date:   Wed Nov 25 13:52:39 2015 +0100
Branches: master
https://developer.blender.org/rBe796581655ed9a36c263a20e7ed97856fc0f1070

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

===================================================================

M	intern/cycles/render/graph.cpp
M	intern/cycles/render/graph.h
M	intern/cycles/render/nodes.cpp
M	intern/cycles/render/nodes.h

===================================================================

diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp
index e888cb3..8468690 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 6ad4072..17fb75d 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 d89e748..2bca860 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 4f40612..259936c 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_NOD

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list