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