diff options
-rw-r--r-- | intern/cycles/render/constant_fold.cpp | 10 | ||||
-rw-r--r-- | intern/cycles/test/CMakeLists.txt | 2 | ||||
-rw-r--r-- | intern/cycles/test/render_graph_finalize_test.cpp | 1320 |
3 files changed, 1323 insertions, 9 deletions
diff --git a/intern/cycles/render/constant_fold.cpp b/intern/cycles/render/constant_fold.cpp index 073bafce98d..200a4c497cd 100644 --- a/intern/cycles/render/constant_fold.cpp +++ b/intern/cycles/render/constant_fold.cpp @@ -40,7 +40,8 @@ bool ConstantFolder::all_inputs_constant() const void ConstantFolder::make_constant(float value) const { - VLOG(1) << "Replacing " << node->name << " with constant " << value << "."; + VLOG(1) << "Folding " << node->name << "::" << output->name() << " to constant (" << value << ")."; + foreach(ShaderInput *sock, output->links) { sock->set(value); } @@ -50,6 +51,8 @@ void ConstantFolder::make_constant(float value) const void ConstantFolder::make_constant(float3 value) const { + VLOG(1) << "Folding " << node->name << "::" << output->name() << " to constant " << value << "."; + foreach(ShaderInput *sock, output->links) { sock->set(value); } @@ -90,6 +93,8 @@ void ConstantFolder::bypass(ShaderOutput *new_output) const { assert(new_output); + VLOG(1) << "Folding " << node->name << "::" << output->name() << " to socket " << new_output->parent->name << "::" << new_output->name() << "."; + /* Remove all outgoing links from socket and connect them to new_output instead. * The graph->relink method affects node inputs, so it's not safe to use in constant * folding if the node has multiple outputs and will thus be folded multiple times. */ @@ -105,6 +110,9 @@ void ConstantFolder::bypass(ShaderOutput *new_output) const void ConstantFolder::discard() const { assert(output->type() == SocketType::CLOSURE); + + VLOG(1) << "Discarding closure " << node->name << "."; + graph->disconnect(output); } diff --git a/intern/cycles/test/CMakeLists.txt b/intern/cycles/test/CMakeLists.txt index a6bcf980df2..80fe893826a 100644 --- a/intern/cycles/test/CMakeLists.txt +++ b/intern/cycles/test/CMakeLists.txt @@ -26,12 +26,12 @@ set(ALL_CYCLES_LIBRARIES cycles_device cycles_bvh cycles_graph - cycles_kernel_osl cycles_util ${OPENIMAGEIO_LIBRARIES} ) if(WITH_CYCLES_OSL) list(APPEND ALL_CYCLES_LIBRARIES + cycles_kernel_osl ${OSL_LIBRARIES} ${LLVM_LIBRARIES} ) diff --git a/intern/cycles/test/render_graph_finalize_test.cpp b/intern/cycles/test/render_graph_finalize_test.cpp index 4566894d490..e329384021a 100644 --- a/intern/cycles/test/render_graph_finalize_test.cpp +++ b/intern/cycles/test/render_graph_finalize_test.cpp @@ -40,6 +40,7 @@ public: : name_(name) { node_ = new T(); + node_->name = name; } const string& name() const { @@ -59,6 +60,13 @@ public: return *this; } + template<typename T2, typename V> + ShaderNodeBuilder& set(V T2::*pfield, V value) + { + static_cast<T*>(node_)->*pfield = value; + return *this; + } + protected: string name_; ShaderNode *node_; @@ -69,6 +77,7 @@ public: explicit ShaderGraphBuilder(ShaderGraph *graph) : graph_(graph) { + node_map_["Output"] = graph->output(); } ShaderNode *find_node(const string& name) @@ -110,6 +119,27 @@ public: return *this; } + /* Common input/output boilerplate. */ + ShaderGraphBuilder& add_attribute(const string &name) + { + return (*this) + .add_node(ShaderNodeBuilder<AttributeNode>(name) + .set(&AttributeNode::attribute, ustring(name))); + } + + ShaderGraphBuilder& output_closure(const string& from) + { + return (*this).add_connection(from, "Output::Surface"); + } + + ShaderGraphBuilder& output_color(const string& from) + { + return (*this) + .add_node(ShaderNodeBuilder<EmissionNode>("EmissionNode")) + .add_connection(from, "EmissionNode::Color") + .output_closure("EmissionNode::Emission"); + } + protected: ShaderGraph *graph_; map<string, ShaderNode *> node_map_; @@ -127,21 +157,1297 @@ protected: ShaderGraph graph; \ ShaderGraphBuilder builder(&graph); \ +#define EXPECT_ANY_MESSAGE(log) \ + EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); \ + +#define CORRECT_INFO_MESSAGE(log, message) \ + EXPECT_CALL(log, Log(google::INFO, _, HasSubstr(message))); + +#define INVALID_INFO_MESSAGE(log, message) \ + EXPECT_CALL(log, Log(google::INFO, _, HasSubstr(message))).Times(0); + +/* + * Test deduplication of nodes that have inputs, some of them folded. + */ +TEST(render_graph, deduplicate_deep) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding Value1::Value to constant (0.8)."); + CORRECT_INFO_MESSAGE(log, "Folding Value2::Value to constant (0.8)."); + + builder + .add_node(ShaderNodeBuilder<GeometryNode>("Geometry1")) + .add_node(ShaderNodeBuilder<GeometryNode>("Geometry2")) + .add_node(ShaderNodeBuilder<ValueNode>("Value1") + .set(&ValueNode::value, 0.8f)) + .add_node(ShaderNodeBuilder<ValueNode>("Value2") + .set(&ValueNode::value, 0.8f)) + .add_node(ShaderNodeBuilder<NoiseTextureNode>("Noise1")) + .add_node(ShaderNodeBuilder<NoiseTextureNode>("Noise2")) + .add_node(ShaderNodeBuilder<MixNode>("Mix") + .set(&MixNode::type, NODE_MIX_BLEND) + .set("Fac", 0.5f)) + .add_connection("Geometry1::Parametric", "Noise1::Vector") + .add_connection("Value1::Value", "Noise1::Scale") + .add_connection("Noise1::Color", "Mix::Color1") + .add_connection("Geometry2::Parametric", "Noise2::Vector") + .add_connection("Value2::Value", "Noise2::Scale") + .add_connection("Noise2::Color", "Mix::Color2") + .output_color("Mix::Color"); + + graph.finalize(&scene); + + EXPECT_EQ(graph.nodes.size(), 5); +} + +/* + * Test RGB to BW node. + */ TEST(render_graph, constant_fold_rgb_to_bw) { DEFINE_COMMON_VARIABLES(builder, log); - EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); - EXPECT_CALL(log, Log(google::INFO, _, - HasSubstr("Replacing rgb_to_bw with constant 0.8."))); + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding RGBToBWNodeNode::Val to constant (0.8)."); + CORRECT_INFO_MESSAGE(log, "Folding convert_float_to_color::value_color to constant (0.8, 0.8, 0.8)."); builder - .add_node(ShaderNodeBuilder<OutputNode>("OutputNode")) - .add_node(ShaderNodeBuilder<EmissionNode>("EmissionNode")) .add_node(ShaderNodeBuilder<RGBToBWNode>("RGBToBWNodeNode") .set("Color", make_float3(0.8f, 0.8f, 0.8f))) - .add_connection("RGBToBWNodeNode::Val", "EmissionNode::Color") - .add_connection("EmissionNode::Emission", "OutputNode::Surface"); + .output_color("RGBToBWNodeNode::Val"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - folding of Emission nodes that don't emit to nothing. + */ +TEST(render_graph, constant_fold_emission1) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Discarding closure Emission."); + + builder + .add_node(ShaderNodeBuilder<EmissionNode>("Emission") + .set("Color", make_float3(0.0f, 0.0f, 0.0f))) + .output_closure("Emission::Emission"); + + graph.finalize(&scene); +} + +TEST(render_graph, constant_fold_emission2) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Discarding closure Emission."); + + builder + .add_node(ShaderNodeBuilder<EmissionNode>("Emission") + .set("Strength", 0.0f)) + .output_closure("Emission::Emission"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - folding of Background nodes that don't emit to nothing. + */ +TEST(render_graph, constant_fold_background1) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Discarding closure Background."); + + builder + .add_node(ShaderNodeBuilder<BackgroundNode>("Background") + .set("Color", make_float3(0.0f, 0.0f, 0.0f))) + .output_closure("Background::Background"); + + graph.finalize(&scene); +} + +TEST(render_graph, constant_fold_background2) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Discarding closure Background."); + + builder + .add_node(ShaderNodeBuilder<BackgroundNode>("Background") + .set("Strength", 0.0f)) + .output_closure("Background::Background"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - Folding of Add Closure with only one input. + */ +TEST(render_graph, constant_fold_shader_add) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding AddClosure1::Closure to socket Diffuse::BSDF."); + CORRECT_INFO_MESSAGE(log, "Folding AddClosure2::Closure to socket Diffuse::BSDF."); + INVALID_INFO_MESSAGE(log, "Folding AddClosure3"); + + builder + .add_node(ShaderNodeBuilder<DiffuseBsdfNode>("Diffuse")) + .add_node(ShaderNodeBuilder<AddClosureNode>("AddClosure1")) + .add_node(ShaderNodeBuilder<AddClosureNode>("AddClosure2")) + .add_node(ShaderNodeBuilder<AddClosureNode>("AddClosure3")) + .add_connection("Diffuse::BSDF", "AddClosure1::Closure1") + .add_connection("Diffuse::BSDF", "AddClosure2::Closure2") + .add_connection("AddClosure1::Closure", "AddClosure3::Closure1") + .add_connection("AddClosure2::Closure", "AddClosure3::Closure2") + .output_closure("AddClosure3::Closure"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - Folding of Mix Closure with 0 or 1 fac. + * - Folding of Mix Closure with both inputs folded to the same node. + */ +TEST(render_graph, constant_fold_shader_mix) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding MixClosure1::Closure to socket Diffuse::BSDF."); + CORRECT_INFO_MESSAGE(log, "Folding MixClosure2::Closure to socket Diffuse::BSDF."); + CORRECT_INFO_MESSAGE(log, "Folding MixClosure3::Closure to socket Diffuse::BSDF."); + + builder + .add_attribute("Attribute") + .add_node(ShaderNodeBuilder<DiffuseBsdfNode>("Diffuse")) + /* choose left */ + .add_node(ShaderNodeBuilder<MixClosureNode>("MixClosure1") + .set("Fac", 0.0f)) + .add_connection("Diffuse::BSDF", "MixClosure1::Closure1") + /* choose right */ + .add_node(ShaderNodeBuilder<MixClosureNode>("MixClosure2") + .set("Fac", 1.0f)) + .add_connection("Diffuse::BSDF", "MixClosure2::Closure2") + /* both inputs folded the same */ + .add_node(ShaderNodeBuilder<MixClosureNode>("MixClosure3")) + .add_connection("Attribute::Fac", "MixClosure3::Fac") + .add_connection("MixClosure1::Closure", "MixClosure3::Closure1") + .add_connection("MixClosure2::Closure", "MixClosure3::Closure2") + .output_closure("MixClosure3::Closure"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - Folding of Invert with all constant inputs. + */ +TEST(render_graph, constant_fold_invert) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding Invert::Color to constant (0.68, 0.5, 0.32)."); + + builder + .add_node(ShaderNodeBuilder<InvertNode>("Invert") + .set("Fac", 0.8f) + .set("Color", make_float3(0.2f, 0.5f, 0.8f))) + .output_color("Invert::Color"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - Folding of Invert with zero Fac. + */ +TEST(render_graph, constant_fold_invert_fac_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding Invert::Color to socket Attribute::Color."); + + builder + .add_attribute("Attribute") + .add_node(ShaderNodeBuilder<InvertNode>("Invert") + .set("Fac", 0.0f)) + .add_connection("Attribute::Color", "Invert::Color") + .output_color("Invert::Color"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - Folding of MixRGB Add with all constant inputs (clamp false). + */ +TEST(render_graph, constant_fold_mix_add) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding MixAdd::Color to constant (0.62, 1.14, 1.42)."); + + builder + .add_node(ShaderNodeBuilder<MixNode>("MixAdd") + .set(&MixNode::type, NODE_MIX_ADD) + .set(&MixNode::use_clamp, false) + .set("Fac", 0.8f) + .set("Color1", make_float3(0.3, 0.5, 0.7)) + .set("Color2", make_float3(0.4, 0.8, 0.9))) + .output_color("MixAdd::Color"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - Folding of MixRGB Add with all constant inputs (clamp true). + */ +TEST(render_graph, constant_fold_mix_add_clamp) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding MixAdd::Color to constant (0.62, 1, 1)."); + + builder + .add_node(ShaderNodeBuilder<MixNode>("MixAdd") + .set(&MixNode::type, NODE_MIX_ADD) + .set(&MixNode::use_clamp, true) + .set("Fac", 0.8f) + .set("Color1", make_float3(0.3, 0.5, 0.7)) + .set("Color2", make_float3(0.4, 0.8, 0.9))) + .output_color("MixAdd::Color"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - No folding on fac 0 for dodge. + */ +TEST(render_graph, constant_fold_part_mix_dodge_no_fac_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + INVALID_INFO_MESSAGE(log, "Folding "); + + builder + .add_attribute("Attribute1") + .add_attribute("Attribute2") + .add_node(ShaderNodeBuilder<MixNode>("Mix") + .set(&MixNode::type, NODE_MIX_DODGE) + .set(&MixNode::use_clamp, false) + .set("Fac", 0.0f)) + .add_connection("Attribute1::Color", "Mix::Color1") + .add_connection("Attribute2::Color", "Mix::Color2") + .output_color("Mix::Color"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - No folding on fac 0 for light. + */ +TEST(render_graph, constant_fold_part_mix_light_no_fac_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + INVALID_INFO_MESSAGE(log, "Folding "); + + builder + .add_attribute("Attribute1") + .add_attribute("Attribute2") + .add_node(ShaderNodeBuilder<MixNode>("Mix") + .set(&MixNode::type, NODE_MIX_LIGHT) + .set(&MixNode::use_clamp, false) + .set("Fac", 0.0f)) + .add_connection("Attribute1::Color", "Mix::Color1") + .add_connection("Attribute2::Color", "Mix::Color2") + .output_color("Mix::Color"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - No folding on fac 0 for burn. + */ +TEST(render_graph, constant_fold_part_mix_burn_no_fac_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + INVALID_INFO_MESSAGE(log, "Folding "); + + builder + .add_attribute("Attribute1") + .add_attribute("Attribute2") + .add_node(ShaderNodeBuilder<MixNode>("Mix") + .set(&MixNode::type, NODE_MIX_BURN) + .set(&MixNode::use_clamp, false) + .set("Fac", 0.0f)) + .add_connection("Attribute1::Color", "Mix::Color1") + .add_connection("Attribute2::Color", "Mix::Color2") + .output_color("Mix::Color"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - No folding on fac 0 for clamped blend. + */ +TEST(render_graph, constant_fold_part_mix_blend_clamped_no_fac_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + INVALID_INFO_MESSAGE(log, "Folding "); + + builder + .add_attribute("Attribute1") + .add_attribute("Attribute2") + .add_node(ShaderNodeBuilder<MixNode>("Mix") + .set(&MixNode::type, NODE_MIX_BLEND) + .set(&MixNode::use_clamp, true) + .set("Fac", 0.0f)) + .add_connection("Attribute1::Color", "Mix::Color1") + .add_connection("Attribute2::Color", "Mix::Color2") + .output_color("Mix::Color"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - Folding of Mix with 0 or 1 Fac. + * - Folding of Mix with both inputs folded to the same node. + */ +TEST(render_graph, constant_fold_part_mix_blend) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding MixBlend1::Color to socket Attribute1::Color."); + CORRECT_INFO_MESSAGE(log, "Folding MixBlend2::Color to socket Attribute1::Color."); + CORRECT_INFO_MESSAGE(log, "Folding MixBlend3::Color to socket Attribute1::Color."); + + builder + .add_attribute("Attribute1") + .add_attribute("Attribute2") + /* choose left */ + .add_node(ShaderNodeBuilder<MixNode>("MixBlend1") + .set(&MixNode::type, NODE_MIX_BLEND) + .set(&MixNode::use_clamp, false) + .set("Fac", 0.0f)) + .add_connection("Attribute1::Color", "MixBlend1::Color1") + .add_connection("Attribute2::Color", "MixBlend1::Color2") + /* choose right */ + .add_node(ShaderNodeBuilder<MixNode>("MixBlend2") + .set(&MixNode::type, NODE_MIX_BLEND) + .set(&MixNode::use_clamp, false) + .set("Fac", 1.0f)) + .add_connection("Attribute1::Color", "MixBlend2::Color2") + .add_connection("Attribute2::Color", "MixBlend2::Color1") + /* both inputs folded to Attribute1 */ + .add_node(ShaderNodeBuilder<MixNode>("MixBlend3") + .set(&MixNode::type, NODE_MIX_BLEND) + .set(&MixNode::use_clamp, false)) + .add_connection("Attribute1::Fac", "MixBlend3::Fac") + .add_connection("MixBlend1::Color", "MixBlend3::Color1") + .add_connection("MixBlend2::Color", "MixBlend3::Color2") + .output_color("MixBlend3::Color"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - NOT folding of MixRGB Sub with the same inputs and fac NOT 1. + */ +TEST(render_graph, constant_fold_part_mix_sub_same_fac_bad) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + INVALID_INFO_MESSAGE(log, "Folding Mix::"); + + builder + .add_attribute("Attribute") + .add_node(ShaderNodeBuilder<MixNode>("Mix") + .set(&MixNode::type, NODE_MIX_SUB) + .set(&MixNode::use_clamp, true) + .set("Fac", 0.5f)) + .add_connection("Attribute::Color", "Mix::Color1") + .add_connection("Attribute::Color", "Mix::Color2") + .output_color("Mix::Color"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - Folding of MixRGB Sub with the same inputs and fac 1. + */ +TEST(render_graph, constant_fold_part_mix_sub_same_fac_1) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding Mix::Color to constant (0, 0, 0)."); + + builder + .add_attribute("Attribute") + .add_node(ShaderNodeBuilder<MixNode>("Mix") + .set(&MixNode::type, NODE_MIX_SUB) + .set(&MixNode::use_clamp, true) + .set("Fac", 1.0f)) + .add_connection("Attribute::Color", "Mix::Color1") + .add_connection("Attribute::Color", "Mix::Color2") + .output_color("Mix::Color"); + + graph.finalize(&scene); +} + +/* + * Graph for testing partial folds of MixRGB with one constant argument. + * Includes 4 tests: constant on each side with fac either unknown or 1. + */ +static void build_mix_partial_test_graph(ShaderGraphBuilder &builder, NodeMix type, float3 constval) +{ + builder + .add_attribute("Attribute") + /* constant on the left */ + .add_node(ShaderNodeBuilder<MixNode>("Mix_Cx_Fx") + .set(&MixNode::type, type) + .set(&MixNode::use_clamp, false) + .set("Color1", constval)) + .add_node(ShaderNodeBuilder<MixNode>("Mix_Cx_F1") + .set(&MixNode::type, type) + .set(&MixNode::use_clamp, false) + .set("Color1", constval) + .set("Fac", 1.0f)) + .add_connection("Attribute::Fac", "Mix_Cx_Fx::Fac") + .add_connection("Attribute::Color", "Mix_Cx_Fx::Color2") + .add_connection("Attribute::Color", "Mix_Cx_F1::Color2") + /* constant on the right */ + .add_node(ShaderNodeBuilder<MixNode>("Mix_xC_Fx") + .set(&MixNode::type, type) + .set(&MixNode::use_clamp, false) + .set("Color2", constval)) + .add_node(ShaderNodeBuilder<MixNode>("Mix_xC_F1") + .set(&MixNode::type, type) + .set(&MixNode::use_clamp, false) + .set("Color2", constval) + .set("Fac", 1.0f)) + .add_connection("Attribute::Fac", "Mix_xC_Fx::Fac") + .add_connection("Attribute::Color", "Mix_xC_Fx::Color1") + .add_connection("Attribute::Color", "Mix_xC_F1::Color1") + /* results of actual tests simply added up to connect to output */ + .add_node(ShaderNodeBuilder<MixNode>("Out12") + .set(&MixNode::type, NODE_MIX_ADD) + .set(&MixNode::use_clamp, true) + .set("Fac", 1.0f)) + .add_node(ShaderNodeBuilder<MixNode>("Out34") + .set(&MixNode::type, NODE_MIX_ADD) + .set(&MixNode::use_clamp, true) + .set("Fac", 1.0f)) + .add_node(ShaderNodeBuilder<MixNode>("Out1234") + .set(&MixNode::type, NODE_MIX_ADD) + .set(&MixNode::use_clamp, true) + .set("Fac", 1.0f)) + .add_connection("Mix_Cx_Fx::Color", "Out12::Color1") + .add_connection("Mix_Cx_F1::Color", "Out12::Color2") + .add_connection("Mix_xC_Fx::Color", "Out34::Color1") + .add_connection("Mix_xC_F1::Color", "Out34::Color2") + .add_connection("Out12::Color", "Out1234::Color1") + .add_connection("Out34::Color", "Out1234::Color2") + .output_color("Out1234::Color"); +} + +/* + * Tests: partial folding for RGB Add with known 0. + */ +TEST(render_graph, constant_fold_part_mix_add_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + /* 0 + X (fac 1) == X */ + INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color"); + CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color to socket Attribute::Color."); + /* X + 0 (fac ?) == X */ + CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color to socket Attribute::Color."); + CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color to socket Attribute::Color."); + INVALID_INFO_MESSAGE(log, "Folding Out"); + + build_mix_partial_test_graph(builder, NODE_MIX_ADD, make_float3(0, 0, 0)); + graph.finalize(&scene); +} + +/* + * Tests: partial folding for RGB Sub with known 0. + */ +TEST(render_graph, constant_fold_part_mix_sub_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color"); + INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color"); + /* X - 0 (fac ?) == X */ + CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color to socket Attribute::Color."); + CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color to socket Attribute::Color."); + INVALID_INFO_MESSAGE(log, "Folding Out"); + + build_mix_partial_test_graph(builder, NODE_MIX_SUB, make_float3(0, 0, 0)); + graph.finalize(&scene); +} + +/* + * Tests: partial folding for RGB Mul with known 1. + */ +TEST(render_graph, constant_fold_part_mix_mul_1) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + /* 1 * X (fac 1) == X */ + INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color"); + CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color to socket Attribute::Color."); + /* X * 1 (fac ?) == X */ + CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color to socket Attribute::Color."); + CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color to socket Attribute::Color."); + INVALID_INFO_MESSAGE(log, "Folding Out"); + + build_mix_partial_test_graph(builder, NODE_MIX_MUL, make_float3(1, 1, 1)); + graph.finalize(&scene); +} + +/* + * Tests: partial folding for RGB Div with known 1. + */ +TEST(render_graph, constant_fold_part_mix_div_1) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color"); + INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color"); + /* X / 1 (fac ?) == X */ + CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color to socket Attribute::Color."); + CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color to socket Attribute::Color."); + INVALID_INFO_MESSAGE(log, "Folding Out"); + + build_mix_partial_test_graph(builder, NODE_MIX_DIV, make_float3(1, 1, 1)); + graph.finalize(&scene); +} + +/* + * Tests: partial folding for RGB Mul with known 0. + */ +TEST(render_graph, constant_fold_part_mix_mul_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + /* 0 * ? (fac ?) == 0 */ + CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color to constant (0, 0, 0)."); + CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color to constant (0, 0, 0)."); + /* ? * 0 (fac 1) == 0 */ + INVALID_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color"); + CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color to constant (0, 0, 0)."); + + CORRECT_INFO_MESSAGE(log, "Folding Out12::Color to constant (0, 0, 0)."); + INVALID_INFO_MESSAGE(log, "Folding Out1234"); + + build_mix_partial_test_graph(builder, NODE_MIX_MUL, make_float3(0, 0, 0)); + graph.finalize(&scene); +} + +/* + * Tests: partial folding for RGB Div with known 0. + */ +TEST(render_graph, constant_fold_part_mix_div_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + /* 0 / ? (fac ?) == 0 */ + CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color to constant (0, 0, 0)."); + CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color to constant (0, 0, 0)."); + INVALID_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color"); + INVALID_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color"); + + CORRECT_INFO_MESSAGE(log, "Folding Out12::Color to constant (0, 0, 0)."); + INVALID_INFO_MESSAGE(log, "Folding Out1234"); + + build_mix_partial_test_graph(builder, NODE_MIX_DIV, make_float3(0, 0, 0)); + graph.finalize(&scene); +} + +/* + * Tests: Separate/Combine RGB with all constant inputs. + */ +TEST(render_graph, constant_fold_separate_combine_rgb) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding SeparateRGB::R to constant (0.3)."); + CORRECT_INFO_MESSAGE(log, "Folding SeparateRGB::G to constant (0.5)."); + CORRECT_INFO_MESSAGE(log, "Folding SeparateRGB::B to constant (0.7)."); + CORRECT_INFO_MESSAGE(log, "Folding CombineRGB::Image to constant (0.3, 0.5, 0.7)."); + + builder + .add_node(ShaderNodeBuilder<SeparateRGBNode>("SeparateRGB") + .set("Image", make_float3(0.3f, 0.5f, 0.7f))) + .add_node(ShaderNodeBuilder<CombineRGBNode>("CombineRGB")) + .add_connection("SeparateRGB::R", "CombineRGB::R") + .add_connection("SeparateRGB::G", "CombineRGB::G") + .add_connection("SeparateRGB::B", "CombineRGB::B") + .output_color("CombineRGB::Image"); + + graph.finalize(&scene); +} + +/* + * Tests: Separate/Combine XYZ with all constant inputs. + */ +TEST(render_graph, constant_fold_separate_combine_xyz) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding SeparateXYZ::X to constant (0.3)."); + CORRECT_INFO_MESSAGE(log, "Folding SeparateXYZ::Y to constant (0.5)."); + CORRECT_INFO_MESSAGE(log, "Folding SeparateXYZ::Z to constant (0.7)."); + CORRECT_INFO_MESSAGE(log, "Folding CombineXYZ::Vector to constant (0.3, 0.5, 0.7)."); + CORRECT_INFO_MESSAGE(log, "Folding convert_vector_to_color::value_color to constant (0.3, 0.5, 0.7)."); + + builder + .add_node(ShaderNodeBuilder<SeparateXYZNode>("SeparateXYZ") + .set("Vector", make_float3(0.3f, 0.5f, 0.7f))) + .add_node(ShaderNodeBuilder<CombineXYZNode>("CombineXYZ")) + .add_connection("SeparateXYZ::X", "CombineXYZ::X") + .add_connection("SeparateXYZ::Y", "CombineXYZ::Y") + .add_connection("SeparateXYZ::Z", "CombineXYZ::Z") + .output_color("CombineXYZ::Vector"); + + graph.finalize(&scene); +} + +/* + * Tests: Separate/Combine HSV with all constant inputs. + */ +TEST(render_graph, constant_fold_separate_combine_hsv) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding SeparateHSV::H to constant (0.583333)."); + CORRECT_INFO_MESSAGE(log, "Folding SeparateHSV::S to constant (0.571429)."); + CORRECT_INFO_MESSAGE(log, "Folding SeparateHSV::V to constant (0.7)."); + CORRECT_INFO_MESSAGE(log, "Folding CombineHSV::Color to constant (0.3, 0.5, 0.7)."); + + builder + .add_node(ShaderNodeBuilder<SeparateHSVNode>("SeparateHSV") + .set("Color", make_float3(0.3f, 0.5f, 0.7f))) + .add_node(ShaderNodeBuilder<CombineHSVNode>("CombineHSV")) + .add_connection("SeparateHSV::H", "CombineHSV::H") + .add_connection("SeparateHSV::S", "CombineHSV::S") + .add_connection("SeparateHSV::V", "CombineHSV::V") + .output_color("CombineHSV::Color"); + + graph.finalize(&scene); +} + +/* + * Tests: Gamma with all constant inputs. + */ +TEST(render_graph, constant_fold_gamma) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding Gamma::Color to constant (0.164317, 0.353553, 0.585662)."); + + builder + .add_node(ShaderNodeBuilder<GammaNode>("Gamma") + .set("Color", make_float3(0.3f, 0.5f, 0.7f)) + .set("Gamma", 1.5f)) + .output_color("Gamma::Color"); + + graph.finalize(&scene); +} + +/* + * Tests: BrightnessContrast with all constant inputs. + */ +TEST(render_graph, constant_fold_bright_contrast) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding BrightContrast::Color to constant (0.16, 0.6, 1.04)."); + + builder + .add_node(ShaderNodeBuilder<BrightContrastNode>("BrightContrast") + .set("Color", make_float3(0.3f, 0.5f, 0.7f)) + .set("Bright", 0.1f) + .set("Contrast", 1.2f)) + .output_color("BrightContrast::Color"); + + graph.finalize(&scene); +} + +/* + * Tests: blackbody with all constant inputs. + */ +TEST(render_graph, constant_fold_blackbody) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding Blackbody::Color to constant (3.94163, 0.226523, 0)."); + + builder + .add_node(ShaderNodeBuilder<BlackbodyNode>("Blackbody") + .set("Temperature", 1200.0f)) + .output_color("Blackbody::Color"); + + graph.finalize(&scene); +} + +/* + * Tests: Math with all constant inputs (clamp false). + */ +TEST(render_graph, constant_fold_math) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding Math::Value to constant (1.6)."); + + builder + .add_node(ShaderNodeBuilder<MathNode>("Math") + .set(&MathNode::type, NODE_MATH_ADD) + .set(&MathNode::use_clamp, false) + .set("Value1", 0.7f) + .set("Value2", 0.9f)) + .output_color("Math::Value"); + + graph.finalize(&scene); +} + +/* + * Tests: Math with all constant inputs (clamp true). + */ +TEST(render_graph, constant_fold_math_clamp) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding Math::Value to constant (1)."); + + builder + .add_node(ShaderNodeBuilder<MathNode>("Math") + .set(&MathNode::type, NODE_MATH_ADD) + .set(&MathNode::use_clamp, true) + .set("Value1", 0.7f) + .set("Value2", 0.9f)) + .output_color("Math::Value"); + + graph.finalize(&scene); +} + +/* + * Graph for testing partial folds of Math with one constant argument. + * Includes 2 tests: constant on each side. + */ +static void build_math_partial_test_graph(ShaderGraphBuilder &builder, NodeMath type, float constval) +{ + builder + .add_attribute("Attribute") + /* constant on the left */ + .add_node(ShaderNodeBuilder<MathNode>("Math_Cx") + .set(&MathNode::type, type) + .set(&MathNode::use_clamp, false) + .set("Value1", constval)) + .add_connection("Attribute::Fac", "Math_Cx::Value2") + /* constant on the right */ + .add_node(ShaderNodeBuilder<MathNode>("Math_xC") + .set(&MathNode::type, type) + .set(&MathNode::use_clamp, false) + .set("Value2", constval)) + .add_connection("Attribute::Fac", "Math_xC::Value1") + /* output sum */ + .add_node(ShaderNodeBuilder<MathNode>("Out") + .set(&MathNode::type, NODE_MATH_ADD) + .set(&MathNode::use_clamp, true)) + .add_connection("Math_Cx::Value", "Out::Value1") + .add_connection("Math_xC::Value", "Out::Value2") + .output_color("Out::Value"); +} + +/* + * Tests: partial folding for Math Add with known 0. + */ +TEST(render_graph, constant_fold_part_math_add_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + /* X + 0 == 0 + X == X */ + CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Value to socket Attribute::Fac."); + CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Value to socket Attribute::Fac."); + INVALID_INFO_MESSAGE(log, "Folding Out::"); + + build_math_partial_test_graph(builder, NODE_MATH_ADD, 0.0f); + graph.finalize(&scene); +} + +/* + * Tests: partial folding for Math Sub with known 0. + */ +TEST(render_graph, constant_fold_part_math_sub_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + /* X - 0 == X */ + INVALID_INFO_MESSAGE(log, "Folding Math_Cx::"); + CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Value to socket Attribute::Fac."); + INVALID_INFO_MESSAGE(log, "Folding Out::"); + + build_math_partial_test_graph(builder, NODE_MATH_SUBTRACT, 0.0f); + graph.finalize(&scene); +} + +/* + * Tests: partial folding for Math Mul with known 1. + */ +TEST(render_graph, constant_fold_part_math_mul_1) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + /* X * 1 == 1 * X == X */ + CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Value to socket Attribute::Fac."); + CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Value to socket Attribute::Fac."); + INVALID_INFO_MESSAGE(log, "Folding Out::"); + + build_math_partial_test_graph(builder, NODE_MATH_MULTIPLY, 1.0f); + graph.finalize(&scene); +} + +/* + * Tests: partial folding for Math Div with known 1. + */ +TEST(render_graph, constant_fold_part_math_div_1) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + /* X / 1 == X */ + INVALID_INFO_MESSAGE(log, "Folding Math_Cx::"); + CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Value to socket Attribute::Fac."); + INVALID_INFO_MESSAGE(log, "Folding Out::"); + + build_math_partial_test_graph(builder, NODE_MATH_DIVIDE, 1.0f); + graph.finalize(&scene); +} + +/* + * Tests: partial folding for Math Mul with known 0. + */ +TEST(render_graph, constant_fold_part_math_mul_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + /* X * 0 == 0 * X == 0 */ + CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Value to constant (0)."); + CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Value to constant (0)."); + CORRECT_INFO_MESSAGE(log, "Folding Out::Value to constant (0)"); + CORRECT_INFO_MESSAGE(log, "Discarding closure EmissionNode."); + + build_math_partial_test_graph(builder, NODE_MATH_MULTIPLY, 0.0f); + graph.finalize(&scene); +} + +/* + * Tests: partial folding for Math Div with known 0. + */ +TEST(render_graph, constant_fold_part_math_div_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + /* 0 / X == 0 */ + CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Value to constant (0)."); + INVALID_INFO_MESSAGE(log, "Folding Math_xC::"); + INVALID_INFO_MESSAGE(log, "Folding Out::"); + + build_math_partial_test_graph(builder, NODE_MATH_DIVIDE, 0.0f); + graph.finalize(&scene); +} + +/* + * Tests: Vector Math with all constant inputs. + */ +TEST(render_graph, constant_fold_vector_math) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding VectorMath::Value to constant (1)."); + CORRECT_INFO_MESSAGE(log, "Folding VectorMath::Vector to constant (3, 0, 0)."); + CORRECT_INFO_MESSAGE(log, "Folding convert_vector_to_float::value_float to constant (1)."); + CORRECT_INFO_MESSAGE(log, "Folding Math::Value to constant (2)."); + CORRECT_INFO_MESSAGE(log, "Folding convert_float_to_color::value_color to constant (2, 2, 2)."); + + builder + .add_node(ShaderNodeBuilder<VectorMathNode>("VectorMath") + .set(&VectorMathNode::type, NODE_VECTOR_MATH_SUBTRACT) + .set("Vector1", make_float3(1.3f, 0.5f, 0.7f)) + .set("Vector2", make_float3(-1.7f, 0.5f, 0.7f))) + .add_node(ShaderNodeBuilder<MathNode>("Math") + .set(&MathNode::type, NODE_MATH_ADD)) + .add_connection("VectorMath::Vector", "Math::Value1") + .add_connection("VectorMath::Value", "Math::Value2") + .output_color("Math::Value"); + + graph.finalize(&scene); +} + +/* + * Graph for testing partial folds of Vector Math with one constant argument. + * Includes 2 tests: constant on each side. + */ +static void build_vecmath_partial_test_graph(ShaderGraphBuilder &builder, NodeVectorMath type, float3 constval) +{ + builder + .add_attribute("Attribute") + /* constant on the left */ + .add_node(ShaderNodeBuilder<VectorMathNode>("Math_Cx") + .set(&VectorMathNode::type, type) + .set("Vector1", constval)) + .add_connection("Attribute::Vector", "Math_Cx::Vector2") + /* constant on the right */ + .add_node(ShaderNodeBuilder<VectorMathNode>("Math_xC") + .set(&VectorMathNode::type, type) + .set("Vector2", constval)) + .add_connection("Attribute::Vector", "Math_xC::Vector1") + /* output sum */ + .add_node(ShaderNodeBuilder<VectorMathNode>("Out") + .set(&VectorMathNode::type, NODE_VECTOR_MATH_ADD)) + .add_connection("Math_Cx::Vector", "Out::Vector1") + .add_connection("Math_xC::Vector", "Out::Vector2") + .output_color("Out::Vector"); +} + +/* + * Tests: partial folding for Vector Math Add with known 0. + */ +TEST(render_graph, constant_fold_part_vecmath_add_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + /* X + 0 == 0 + X == X */ + CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Vector to socket Attribute::Vector."); + CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Vector to socket Attribute::Vector."); + INVALID_INFO_MESSAGE(log, "Folding Out::"); + + build_vecmath_partial_test_graph(builder, NODE_VECTOR_MATH_ADD, make_float3(0,0,0)); + graph.finalize(&scene); +} + +/* + * Tests: partial folding for Vector Math Sub with known 0. + */ +TEST(render_graph, constant_fold_part_vecmath_sub_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + /* X - 0 == X */ + INVALID_INFO_MESSAGE(log, "Folding Math_Cx::"); + CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Vector to socket Attribute::Vector."); + INVALID_INFO_MESSAGE(log, "Folding Out::"); + + build_vecmath_partial_test_graph(builder, NODE_VECTOR_MATH_SUBTRACT, make_float3(0,0,0)); + graph.finalize(&scene); +} + +/* + * Tests: partial folding for Vector Math Dot Product with known 0. + */ +TEST(render_graph, constant_fold_part_vecmath_dot_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + /* X * 0 == 0 * X == X */ + CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Vector to constant (0, 0, 0)."); + CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Vector to constant (0, 0, 0)."); + CORRECT_INFO_MESSAGE(log, "Folding Out::Vector to constant (0, 0, 0)."); + CORRECT_INFO_MESSAGE(log, "Discarding closure EmissionNode."); + + build_vecmath_partial_test_graph(builder, NODE_VECTOR_MATH_DOT_PRODUCT, make_float3(0,0,0)); + graph.finalize(&scene); +} + +/* + * Tests: partial folding for Vector Math Cross Product with known 0. + */ +TEST(render_graph, constant_fold_part_vecmath_cross_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + /* X * 0 == 0 * X == X */ + CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Vector to constant (0, 0, 0)."); + CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Vector to constant (0, 0, 0)."); + CORRECT_INFO_MESSAGE(log, "Folding Out::Vector to constant (0, 0, 0)."); + CORRECT_INFO_MESSAGE(log, "Discarding closure EmissionNode."); + + build_vecmath_partial_test_graph(builder, NODE_VECTOR_MATH_CROSS_PRODUCT, make_float3(0,0,0)); + graph.finalize(&scene); +} + +/* + * Tests: Bump with no height input folded to Normal input. + */ +TEST(render_graph, constant_fold_bump) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding Bump::Normal to socket Geometry1::Normal."); + + builder + .add_node(ShaderNodeBuilder<GeometryNode>("Geometry1")) + .add_node(ShaderNodeBuilder<BumpNode>("Bump")) + .add_connection("Geometry1::Normal", "Bump::Normal") + .output_color("Bump::Normal"); + + graph.finalize(&scene); +} + +/* + * Tests: Bump with no inputs folded to Geometry::Normal. + */ +TEST(render_graph, constant_fold_bump_no_input) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding Bump::Normal to socket geometry::Normal."); + + builder + .add_node(ShaderNodeBuilder<BumpNode>("Bump")) + .output_color("Bump::Normal"); + + graph.finalize(&scene); +} + +template<class T> +void init_test_curve(array<T> &buffer, T start, T end, int steps) +{ + buffer.resize(steps); + + for (int i = 0; i < steps; i++) + buffer[i] = lerp(start, end, float(i)/(steps-1)); +} + +/* + * Tests: + * - Folding of RGB Curves with all constant inputs. + */ +TEST(render_graph, constant_fold_rgb_curves) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding Curves::Color to constant (0.275, 0.5, 0.475)."); + + array<float3> curve; + init_test_curve(curve, make_float3(0.0f, 0.25f, 1.0f), make_float3(1.0f, 0.75f, 0.0f), 257); + + builder + .add_node(ShaderNodeBuilder<RGBCurvesNode>("Curves") + .set(&CurvesNode::curves, curve) + .set(&CurvesNode::min_x, 0.1f) + .set(&CurvesNode::max_x, 0.9f) + .set("Fac", 0.5f) + .set("Color", make_float3(0.3f, 0.5f, 0.7f))) + .output_color("Curves::Color"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - Folding of RGB Curves with zero Fac. + */ +TEST(render_graph, constant_fold_rgb_curves_fac_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding Curves::Color to socket Attribute::Color."); + + array<float3> curve; + init_test_curve(curve, make_float3(0.0f, 0.25f, 1.0f), make_float3(1.0f, 0.75f, 0.0f), 257); + + builder + .add_attribute("Attribute") + .add_node(ShaderNodeBuilder<RGBCurvesNode>("Curves") + .set(&CurvesNode::curves, curve) + .set(&CurvesNode::min_x, 0.1f) + .set(&CurvesNode::max_x, 0.9f) + .set("Fac", 0.0f)) + .add_connection("Attribute::Color", "Curves::Color") + .output_color("Curves::Color"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - Folding of Vector Curves with all constant inputs. + */ +TEST(render_graph, constant_fold_vector_curves) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding Curves::Vector to constant (0.275, 0.5, 0.475)."); + + array<float3> curve; + init_test_curve(curve, make_float3(0.0f, 0.25f, 1.0f), make_float3(1.0f, 0.75f, 0.0f), 257); + + builder + .add_node(ShaderNodeBuilder<VectorCurvesNode>("Curves") + .set(&CurvesNode::curves, curve) + .set(&CurvesNode::min_x, 0.1f) + .set(&CurvesNode::max_x, 0.9f) + .set("Fac", 0.5f) + .set("Vector", make_float3(0.3f, 0.5f, 0.7f))) + .output_color("Curves::Vector"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - Folding of Vector Curves with zero Fac. + */ +TEST(render_graph, constant_fold_vector_curves_fac_0) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding Curves::Vector to socket Attribute::Vector."); + + array<float3> curve; + init_test_curve(curve, make_float3(0.0f, 0.25f, 1.0f), make_float3(1.0f, 0.75f, 0.0f), 257); + + builder + .add_attribute("Attribute") + .add_node(ShaderNodeBuilder<VectorCurvesNode>("Curves") + .set(&CurvesNode::curves, curve) + .set(&CurvesNode::min_x, 0.1f) + .set(&CurvesNode::max_x, 0.9f) + .set("Fac", 0.0f)) + .add_connection("Attribute::Vector", "Curves::Vector") + .output_color("Curves::Vector"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - Folding of Color Ramp with all constant inputs. + */ +TEST(render_graph, constant_fold_rgb_ramp) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding Ramp::Color to constant (0.14, 0.39, 0.64)."); + CORRECT_INFO_MESSAGE(log, "Folding Ramp::Alpha to constant (0.89)."); + + array<float3> curve; + array<float> alpha; + init_test_curve(curve, make_float3(0.0f, 0.25f, 0.5f), make_float3(0.25f, 0.5f, 0.75f), 9); + init_test_curve(alpha, 0.75f, 1.0f, 9); + + builder + .add_node(ShaderNodeBuilder<RGBRampNode>("Ramp") + .set(&RGBRampNode::ramp, curve) + .set(&RGBRampNode::ramp_alpha, alpha) + .set(&RGBRampNode::interpolate, true) + .set("Fac", 0.56f)) + .add_node(ShaderNodeBuilder<MixNode>("Mix") + .set(&MixNode::type, NODE_MIX_ADD)) + .add_connection("Ramp::Color", "Mix::Color1") + .add_connection("Ramp::Alpha", "Mix::Color2") + .output_color("Mix::Color"); + + graph.finalize(&scene); +} + +/* + * Tests: + * - Folding of Color Ramp with all constant inputs (interpolate false). + */ +TEST(render_graph, constant_fold_rgb_ramp_flat) +{ + DEFINE_COMMON_VARIABLES(builder, log); + + EXPECT_ANY_MESSAGE(log); + CORRECT_INFO_MESSAGE(log, "Folding Ramp::Color to constant (0.125, 0.375, 0.625)."); + CORRECT_INFO_MESSAGE(log, "Folding Ramp::Alpha to constant (0.875)."); + + array<float3> curve; + array<float> alpha; + init_test_curve(curve, make_float3(0.0f, 0.25f, 0.5f), make_float3(0.25f, 0.5f, 0.75f), 9); + init_test_curve(alpha, 0.75f, 1.0f, 9); + + builder + .add_node(ShaderNodeBuilder<RGBRampNode>("Ramp") + .set(&RGBRampNode::ramp, curve) + .set(&RGBRampNode::ramp_alpha, alpha) + .set(&RGBRampNode::interpolate, false) + .set("Fac", 0.56f)) + .add_node(ShaderNodeBuilder<MixNode>("Mix") + .set(&MixNode::type, NODE_MIX_ADD)) + .add_connection("Ramp::Color", "Mix::Color1") + .add_connection("Ramp::Alpha", "Mix::Color2") + .output_color("Mix::Color"); graph.finalize(&scene); } |