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