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