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