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