Blender  V3.3
FN_field_test.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0 */
2 
3 #include "testing/testing.h"
4 
5 #include "BLI_cpp_type.hh"
6 #include "FN_field.hh"
9 
10 namespace blender::fn::tests {
11 
12 TEST(field, ConstantFunction)
13 {
14  /* TODO: Figure out how to not use another "FieldOperation(" inside of std::make_shared. */
15  GField constant_field{std::make_shared<FieldOperation>(
16  FieldOperation(std::make_unique<CustomMF_Constant<int>>(10), {})),
17  0};
18 
19  Array<int> result(4);
20 
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 
32  public:
33  IndexFieldInput() : FieldInput(CPPType::get<int>(), "Index")
34  {
35  }
36 
39  ResourceScope &UNUSED(scope)) const final
40  {
41  auto index_func = [](int i) { return i; };
42  return VArray<int>::ForFunc(mask.min_array_size(), index_func);
43  }
44 };
45 
46 TEST(field, VArrayInput)
47 {
48  GField index_field{std::make_shared<IndexFieldInput>()};
49 
50  Array<int> result_1(4);
51 
53  FieldEvaluator evaluator{context, 4};
54  evaluator.add_with_destination(index_field, result_1.as_mutable_span());
55  evaluator.evaluate();
56  EXPECT_EQ(result_1[0], 0);
57  EXPECT_EQ(result_1[1], 1);
58  EXPECT_EQ(result_1[2], 2);
59  EXPECT_EQ(result_1[3], 3);
60 
61  /* Evaluate a second time, just to test that the first didn't break anything. */
62  Array<int> result_2(10);
63 
64  const Array<int64_t> indices = {2, 4, 6, 8};
65  const IndexMask mask{indices};
66 
67  FieldEvaluator evaluator_2{context, &mask};
68  evaluator_2.add_with_destination(index_field, result_2.as_mutable_span());
69  evaluator_2.evaluate();
70  EXPECT_EQ(result_2[2], 2);
71  EXPECT_EQ(result_2[4], 4);
72  EXPECT_EQ(result_2[6], 6);
73  EXPECT_EQ(result_2[8], 8);
74 }
75 
76 TEST(field, VArrayInputMultipleOutputs)
77 {
78  std::shared_ptr<FieldInput> index_input = std::make_shared<IndexFieldInput>();
79  GField field_1{index_input};
80  GField field_2{index_input};
81 
82  Array<int> result_1(10);
83  Array<int> result_2(10);
84 
85  const Array<int64_t> indices = {2, 4, 6, 8};
86  const IndexMask mask{indices};
87 
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 
103 TEST(field, InputAndFunction)
104 {
105  GField index_field{std::make_shared<IndexFieldInput>()};
106 
107  std::unique_ptr<MultiFunction> add_fn = std::make_unique<CustomMF_SI_SI_SO<int, int, int>>(
108  "add", [](int a, int b) { return a + b; });
109  GField output_field{std::make_shared<FieldOperation>(
110  FieldOperation(std::move(add_fn), {index_field, index_field})),
111  0};
112 
113  Array<int> result(10);
114 
115  const Array<int64_t> indices = {2, 4, 6, 8};
116  const IndexMask mask{indices};
117 
119  FieldEvaluator evaluator{context, &mask};
120  evaluator.add_with_destination(output_field, result.as_mutable_span());
121  evaluator.evaluate();
122  EXPECT_EQ(result[2], 4);
123  EXPECT_EQ(result[4], 8);
124  EXPECT_EQ(result[6], 12);
125  EXPECT_EQ(result[8], 16);
126 }
127 
128 TEST(field, TwoFunctions)
129 {
130  GField index_field{std::make_shared<IndexFieldInput>()};
131 
132  std::unique_ptr<MultiFunction> add_fn = std::make_unique<CustomMF_SI_SI_SO<int, int, int>>(
133  "add", [](int a, int b) { return a + b; });
134  GField add_field{std::make_shared<FieldOperation>(
135  FieldOperation(std::move(add_fn), {index_field, index_field})),
136  0};
137 
138  std::unique_ptr<MultiFunction> add_10_fn = std::make_unique<CustomMF_SI_SO<int, int>>(
139  "add_10", [](int a) { return a + 10; });
140  GField result_field{
141  std::make_shared<FieldOperation>(FieldOperation(std::move(add_10_fn), {add_field})), 0};
142 
143  Array<int> result(10);
144 
145  const Array<int64_t> indices = {2, 4, 6, 8};
146  const IndexMask mask{indices};
147 
149  FieldEvaluator evaluator{context, &mask};
150  evaluator.add_with_destination(result_field, result.as_mutable_span());
151  evaluator.evaluate();
152  EXPECT_EQ(result[2], 14);
153  EXPECT_EQ(result[4], 18);
154  EXPECT_EQ(result[6], 22);
155  EXPECT_EQ(result[8], 26);
156 }
157 
159  private:
160  MFSignature signature_;
161 
162  public:
164  {
165  MFSignatureBuilder signature{"Two Outputs"};
166  signature.single_input<int>("In1");
167  signature.single_input<int>("In2");
168  signature.single_output<int>("Add");
169  signature.single_output<int>("Add10");
170  signature_ = signature.build();
171  this->set_signature(&signature_);
172  }
173 
175  {
176  const VArray<int> &in1 = params.readonly_single_input<int>(0, "In1");
177  const VArray<int> &in2 = params.readonly_single_input<int>(1, "In2");
178  MutableSpan<int> add = params.uninitialized_single_output<int>(2, "Add");
179  MutableSpan<int> add_10 = params.uninitialized_single_output<int>(3, "Add10");
180  mask.foreach_index([&](const int64_t i) {
181  add[i] = in1[i] + in2[i];
182  add_10[i] = add[i] + 10;
183  });
184  }
185 };
186 
187 TEST(field, FunctionTwoOutputs)
188 {
189  /* Also use two separate input fields, why not. */
190  GField index_field_1{std::make_shared<IndexFieldInput>()};
191  GField index_field_2{std::make_shared<IndexFieldInput>()};
192 
193  std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(
194  FieldOperation(std::make_unique<TwoOutputFunction>(), {index_field_1, index_field_2}));
195 
196  GField result_field_1{fn, 0};
197  GField result_field_2{fn, 1};
198 
199  Array<int> result_1(10);
200  Array<int> result_2(10);
201 
202  const Array<int64_t> indices = {2, 4, 6, 8};
203  const IndexMask mask{indices};
204 
206  FieldEvaluator evaluator{context, &mask};
207  evaluator.add_with_destination(result_field_1, result_1.as_mutable_span());
208  evaluator.add_with_destination(result_field_2, result_2.as_mutable_span());
209  evaluator.evaluate();
210  EXPECT_EQ(result_1[2], 4);
211  EXPECT_EQ(result_1[4], 8);
212  EXPECT_EQ(result_1[6], 12);
213  EXPECT_EQ(result_1[8], 16);
214  EXPECT_EQ(result_2[2], 14);
215  EXPECT_EQ(result_2[4], 18);
216  EXPECT_EQ(result_2[6], 22);
217  EXPECT_EQ(result_2[8], 26);
218 }
219 
220 TEST(field, TwoFunctionsTwoOutputs)
221 {
222  GField index_field{std::make_shared<IndexFieldInput>()};
223 
224  std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(
225  FieldOperation(std::make_unique<TwoOutputFunction>(), {index_field, index_field}));
226 
227  Array<int64_t> mask_indices = {2, 4, 6, 8};
228  IndexMask mask = mask_indices.as_span();
229 
230  Field<int> result_field_1{fn, 0};
231  Field<int> intermediate_field{fn, 1};
232 
233  std::unique_ptr<MultiFunction> add_10_fn = std::make_unique<CustomMF_SI_SO<int, int>>(
234  "add_10", [](int a) { return a + 10; });
235  Field<int> result_field_2{
236  std::make_shared<FieldOperation>(FieldOperation(std::move(add_10_fn), {intermediate_field})),
237  0};
238 
239  FieldContext field_context;
240  FieldEvaluator field_evaluator{field_context, &mask};
241  VArray<int> result_1;
242  VArray<int> result_2;
243  field_evaluator.add(result_field_1, &result_1);
244  field_evaluator.add(result_field_2, &result_2);
245  field_evaluator.evaluate();
246 
247  EXPECT_EQ(result_1.get(2), 4);
248  EXPECT_EQ(result_1.get(4), 8);
249  EXPECT_EQ(result_1.get(6), 12);
250  EXPECT_EQ(result_1.get(8), 16);
251  EXPECT_EQ(result_2.get(2), 24);
252  EXPECT_EQ(result_2.get(4), 28);
253  EXPECT_EQ(result_2.get(6), 32);
254  EXPECT_EQ(result_2.get(8), 36);
255 }
256 
257 TEST(field, SameFieldTwice)
258 {
259  GField constant_field{
260  std::make_shared<FieldOperation>(std::make_unique<CustomMF_Constant<int>>(10)), 0};
261 
262  FieldContext field_context;
264  ResourceScope scope;
266  scope, {constant_field, constant_field}, mask, field_context);
267 
268  VArray<int> varray1 = results[0].typed<int>();
269  VArray<int> varray2 = results[1].typed<int>();
270 
271  EXPECT_EQ(varray1.get(0), 10);
272  EXPECT_EQ(varray1.get(1), 10);
273  EXPECT_EQ(varray2.get(0), 10);
274  EXPECT_EQ(varray2.get(1), 10);
275 }
276 
277 TEST(field, IgnoredOutput)
278 {
279  static OptionalOutputsFunction fn;
280  Field<int> field{std::make_shared<FieldOperation>(fn), 0};
281 
282  FieldContext field_context;
283  FieldEvaluator field_evaluator{field_context, 10};
284  VArray<int> results;
285  field_evaluator.add(field, &results);
286  field_evaluator.evaluate();
287 
288  EXPECT_EQ(results.get(0), 5);
289  EXPECT_EQ(results.get(3), 5);
290 }
291 
292 } // namespace blender::fn::tests
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
#define final(a, b, c)
Definition: BLI_hash.h:21
#define UNUSED(x)
Span< T > as_span() const
Definition: BLI_array.hh:231
MutableSpan< T > as_mutable_span()
Definition: BLI_array.hh:236
T get(const int64_t index) const
static VArray ForFunc(const int64_t size, GetFunc get_func)
void set_signature(const MFSignature *signature)
const MFSignature & signature() const
GVArray get_varray_for_context(const FieldContext &UNUSED(context), IndexMask mask, ResourceScope &UNUSED(scope)) const final
void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_gpu_kernel_postfix int ccl_global int * indices
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
static unsigned a[3]
Definition: RandGen.cpp:78
bool add(void *owner, const AttributeIDRef &attribute_id, eAttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer)
TEST(field, ConstantFunction)
Vector< GVArray > evaluate_fields(ResourceScope &scope, Span< GFieldRef > fields_to_evaluate, IndexMask mask, const FieldContext &context, Span< GVMutableArray > dst_varrays={})
Definition: field.cc:278
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
__int64 int64_t
Definition: stdint.h:89