Blender V4.3
FN_field_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "testing/testing.h"
6
7#include "BLI_cpp_type.hh"
8#include "FN_field.hh"
11
13
14TEST(field, ConstantFunction)
15{
16 GField constant_field{
17 FieldOperation::Create(std::make_unique<mf::CustomMF_Constant<int>>(10), {}), 0};
18
20
21 FieldContext context;
22 FieldEvaluator evaluator{context, 4};
23 evaluator.add_with_destination(constant_field, result.as_mutable_span());
24 evaluator.evaluate();
25 EXPECT_EQ(result[0], 10);
26 EXPECT_EQ(result[1], 10);
27 EXPECT_EQ(result[2], 10);
28 EXPECT_EQ(result[3], 10);
29}
30
31class IndexFieldInput final : public FieldInput {
32 public:
33 IndexFieldInput() : FieldInput(CPPType::get<int>(), "Index") {}
34
36 const IndexMask &mask,
37 ResourceScope & /*scope*/) const final
38 {
39 auto index_func = [](int i) { return i; };
40 return VArray<int>::ForFunc(mask.min_array_size(), index_func);
41 }
42};
43
44TEST(field, VArrayInput)
45{
46 GField index_field{std::make_shared<IndexFieldInput>()};
47
48 Array<int> result_1(4);
49
50 FieldContext context;
51 FieldEvaluator evaluator{context, 4};
52 evaluator.add_with_destination(index_field, result_1.as_mutable_span());
53 evaluator.evaluate();
54 EXPECT_EQ(result_1[0], 0);
55 EXPECT_EQ(result_1[1], 1);
56 EXPECT_EQ(result_1[2], 2);
57 EXPECT_EQ(result_1[3], 3);
58
59 /* Evaluate a second time, just to test that the first didn't break anything. */
60 Array<int> result_2(10);
61
62 const Array<int64_t> indices = {2, 4, 6, 8};
63 IndexMaskMemory memory;
64 const IndexMask mask = IndexMask::from_indices<int64_t>(indices, memory);
65
66 FieldEvaluator evaluator_2{context, &mask};
67 evaluator_2.add_with_destination(index_field, result_2.as_mutable_span());
68 evaluator_2.evaluate();
69 EXPECT_EQ(result_2[2], 2);
70 EXPECT_EQ(result_2[4], 4);
71 EXPECT_EQ(result_2[6], 6);
72 EXPECT_EQ(result_2[8], 8);
73}
74
75TEST(field, VArrayInputMultipleOutputs)
76{
77 std::shared_ptr<FieldInput> index_input = std::make_shared<IndexFieldInput>();
78 GField field_1{index_input};
79 GField field_2{index_input};
80
81 Array<int> result_1(10);
82 Array<int> result_2(10);
83
84 const Array<int64_t> indices = {2, 4, 6, 8};
85 IndexMaskMemory memory;
86 const IndexMask mask = IndexMask::from_indices<int64_t>(indices, memory);
87
88 FieldContext context;
89 FieldEvaluator evaluator{context, &mask};
90 evaluator.add_with_destination(field_1, result_1.as_mutable_span());
91 evaluator.add_with_destination(field_2, result_2.as_mutable_span());
92 evaluator.evaluate();
93 EXPECT_EQ(result_1[2], 2);
94 EXPECT_EQ(result_1[4], 4);
95 EXPECT_EQ(result_1[6], 6);
96 EXPECT_EQ(result_1[8], 8);
97 EXPECT_EQ(result_2[2], 2);
98 EXPECT_EQ(result_2[4], 4);
99 EXPECT_EQ(result_2[6], 6);
100 EXPECT_EQ(result_2[8], 8);
101}
102
103TEST(field, InputAndFunction)
104{
105 GField index_field{std::make_shared<IndexFieldInput>()};
106
107 auto add_fn = mf::build::SI2_SO<int, int, int>("add", [](int a, int b) { return a + b; });
108 GField output_field{FieldOperation::Create(add_fn, {index_field, index_field}), 0};
109
110 Array<int> result(10);
111
112 const Array<int64_t> indices = {2, 4, 6, 8};
113 IndexMaskMemory memory;
114 const IndexMask mask = IndexMask::from_indices<int64_t>(indices, memory);
115
116 FieldContext context;
117 FieldEvaluator evaluator{context, &mask};
118 evaluator.add_with_destination(output_field, result.as_mutable_span());
119 evaluator.evaluate();
120 EXPECT_EQ(result[2], 4);
121 EXPECT_EQ(result[4], 8);
122 EXPECT_EQ(result[6], 12);
123 EXPECT_EQ(result[8], 16);
124}
125
126TEST(field, TwoFunctions)
127{
128 GField index_field{std::make_shared<IndexFieldInput>()};
129
130 auto add_fn = mf::build::SI2_SO<int, int, int>("add", [](int a, int b) { return a + b; });
131 GField add_field{FieldOperation::Create(add_fn, {index_field, index_field}), 0};
132
133 auto add_10_fn = mf::build::SI1_SO<int, int>("add_10", [](int a) { return a + 10; });
134 GField result_field{FieldOperation::Create(add_10_fn, {add_field}), 0};
135
136 Array<int> result(10);
137
138 const Array<int64_t> indices = {2, 4, 6, 8};
139 IndexMaskMemory memory;
140 const IndexMask mask = IndexMask::from_indices<int64_t>(indices, memory);
141
142 FieldContext context;
143 FieldEvaluator evaluator{context, &mask};
144 evaluator.add_with_destination(result_field, result.as_mutable_span());
145 evaluator.evaluate();
146 EXPECT_EQ(result[2], 14);
147 EXPECT_EQ(result[4], 18);
148 EXPECT_EQ(result[6], 22);
149 EXPECT_EQ(result[8], 26);
150}
151
153 private:
154 mf::Signature signature_;
155
156 public:
158 {
159 mf::SignatureBuilder builder{"Two Outputs", signature_};
160 builder.single_input<int>("In1");
161 builder.single_input<int>("In2");
162 builder.single_output<int>("Add");
163 builder.single_output<int>("Add10");
164 this->set_signature(&signature_);
165 }
166
167 void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override
168 {
169 const VArray<int> &in1 = params.readonly_single_input<int>(0, "In1");
170 const VArray<int> &in2 = params.readonly_single_input<int>(1, "In2");
171 MutableSpan<int> add = params.uninitialized_single_output<int>(2, "Add");
172 MutableSpan<int> add_10 = params.uninitialized_single_output<int>(3, "Add10");
173 mask.foreach_index([&](const int64_t i) {
174 add[i] = in1[i] + in2[i];
175 add_10[i] = add[i] + 10;
176 });
177 }
178};
179
180TEST(field, FunctionTwoOutputs)
181{
182 /* Also use two separate input fields, why not. */
183 GField index_field_1{std::make_shared<IndexFieldInput>()};
184 GField index_field_2{std::make_shared<IndexFieldInput>()};
185
186 std::shared_ptr<FieldOperation> fn = FieldOperation::Create(
187 std::make_unique<TwoOutputFunction>(), {index_field_1, index_field_2});
188
189 GField result_field_1{fn, 0};
190 GField result_field_2{fn, 1};
191
192 Array<int> result_1(10);
193 Array<int> result_2(10);
194
195 const Array<int64_t> indices = {2, 4, 6, 8};
196 IndexMaskMemory memory;
197 const IndexMask mask = IndexMask::from_indices<int64_t>(indices, memory);
198
199 FieldContext context;
200 FieldEvaluator evaluator{context, &mask};
201 evaluator.add_with_destination(result_field_1, result_1.as_mutable_span());
202 evaluator.add_with_destination(result_field_2, result_2.as_mutable_span());
203 evaluator.evaluate();
204 EXPECT_EQ(result_1[2], 4);
205 EXPECT_EQ(result_1[4], 8);
206 EXPECT_EQ(result_1[6], 12);
207 EXPECT_EQ(result_1[8], 16);
208 EXPECT_EQ(result_2[2], 14);
209 EXPECT_EQ(result_2[4], 18);
210 EXPECT_EQ(result_2[6], 22);
211 EXPECT_EQ(result_2[8], 26);
212}
213
214TEST(field, TwoFunctionsTwoOutputs)
215{
216 GField index_field{std::make_shared<IndexFieldInput>()};
217
218 std::shared_ptr<FieldOperation> fn = FieldOperation::Create(
219 std::make_unique<TwoOutputFunction>(), {index_field, index_field});
220
221 Array<int64_t> mask_indices = {2, 4, 6, 8};
222 IndexMaskMemory memory;
223 IndexMask mask = IndexMask::from_indices<int64_t>(mask_indices, memory);
224
225 Field<int> result_field_1{fn, 0};
226 Field<int> intermediate_field{fn, 1};
227
228 auto add_10_fn = mf::build::SI1_SO<int, int>("add_10", [](int a) { return a + 10; });
229 Field<int> result_field_2{FieldOperation::Create(add_10_fn, {intermediate_field}), 0};
230
231 FieldContext field_context;
232 FieldEvaluator field_evaluator{field_context, &mask};
233 VArray<int> result_1;
234 VArray<int> result_2;
235 field_evaluator.add(result_field_1, &result_1);
236 field_evaluator.add(result_field_2, &result_2);
237 field_evaluator.evaluate();
238
239 EXPECT_EQ(result_1.get(2), 4);
240 EXPECT_EQ(result_1.get(4), 8);
241 EXPECT_EQ(result_1.get(6), 12);
242 EXPECT_EQ(result_1.get(8), 16);
243 EXPECT_EQ(result_2.get(2), 24);
244 EXPECT_EQ(result_2.get(4), 28);
245 EXPECT_EQ(result_2.get(6), 32);
246 EXPECT_EQ(result_2.get(8), 36);
247}
248
249TEST(field, SameFieldTwice)
250{
251 GField constant_field{FieldOperation::Create(std::make_unique<mf::CustomMF_Constant<int>>(10)),
252 0};
253
254 FieldContext field_context;
255 IndexMask mask{IndexRange(2)};
256 ResourceScope scope;
258 scope, {constant_field, constant_field}, mask, field_context);
259
260 VArray<int> varray1 = results[0].typed<int>();
261 VArray<int> varray2 = results[1].typed<int>();
262
263 EXPECT_EQ(varray1.get(0), 10);
264 EXPECT_EQ(varray1.get(1), 10);
265 EXPECT_EQ(varray2.get(0), 10);
266 EXPECT_EQ(varray2.get(1), 10);
267}
268
269TEST(field, IgnoredOutput)
270{
271 static mf::tests::OptionalOutputsFunction fn;
273
274 FieldContext field_context;
275 FieldEvaluator field_evaluator{field_context, 10};
276 VArray<int> results;
277 field_evaluator.add(field, &results);
278 field_evaluator.evaluate();
279
280 EXPECT_EQ(results.get(0), 5);
281 EXPECT_EQ(results.get(3), 5);
282}
283
284} // namespace blender::fn::tests
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:237
T get(const int64_t index) const
static VArray ForFunc(const int64_t size, GetFunc get_func)
int add_with_destination(GField field, GVMutableArray dst)
Definition field.cc:743
static std::shared_ptr< FieldOperation > Create(std::shared_ptr< const mf::MultiFunction > function, Vector< GField > inputs={})
Definition FN_field.hh:244
void set_signature(const Signature *signature)
GVArray get_varray_for_context(const FieldContext &, const IndexMask &mask, ResourceScope &) const final
void call(const IndexMask &mask, mf::Params params, mf::Context) const override
static IndexMask from_indices(Span< T > indices, IndexMaskMemory &memory)
local_group_size(16, 16) .push_constant(Type b
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_device_inline float4 mask(const int4 mask, const float4 a)
TEST(field, ConstantFunction)
Vector< GVArray > evaluate_fields(ResourceScope &scope, Span< GFieldRef > fields_to_evaluate, const IndexMask &mask, const FieldContext &context, Span< GVMutableArray > dst_varrays={})
Definition field.cc:281
__int64 int64_t
Definition stdint.h:89