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