Cycles: add unit tests for supported constant folding rules.
[blender.git] / intern / cycles / test / render_graph_finalize_test.cpp
1 /*
2  * Copyright 2011-2016 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "testing/testing.h"
18 #include "testing/mock_log.h"
19
20 #include "render/graph.h"
21 #include "render/scene.h"
22 #include "render/nodes.h"
23 #include "util/util_logging.h"
24 #include "util/util_string.h"
25 #include "util/util_vector.h"
26
27 using testing::AnyNumber;
28 using testing::HasSubstr;
29 using testing::ScopedMockLog;
30 using testing::_;
31
32 CCL_NAMESPACE_BEGIN
33
34 namespace {
35
36 template<typename T>
37 class ShaderNodeBuilder {
38 public:
39         ShaderNodeBuilder(const string& name)
40           : name_(name)
41         {
42                 node_ = new T();
43                 node_->name = name;
44         }
45
46         const string& name() const {
47                 return name_;
48         }
49
50         ShaderNode *node() const {
51                 return node_;
52         }
53
54         template<typename V>
55         ShaderNodeBuilder& set(const string& input_name, V value)
56         {
57                 ShaderInput *input_socket = node_->input(input_name.c_str());
58                 EXPECT_NE((void*)NULL, input_socket);
59                 input_socket->set(value);
60                 return *this;
61         }
62
63         template<typename T2, typename V>
64         ShaderNodeBuilder& set(V T2::*pfield, V value)
65         {
66                 static_cast<T*>(node_)->*pfield = value;
67                 return *this;
68         }
69
70 protected:
71         string name_;
72         ShaderNode *node_;
73 };
74
75 class ShaderGraphBuilder {
76 public:
77         explicit ShaderGraphBuilder(ShaderGraph *graph)
78           : graph_(graph)
79         {
80                 node_map_["Output"] = graph->output();
81         }
82
83         ShaderNode *find_node(const string& name)
84         {
85                 map<string, ShaderNode *>::iterator it = node_map_.find(name);
86                 if(it == node_map_.end()) {
87                         return NULL;
88                 }
89                 return it->second;
90         }
91
92         template<typename T>
93         ShaderGraphBuilder& add_node(const T& node)
94         {
95                 EXPECT_EQ(NULL, find_node(node.name()));
96                 graph_->add(node.node());
97                 node_map_[node.name()] = node.node();
98                 return *this;
99         }
100
101         ShaderGraphBuilder& add_connection(const string& from,
102                                            const string& to)
103         {
104                 vector<string> tokens_from, tokens_to;
105                 string_split(tokens_from, from, "::");
106                 string_split(tokens_to, to, "::");
107                 EXPECT_EQ(2, tokens_from.size());
108                 EXPECT_EQ(2, tokens_to.size());
109                 ShaderNode *node_from = find_node(tokens_from[0]),
110                            *node_to = find_node(tokens_to[0]);
111                 EXPECT_NE((void*)NULL, node_from);
112                 EXPECT_NE((void*)NULL, node_to);
113                 EXPECT_NE(node_from, node_to);
114                 ShaderOutput *socket_from = node_from->output(tokens_from[1].c_str());
115                 ShaderInput *socket_to = node_to->input(tokens_to[1].c_str());
116                 EXPECT_NE((void*)NULL, socket_from);
117                 EXPECT_NE((void*)NULL, socket_to);
118                 graph_->connect(socket_from, socket_to);
119                 return *this;
120         }
121
122         /* Common input/output boilerplate. */
123         ShaderGraphBuilder& add_attribute(const string &name)
124         {
125                 return (*this)
126                         .add_node(ShaderNodeBuilder<AttributeNode>(name)
127                                   .set(&AttributeNode::attribute, ustring(name)));
128         }
129
130         ShaderGraphBuilder& output_closure(const string& from)
131         {
132                 return (*this).add_connection(from, "Output::Surface");
133         }
134
135         ShaderGraphBuilder& output_color(const string& from)
136         {
137                 return (*this)
138                         .add_node(ShaderNodeBuilder<EmissionNode>("EmissionNode"))
139                         .add_connection(from, "EmissionNode::Color")
140                         .output_closure("EmissionNode::Emission");
141         }
142
143 protected:
144         ShaderGraph *graph_;
145         map<string, ShaderNode *> node_map_;
146 };
147
148 }  // namespace
149
150 #define DEFINE_COMMON_VARIABLES(builder_name, mock_log_name) \
151         util_logging_start(); \
152         util_logging_verbosity_set(1); \
153         ScopedMockLog mock_log_name; \
154         DeviceInfo device_info; \
155         SceneParams scene_params; \
156         Scene scene(scene_params, device_info); \
157         ShaderGraph graph; \
158         ShaderGraphBuilder builder(&graph); \
159
160 #define EXPECT_ANY_MESSAGE(log) \
161         EXPECT_CALL(log, Log(_, _, _)).Times(AnyNumber()); \
162
163 #define CORRECT_INFO_MESSAGE(log, message) \
164         EXPECT_CALL(log, Log(google::INFO, _, HasSubstr(message)));
165
166 #define INVALID_INFO_MESSAGE(log, message) \
167         EXPECT_CALL(log, Log(google::INFO, _, HasSubstr(message))).Times(0);
168
169 /*
170  * Test deduplication of nodes that have inputs, some of them folded.
171  */
172 TEST(render_graph, deduplicate_deep)
173 {
174         DEFINE_COMMON_VARIABLES(builder, log);
175
176         EXPECT_ANY_MESSAGE(log);
177         CORRECT_INFO_MESSAGE(log, "Folding Value1::Value to constant (0.8).");
178         CORRECT_INFO_MESSAGE(log, "Folding Value2::Value to constant (0.8).");
179
180         builder
181                 .add_node(ShaderNodeBuilder<GeometryNode>("Geometry1"))
182                 .add_node(ShaderNodeBuilder<GeometryNode>("Geometry2"))
183                 .add_node(ShaderNodeBuilder<ValueNode>("Value1")
184                           .set(&ValueNode::value, 0.8f))
185                 .add_node(ShaderNodeBuilder<ValueNode>("Value2")
186                           .set(&ValueNode::value, 0.8f))
187                 .add_node(ShaderNodeBuilder<NoiseTextureNode>("Noise1"))
188                 .add_node(ShaderNodeBuilder<NoiseTextureNode>("Noise2"))
189                 .add_node(ShaderNodeBuilder<MixNode>("Mix")
190                           .set(&MixNode::type, NODE_MIX_BLEND)
191                           .set("Fac", 0.5f))
192                 .add_connection("Geometry1::Parametric", "Noise1::Vector")
193                 .add_connection("Value1::Value", "Noise1::Scale")
194                 .add_connection("Noise1::Color", "Mix::Color1")
195                 .add_connection("Geometry2::Parametric", "Noise2::Vector")
196                 .add_connection("Value2::Value", "Noise2::Scale")
197                 .add_connection("Noise2::Color", "Mix::Color2")
198                 .output_color("Mix::Color");
199
200         graph.finalize(&scene);
201
202         EXPECT_EQ(graph.nodes.size(), 5);
203 }
204
205 /*
206  * Test RGB to BW node.
207  */
208 TEST(render_graph, constant_fold_rgb_to_bw)
209 {
210         DEFINE_COMMON_VARIABLES(builder, log);
211
212         EXPECT_ANY_MESSAGE(log);
213         CORRECT_INFO_MESSAGE(log, "Folding RGBToBWNodeNode::Val to constant (0.8).");
214         CORRECT_INFO_MESSAGE(log, "Folding convert_float_to_color::value_color to constant (0.8, 0.8, 0.8).");
215
216         builder
217                 .add_node(ShaderNodeBuilder<RGBToBWNode>("RGBToBWNodeNode")
218                           .set("Color", make_float3(0.8f, 0.8f, 0.8f)))
219                 .output_color("RGBToBWNodeNode::Val");
220
221         graph.finalize(&scene);
222 }
223
224 /*
225  * Tests:
226  *  - folding of Emission nodes that don't emit to nothing.
227  */
228 TEST(render_graph, constant_fold_emission1)
229 {
230         DEFINE_COMMON_VARIABLES(builder, log);
231
232         EXPECT_ANY_MESSAGE(log);
233         CORRECT_INFO_MESSAGE(log, "Discarding closure Emission.");
234
235         builder
236                 .add_node(ShaderNodeBuilder<EmissionNode>("Emission")
237                           .set("Color", make_float3(0.0f, 0.0f, 0.0f)))
238                 .output_closure("Emission::Emission");
239
240         graph.finalize(&scene);
241 }
242
243 TEST(render_graph, constant_fold_emission2)
244 {
245         DEFINE_COMMON_VARIABLES(builder, log);
246
247         EXPECT_ANY_MESSAGE(log);
248         CORRECT_INFO_MESSAGE(log, "Discarding closure Emission.");
249
250         builder
251                 .add_node(ShaderNodeBuilder<EmissionNode>("Emission")
252                           .set("Strength", 0.0f))
253                 .output_closure("Emission::Emission");
254
255         graph.finalize(&scene);
256 }
257
258 /*
259  * Tests:
260  *  - folding of Background nodes that don't emit to nothing.
261  */
262 TEST(render_graph, constant_fold_background1)
263 {
264         DEFINE_COMMON_VARIABLES(builder, log);
265
266         EXPECT_ANY_MESSAGE(log);
267         CORRECT_INFO_MESSAGE(log, "Discarding closure Background.");
268
269         builder
270                 .add_node(ShaderNodeBuilder<BackgroundNode>("Background")
271                           .set("Color", make_float3(0.0f, 0.0f, 0.0f)))
272                 .output_closure("Background::Background");
273
274         graph.finalize(&scene);
275 }
276
277 TEST(render_graph, constant_fold_background2)
278 {
279         DEFINE_COMMON_VARIABLES(builder, log);
280
281         EXPECT_ANY_MESSAGE(log);
282         CORRECT_INFO_MESSAGE(log, "Discarding closure Background.");
283
284         builder
285                 .add_node(ShaderNodeBuilder<BackgroundNode>("Background")
286                           .set("Strength", 0.0f))
287                 .output_closure("Background::Background");
288
289         graph.finalize(&scene);
290 }
291
292 /*
293  * Tests:
294  *  - Folding of Add Closure with only one input.
295  */
296 TEST(render_graph, constant_fold_shader_add)
297 {
298         DEFINE_COMMON_VARIABLES(builder, log);
299
300         EXPECT_ANY_MESSAGE(log);
301         CORRECT_INFO_MESSAGE(log, "Folding AddClosure1::Closure to socket Diffuse::BSDF.");
302         CORRECT_INFO_MESSAGE(log, "Folding AddClosure2::Closure to socket Diffuse::BSDF.");
303         INVALID_INFO_MESSAGE(log, "Folding AddClosure3");
304
305         builder
306                 .add_node(ShaderNodeBuilder<DiffuseBsdfNode>("Diffuse"))
307                 .add_node(ShaderNodeBuilder<AddClosureNode>("AddClosure1"))
308                 .add_node(ShaderNodeBuilder<AddClosureNode>("AddClosure2"))
309                 .add_node(ShaderNodeBuilder<AddClosureNode>("AddClosure3"))
310                 .add_connection("Diffuse::BSDF", "AddClosure1::Closure1")
311                 .add_connection("Diffuse::BSDF", "AddClosure2::Closure2")
312                 .add_connection("AddClosure1::Closure", "AddClosure3::Closure1")
313                 .add_connection("AddClosure2::Closure", "AddClosure3::Closure2")
314                 .output_closure("AddClosure3::Closure");
315
316         graph.finalize(&scene);
317 }
318
319 /*
320  * Tests:
321  *  - Folding of Mix Closure with 0 or 1 fac.
322  *  - Folding of Mix Closure with both inputs folded to the same node.
323  */
324 TEST(render_graph, constant_fold_shader_mix)
325 {
326         DEFINE_COMMON_VARIABLES(builder, log);
327
328         EXPECT_ANY_MESSAGE(log);
329         CORRECT_INFO_MESSAGE(log, "Folding MixClosure1::Closure to socket Diffuse::BSDF.");
330         CORRECT_INFO_MESSAGE(log, "Folding MixClosure2::Closure to socket Diffuse::BSDF.");
331         CORRECT_INFO_MESSAGE(log, "Folding MixClosure3::Closure to socket Diffuse::BSDF.");
332
333         builder
334                 .add_attribute("Attribute")
335                 .add_node(ShaderNodeBuilder<DiffuseBsdfNode>("Diffuse"))
336                 /* choose left */
337                 .add_node(ShaderNodeBuilder<MixClosureNode>("MixClosure1")
338                           .set("Fac", 0.0f))
339                 .add_connection("Diffuse::BSDF", "MixClosure1::Closure1")
340                 /* choose right */
341                 .add_node(ShaderNodeBuilder<MixClosureNode>("MixClosure2")
342                           .set("Fac", 1.0f))
343                 .add_connection("Diffuse::BSDF", "MixClosure2::Closure2")
344                 /* both inputs folded the same */
345                 .add_node(ShaderNodeBuilder<MixClosureNode>("MixClosure3"))
346                 .add_connection("Attribute::Fac", "MixClosure3::Fac")
347                 .add_connection("MixClosure1::Closure", "MixClosure3::Closure1")
348                 .add_connection("MixClosure2::Closure", "MixClosure3::Closure2")
349                 .output_closure("MixClosure3::Closure");
350
351         graph.finalize(&scene);
352 }
353
354 /*
355  * Tests:
356  *  - Folding of Invert with all constant inputs.
357  */
358 TEST(render_graph, constant_fold_invert)
359 {
360         DEFINE_COMMON_VARIABLES(builder, log);
361
362         EXPECT_ANY_MESSAGE(log);
363         CORRECT_INFO_MESSAGE(log, "Folding Invert::Color to constant (0.68, 0.5, 0.32).");
364
365         builder
366                 .add_node(ShaderNodeBuilder<InvertNode>("Invert")
367                           .set("Fac", 0.8f)
368                           .set("Color", make_float3(0.2f, 0.5f, 0.8f)))
369                 .output_color("Invert::Color");
370
371         graph.finalize(&scene);
372 }
373
374 /*
375  * Tests:
376  *  - Folding of Invert with zero Fac.
377  */
378 TEST(render_graph, constant_fold_invert_fac_0)
379 {
380         DEFINE_COMMON_VARIABLES(builder, log);
381
382         EXPECT_ANY_MESSAGE(log);
383         CORRECT_INFO_MESSAGE(log, "Folding Invert::Color to socket Attribute::Color.");
384
385         builder
386                 .add_attribute("Attribute")
387                 .add_node(ShaderNodeBuilder<InvertNode>("Invert")
388                           .set("Fac", 0.0f))
389                 .add_connection("Attribute::Color", "Invert::Color")
390                 .output_color("Invert::Color");
391
392         graph.finalize(&scene);
393 }
394
395 /*
396  * Tests:
397  *  - Folding of MixRGB Add with all constant inputs (clamp false).
398  */
399 TEST(render_graph, constant_fold_mix_add)
400 {
401         DEFINE_COMMON_VARIABLES(builder, log);
402
403         EXPECT_ANY_MESSAGE(log);
404         CORRECT_INFO_MESSAGE(log, "Folding MixAdd::Color to constant (0.62, 1.14, 1.42).");
405
406         builder
407                 .add_node(ShaderNodeBuilder<MixNode>("MixAdd")
408                           .set(&MixNode::type, NODE_MIX_ADD)
409                           .set(&MixNode::use_clamp, false)
410                           .set("Fac", 0.8f)
411                           .set("Color1", make_float3(0.3, 0.5, 0.7))
412                           .set("Color2", make_float3(0.4, 0.8, 0.9)))
413                 .output_color("MixAdd::Color");
414
415         graph.finalize(&scene);
416 }
417
418 /*
419  * Tests:
420  *  - Folding of MixRGB Add with all constant inputs (clamp true).
421  */
422 TEST(render_graph, constant_fold_mix_add_clamp)
423 {
424         DEFINE_COMMON_VARIABLES(builder, log);
425
426         EXPECT_ANY_MESSAGE(log);
427         CORRECT_INFO_MESSAGE(log, "Folding MixAdd::Color to constant (0.62, 1, 1).");
428
429         builder
430                 .add_node(ShaderNodeBuilder<MixNode>("MixAdd")
431                           .set(&MixNode::type, NODE_MIX_ADD)
432                           .set(&MixNode::use_clamp, true)
433                           .set("Fac", 0.8f)
434                           .set("Color1", make_float3(0.3, 0.5, 0.7))
435                           .set("Color2", make_float3(0.4, 0.8, 0.9)))
436                 .output_color("MixAdd::Color");
437
438         graph.finalize(&scene);
439 }
440
441 /*
442  * Tests:
443  *  - No folding on fac 0 for dodge.
444  */
445 TEST(render_graph, constant_fold_part_mix_dodge_no_fac_0)
446 {
447         DEFINE_COMMON_VARIABLES(builder, log);
448
449         EXPECT_ANY_MESSAGE(log);
450         INVALID_INFO_MESSAGE(log, "Folding ");
451
452         builder
453                 .add_attribute("Attribute1")
454                 .add_attribute("Attribute2")
455                 .add_node(ShaderNodeBuilder<MixNode>("Mix")
456                           .set(&MixNode::type, NODE_MIX_DODGE)
457                           .set(&MixNode::use_clamp, false)
458                           .set("Fac", 0.0f))
459                 .add_connection("Attribute1::Color", "Mix::Color1")
460                 .add_connection("Attribute2::Color", "Mix::Color2")
461                 .output_color("Mix::Color");
462
463         graph.finalize(&scene);
464 }
465
466 /*
467  * Tests:
468  *  - No folding on fac 0 for light.
469  */
470 TEST(render_graph, constant_fold_part_mix_light_no_fac_0)
471 {
472         DEFINE_COMMON_VARIABLES(builder, log);
473
474         EXPECT_ANY_MESSAGE(log);
475         INVALID_INFO_MESSAGE(log, "Folding ");
476
477         builder
478                 .add_attribute("Attribute1")
479                 .add_attribute("Attribute2")
480                 .add_node(ShaderNodeBuilder<MixNode>("Mix")
481                           .set(&MixNode::type, NODE_MIX_LIGHT)
482                           .set(&MixNode::use_clamp, false)
483                           .set("Fac", 0.0f))
484                 .add_connection("Attribute1::Color", "Mix::Color1")
485                 .add_connection("Attribute2::Color", "Mix::Color2")
486                 .output_color("Mix::Color");
487
488         graph.finalize(&scene);
489 }
490
491 /*
492  * Tests:
493  *  - No folding on fac 0 for burn.
494  */
495 TEST(render_graph, constant_fold_part_mix_burn_no_fac_0)
496 {
497         DEFINE_COMMON_VARIABLES(builder, log);
498
499         EXPECT_ANY_MESSAGE(log);
500         INVALID_INFO_MESSAGE(log, "Folding ");
501
502         builder
503                 .add_attribute("Attribute1")
504                 .add_attribute("Attribute2")
505                 .add_node(ShaderNodeBuilder<MixNode>("Mix")
506                           .set(&MixNode::type, NODE_MIX_BURN)
507                           .set(&MixNode::use_clamp, false)
508                           .set("Fac", 0.0f))
509                 .add_connection("Attribute1::Color", "Mix::Color1")
510                 .add_connection("Attribute2::Color", "Mix::Color2")
511                 .output_color("Mix::Color");
512
513         graph.finalize(&scene);
514 }
515
516 /*
517  * Tests:
518  *  - No folding on fac 0 for clamped blend.
519  */
520 TEST(render_graph, constant_fold_part_mix_blend_clamped_no_fac_0)
521 {
522         DEFINE_COMMON_VARIABLES(builder, log);
523
524         EXPECT_ANY_MESSAGE(log);
525         INVALID_INFO_MESSAGE(log, "Folding ");
526
527         builder
528                 .add_attribute("Attribute1")
529                 .add_attribute("Attribute2")
530                 .add_node(ShaderNodeBuilder<MixNode>("Mix")
531                           .set(&MixNode::type, NODE_MIX_BLEND)
532                           .set(&MixNode::use_clamp, true)
533                           .set("Fac", 0.0f))
534                 .add_connection("Attribute1::Color", "Mix::Color1")
535                 .add_connection("Attribute2::Color", "Mix::Color2")
536                 .output_color("Mix::Color");
537
538         graph.finalize(&scene);
539 }
540
541 /*
542  * Tests:
543  *  - Folding of Mix with 0 or 1 Fac.
544  *  - Folding of Mix with both inputs folded to the same node.
545  */
546 TEST(render_graph, constant_fold_part_mix_blend)
547 {
548         DEFINE_COMMON_VARIABLES(builder, log);
549
550         EXPECT_ANY_MESSAGE(log);
551         CORRECT_INFO_MESSAGE(log, "Folding MixBlend1::Color to socket Attribute1::Color.");
552         CORRECT_INFO_MESSAGE(log, "Folding MixBlend2::Color to socket Attribute1::Color.");
553         CORRECT_INFO_MESSAGE(log, "Folding MixBlend3::Color to socket Attribute1::Color.");
554
555         builder
556                 .add_attribute("Attribute1")
557                 .add_attribute("Attribute2")
558                 /* choose left */
559                 .add_node(ShaderNodeBuilder<MixNode>("MixBlend1")
560                           .set(&MixNode::type, NODE_MIX_BLEND)
561                           .set(&MixNode::use_clamp, false)
562                           .set("Fac", 0.0f))
563                 .add_connection("Attribute1::Color", "MixBlend1::Color1")
564                 .add_connection("Attribute2::Color", "MixBlend1::Color2")
565                 /* choose right */
566                 .add_node(ShaderNodeBuilder<MixNode>("MixBlend2")
567                           .set(&MixNode::type, NODE_MIX_BLEND)
568                           .set(&MixNode::use_clamp, false)
569                           .set("Fac", 1.0f))
570                 .add_connection("Attribute1::Color", "MixBlend2::Color2")
571                 .add_connection("Attribute2::Color", "MixBlend2::Color1")
572                 /* both inputs folded to Attribute1 */
573                 .add_node(ShaderNodeBuilder<MixNode>("MixBlend3")
574                           .set(&MixNode::type, NODE_MIX_BLEND)
575                           .set(&MixNode::use_clamp, false))
576                 .add_connection("Attribute1::Fac", "MixBlend3::Fac")
577                 .add_connection("MixBlend1::Color", "MixBlend3::Color1")
578                 .add_connection("MixBlend2::Color", "MixBlend3::Color2")
579                 .output_color("MixBlend3::Color");
580
581         graph.finalize(&scene);
582 }
583
584 /*
585  * Tests:
586  *  - NOT folding of MixRGB Sub with the same inputs and fac NOT 1.
587  */
588 TEST(render_graph, constant_fold_part_mix_sub_same_fac_bad)
589 {
590         DEFINE_COMMON_VARIABLES(builder, log);
591
592         EXPECT_ANY_MESSAGE(log);
593         INVALID_INFO_MESSAGE(log, "Folding Mix::");
594
595         builder
596                 .add_attribute("Attribute")
597                 .add_node(ShaderNodeBuilder<MixNode>("Mix")
598                           .set(&MixNode::type, NODE_MIX_SUB)
599                           .set(&MixNode::use_clamp, true)
600                           .set("Fac", 0.5f))
601                 .add_connection("Attribute::Color", "Mix::Color1")
602                 .add_connection("Attribute::Color", "Mix::Color2")
603                 .output_color("Mix::Color");
604
605         graph.finalize(&scene);
606 }
607
608 /*
609  * Tests:
610  *  - Folding of MixRGB Sub with the same inputs and fac 1.
611  */
612 TEST(render_graph, constant_fold_part_mix_sub_same_fac_1)
613 {
614         DEFINE_COMMON_VARIABLES(builder, log);
615
616         EXPECT_ANY_MESSAGE(log);
617         CORRECT_INFO_MESSAGE(log, "Folding Mix::Color to constant (0, 0, 0).");
618
619         builder
620                 .add_attribute("Attribute")
621                 .add_node(ShaderNodeBuilder<MixNode>("Mix")
622                           .set(&MixNode::type, NODE_MIX_SUB)
623                           .set(&MixNode::use_clamp, true)
624                           .set("Fac", 1.0f))
625                 .add_connection("Attribute::Color", "Mix::Color1")
626                 .add_connection("Attribute::Color", "Mix::Color2")
627                 .output_color("Mix::Color");
628
629         graph.finalize(&scene);
630 }
631
632 /*
633  * Graph for testing partial folds of MixRGB with one constant argument.
634  * Includes 4 tests: constant on each side with fac either unknown or 1.
635  */
636 static void build_mix_partial_test_graph(ShaderGraphBuilder &builder, NodeMix type, float3 constval)
637 {
638         builder
639                 .add_attribute("Attribute")
640                 /* constant on the left */
641                 .add_node(ShaderNodeBuilder<MixNode>("Mix_Cx_Fx")
642                           .set(&MixNode::type, type)
643                           .set(&MixNode::use_clamp, false)
644                           .set("Color1", constval))
645                 .add_node(ShaderNodeBuilder<MixNode>("Mix_Cx_F1")
646                           .set(&MixNode::type, type)
647                           .set(&MixNode::use_clamp, false)
648                           .set("Color1", constval)
649                           .set("Fac", 1.0f))
650                 .add_connection("Attribute::Fac", "Mix_Cx_Fx::Fac")
651                 .add_connection("Attribute::Color", "Mix_Cx_Fx::Color2")
652                 .add_connection("Attribute::Color", "Mix_Cx_F1::Color2")
653                 /* constant on the right */
654                 .add_node(ShaderNodeBuilder<MixNode>("Mix_xC_Fx")
655                           .set(&MixNode::type, type)
656                           .set(&MixNode::use_clamp, false)
657                           .set("Color2", constval))
658                 .add_node(ShaderNodeBuilder<MixNode>("Mix_xC_F1")
659                           .set(&MixNode::type, type)
660                           .set(&MixNode::use_clamp, false)
661                           .set("Color2", constval)
662                           .set("Fac", 1.0f))
663                 .add_connection("Attribute::Fac", "Mix_xC_Fx::Fac")
664                 .add_connection("Attribute::Color", "Mix_xC_Fx::Color1")
665                 .add_connection("Attribute::Color", "Mix_xC_F1::Color1")
666                 /* results of actual tests simply added up to connect to output */
667                 .add_node(ShaderNodeBuilder<MixNode>("Out12")
668                           .set(&MixNode::type, NODE_MIX_ADD)
669                           .set(&MixNode::use_clamp, true)
670                           .set("Fac", 1.0f))
671                 .add_node(ShaderNodeBuilder<MixNode>("Out34")
672                           .set(&MixNode::type, NODE_MIX_ADD)
673                           .set(&MixNode::use_clamp, true)
674                           .set("Fac", 1.0f))
675                 .add_node(ShaderNodeBuilder<MixNode>("Out1234")
676                           .set(&MixNode::type, NODE_MIX_ADD)
677                           .set(&MixNode::use_clamp, true)
678                           .set("Fac", 1.0f))
679                 .add_connection("Mix_Cx_Fx::Color", "Out12::Color1")
680                 .add_connection("Mix_Cx_F1::Color", "Out12::Color2")
681                 .add_connection("Mix_xC_Fx::Color", "Out34::Color1")
682                 .add_connection("Mix_xC_F1::Color", "Out34::Color2")
683                 .add_connection("Out12::Color", "Out1234::Color1")
684                 .add_connection("Out34::Color", "Out1234::Color2")
685                 .output_color("Out1234::Color");
686 }
687
688 /*
689  * Tests: partial folding for RGB Add with known 0.
690  */
691 TEST(render_graph, constant_fold_part_mix_add_0)
692 {
693         DEFINE_COMMON_VARIABLES(builder, log);
694
695         EXPECT_ANY_MESSAGE(log);
696         /* 0 + X (fac 1) == X */
697         INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color");
698         CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color to socket Attribute::Color.");
699         /* X + 0 (fac ?) == X */
700         CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color to socket Attribute::Color.");
701         CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color to socket Attribute::Color.");
702         INVALID_INFO_MESSAGE(log, "Folding Out");
703
704         build_mix_partial_test_graph(builder, NODE_MIX_ADD, make_float3(0, 0, 0));
705         graph.finalize(&scene);
706 }
707
708 /*
709  * Tests: partial folding for RGB Sub with known 0.
710  */
711 TEST(render_graph, constant_fold_part_mix_sub_0)
712 {
713         DEFINE_COMMON_VARIABLES(builder, log);
714
715         EXPECT_ANY_MESSAGE(log);
716         INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color");
717         INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color");
718         /* X - 0 (fac ?) == X */
719         CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color to socket Attribute::Color.");
720         CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color to socket Attribute::Color.");
721         INVALID_INFO_MESSAGE(log, "Folding Out");
722
723         build_mix_partial_test_graph(builder, NODE_MIX_SUB, make_float3(0, 0, 0));
724         graph.finalize(&scene);
725 }
726
727 /*
728  * Tests: partial folding for RGB Mul with known 1.
729  */
730 TEST(render_graph, constant_fold_part_mix_mul_1)
731 {
732         DEFINE_COMMON_VARIABLES(builder, log);
733
734         EXPECT_ANY_MESSAGE(log);
735         /* 1 * X (fac 1) == X */
736         INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color");
737         CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color to socket Attribute::Color.");
738         /* X * 1 (fac ?) == X */
739         CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color to socket Attribute::Color.");
740         CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color to socket Attribute::Color.");
741         INVALID_INFO_MESSAGE(log, "Folding Out");
742
743         build_mix_partial_test_graph(builder, NODE_MIX_MUL, make_float3(1, 1, 1));
744         graph.finalize(&scene);
745 }
746
747 /*
748  * Tests: partial folding for RGB Div with known 1.
749  */
750 TEST(render_graph, constant_fold_part_mix_div_1)
751 {
752         DEFINE_COMMON_VARIABLES(builder, log);
753
754         EXPECT_ANY_MESSAGE(log);
755         INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color");
756         INVALID_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color");
757         /* X / 1 (fac ?) == X */
758         CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color to socket Attribute::Color.");
759         CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color to socket Attribute::Color.");
760         INVALID_INFO_MESSAGE(log, "Folding Out");
761
762         build_mix_partial_test_graph(builder, NODE_MIX_DIV, make_float3(1, 1, 1));
763         graph.finalize(&scene);
764 }
765
766 /*
767  * Tests: partial folding for RGB Mul with known 0.
768  */
769 TEST(render_graph, constant_fold_part_mix_mul_0)
770 {
771         DEFINE_COMMON_VARIABLES(builder, log);
772
773         EXPECT_ANY_MESSAGE(log);
774         /* 0 * ? (fac ?) == 0 */
775         CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color to constant (0, 0, 0).");
776         CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color to constant (0, 0, 0).");
777         /* ? * 0 (fac 1) == 0 */
778         INVALID_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color");
779         CORRECT_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color to constant (0, 0, 0).");
780
781         CORRECT_INFO_MESSAGE(log, "Folding Out12::Color to constant (0, 0, 0).");
782         INVALID_INFO_MESSAGE(log, "Folding Out1234");
783
784         build_mix_partial_test_graph(builder, NODE_MIX_MUL, make_float3(0, 0, 0));
785         graph.finalize(&scene);
786 }
787
788 /*
789  * Tests: partial folding for RGB Div with known 0.
790  */
791 TEST(render_graph, constant_fold_part_mix_div_0)
792 {
793         DEFINE_COMMON_VARIABLES(builder, log);
794
795         EXPECT_ANY_MESSAGE(log);
796         /* 0 / ? (fac ?) == 0 */
797         CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_Fx::Color to constant (0, 0, 0).");
798         CORRECT_INFO_MESSAGE(log, "Folding Mix_Cx_F1::Color to constant (0, 0, 0).");
799         INVALID_INFO_MESSAGE(log, "Folding Mix_xC_Fx::Color");
800         INVALID_INFO_MESSAGE(log, "Folding Mix_xC_F1::Color");
801
802         CORRECT_INFO_MESSAGE(log, "Folding Out12::Color to constant (0, 0, 0).");
803         INVALID_INFO_MESSAGE(log, "Folding Out1234");
804
805         build_mix_partial_test_graph(builder, NODE_MIX_DIV, make_float3(0, 0, 0));
806         graph.finalize(&scene);
807 }
808
809 /*
810  * Tests: Separate/Combine RGB with all constant inputs.
811  */
812 TEST(render_graph, constant_fold_separate_combine_rgb)
813 {
814         DEFINE_COMMON_VARIABLES(builder, log);
815
816         EXPECT_ANY_MESSAGE(log);
817         CORRECT_INFO_MESSAGE(log, "Folding SeparateRGB::R to constant (0.3).");
818         CORRECT_INFO_MESSAGE(log, "Folding SeparateRGB::G to constant (0.5).");
819         CORRECT_INFO_MESSAGE(log, "Folding SeparateRGB::B to constant (0.7).");
820         CORRECT_INFO_MESSAGE(log, "Folding CombineRGB::Image to constant (0.3, 0.5, 0.7).");
821
822         builder
823                 .add_node(ShaderNodeBuilder<SeparateRGBNode>("SeparateRGB")
824                           .set("Image", make_float3(0.3f, 0.5f, 0.7f)))
825                 .add_node(ShaderNodeBuilder<CombineRGBNode>("CombineRGB"))
826                 .add_connection("SeparateRGB::R", "CombineRGB::R")
827                 .add_connection("SeparateRGB::G", "CombineRGB::G")
828                 .add_connection("SeparateRGB::B", "CombineRGB::B")
829                 .output_color("CombineRGB::Image");
830
831         graph.finalize(&scene);
832 }
833
834 /*
835  * Tests: Separate/Combine XYZ with all constant inputs.
836  */
837 TEST(render_graph, constant_fold_separate_combine_xyz)
838 {
839         DEFINE_COMMON_VARIABLES(builder, log);
840
841         EXPECT_ANY_MESSAGE(log);
842         CORRECT_INFO_MESSAGE(log, "Folding SeparateXYZ::X to constant (0.3).");
843         CORRECT_INFO_MESSAGE(log, "Folding SeparateXYZ::Y to constant (0.5).");
844         CORRECT_INFO_MESSAGE(log, "Folding SeparateXYZ::Z to constant (0.7).");
845         CORRECT_INFO_MESSAGE(log, "Folding CombineXYZ::Vector to constant (0.3, 0.5, 0.7).");
846         CORRECT_INFO_MESSAGE(log, "Folding convert_vector_to_color::value_color to constant (0.3, 0.5, 0.7).");
847
848         builder
849                 .add_node(ShaderNodeBuilder<SeparateXYZNode>("SeparateXYZ")
850                           .set("Vector", make_float3(0.3f, 0.5f, 0.7f)))
851                 .add_node(ShaderNodeBuilder<CombineXYZNode>("CombineXYZ"))
852                 .add_connection("SeparateXYZ::X", "CombineXYZ::X")
853                 .add_connection("SeparateXYZ::Y", "CombineXYZ::Y")
854                 .add_connection("SeparateXYZ::Z", "CombineXYZ::Z")
855                 .output_color("CombineXYZ::Vector");
856
857         graph.finalize(&scene);
858 }
859
860 /*
861  * Tests: Separate/Combine HSV with all constant inputs.
862  */
863 TEST(render_graph, constant_fold_separate_combine_hsv)
864 {
865         DEFINE_COMMON_VARIABLES(builder, log);
866
867         EXPECT_ANY_MESSAGE(log);
868         CORRECT_INFO_MESSAGE(log, "Folding SeparateHSV::H to constant (0.583333).");
869         CORRECT_INFO_MESSAGE(log, "Folding SeparateHSV::S to constant (0.571429).");
870         CORRECT_INFO_MESSAGE(log, "Folding SeparateHSV::V to constant (0.7).");
871         CORRECT_INFO_MESSAGE(log, "Folding CombineHSV::Color to constant (0.3, 0.5, 0.7).");
872
873         builder
874                 .add_node(ShaderNodeBuilder<SeparateHSVNode>("SeparateHSV")
875                           .set("Color", make_float3(0.3f, 0.5f, 0.7f)))
876                 .add_node(ShaderNodeBuilder<CombineHSVNode>("CombineHSV"))
877                 .add_connection("SeparateHSV::H", "CombineHSV::H")
878                 .add_connection("SeparateHSV::S", "CombineHSV::S")
879                 .add_connection("SeparateHSV::V", "CombineHSV::V")
880                 .output_color("CombineHSV::Color");
881
882         graph.finalize(&scene);
883 }
884
885 /*
886  * Tests: Gamma with all constant inputs.
887  */
888 TEST(render_graph, constant_fold_gamma)
889 {
890         DEFINE_COMMON_VARIABLES(builder, log);
891
892         EXPECT_ANY_MESSAGE(log);
893         CORRECT_INFO_MESSAGE(log, "Folding Gamma::Color to constant (0.164317, 0.353553, 0.585662).");
894
895         builder
896                 .add_node(ShaderNodeBuilder<GammaNode>("Gamma")
897                           .set("Color", make_float3(0.3f, 0.5f, 0.7f))
898                           .set("Gamma", 1.5f))
899                 .output_color("Gamma::Color");
900
901         graph.finalize(&scene);
902 }
903
904 /*
905  * Tests: BrightnessContrast with all constant inputs.
906  */
907 TEST(render_graph, constant_fold_bright_contrast)
908 {
909         DEFINE_COMMON_VARIABLES(builder, log);
910
911         EXPECT_ANY_MESSAGE(log);
912         CORRECT_INFO_MESSAGE(log, "Folding BrightContrast::Color to constant (0.16, 0.6, 1.04).");
913
914         builder
915                 .add_node(ShaderNodeBuilder<BrightContrastNode>("BrightContrast")
916                           .set("Color", make_float3(0.3f, 0.5f, 0.7f))
917                           .set("Bright", 0.1f)
918                           .set("Contrast", 1.2f))
919                 .output_color("BrightContrast::Color");
920
921         graph.finalize(&scene);
922 }
923
924 /*
925  * Tests: blackbody with all constant inputs.
926  */
927 TEST(render_graph, constant_fold_blackbody)
928 {
929         DEFINE_COMMON_VARIABLES(builder, log);
930
931         EXPECT_ANY_MESSAGE(log);
932         CORRECT_INFO_MESSAGE(log, "Folding Blackbody::Color to constant (3.94163, 0.226523, 0).");
933
934         builder
935                 .add_node(ShaderNodeBuilder<BlackbodyNode>("Blackbody")
936                           .set("Temperature", 1200.0f))
937                 .output_color("Blackbody::Color");
938
939         graph.finalize(&scene);
940 }
941
942 /*
943  * Tests: Math with all constant inputs (clamp false).
944  */
945 TEST(render_graph, constant_fold_math)
946 {
947         DEFINE_COMMON_VARIABLES(builder, log);
948
949         EXPECT_ANY_MESSAGE(log);
950         CORRECT_INFO_MESSAGE(log, "Folding Math::Value to constant (1.6).");
951
952         builder
953                 .add_node(ShaderNodeBuilder<MathNode>("Math")
954                           .set(&MathNode::type, NODE_MATH_ADD)
955                           .set(&MathNode::use_clamp, false)
956                           .set("Value1", 0.7f)
957                           .set("Value2", 0.9f))
958                 .output_color("Math::Value");
959
960         graph.finalize(&scene);
961 }
962
963 /*
964  * Tests: Math with all constant inputs (clamp true).
965  */
966 TEST(render_graph, constant_fold_math_clamp)
967 {
968         DEFINE_COMMON_VARIABLES(builder, log);
969
970         EXPECT_ANY_MESSAGE(log);
971         CORRECT_INFO_MESSAGE(log, "Folding Math::Value to constant (1).");
972
973         builder
974                 .add_node(ShaderNodeBuilder<MathNode>("Math")
975                           .set(&MathNode::type, NODE_MATH_ADD)
976                           .set(&MathNode::use_clamp, true)
977                           .set("Value1", 0.7f)
978                           .set("Value2", 0.9f))
979                 .output_color("Math::Value");
980
981         graph.finalize(&scene);
982 }
983
984 /*
985  * Graph for testing partial folds of Math with one constant argument.
986  * Includes 2 tests: constant on each side.
987  */
988 static void build_math_partial_test_graph(ShaderGraphBuilder &builder, NodeMath type, float constval)
989 {
990         builder
991                 .add_attribute("Attribute")
992                 /* constant on the left */
993                 .add_node(ShaderNodeBuilder<MathNode>("Math_Cx")
994                           .set(&MathNode::type, type)
995                           .set(&MathNode::use_clamp, false)
996                           .set("Value1", constval))
997                 .add_connection("Attribute::Fac", "Math_Cx::Value2")
998                 /* constant on the right */
999                 .add_node(ShaderNodeBuilder<MathNode>("Math_xC")
1000                           .set(&MathNode::type, type)
1001                           .set(&MathNode::use_clamp, false)
1002                           .set("Value2", constval))
1003                 .add_connection("Attribute::Fac", "Math_xC::Value1")
1004                 /* output sum */
1005                 .add_node(ShaderNodeBuilder<MathNode>("Out")
1006                           .set(&MathNode::type, NODE_MATH_ADD)
1007                           .set(&MathNode::use_clamp, true))
1008                 .add_connection("Math_Cx::Value", "Out::Value1")
1009                 .add_connection("Math_xC::Value", "Out::Value2")
1010                 .output_color("Out::Value");
1011 }
1012
1013 /*
1014  * Tests: partial folding for Math Add with known 0.
1015  */
1016 TEST(render_graph, constant_fold_part_math_add_0)
1017 {
1018         DEFINE_COMMON_VARIABLES(builder, log);
1019
1020         EXPECT_ANY_MESSAGE(log);
1021         /* X + 0 == 0 + X == X */
1022         CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Value to socket Attribute::Fac.");
1023         CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Value to socket Attribute::Fac.");
1024         INVALID_INFO_MESSAGE(log, "Folding Out::");
1025
1026         build_math_partial_test_graph(builder, NODE_MATH_ADD, 0.0f);
1027         graph.finalize(&scene);
1028 }
1029
1030 /*
1031  * Tests: partial folding for Math Sub with known 0.
1032  */
1033 TEST(render_graph, constant_fold_part_math_sub_0)
1034 {
1035         DEFINE_COMMON_VARIABLES(builder, log);
1036
1037         EXPECT_ANY_MESSAGE(log);
1038         /* X - 0 == X */
1039         INVALID_INFO_MESSAGE(log, "Folding Math_Cx::");
1040         CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Value to socket Attribute::Fac.");
1041         INVALID_INFO_MESSAGE(log, "Folding Out::");
1042
1043         build_math_partial_test_graph(builder, NODE_MATH_SUBTRACT, 0.0f);
1044         graph.finalize(&scene);
1045 }
1046
1047 /*
1048  * Tests: partial folding for Math Mul with known 1.
1049  */
1050 TEST(render_graph, constant_fold_part_math_mul_1)
1051 {
1052         DEFINE_COMMON_VARIABLES(builder, log);
1053
1054         EXPECT_ANY_MESSAGE(log);
1055         /* X * 1 == 1 * X == X */
1056         CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Value to socket Attribute::Fac.");
1057         CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Value to socket Attribute::Fac.");
1058         INVALID_INFO_MESSAGE(log, "Folding Out::");
1059
1060         build_math_partial_test_graph(builder, NODE_MATH_MULTIPLY, 1.0f);
1061         graph.finalize(&scene);
1062 }
1063
1064 /*
1065  * Tests: partial folding for Math Div with known 1.
1066  */
1067 TEST(render_graph, constant_fold_part_math_div_1)
1068 {
1069         DEFINE_COMMON_VARIABLES(builder, log);
1070
1071         EXPECT_ANY_MESSAGE(log);
1072         /* X / 1 == X */
1073         INVALID_INFO_MESSAGE(log, "Folding Math_Cx::");
1074         CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Value to socket Attribute::Fac.");
1075         INVALID_INFO_MESSAGE(log, "Folding Out::");
1076
1077         build_math_partial_test_graph(builder, NODE_MATH_DIVIDE, 1.0f);
1078         graph.finalize(&scene);
1079 }
1080
1081 /*
1082  * Tests: partial folding for Math Mul with known 0.
1083  */
1084 TEST(render_graph, constant_fold_part_math_mul_0)
1085 {
1086         DEFINE_COMMON_VARIABLES(builder, log);
1087
1088         EXPECT_ANY_MESSAGE(log);
1089         /* X * 0 == 0 * X == 0 */
1090         CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Value to constant (0).");
1091         CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Value to constant (0).");
1092         CORRECT_INFO_MESSAGE(log, "Folding Out::Value to constant (0)");
1093         CORRECT_INFO_MESSAGE(log, "Discarding closure EmissionNode.");
1094
1095         build_math_partial_test_graph(builder, NODE_MATH_MULTIPLY, 0.0f);
1096         graph.finalize(&scene);
1097 }
1098
1099 /*
1100  * Tests: partial folding for Math Div with known 0.
1101  */
1102 TEST(render_graph, constant_fold_part_math_div_0)
1103 {
1104         DEFINE_COMMON_VARIABLES(builder, log);
1105
1106         EXPECT_ANY_MESSAGE(log);
1107         /* 0 / X == 0 */
1108         CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Value to constant (0).");
1109         INVALID_INFO_MESSAGE(log, "Folding Math_xC::");
1110         INVALID_INFO_MESSAGE(log, "Folding Out::");
1111
1112         build_math_partial_test_graph(builder, NODE_MATH_DIVIDE, 0.0f);
1113         graph.finalize(&scene);
1114 }
1115
1116 /*
1117  * Tests: Vector Math with all constant inputs.
1118  */
1119 TEST(render_graph, constant_fold_vector_math)
1120 {
1121         DEFINE_COMMON_VARIABLES(builder, log);
1122
1123         EXPECT_ANY_MESSAGE(log);
1124         CORRECT_INFO_MESSAGE(log, "Folding VectorMath::Value to constant (1).");
1125         CORRECT_INFO_MESSAGE(log, "Folding VectorMath::Vector to constant (3, 0, 0).");
1126         CORRECT_INFO_MESSAGE(log, "Folding convert_vector_to_float::value_float to constant (1).");
1127         CORRECT_INFO_MESSAGE(log, "Folding Math::Value to constant (2).");
1128         CORRECT_INFO_MESSAGE(log, "Folding convert_float_to_color::value_color to constant (2, 2, 2).");
1129
1130         builder
1131                 .add_node(ShaderNodeBuilder<VectorMathNode>("VectorMath")
1132                           .set(&VectorMathNode::type, NODE_VECTOR_MATH_SUBTRACT)
1133                           .set("Vector1", make_float3(1.3f, 0.5f, 0.7f))
1134                           .set("Vector2", make_float3(-1.7f, 0.5f, 0.7f)))
1135                 .add_node(ShaderNodeBuilder<MathNode>("Math")
1136                           .set(&MathNode::type, NODE_MATH_ADD))
1137                 .add_connection("VectorMath::Vector", "Math::Value1")
1138                 .add_connection("VectorMath::Value", "Math::Value2")
1139                 .output_color("Math::Value");
1140
1141         graph.finalize(&scene);
1142 }
1143
1144 /*
1145  * Graph for testing partial folds of Vector Math with one constant argument.
1146  * Includes 2 tests: constant on each side.
1147  */
1148 static void build_vecmath_partial_test_graph(ShaderGraphBuilder &builder, NodeVectorMath type, float3 constval)
1149 {
1150         builder
1151                 .add_attribute("Attribute")
1152                 /* constant on the left */
1153                 .add_node(ShaderNodeBuilder<VectorMathNode>("Math_Cx")
1154                           .set(&VectorMathNode::type, type)
1155                           .set("Vector1", constval))
1156                 .add_connection("Attribute::Vector", "Math_Cx::Vector2")
1157                 /* constant on the right */
1158                 .add_node(ShaderNodeBuilder<VectorMathNode>("Math_xC")
1159                           .set(&VectorMathNode::type, type)
1160                           .set("Vector2", constval))
1161                 .add_connection("Attribute::Vector", "Math_xC::Vector1")
1162                 /* output sum */
1163                 .add_node(ShaderNodeBuilder<VectorMathNode>("Out")
1164                           .set(&VectorMathNode::type, NODE_VECTOR_MATH_ADD))
1165                 .add_connection("Math_Cx::Vector", "Out::Vector1")
1166                 .add_connection("Math_xC::Vector", "Out::Vector2")
1167                 .output_color("Out::Vector");
1168 }
1169
1170 /*
1171  * Tests: partial folding for Vector Math Add with known 0.
1172  */
1173 TEST(render_graph, constant_fold_part_vecmath_add_0)
1174 {
1175         DEFINE_COMMON_VARIABLES(builder, log);
1176
1177         EXPECT_ANY_MESSAGE(log);
1178         /* X + 0 == 0 + X == X */
1179         CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Vector to socket Attribute::Vector.");
1180         CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Vector to socket Attribute::Vector.");
1181         INVALID_INFO_MESSAGE(log, "Folding Out::");
1182
1183         build_vecmath_partial_test_graph(builder, NODE_VECTOR_MATH_ADD, make_float3(0,0,0));
1184         graph.finalize(&scene);
1185 }
1186
1187 /*
1188  * Tests: partial folding for Vector Math Sub with known 0.
1189  */
1190 TEST(render_graph, constant_fold_part_vecmath_sub_0)
1191 {
1192         DEFINE_COMMON_VARIABLES(builder, log);
1193
1194         EXPECT_ANY_MESSAGE(log);
1195         /* X - 0 == X */
1196         INVALID_INFO_MESSAGE(log, "Folding Math_Cx::");
1197         CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Vector to socket Attribute::Vector.");
1198         INVALID_INFO_MESSAGE(log, "Folding Out::");
1199
1200         build_vecmath_partial_test_graph(builder, NODE_VECTOR_MATH_SUBTRACT, make_float3(0,0,0));
1201         graph.finalize(&scene);
1202 }
1203
1204 /*
1205  * Tests: partial folding for Vector Math Dot Product with known 0.
1206  */
1207 TEST(render_graph, constant_fold_part_vecmath_dot_0)
1208 {
1209         DEFINE_COMMON_VARIABLES(builder, log);
1210
1211         EXPECT_ANY_MESSAGE(log);
1212         /* X * 0 == 0 * X == X */
1213         CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Vector to constant (0, 0, 0).");
1214         CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Vector to constant (0, 0, 0).");
1215         CORRECT_INFO_MESSAGE(log, "Folding Out::Vector to constant (0, 0, 0).");
1216         CORRECT_INFO_MESSAGE(log, "Discarding closure EmissionNode.");
1217
1218         build_vecmath_partial_test_graph(builder, NODE_VECTOR_MATH_DOT_PRODUCT, make_float3(0,0,0));
1219         graph.finalize(&scene);
1220 }
1221
1222 /*
1223  * Tests: partial folding for Vector Math Cross Product with known 0.
1224  */
1225 TEST(render_graph, constant_fold_part_vecmath_cross_0)
1226 {
1227         DEFINE_COMMON_VARIABLES(builder, log);
1228
1229         EXPECT_ANY_MESSAGE(log);
1230         /* X * 0 == 0 * X == X */
1231         CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Vector to constant (0, 0, 0).");
1232         CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Vector to constant (0, 0, 0).");
1233         CORRECT_INFO_MESSAGE(log, "Folding Out::Vector to constant (0, 0, 0).");
1234         CORRECT_INFO_MESSAGE(log, "Discarding closure EmissionNode.");
1235
1236         build_vecmath_partial_test_graph(builder, NODE_VECTOR_MATH_CROSS_PRODUCT, make_float3(0,0,0));
1237         graph.finalize(&scene);
1238 }
1239
1240 /*
1241  * Tests: Bump with no height input folded to Normal input.
1242  */
1243 TEST(render_graph, constant_fold_bump)
1244 {
1245         DEFINE_COMMON_VARIABLES(builder, log);
1246
1247         EXPECT_ANY_MESSAGE(log);
1248         CORRECT_INFO_MESSAGE(log, "Folding Bump::Normal to socket Geometry1::Normal.");
1249
1250         builder
1251                 .add_node(ShaderNodeBuilder<GeometryNode>("Geometry1"))
1252                 .add_node(ShaderNodeBuilder<BumpNode>("Bump"))
1253                 .add_connection("Geometry1::Normal", "Bump::Normal")
1254                 .output_color("Bump::Normal");
1255
1256         graph.finalize(&scene);
1257 }
1258
1259 /*
1260  * Tests: Bump with no inputs folded to Geometry::Normal.
1261  */
1262 TEST(render_graph, constant_fold_bump_no_input)
1263 {
1264         DEFINE_COMMON_VARIABLES(builder, log);
1265
1266         EXPECT_ANY_MESSAGE(log);
1267         CORRECT_INFO_MESSAGE(log, "Folding Bump::Normal to socket geometry::Normal.");
1268
1269         builder
1270                 .add_node(ShaderNodeBuilder<BumpNode>("Bump"))
1271                 .output_color("Bump::Normal");
1272
1273         graph.finalize(&scene);
1274 }
1275
1276 template<class T>
1277 void init_test_curve(array<T> &buffer, T start, T end, int steps)
1278 {
1279         buffer.resize(steps);
1280
1281         for (int i = 0; i < steps; i++)
1282                 buffer[i] = lerp(start, end, float(i)/(steps-1));
1283 }
1284
1285 /*
1286  * Tests:
1287  *  - Folding of RGB Curves with all constant inputs.
1288  */
1289 TEST(render_graph, constant_fold_rgb_curves)
1290 {
1291         DEFINE_COMMON_VARIABLES(builder, log);
1292
1293         EXPECT_ANY_MESSAGE(log);
1294         CORRECT_INFO_MESSAGE(log, "Folding Curves::Color to constant (0.275, 0.5, 0.475).");
1295
1296         array<float3> curve;
1297         init_test_curve(curve, make_float3(0.0f, 0.25f, 1.0f), make_float3(1.0f, 0.75f, 0.0f), 257);
1298
1299         builder
1300                 .add_node(ShaderNodeBuilder<RGBCurvesNode>("Curves")
1301                           .set(&CurvesNode::curves, curve)
1302                           .set(&CurvesNode::min_x, 0.1f)
1303                           .set(&CurvesNode::max_x, 0.9f)
1304                           .set("Fac", 0.5f)
1305                           .set("Color", make_float3(0.3f, 0.5f, 0.7f)))
1306                 .output_color("Curves::Color");
1307
1308         graph.finalize(&scene);
1309 }
1310
1311 /*
1312  * Tests:
1313  *  - Folding of RGB Curves with zero Fac.
1314  */
1315 TEST(render_graph, constant_fold_rgb_curves_fac_0)
1316 {
1317         DEFINE_COMMON_VARIABLES(builder, log);
1318
1319         EXPECT_ANY_MESSAGE(log);
1320         CORRECT_INFO_MESSAGE(log, "Folding Curves::Color to socket Attribute::Color.");
1321
1322         array<float3> curve;
1323         init_test_curve(curve, make_float3(0.0f, 0.25f, 1.0f), make_float3(1.0f, 0.75f, 0.0f), 257);
1324
1325         builder
1326                 .add_attribute("Attribute")
1327                 .add_node(ShaderNodeBuilder<RGBCurvesNode>("Curves")
1328                           .set(&CurvesNode::curves, curve)
1329                           .set(&CurvesNode::min_x, 0.1f)
1330                           .set(&CurvesNode::max_x, 0.9f)
1331                           .set("Fac", 0.0f))
1332                 .add_connection("Attribute::Color", "Curves::Color")
1333                 .output_color("Curves::Color");
1334
1335         graph.finalize(&scene);
1336 }
1337
1338 /*
1339  * Tests:
1340  *  - Folding of Vector Curves with all constant inputs.
1341  */
1342 TEST(render_graph, constant_fold_vector_curves)
1343 {
1344         DEFINE_COMMON_VARIABLES(builder, log);
1345
1346         EXPECT_ANY_MESSAGE(log);
1347         CORRECT_INFO_MESSAGE(log, "Folding Curves::Vector to constant (0.275, 0.5, 0.475).");
1348
1349         array<float3> curve;
1350         init_test_curve(curve, make_float3(0.0f, 0.25f, 1.0f), make_float3(1.0f, 0.75f, 0.0f), 257);
1351
1352         builder
1353                 .add_node(ShaderNodeBuilder<VectorCurvesNode>("Curves")
1354                           .set(&CurvesNode::curves, curve)
1355                           .set(&CurvesNode::min_x, 0.1f)
1356                           .set(&CurvesNode::max_x, 0.9f)
1357                           .set("Fac", 0.5f)
1358                           .set("Vector", make_float3(0.3f, 0.5f, 0.7f)))
1359                 .output_color("Curves::Vector");
1360
1361         graph.finalize(&scene);
1362 }
1363
1364 /*
1365  * Tests:
1366  *  - Folding of Vector Curves with zero Fac.
1367  */
1368 TEST(render_graph, constant_fold_vector_curves_fac_0)
1369 {
1370         DEFINE_COMMON_VARIABLES(builder, log);
1371
1372         EXPECT_ANY_MESSAGE(log);
1373         CORRECT_INFO_MESSAGE(log, "Folding Curves::Vector to socket Attribute::Vector.");
1374
1375         array<float3> curve;
1376         init_test_curve(curve, make_float3(0.0f, 0.25f, 1.0f), make_float3(1.0f, 0.75f, 0.0f), 257);
1377
1378         builder
1379                 .add_attribute("Attribute")
1380                 .add_node(ShaderNodeBuilder<VectorCurvesNode>("Curves")
1381                           .set(&CurvesNode::curves, curve)
1382                           .set(&CurvesNode::min_x, 0.1f)
1383                           .set(&CurvesNode::max_x, 0.9f)
1384                           .set("Fac", 0.0f))
1385                 .add_connection("Attribute::Vector", "Curves::Vector")
1386                 .output_color("Curves::Vector");
1387
1388         graph.finalize(&scene);
1389 }
1390
1391 /*
1392  * Tests:
1393  *  - Folding of Color Ramp with all constant inputs.
1394  */
1395 TEST(render_graph, constant_fold_rgb_ramp)
1396 {
1397         DEFINE_COMMON_VARIABLES(builder, log);
1398
1399         EXPECT_ANY_MESSAGE(log);
1400         CORRECT_INFO_MESSAGE(log, "Folding Ramp::Color to constant (0.14, 0.39, 0.64).");
1401         CORRECT_INFO_MESSAGE(log, "Folding Ramp::Alpha to constant (0.89).");
1402
1403         array<float3> curve;
1404         array<float> alpha;
1405         init_test_curve(curve, make_float3(0.0f, 0.25f, 0.5f), make_float3(0.25f, 0.5f, 0.75f), 9);
1406         init_test_curve(alpha, 0.75f, 1.0f, 9);
1407
1408         builder
1409                 .add_node(ShaderNodeBuilder<RGBRampNode>("Ramp")
1410                           .set(&RGBRampNode::ramp, curve)
1411                           .set(&RGBRampNode::ramp_alpha, alpha)
1412                           .set(&RGBRampNode::interpolate, true)
1413                           .set("Fac", 0.56f))
1414                 .add_node(ShaderNodeBuilder<MixNode>("Mix")
1415                           .set(&MixNode::type, NODE_MIX_ADD))
1416                 .add_connection("Ramp::Color", "Mix::Color1")
1417                 .add_connection("Ramp::Alpha", "Mix::Color2")
1418                 .output_color("Mix::Color");
1419
1420         graph.finalize(&scene);
1421 }
1422
1423 /*
1424  * Tests:
1425  *  - Folding of Color Ramp with all constant inputs (interpolate false).
1426  */
1427 TEST(render_graph, constant_fold_rgb_ramp_flat)
1428 {
1429         DEFINE_COMMON_VARIABLES(builder, log);
1430
1431         EXPECT_ANY_MESSAGE(log);
1432         CORRECT_INFO_MESSAGE(log, "Folding Ramp::Color to constant (0.125, 0.375, 0.625).");
1433         CORRECT_INFO_MESSAGE(log, "Folding Ramp::Alpha to constant (0.875).");
1434
1435         array<float3> curve;
1436         array<float> alpha;
1437         init_test_curve(curve, make_float3(0.0f, 0.25f, 0.5f), make_float3(0.25f, 0.5f, 0.75f), 9);
1438         init_test_curve(alpha, 0.75f, 1.0f, 9);
1439
1440         builder
1441                 .add_node(ShaderNodeBuilder<RGBRampNode>("Ramp")
1442                           .set(&RGBRampNode::ramp, curve)
1443                           .set(&RGBRampNode::ramp_alpha, alpha)
1444                           .set(&RGBRampNode::interpolate, false)
1445                           .set("Fac", 0.56f))
1446                 .add_node(ShaderNodeBuilder<MixNode>("Mix")
1447                           .set(&MixNode::type, NODE_MIX_ADD))
1448                 .add_connection("Ramp::Color", "Mix::Color1")
1449                 .add_connection("Ramp::Alpha", "Mix::Color2")
1450                 .output_color("Mix::Color");
1451
1452         graph.finalize(&scene);
1453 }
1454
1455 CCL_NAMESPACE_END