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